commit 9d9fc756ca2c93c6f274965c654d92095c0ef1d3 Author: archive Date: Sun Sep 17 00:00:00 2000 +0000 as released 2000-09-17 diff --git a/bin/Mp3dec.asi b/bin/Mp3dec.asi new file mode 100644 index 0000000..89b7eb0 Binary files /dev/null and b/bin/Mp3dec.asi differ diff --git a/bin/Mss32.dll b/bin/Mss32.dll new file mode 100644 index 0000000..ca1dd5d Binary files /dev/null and b/bin/Mss32.dll differ diff --git a/bin/Radiant plugins/Fakk2Plug.dll b/bin/Radiant plugins/Fakk2Plug.dll new file mode 100644 index 0000000..369c1f6 Binary files /dev/null and b/bin/Radiant plugins/Fakk2Plug.dll differ diff --git a/bin/dlgedit.exe b/bin/dlgedit.exe new file mode 100755 index 0000000..6eb0e24 Binary files /dev/null and b/bin/dlgedit.exe differ diff --git a/bin/fontgen.exe b/bin/fontgen.exe new file mode 100755 index 0000000..e578516 Binary files /dev/null and b/bin/fontgen.exe differ diff --git a/bin/ftxconvert.exe b/bin/ftxconvert.exe new file mode 100755 index 0000000..ad520cf Binary files /dev/null and b/bin/ftxconvert.exe differ diff --git a/bin/lipsync.exe b/bin/lipsync.exe new file mode 100755 index 0000000..b62de51 Binary files /dev/null and b/bin/lipsync.exe differ diff --git a/bin/lw2tan.exe b/bin/lw2tan.exe new file mode 100755 index 0000000..4aeb514 Binary files /dev/null and b/bin/lw2tan.exe differ diff --git a/bin/max2plugins/animout.dle b/bin/max2plugins/animout.dle new file mode 100644 index 0000000..6e1dcbd Binary files /dev/null and b/bin/max2plugins/animout.dle differ diff --git a/bin/max2plugins/animout.ilk b/bin/max2plugins/animout.ilk new file mode 100644 index 0000000..797d58e Binary files /dev/null and b/bin/max2plugins/animout.ilk differ diff --git a/bin/max2plugins/skelout.dle b/bin/max2plugins/skelout.dle new file mode 100644 index 0000000..b01b102 Binary files /dev/null and b/bin/max2plugins/skelout.dle differ diff --git a/bin/max2plugins/skelout.ilk b/bin/max2plugins/skelout.ilk new file mode 100644 index 0000000..518ca12 Binary files /dev/null and b/bin/max2plugins/skelout.ilk differ diff --git a/bin/max2plugins/uvout.dle b/bin/max2plugins/uvout.dle new file mode 100644 index 0000000..131e58a Binary files /dev/null and b/bin/max2plugins/uvout.dle differ diff --git a/bin/max2skl.exe b/bin/max2skl.exe new file mode 100755 index 0000000..6408c23 Binary files /dev/null and b/bin/max2skl.exe differ diff --git a/bin/max2tan.exe b/bin/max2tan.exe new file mode 100755 index 0000000..e60ca70 Binary files /dev/null and b/bin/max2tan.exe differ diff --git a/bin/max3plugins/animout.dle b/bin/max3plugins/animout.dle new file mode 100644 index 0000000..74b3118 Binary files /dev/null and b/bin/max3plugins/animout.dle differ diff --git a/bin/max3plugins/animout.ilk b/bin/max3plugins/animout.ilk new file mode 100644 index 0000000..c6d28fa Binary files /dev/null and b/bin/max3plugins/animout.ilk differ diff --git a/bin/max3plugins/skelout.dle b/bin/max3plugins/skelout.dle new file mode 100644 index 0000000..f6404e8 Binary files /dev/null and b/bin/max3plugins/skelout.dle differ diff --git a/bin/max3plugins/skelout.ilk b/bin/max3plugins/skelout.ilk new file mode 100644 index 0000000..d9e60b8 Binary files /dev/null and b/bin/max3plugins/skelout.ilk differ diff --git a/bin/max3plugins/uvout.dle b/bin/max3plugins/uvout.dle new file mode 100644 index 0000000..974809b Binary files /dev/null and b/bin/max3plugins/uvout.dle differ diff --git a/bin/maxscripts/example.ms b/bin/maxscripts/example.ms new file mode 100644 index 0000000..dc4e9fc --- /dev/null +++ b/bin/maxscripts/example.ms @@ -0,0 +1,26 @@ +-- Always include this line. It defines the "exportskl" command. +include "o:\fakkutils\maxscripts\exportskl.ms" + +-- This is a comment. All comments begin with double dashes + +-- Because of some wierd behavior of slashes in filename strings, I +-- recommend you only use forwardslashes in filenames. That means +-- that "h:\hm\fakk\models\julie\walk_norm.skl" should be +-- written as "h:/hm/fakk/models/julie/walk_norm.skl". The +-- other alternative is to use double forward slashes ( "\\" ), +-- like this: "h:\\hm\\fakk\\models\\julie\\walk_norm.skl". +-- Choose whichever is easiest for you to do. + +-- The following line says to export froms 449 through 481 to the +-- file d:/winnt/profiles/jimdose/desktop/test.skl. Do this +-- for each animation you want to export. If you have a lot +-- of animations listed and only want to export some of them, +-- comment out lines that you don't need by placing a '--' in front +-- of them. + +exportskl "d:/winnt/profiles/jimdose/desktop/test.skl" 449 481 + +-- The command "exportsklf" tells Max to export the animation +-- at a different frame rate. The 3rd parameter after the filename +-- is the target frame rate. +exportsklf "d:/winnt/profiles/jimdose/desktop/test.skl" 449 481 10 \ No newline at end of file diff --git a/bin/maxscripts/exportskl.ms b/bin/maxscripts/exportskl.ms new file mode 100644 index 0000000..f703a1e --- /dev/null +++ b/bin/maxscripts/exportskl.ms @@ -0,0 +1,26 @@ +function exportskl name start end = +( +local range = animationRange + +-- HACK to prevent Max from crashing from a divide by zero. +if start == end then end = end + 0.1 + +animationRange = interval start end +exportFile name #noPrompt +animationRange = range +) + +function exportsklf name start end rate= +( +local range = animationRange +local oldrate = frameRate + +-- HACK to prevent Max from crashing from a divide by zero. +if start == end then end = end + 0.1 + +frameRate = rate +animationRange = interval start end +exportFile name #noPrompt +animationRange = range +frameRate = oldrate +) diff --git a/bin/maxscripts/jimtest.ms b/bin/maxscripts/jimtest.ms new file mode 100644 index 0000000..a7378db --- /dev/null +++ b/bin/maxscripts/jimtest.ms @@ -0,0 +1,56 @@ +animate on +lastpos = 0 +thepos = 0 +for t in 1920 to 1941 by 1 do + ( + format "Frame: % \t" t + + guysize=80 + bboxminy = -9 + 15 + horizminy = -9 + bboxminz = 118.5 + + at time t PelvisPos=$Bip01_Pelvis.objectTransform.pos + at time t $TAG_ORIGIN_MANUAL.pos.x=PelvisPos.x + if ( PelvisPos.y <= horizminy ) then + ( + format " One: %, %\t\t" PelvisPos.y horizminy + if ( lastpos == 2 ) then + ( + print "Last pos" + at time t $TAG_ORIGIN_MANUAL.pos.z=bboxminz + at time t $TAG_ORIGIN_MANUAL.pos.y=bboxminy + ) + else + ( + at time t $TAG_ORIGIN_MANUAL.pos.y=PelvisPos.y + + if ( PelvisPos.z - guysize <= bboxminz ) then + at time t $TAG_ORIGIN_MANUAL.pos.z=bboxminz + else + at time t $TAG_ORIGIN_MANUAL.pos.z=PelvisPos.z-guysize + + ) + lastpos = 1 + ) + else + ( + format " Two: %, %\t\t" PelvisPos.y horizminy + if ( PelvisPos.y <= bboxminy ) then + ( + thepos = bboxminy + at time t $TAG_ORIGIN_MANUAL.pos.y = bboxminy + ) + else + ( + thepos = PelvisPos.y + at time t $TAG_ORIGIN_MANUAL.pos.y=PelvisPos.y + ) + + at time t $TAG_ORIGIN_MANUAL.pos.z=PelvisPos.z-guysize + + lastpos = 2 + ) + + at time t format " Result: %\n" $TAG_ORIGIN_MANUAL.pos.y + ) diff --git a/bin/mcopy.exe b/bin/mcopy.exe new file mode 100755 index 0000000..09e6156 Binary files /dev/null and b/bin/mcopy.exe differ diff --git a/bin/newq3map.exe b/bin/newq3map.exe new file mode 100755 index 0000000..e9749ae Binary files /dev/null and b/bin/newq3map.exe differ diff --git a/bin/q3map.exe b/bin/q3map.exe new file mode 100755 index 0000000..6dd4fa3 Binary files /dev/null and b/bin/q3map.exe differ diff --git a/bin/q3radiant.exe b/bin/q3radiant.exe new file mode 100755 index 0000000..ee8e58f Binary files /dev/null and b/bin/q3radiant.exe differ diff --git a/bin/radiant.ini b/bin/radiant.ini new file mode 100644 index 0000000..8507cfb --- /dev/null +++ b/bin/radiant.ini @@ -0,0 +1,241 @@ +; Command mapping for QERadiant +; +; Syntax is as follows: +; Command name=+modifier+modifier +; +; Use +ALT, +SHIFT, and +CTRL to modify the keys +; +; Example: +; FileNew=N+CTRL +; +; Valid keys are: +; +; A-Z +; 0-9 +; ESCAPE +; TAB +; SPACE +; BACKSPACE +; RETURN +; INSERT +; DELETE +; HOME +; END +; PAGEUP +; PAGEDOWN +; UP +; DOWN +; LEFT +; RIGHT +; PLUS +; MINUS +; MULTIPLY +; DIVIDE +; COMMA +; PERIOD +; LBRACKET +; RBRACKET +; TILDE +; BKSLASH +; FWSLASH +; SEMICOLON +; QUOTE +; F1 +; F2 +; F3 +; F4 +; F5 +; F6 +; F7 +; F8 +; F9 +; F10 +; F11 +; F12 +; NUMPAD0 +; NUMPAD1 +; NUMPAD2 +; NUMPAD3 +; NUMPAD4 +; NUMPAD5 +; NUMPAD6 +; NUMPAD7 +; NUMPAD8 +; NUMPAD9 + + +[Commands] +;file menu +FileNew=N+CTRL +FileOpen=O+CTRL +FileSave=S+CTRL +;Exit= + +; edit menu +Undo=Z+CTRL +Copy=C+CTRL +Paste=V+CTRL +;Preferences= + +; view menu +NextView=TAB+CTRL +;ToggleCamera= +;ToggleConsole= +;ToggleEntity= +;ToggleZ= +CenterView=END +UpFloor=PAGEUP +DownFloor=PAGEDOWN +ZoomOut=INSERT +ZoomIn=DELETE +ZZoomOut=INSERT+CTRL +ZZoomIn=DELETE+CTRL +FilterWorldBrushes=1+ALT +FilterEntities=2+ALT +FilterPatches=3+ALT +FilterTranslucent4+ALT +FilterLiquids=5+ALT +FilterCaulk=6+ALT +FilterClips=7+ALT +FilterPaths=8+ALT +FilterAINodes=9+ALT +FilterLights=0+ALT +FilterDetails=D+CTRL +FilterHintsSkips=H+CTRL +FilterModels=M+CTRL +FilterAreaportals=P+CTRL +FilterTriggers=T+CTRL +CameraFromEntity=J+CTRL +CameraToEntity=J+CTRL+SHIFT +CameraGridMove=FWSLASH +;ToggleCubicClip= +CubicClipZoomOut=RBRACKET +CubicClipZoomIn=LBRACKET +ToggleSizePaint=Q+SHIFT +CenterXYFromCamera=X+ALT +; select menu +DragEdges=E +DragVertices=V +CloneSelection=SPACE +CloneSelectionExact=SPACE+CTRL +UnSelectSelection=ESCAPE +DeleteSelection=BACKSPACE +SelectCompleteEntity=E+CTRL +;SelectNextTarget= +;SelectAllOfType= +SelectSnapPointsToGrid=G+CTRL +SelectClampPlanePoints=G+CTRL+SHIFT +IncreaseLightmapDensity=RBRACKET+CTRL +DecreaseLightmapDensity=LBRACKET+CTRL +MouseRotate=R +MouseScale=L +;SelectScale= +ToggleClipper=X +FlipClip=TILDE +ClipSelected=RETURN +SplitSelected=RETURN+SHIFT +EntityColor=K +ConnectSelection=K+CTRL +MakeDetail=D+CTRL+SHIFT +MakeStructural=D+CTRL+ALT +ToggleDetail=D+CTRL+ALT+SHIFT + +; grid menu +SetGrid1=1 +SetGrid2=2 +SetGrid4=3 +SetGrid8=4 +SetGrid16=5 +SetGrid32=6 +SetGrid64=7 +;ToggleGrid= +;GridUp= +;GridDown= + +; texture menu +ShowAllTextures=A+CTRL +ShowInUseTextures=U +SurfaceInspector=S +CloseSurfDialog=ESCAPE+SHIFT +PatchInspector=P +TextureFit=F+CTRL +ToggleMoveLock=M+SHIFT +ToggleRotateLock=R+SHIFT + +; misc menu +NextLeakSpot=L+CTRL +PrevLeakSpot=L+SHIFT + +; brush menu +Brush3Sided=3+CTRL +Brush4Sided=4+CTRL +Brush5Sided=5+CTRL +Brush6Sided=6+CTRL +Brush7Sided=7+CTRL +Brush8Sided=8+CTRL +Brush9Sided=9+CTRL + +; curve menu +InvertCurve=I+CTRL +BendMode=B+CTRL +PatchTAB=TAB +TogglePatchOverlay=Y+CTRL +;MakeOverlayPatch= +;ClearPatchOverlays= +;RedisperseRows= +;RedisperseCols= +ThickenPatch=T+CTRL +;IncPatchColumn= +;IncPatchRow= +;DecPatchColumn= +;DecPatchRow= +IncreaseComplexity=RBRACKET+SHIFT +DecreaseComplexity=LBRACKET+SHIFT + +; commands not on the menu +ViewEntityInfo=N +ViewConsole=O +ViewTextures=T +ToggleCurveSelection=U+CTRL +CameraForward=UP +CameraBack=DOWN +CameraLeft=LEFT +CameraRight=RIGHT +CameraUp=D +CameraDown=C +CameraAngleUp=A +CameraAngleDown=Z +CameraStrafeRight=PERIOD +CameraStrafeLeft=COMMA +CameraGridForward=UP+CTRL +CameraGridBack=DOWN+CTRL +;CameraGridUp= +;CameraGridDown= +CameraGridStrafeRight=PERIOD+CTRL +CameraGridStrafeLeft=COMMA+CTRL +CameraFastForward=UP+SHIFT +CameraFastBack=DOWN+SHIFT +CameraFastUp=D+SHIFT +CameraFastDown=C+SHIFT +CameraFastStrafeRight=PERIOD+SHIFT +CameraFastStrafeLeft=COMMA+SHIFT +IncreaseLightRadius=RBRACKET+ALT +DecreaseLightRadius=LBRACKET+ALT +;TexShiftLeft= +;TexShiftRight= +;TexShiftUp= +;TexShiftDown= +;TexScaleLeft= +;TexScaleRight= +;TexScaleUp= +;TexScaleDown= +TexRotateClock=PAGEDOWN+SHIFT +TexRotateCounter=PAGEUP+SHIFT +TexDecrement=SUBTRACT+SHIFT +TexIncrement=ADD+SHIFT +MoveSelectionDown=SUBTRACT +MoveSelectionUp=ADD +SelectNudgeLeft=LEFT+ALT +SelectNudgeRight=RIGHT+ALT +SelectNudgeUp=UP+ALT +SelectNudgeDown=DOWN+ALT diff --git a/bin/runq3radiant.bat b/bin/runq3radiant.bat new file mode 100644 index 0000000..29918ac --- /dev/null +++ b/bin/runq3radiant.bat @@ -0,0 +1 @@ +q3radiant ..\fakk\scripts\fakk.qe4 \ No newline at end of file diff --git a/bin/tgaconvert.exe b/bin/tgaconvert.exe new file mode 100755 index 0000000..6029dbc Binary files /dev/null and b/bin/tgaconvert.exe differ diff --git a/docs/AI.doc b/docs/AI.doc new file mode 100644 index 0000000..c8474ca Binary files /dev/null and b/docs/AI.doc differ diff --git a/docs/CVAR DOCUMENTATION.doc b/docs/CVAR DOCUMENTATION.doc new file mode 100644 index 0000000..2a1ff70 Binary files /dev/null and b/docs/CVAR DOCUMENTATION.doc differ diff --git a/docs/Client Side Commands.doc b/docs/Client Side Commands.doc new file mode 100644 index 0000000..b8d79ab Binary files /dev/null and b/docs/Client Side Commands.doc differ diff --git a/docs/Coordinate System.doc b/docs/Coordinate System.doc new file mode 100644 index 0000000..c31e3eb Binary files /dev/null and b/docs/Coordinate System.doc differ diff --git a/docs/Description of Menus and Ingame Utils.doc b/docs/Description of Menus and Ingame Utils.doc new file mode 100644 index 0000000..da73cb8 Binary files /dev/null and b/docs/Description of Menus and Ingame Utils.doc differ diff --git a/docs/Dialog System.doc b/docs/Dialog System.doc new file mode 100644 index 0000000..4e4dd00 Binary files /dev/null and b/docs/Dialog System.doc differ diff --git a/docs/Dumping Demo AVI.doc b/docs/Dumping Demo AVI.doc new file mode 100644 index 0000000..ff4127c Binary files /dev/null and b/docs/Dumping Demo AVI.doc differ diff --git a/docs/Event Spec Documentation.doc b/docs/Event Spec Documentation.doc new file mode 100644 index 0000000..107c21d Binary files /dev/null and b/docs/Event Spec Documentation.doc differ diff --git a/docs/FAKK FAQ.doc b/docs/FAKK FAQ.doc new file mode 100644 index 0000000..89e70ef Binary files /dev/null and b/docs/FAKK FAQ.doc differ diff --git a/docs/GUI Documentation.doc b/docs/GUI Documentation.doc new file mode 100644 index 0000000..a661acb Binary files /dev/null and b/docs/GUI Documentation.doc differ diff --git a/docs/Ghost Particle System.doc b/docs/Ghost Particle System.doc new file mode 100644 index 0000000..e3e6cdb Binary files /dev/null and b/docs/Ghost Particle System.doc differ diff --git a/docs/Gibs.doc b/docs/Gibs.doc new file mode 100644 index 0000000..4d6bc53 Binary files /dev/null and b/docs/Gibs.doc differ diff --git a/docs/How to Make Weapons and Ammo.doc b/docs/How to Make Weapons and Ammo.doc new file mode 100644 index 0000000..5a1d7f6 Binary files /dev/null and b/docs/How to Make Weapons and Ammo.doc differ diff --git a/docs/Inventory System Commands.doc b/docs/Inventory System Commands.doc new file mode 100644 index 0000000..6fddcee Binary files /dev/null and b/docs/Inventory System Commands.doc differ diff --git a/docs/Items.doc b/docs/Items.doc new file mode 100644 index 0000000..ebcd04b Binary files /dev/null and b/docs/Items.doc differ diff --git a/docs/MAX2SKL Reference Guide.doc b/docs/MAX2SKL Reference Guide.doc new file mode 100644 index 0000000..9ba8b1a Binary files /dev/null and b/docs/MAX2SKL Reference Guide.doc differ diff --git a/docs/Radiant Commands.doc b/docs/Radiant Commands.doc new file mode 100644 index 0000000..60a476a Binary files /dev/null and b/docs/Radiant Commands.doc differ diff --git a/docs/Sound System.doc b/docs/Sound System.doc new file mode 100644 index 0000000..0c185ba Binary files /dev/null and b/docs/Sound System.doc differ diff --git a/docs/TIKI Model System.doc b/docs/TIKI Model System.doc new file mode 100644 index 0000000..542abbb Binary files /dev/null and b/docs/TIKI Model System.doc differ diff --git a/docs/Tiki QuakeEd Specs.doc b/docs/Tiki QuakeEd Specs.doc new file mode 100644 index 0000000..e2d7edf Binary files /dev/null and b/docs/Tiki QuakeEd Specs.doc differ diff --git a/docs/camera documentation.doc b/docs/camera documentation.doc new file mode 100644 index 0000000..70e107f Binary files /dev/null and b/docs/camera documentation.doc differ diff --git a/docs/commands.txt b/docs/commands.txt new file mode 100644 index 0000000..24b2b73 --- /dev/null +++ b/docs/commands.txt @@ -0,0 +1,273 @@ +COMMAND DOCUMENTATION +- Version 1.0, March 13, 2000 + + +Client Game +=========== + +cg_classlist +cg_classtree +cg_dumpevents +cg_eventhelp +cg_eventlist +cg_pendingevents + +AI/Routing/Actor stuff +========== + +ai_clearnodes +ai_load +ai_recalcpaths +ai_save +ai_savepaths +actor +actorinfo + +Client +====== + +cl_classlist +cl_classtree +cl_dumpevents +cl_eventhelp +cl_eventlist +cl_pendingevents +clientinfo +fov +rcon +reconnect + +Game Module +=========== + +cam +changeoutfit +classlist +classtree +dualwield +dumpevents +evaluatetorsoanim +eventhelp +eventlist +exec +gameversion +give +giveweapon +god +headtarget +kill +killclass +killent +noclip +notarget +pendingevents +removeclass +removeent +reset +resetstate +restart +script +showvar +snd +spawn +state +testthread +viewangles +viewanimate +viewattach +viewdelete +viewdeleteall +viewdetach +viewdetachall +viewmodel +viewnext +viewnextanim +vieworigin +viewpitch +viewpos +viewprev +viewprevanim +viewroll +viewscale +viewscaledown +viewscaleup +viewspawn +viewthingnext +viewthingprev +viewyaw +whatis +wuss + +Server +====== + +kick +killserver +pause +record +sectorlist +serverinfo +status +stoprecord +systeminfo + + +Sound +===== + +loadsoundtrack +play +playmp3 +playsong +snd_restart +soundinfo +soundlist +stopmp3 +stopsound + +Network +======= +changeVectors +configstrings +globalservers +localservers +heartbeat +net_restart + + +Renderer +======== + +gfxinfo +imagelist +modelist +shaderlist +skinlist +vidmode + + +Input System +============ + ++attack ++attackleft ++attackright ++back ++button0 ++button1 ++button2 ++button3 ++button4 ++button5 ++button6 ++cameralook ++forward ++holster ++info ++left ++lookdown ++lookup ++mlook ++movedown ++moveleft ++moveright ++moveup ++right ++scores ++sneak ++speed ++strafe ++togglemouse ++use +centerview +in_restart +midiinfo + +User Interface +============== + +dumpemitter +editscript +editshader +inv_restart +inventory +invnext +invprev +invuse +listinventory +listmenus +loadmenu +notepad +pushmenu +soundpicker +testcenterprint +testemitter +togglemenu +ui_hidemouse +ui_loadconsolepos +ui_saveconsolepos +ui_showmouse +ui_testlist +usedualwield +warpinv + +File System +=========== + +cd +dir +path +touchFile + +General / Common +======= + +add +alias +bind +bindlist +clear +cmd +connect +cvar_restart +cvarlist +demo +devmap +disconnect +dumpuser +echo +map +map_restart +maplist +meminfo +modellist +nextframe +nextskin +ping +prevframe +prevskin +quit +scale +set +seta +setenv +sets +setu +subtract +testmodel +tiki +tikilist +toggle +unbind +unbindall +vstr +wait +writeconfig + +Video System +============ + +screenshot +sizedown +sizeup +vid_restart \ No newline at end of file diff --git a/docs/shader_manual_new.doc b/docs/shader_manual_new.doc new file mode 100644 index 0000000..2bca65e Binary files /dev/null and b/docs/shader_manual_new.doc differ diff --git a/entities/entities.def b/entities/entities.def new file mode 100644 index 0000000..76c0098 --- /dev/null +++ b/entities/entities.def @@ -0,0 +1,1194 @@ +/*QUAKED func_beam (0 0.25 .5) (-8 -8 -8) (8 8 8) START_ON PERSIST WAVE NOISE + +This creates a beam effect from the origin to the target's origin. If no +target is specified, uses angles and projects beam out from there. + +"model" Specifies the model to use as the beam +"overlap" Specifies the amount of overlap each beam link should have. Use this to fill +in the cracks when using electric on beams. (Default is 0) +"minoffset" Minimum amount of electrical variation (Default is 0) +"maxoffset" Maximum amount of electrical variation (Default is 5) +"color" Vector specifiying the red,green, and blue components. (Default is "1 1 1") +"alpha" Alpha of the beam (Default is 1.0) +"damage" Amount of damage the beam inflicts if beam hits someone (Default is 0) +"angles" Sets the angle of the beam if no target is specified. +"life" Sets the life of the beam for use with the persist spawnflag. This is how long a beam will +be displayed. +"numsegments" Number of segments in a beam (Default is 4) +"delay" Delay between beam updates. (i.e. slows the effect of the beam down) +"shader" Set the shader of the beam +"scale" Set the width of the beam + +START_ON - Starts the beam on +PERSIST - Keeps the last few beams around and fades them out over the life of the beam +WAVE - Make the beam follow a sin wave pattern +NOISE - Use a more computationally expensive random effect, but the results are smoother + +If the model field is not set, then a renderer generated beam will be created +using the color, minoffset, maxoffset, scale, and subdivisions fields + +If the targetname is set, it will use the target specified as the endpoint of the beam + +/*****************************************************************************/ + + +/*QUAKED func_rotatingdoor (0 0.25 0.5) ? START_OPEN OPEN_DIRECTION DOOR_DONT_LINK NOT_PLAYERS NOT_MONSTERS TOGGLE AUTO_OPEN TARGETED +if two doors touch, they are assumed to be connected and operate as a unit. + +TOGGLE causes the door to wait in both the start and end states for a trigger event. +DOOR_DONT_LINK is for when you have two doors that are touching but you want to operate independently. + +START_OPEN causes the door to move to its destination when spawned, and operate in reverse. It is used to temporarily or permanently close off an area when triggered (not usefull for touch or takedamage doors). +OPEN_DIRECTION indicates which direction to open when START_OPEN is set. +AUTO_OPEN causes the door to open when a player is near instead of waiting for the player to use the door. +TARGETED door is only operational from triggers or script + +"message" is printed when the door is touched if it is a trigger door and it hasn't been fired yet +"openangle" how wide to open the door +"angle" determines the opening direction. point toward the middle of the door (away from the hinge) +"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 +"time" move time (0.3 default) +"wait" wait before returning (3 default, -1 = never return) +"dmg" damage to inflict when blocked (0 default) +"key" The item needed to open this door (default nothing) + +"sound_stop" Specify the sound that plays when the door stops moving (default global door_stop) +"sound_move" Specify the sound that plays when the door opens or closes (default global door_moving) +"sound_message" Specify the sound that plays when the door displays a message +"sound_locked" Specify the sound that plays when the door is locked + +******************************************************************************/ + + +/*QUAKED func_door (0 0.25 0.5) ? START_OPEN x DOOR_DONT_LINK NOT_PLAYERS NOT_MONSTERS TOGGLE AUTO_OPEN TARGETED +if two doors touch, they are assumed to be connected and operate as a unit. + +TOGGLE causes the door to wait in both the start and end states for a trigger event. +DOOR_DONT_LINK is for when you have two doors that are touching but you want to operate independently. + +START_OPEN causes the door to move to its destination when spawned, and operate in reverse. It is used to temporarily or permanently close off an area when triggered (not usefull for touch or takedamage doors). +OPEN_DIRECTION indicates which direction to open when START_OPEN is set. +AUTO_OPEN causes the door to open when a player is near instead of waiting for the player to use the door. +TARGETED door is only operational from triggers or script + +"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. point toward the middle of the door (away from the hinge) +"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" move speed (100 default) +"time" move time (1/speed default, overides speed) +"wait" wait before returning (3 default, -1 = never return) +"lip" lip remaining at end of move (8 default) +"dmg" damage to inflict when blocked (0 default) +"key" The item needed to open this door (default nothing) + +"sound_stop" Specify the sound that plays when the door stops moving (default global door_stop) +"sound_move" Specify the sound that plays when the door opens or closes (default global door_moving) +"sound_message" Specify the sound that plays when the door displays a message +"sound_locked" Specify the sound that plays when the door is locked + +******************************************************************************/ + + +/*QUAKED script_door (0 0.5 1) ? START_OPEN x DOOR_DONT_LINK NOT_PLAYERS NOT_MONSTERS TOGGLE AUTO_OPEN TARGETED +if two doors touch, they are assumed to be connected and operate as a unit. + +TOGGLE causes the door to wait in both the start and end states for a trigger event. +DOOR_DONT_LINK is for when you have two doors that are touching but you want to operate independently. + +START_OPEN causes the door to move to its destination when spawned, and operate in reverse. It is used to temporarily or permanently close off an area when triggered (not usefull for touch or takedamage doors). +OPEN_DIRECTION indicates which direction to open when START_OPEN is set. +AUTO_OPEN causes the door to open when a player is near instead of waiting for the player to use the door. +TARGETED door is only operational from triggers or script + +"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. point toward the middle of the door (away from the hinge) +"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" move speed (100 default) +"time" move time (1/speed default, overides speed) +"wait" wait before returning (3 default, -1 = never return) +"dmg" damage to inflict when blocked (0 default) +"key" The item needed to open this door (default nothing) +"initthread" code to execute to setup the door (optional) +"openthread" code to execute when opening the door (required) + The openthread should send the "dooropened" event to the door, when it is completely open +"closethread" code to execute when closing the door (required) + The closethread should send the "doorclosed" event to the door, when it is completely closed + +"sound_stop" Specify the sound that plays when the door stops moving (default global door_stop) +"sound_move" Specify the sound that plays when the door opens or closes (default global door_moving) +"sound_message" Specify the sound that plays when the door displays a message +"sound_locked" Specify the sound that plays when the door is locked + +******************************************************************************/ + + +/*QUAKED func_earthquake (0 0.25 0.5) (-8 -8 -8) (8 8 8) NO_RAMPUP NO_RAMPDOWN + Causes an earthquake +"duration" is the duration of the earthquake. Default is 0.8 seconds. +"magnitude" severity of the quake. Default 1.0 +******************************************************************************/ + + +/*QUAKED func_exploder (0 0.25 0.5) (0 0 0) (8 8 8) + + Spawns an explosion when triggered. Triggers any targets. + + "dmg" specifies how much damage to cause. Default indicates 120. + "key" The item needed to activate this. (default nothing) + "thread" name of thread to trigger. This can be in a different script file as well\ +by using the '::' notation. +******************************************************************************/ + + +/*QUAKED func_multi_exploder (0 0.25 0.5) ? MULTI_USE RANDOM_TIME VISIBLE RANDOM_SCALE + + Spawns an explosion when triggered. Triggers any targets. + size of brush determines where explosions will occur. + + "dmg" specifies how much damage to cause from each explosion. (Default 120) + "delay" delay before exploding (Default 0 seconds) + "duration" how long to explode for (Default 1 second) + "wait" time between each explosion (default 0.25 seconds) + "random" random factor (default 0.25) + "key" The item needed to activate this. (default nothing) + "thread" name of thread to trigger. This can be in a different script file as well\ +by using the '::' notation. + "health" makes the object damageable + "scale" set the maximum size for spawned debris and explosions. + + MULTI_USE allows the func_multi_exploder to be used more than once + RANDOM_TIME adjusts the wait between each explosion by the random factor + VISIBLE allows you to make the trigger visible + RANDOM_SCALE scale explosions randomly. size will be between 0.25 and 1 times scale + +******************************************************************************/ + + +/*QUAKED func_explodeobject (0 0.25 0.5) ? MULTI_USE RANDOM_TIME VISIBLE RANDOM_SCALE NO_EXPLOSIONS METAL_DEBRIS ROCK_DEBRIS NOTSOLID + + Spawns different kinds of debris when triggered. Triggers any targets. + size of brush determines where explosions and debris will be spawned. + + "dmg" specifies how much damage to cause from each explosion. (Default 120) + "delay" delay before exploding (Default 0 seconds) + "duration" how long to explode for (Default 1 second) + "wait" time between each explosion (default 0.25 seconds) + "random" random factor (default 0.25) + "health" if specified, object must be damaged to trigger + "key" The item needed to activate this. (default nothing) + "severity" how violent the debris should be ejected from the object( default 1.0 ) + "debrismodel" What kind of debris to spawn (default nothing) + "amount" how much debris to spawn for each explosion (default 4) + "thread" name of thread to trigger. This can be in a different script file as well\ +by using the '::' notation. + "health" makes the object damageable + "scale" set the maximum size for spawned debris and explosions + + MULTI_USE allows the func_explodeobject to be used more than once + RANDOM_TIME adjusts the wait between each explosion by the random factor + VISIBLE allows you to make the trigger visible + RANDOM_SCALE scale explosions and debris randomly. size will be between 0.25 and 1 times scale + NO_EXPLOSIONS, if checked no explosions will be created + METAL_DEBRIS automatically spawn metal debris, no need for debrismodel to be set + ROCK_DEBRIS automatically spawn rock debris, no need for debrismodel to be set + NOTSOLID debris is not solid + + other valid tiki files include: + + obj_debris_glass1-4.tik + obj_debris_wood1-4.tik + +******************************************************************************/ + + +/*QUAKED info_grav_pathnode (0 0 .5) (-16 -16 0) (16 16 32) HEADNODE FORCE PULL_UPWARDS + "radius" Radius of the effect of the pull (Default is 256) + "speed" Speed of the pull (Use negative for a repulsion) (Default is 100) + + Set HEADNODE to signify the head of the path. + Set FORCE if you want un-fightable gravity ( i.e. can't go backwards ) + Set PULL_UPWARDS if you want the gravnodes to pull you upwards also +******************************************************************************/ + + +/*QUAKED light (0.75 0.5 0) (-8 -8 -8) (8 8 8) LINEAR NO_ENTITIES ENTITY_TRACE + +Non-displayed light. If it targets another entity it will become a spot light +if "LINEAR" is set, it will be a linear light +if "NO_ENTITIES" is set, this light will only effect the world, not entities +if "ENTITY_TRACE" is set, a trace is done betwee the light and the entity.\ +The light is only added if the trace is clear + +"no_entity_light" - this light will not effect entities, just the world +"light" - the intensity of the light, default 300 +"color" - the color of the light +"falloff" - if linear, specify the linear falloff (defaults to 1) +"radius" - make this a spot light of the given radius +"angles" - make this a spot light centered on angles +"spot_angle" - if this is a spot light, what angle to use (default 45) +"entity_trace" - trace between the entity and the light + +******************************************************************************/ + + +/*QUAKED detail (0.5 0 1.0) ? + +Used to fake detail brushes, convenient for grouping + +******************************************************************************/ + + +/*QUAKED func_group (0.5 0.5 0.5) ? + +Used to group brushes together just for editor convenience. + +******************************************************************************/ + + +/*QUAKED func_remove (0.75 0.75 0.75) ? + +Used for lighting and such + +******************************************************************************/ + + +/*QUAKED misc_model (1 0.5 1) (0 0 0) (0 0 0) +"model" arbitrary .tik file to display +******************************************************************************/ + + +/*QUAKED info_null (0 0.5 0) (-4 -4 -4) (4 4 4) + +Used as a positional target for spotlights, etc. + +******************************************************************************/ + + +/*QUAKED info_notnull (0 0.5 0) (-4 -4 -4) (4 4 4) + +Used as a positional target for lightning. + +******************************************************************************/ + + +/*QUAKED func_explodingwall (0 0.25 0.5) ? RANDOMANGLES LANDSHATTER NOT_PLAYERS MONSTERS PROJECTILES INVISIBLE ACCUMALATIVE TWOSTAGE + +Blows up on activation or when attacked + +"explosions" number of explosions to spawn ( default 1 ) +"land_angles" The angles you want this piece to\ + orient to when it lands on the ground +"land_radius" The distance of the ground the piece\ + should be when on the ground ( default 16 ) +"anglespeed" Speed at which pieces rotate ( default 100 ) \ + if RANDOMANGLES ( default is 600 ) +"key" The item needed to activate this. (default nothing) +"base_velocity" The speed that the debris will have when triggered. (default 0 0 280) +"random_velocity" The variation of the velocity. x & y will be from -n < X,Y < n and z is 0 <= Z < n. (default 140 140 140) + + +IF RANDOMANGLES is set, object randomly spins while in the air. +IF LANDSHATTER is set, object shatters when it hits the ground. +IF TWOSTAGE is set, object can be shattered once it lands on the ground. +IF ACCUMALATIVE is set, damage is accumlative not threshold +IF INVISIBLE is set, these are invisible and not solid until triggered +If NOT_PLAYERS is set, the trigger does not respond to players +If MONSTERS is set, the trigger will respond to monsters +If PROJECTILES is set, the trigger will respond to projectiles (rockets, grenades, etc.) + +******************************************************************************/ + + +/*QUAKED trigger_teleport (0.5 0.5 0.5) ? VISIBLE x NOT_PLAYERS NOT_MONSTERS NOT_PROJECTILES NO_EFFECTS + +Touching this entity will teleport players to the targeted object. + +"key" The item needed to activate this. (default nothing) + +"teleportthread" The thread that is run when the player is teleported + +If NOT_PLAYERS is set, the teleporter does not teleport players +If NOT_MONSTERS is set, the teleporter does not teleport monsters +If NOT_PROJECTILES is set, the teleporter does not teleport projectiles (rockets, grenades, etc.) +If NO_EFFECTS is set, the special effect will not happen and the teleport will be instant + +******************************************************************************/ + + +/*QUAKED func_teleportdest (0 0.25 0.5) (-32 -32 0) (32 32 8) + +Point trigger_teleport at these. + +******************************************************************************/ + + +/*QUAKED func_useanim (0 0.5 0) ? VISIBLE TOUCHABLE CONTINUOUS + +This object allows you to place the player into a specific animation for the +purposes of using an object within the world. + +This object should point at a func_useanimdest which contains specific +information about how the player is supposed to be posed. + +"count" - how many times this should trigger (default -1, infinite) +"thread" - thread to fire when used +"triggertarget" - what to trigger when used. +"delay" - how long it takes to be re-triggered ( default 3 seconds ) +"key" - item needed to activate this + +VISIBLE - if this is checked the trigger itself will be visible +TOUCHABLE - if this is set we can activate the trigger by standing in it. +CONTINUOUS - if this is checked the thing will re-trigger continously, otherwise +it waits until the player has left the trigger field. + +******************************************************************************/ + + +/*QUAKED func_useobject (0 0.5 0) ? MULTI-STATE + +Allows you to setup a special object that places the player into a specific state +sequence. Primarily used for levers and cranks. + +Object starts out in the "start" animation, when used the following occurs: + +It is determined whether or not the player is in the right position to activate +the object, if it is, the player is moved to the exact offset and angle specified +by "offset" and "yaw_offset". The right position is determined by a dot product +with "offset" and "yaw_offset". The "cone" parameter controls the cone in which the +object can be triggered. Once the player is in the right position, the player is placed +into "state" and the "move" animation is played. Once the player animation ends, the +"move_thread" will be called. If the use button is continued to be held down and count +is not finite, the animation will be continued to be played until the use key is held +down. Once the use key is let go, the "stop" animation will be played on the lever and +the "stop_thread" will be called. + +"activate" - turns the useobject on +"deactivate" - turns the useobject off +"offset" - vector offset of where the player should stand +"state" - state to go into when used +"state_backwards" - what state to use when reversing the object +"yaw_offset" - what direction the player should be facing when using the object +"cone" - the cone in which the object can be used +"count" - how many times this should trigger (default -1, infinite) +"move_thread" - thread that is fired when the object has cycled one animation +"stop_thread" - thread that is fired when the object has finished animating +"reset_thread" - thread that is fired when the object is resetting itself +"reset_time" - the time it takes for the object to reset, (default 0, it doesn't) +"triggertarget" - target to trigger when finished animating, if reset_time is set, target +will be fired again when resetting +"damage_type" - if set, can be triggered by using a weapon to activate it. If set to "all", +any damage will activate it. + +MULTI-STATE - the object has two different states and must be used each time to set the state +when multi state is active, the reset_thread is called instead of stop_thread. All UseObjects +have two states on and off. When reset_time is set, the object will automatically return to the +off state after a preset amount of time. When multi-state is set this must be done manually. + +******************************************************************************/ + + +/*QUAKED info_waypoint (0 0.5 0) (-8 -8 -8) (8 8 8) + +Used as a positioning device for objects + +******************************************************************************/ + + +/*QUAKED func_monkeybars (0.75 0.75 0.75) ? + +Monkey bars + +******************************************************************************/ + + +/*QUAKED func_horizontalpipe (0.75 0.75 0.75) ? + +Horizontal pipe that play can crawl upside down on. + +******************************************************************************/ + + +/*QUAKED func_pushobject (0.75 0.75 0.75) ? + +Pushable object + +"dmg" how much damage to cause when blocked. (default 2) +"pushsound" Sound to play when object is pushed (default is none) + +******************************************************************************/ + + +/*QUAKED func_fallingrock (0.75 0.75 0.75) ? AUTO_RESET NO_RANDOMNESS REMOVE_ON_GROUND + +Creates a rock that, when triggered, begins falling and bounces along a path +specified by targetname. Use info_waypoint for the path. + +"targetname" the path to follow. +"dmg" how much damage to cause creatures it hits (default 20). +"speed" how fast to move (default 200). +"wait" how long to wait before falling when triggered (default 0). +"noise" sound to play when rock touches the world + +AUTO_RESET - when done falling, automatically return to the start +NO_RANDOMNESS - don't use any randomness when making the rocks fall +REMOVE_ON_GROUND - remove the rocks when done + +******************************************************************************/ + + +/*QUAKED func_supplywater (0.75 0.75 0.75) ? x x NOT_PLAYERS MONSTERS PROJECTILES + +Creates a trigger than when touched gives the player water over a continuous time + +"wait" - how long to wait before re-triggering ( default 0.1 seconds ) +"amount" - how much water to give player on each trigger ( default 1 unit ) +"maxwater" - what the maximum amount of water this supply should charge the player to ( default 50 ) + +If NOT_PLAYERS is set, the trigger does not respond to players +If MONSTERS is set, the trigger will respond to monsters +If PROJECTILES is set, the trigger will respond to projectiles (rockets, grenades, etc.) + +******************************************************************************/ + + +/*QUAKED func_emitter (0 0.25 0.5) ? + +"emitter" - Name of emitter to use. +******************************************************************************/ + + +/*QUAKED func_rain (0 0.25 0.5) ? + +This creates a raining effect in the brush + +"emitter" - Name of emitter to use for the rain. +******************************************************************************/ + + +/*QUAKED info_pathnode (1 0 0) (-24 -24 0) (24 24 32) FLEE DUCK COVER DOOR JUMP LADDER + +FLEE marks the node as a safe place to flee to. Actor will be removed when it reaches a flee node and is not visible to a player. + +DUCK marks the node as a good place to duck behind during weapon fire. + +COVER marks the node as a good place to hide behind during weapon fire. + +DOOR marks the node as a door node. If an adjacent node has DOOR marked as well, the actor will only use the path if the door in between them is unlocked. + +JUMP marks the node as one to jump from when going to the node specified by target. +"target" the pathnode to jump to. + +******************************************************************************/ + + +/*QUAKED func_throwobject (0 0.25 0.5) (-16 -16 0) (16 16 32) + +This is an object you can pickup and throw at people +******************************************************************************/ + + +/*QUAKED info_player_start (0.75 0.75 0) (-16 -16 0) (16 16 96) + +The normal starting point for a level. + +"angle" - the direction the player should face +"thread" - the thread that should be called when spawned at this position + +******************************************************************************/ + + +/*QUAKED info_player_deathmatch (0.75 0.75 1) (-16 -16 0) (16 16 96) + +potential spawning position for deathmatch games + +"angle" - the direction the player should face +"thread" - the thread that should be called when spawned at this position + +******************************************************************************/ + + +/*QUAKED info_player_intermission (0.75 0.75 0) (-16 -16 0) (16 16 96) + +viewing point in between deathmatch levels + +******************************************************************************/ + + +/*QUAKED portal_surface (1 0 1) (-8 -8 -8) (8 8 8) +The portal surface nearest this entity will show a view from the targeted portal_camera, or a mirror view if untargeted. +*/ + + +/*QUAKED portal_camera (1 0 1) (-8 -8 -8) (8 8 8) slowrotate fastrotate +The target for a portal_surface. You can set either angles or target another entity to determine the direction of view. +"roll" an angle modifier to orient the camera around the target vector; +*/ + + +/*QUAKED func_rope (0.0 0.25 0.5) ? + +The rope is defined by a bounding box. The top of the box denotes the top of the rope and +the bottom of the rope is denoted by the bottom of the box. The width of the box determines +the trigger field in which the player will hang on to the rope when grabbing it. + +"ropeshader" : Name of the shader to use to render the rope (default is "ropeshader") +*/ + + +/*QUAKED func_rope_piece (0.0 0.25 0.5) (-16 -16 -16) (16 16 16) WIGGLE ATT_WIGGLE +Rope Piece - A single piece of a rope + +WIGGLE : Makes this piece of the rope wiggle about randomly. Only does this while not attached. + +ATT_WIGGLE : Makes this piece of the rope wiggle around even while attached. WIGGLE must also be marked for this to work. + +"target" : the "targetname" of the next piece in the rope. This should be blank if it's the last piece in the rope. +If a non-rope_piece entity is targeted, it will attach itself to it. + +"targetname" : used for the previous piece in the rope to find and link to this piece of the rope. + +"target2" : the targetname of the entity to attach this piece of the rope to. +Any piece of a rope can be attached to something and be triggered at any time to detach it. +Triggering the base of an attached rope will detach all attached points on that rope. + +"wigglemove" : the amount of force the random wiggling has. + Default = 32 + +"wiggletime" : number of seconds between each time the rope wiggles. + Default = 0.5 + +All other settings are set in the rope's rope_base entity. +*/ + + +/*QUAKED func_rope_base (0.0 0.25 0.5) (-16 -16 -16) (16 16 16) START_STILL +Rope Base - the main control and top end attachment entity for ropes + +This entity is the point to where ropes attach their top end. It's a stationary point entity. +All setting for the whole rope are specified through this entity. +If you want/need to trigger a rope to do something, then this is the entity to trigger. +Trying to trigger a rope_piece will do nothing. + +START_STILL : Specifies that the whole rope will be completely stationary untill it is either triggered, or grabbed. + +"targetname" : The name that the rope is triggered with. + +"target" : The "targetname" of the first rope_piece in the rope. + +"piecelength" : The distance between each piece of the rope. + Default = 24 + +"piecemodel" : The model to use for the rope pieces. + +"ropedampener" : Horizontal velocity dampener for the rope. + Default = 0.8 + +"stiffness" : Movement restricter on the amount that the rope can flex and bend. +Valid values are from -1 (no restriction) to 1 (tried to be perfectly straight. +The position of the first rope piece determines what direction the rope is pushed from the base of the rope. + Default = -1 + +"strength" : How strongly a stiff rope goes to position. + Default = 1; + +"attachmodel" : name of a model to attach onto this piece of rope + +"ropeshader" : Name of the shader to use to render the rope (default is "ropeshader") +*/ + + +/*QUAKED script_object (0 0.5 1) ? NOT_SOLID + +******************************************************************************/ + + +/*QUAKED script_model (0 0.5 1) (0 0 0) (0 0 0) NOT_SOLID + +******************************************************************************/ + + +/*QUAKED script_origin (1.0 0 0) (-8 -8 -8) (8 8 8) + +Used as an alternate origin for objects. Bind the object to the script_origin +in order to simulate changing that object's origin. +******************************************************************************/ + + +/*QUAKED script_skyorigin (1.0 0 0) ? + +Used to specify the origin of a portal sky +******************************************************************************/ + + +/*QUAKED func_spawn(0 0.25 0.5) (-8 -8 -8) (8 8 8) +"modelname" The name of the TIKI file you wish to spawn. (Required) +"spawntargetname" This will be the targetname of the spawned model. (default is null) +"spawntarget" This will be the target of the spawned model. (default is null) +"pickup_thread" passed on to the spawned model +"key" The item needed to activate this. (default nothing) +"attackmode" Attacking mode of the spawned actor (default 0) +******************************************************************************/ + + +/*QUAKED func_randomspawn(0 0.25 0.5) (-8 -8 -8) (8 8 8) START_OFF +Randomly spawns an entity. The time between spawns is determined by min_time and max_time +The entity can be turned off and on by triggering it +"modelname" The name of the TIKI file you wish to spawn. (Required) +"key" The item needed to activate this. (default nothing) +"min_time" The minimum time between spawns (default 0.2 seconds) +"max_time" The maximum time between spawns (default 1 seconds) +START_OFF - spawn is off by default +******************************************************************************/ + + +/*QUAKED func_respawn(0 0.25 0.5) (-8 -8 -8) (8 8 8) +When the thing that is spawned is killed, this func_respawn will get +triggered. +"modelname" The name of the TIKI file you wish to spawn. (Required) +"key" The item needed to activate this. (default nothing) +******************************************************************************/ + + +/*QUAKED func_spawnoutofsight(0 0.25 0.5) (-8 -8 -8) (8 8 8) +Will only spawn something out of sight of its targets. +"modelname" The name of the TIKI file you wish to spawn. (Required) +"spawntargetname" This will be the targetname of the spawned model. (default is null) +"spawntarget" This will be the target of the spawned model. (default is null) +"key" The item needed to activate this. (default nothing) +******************************************************************************/ + + +/*QUAKED func_spawnchain(0 0.25 0.5) (-8 -8 -8) (8 8 8) +Tries to spawn something out of the sight of players. If it fails, it will +trigger its targets. +"modelname" The name of the TIKI file you wish to spawn. (Required) +"spawntargetname" This will be the targetname of the spawned model. (default is null) +"spawntarget" This will be the target of the spawned model. (default is null) +"key" The item needed to activate this. (default nothing) +******************************************************************************/ + + +/*QUAKED func_fulcrum (0 0 1) ? X_AXIS_ONLY Y_AXIS_ONLY + +This creates a fulcrum that when you stand on it, it will rotate due to +the weight exerted it will start rotating, when not standing on it, it +will return to its rest position. +"speed" - set the speed at which the fulcrum will operate (default is 48) +"resetspeed" - speed at whcih fulcrum resets, (default speed * 0.002) +"dampening" - dampen constant (default 0.95) +"limit" - limit the movement of the fulcrum (default 90 degrees) +"movesound" - sound to be played while fulcrum is moving + +X_AXIS_ONLY - only adjust the X axis +Y_AXIS_ONLY - only adjust the Y axis + +******************************************************************************/ + + +/*QUAKED func_runthrough (0 0 1) ? + +This is a trigger field that the player can run through and spawn tiki models +at that position. Used for releasing chaff from grass or butterflys from +flower gardens +"speed" - speed at which you have to be moving to trigger ( default 100 ) +"delay" - time between triggering ( default 0.1 ) +"chance" - chance that the trigger will spawn something( default 0.5 ) +"lip" - how far below the surface of the trigger we should spawn these things ( default 3 ) +"offset" - vector offset oriented along velocity vector( default "0 0 0" ) +"spawnmodel" - thing to spawn when triggered + +******************************************************************************/ + + +/*QUAKED func_sinkobject (0 0 1) ? x FALLAWAY NO_RESET + +This creates an object which gradually sinks downward when stepped on. +"delay" - delay between when object starts reacting towards weight (default 0 seconds) +"speed" - set the speed at which sinkobject sinks (default is 50) +"resetspeed" - speed at which sinkobject resets its position, (default speed * 0.1) +"dampening" - dampening constant to mitigate acceleration (default 0.95) +"limit" - limit the movement of the sinkobject how far down it should go (default 1000 units) +"resetdelay" - time between player gets off platform, and platform starts resetting itself. +"sinksound" - sound to be played while platform is sinking. +"resetsound" - sound to be played while platform is resetting. +"active" - make the sink object active +"notactive" - make the sink object not active + +FALLAWAY - the sink object will progressively fall down faster and faster +NO_RESET - the sink object will not reset, only move downward + +******************************************************************************/ + + +/*QUAKED trigger_multiple (1 0 0) ? x x NOT_PLAYERS MONSTERS PROJECTILES + +Variable sized repeatable trigger. Must be targeted at one or more entities. + +If "health" is set, the trigger must be killed to activate each time. +If "delay" is set, the trigger waits some time after activating before firing. + +"thread" name of thread to trigger. This can be in a different script file as well\ +by using the '::' notation. + +if "angle" is set, the trigger will only fire when someone is facing the +direction of the angle. +"cone" the cone in which a directed trigger can be triggered (default 60 degrees) + +"wait" : Seconds between triggerings. (.2 default) +"cnt" how many times it can be triggered (infinite default) + +"triggerable" turn trigger on +"nottriggerable" turn trigger off + +If NOT_PLAYERS is set, the trigger does not respond to players +If MONSTERS is set, the trigger will respond to monsters +If PROJECTILES is set, the trigger will respond to projectiles (rockets, grenades, etc.) + +set "message" to text string + +******************************************************************************/ + + +/*QUAKED trigger_once (1 0 0) ? NOTOUCH x NOT_PLAYERS MONSTERS PROJECTILES + +Variable sized trigger. Triggers once, then removes itself. +You must set the key "target" to the name of another object in the +level that has a matching + +If "health" is set, the trigger must be killed to activate it. +If "delay" is set, the trigger waits some time after activating before firing. + +"targetname". If "health" is set, the trigger must be killed to activate. + +"thread" name of thread to trigger. This can be in a different script file as well\ +by using the '::' notation. + +if "killtarget" is set, any objects that have a matching "target" will be +removed when the trigger is fired. + +if "angle" is set, the trigger will only fire when someone is facing the +direction of the angle. +"cone" the cone in which a directed trigger can be triggered (default 60 degrees) + +"key" The item needed to activate this. (default nothing) + +"triggerable" turn trigger on +"nottriggerable" turn trigger off + +If NOTOUCH is set, trigger will not respond to touch +If NOT_PLAYERS is set, the trigger does not respond to players +If MONSTERS is set, the trigger will respond to monsters +If PROJECTILES is set, the trigger will respond to projectiles (rockets, grenades, etc.) + +set "message" to text string + +******************************************************************************/ + + +/*QUAKED trigger_relay (1 0 0) (-8 -8 -8) (8 8 8) x x NOT_PLAYERS MONSTERS PROJECTILES + +This fixed size trigger cannot be touched, it can only be fired by other events. +It can contain killtargets, targets, delays, and messages. + +If NOT_PLAYERS is set, the trigger does not respond to events triggered by players +If MONSTERS is set, the trigger will respond to events triggered by monsters +If PROJECTILES is set, the trigger will respond to events triggered by projectiles (rockets, grenades, etc.) + +******************************************************************************/ + + +/*QUAKED trigger_secret (1 0 0) ? NOTOUCH x NOT_PLAYERS MONSTERS PROJECTILES +Secret counter trigger. Automatically sets and increments script variables \ +level.total_secrets and level.found_secrets. + +set "message" to text string + +"key" The item needed to activate this. (default nothing) + +if "angle" is set, the trigger will only fire when someone is facing the +direction of the angle. +"cone" the cone in which a directed trigger can be triggered (default 60 degrees) + +"thread" name of thread to trigger. This can be in a different script file as well \ +by using the '::' notation. (defaults to "global/universal_script.scr::secret") + +"triggerable" turn trigger on +"nottriggerable" turn trigger off + +If NOTOUCH is set, trigger will not respond to touch +If NOT_PLAYERS is set, the trigger does not respond to players +If MONSTERS is set, the trigger will respond to monsters +If PROJECTILES is set, the trigger will respond to projectiles (rockets, grenades, etc.) + +******************************************************************************/ + + +/*QUAKED trigger_setvariable (1 0 0) ? NOTOUCH LEVEL NOT_PLAYERS MONSTERS PROJECTILES + +Sets a variable specified by "variable" and "value". +Variable is assumed to be of the "global" variety unless LEVEL is set. +Variable sized trigger. Triggers once by default. +You must set the key "target" to the name of another object in the +level that has a matching + +"variable" - variable to set +"value" - value to set in variable, value can also be one of the following reserved\ +tokens. + - "increment" - add one to the variable + - "decrement" - subtract one from the variable + - "toggle" - if 1, then zero. If zero then 1. + +If "health" is set, the trigger must be killed to activate it. +If "delay" is set, the trigger waits some time after activating before firing. + +"targetname". If "health" is set, the trigger must be killed to activate. + +"thread" name of thread to trigger. This can be in a different script file as well\ +by using the '::' notation. + +if "killtarget" is set, any objects that have a matching "target" will be +removed when the trigger is fired. + +if "angle" is set, the trigger will only fire when someone is facing the +direction of the angle. +"cone" the cone in which a directed trigger can be triggered (default 60 degrees) + +"key" The item needed to activate this. (default nothing) + +"triggerable" turn trigger on +"nottriggerable" turn trigger off + +If NOTOUCH is set, trigger will not respond to touch +if LEVEL is set, variable will be a level variable otherwise it will be a game variable +If NOT_PLAYERS is set, the trigger does not respond to players +If MONSTERS is set, the trigger will respond to monsters +If PROJECTILES is set, the trigger will respond to projectiles (rockets, grenades, etc.) + +set "message" to text string + +******************************************************************************/ + + +/*QUAKED trigger_push (1 0 0) ? x x NOT_PLAYERS NOT_MONSTERS NOT_PROJECTILES + +Pushes entities as if they were caught in a heavy wind. + +"speed" indicates the rate that entities are pushed (default 1000). + +"angle" indicates the direction the wind is blowing (-1 is up, -2 is down) + +"key" The item needed to activate this. (default nothing) + +"target" if target is set, then a velocity will be calculated based on speed + +"triggerable" turn trigger on +"nottriggerable" turn trigger off + +If NOT_PLAYERS is set, the trigger does not push players +If NOT_MONSTERS is set, the trigger will not push monsters +If NOT_PROJECTILES is set, the trigger will not push projectiles (rockets, grenades, etc.) + +******************************************************************************/ + + +/*QUAKED trigger_pushany (1 0 0) ? x x NOT_PLAYERS NOT_MONSTERS NOT_PROJECTILES + +Pushes entities as if they were caught in a heavy wind. + +"speed" indicates the rate that entities are pushed (default 1000). +"angles" indicates the direction of the push +"key" The item needed to activate this. (default nothing) +"target" if target is set, then a velocity will be calculated based on speed + +"triggerable" turn trigger on +"nottriggerable" turn trigger off + +If NOT_PLAYERS is set, the trigger does not push players +If NOT_MONSTERS is set, the trigger will not push monsters +If NOT_PROJECTILES is set, the trigger will not push projectiles (rockets, grenades, etc.) + +******************************************************************************/ + + +/*QUAKED sound_speaker (0 0.75 0.75) (-8 -8 -8) (8 8 8) AMBIENT-ON AMBIENT-OFF NOT_PLAYERS MONSTERS PROJECTILES TOGGLE + +play a sound when it is used + +AMBIENT-ON specifies an ambient sound that starts on +AMBIENT-OFF specifies an ambient sound that starts off +TOGGLE specifies that the speaker toggles on triggering + +if (AMBIENT-?) is not set, then the sound is sent over explicitly this creates more net traffic + +"volume" how loud 0-4 (1 default full volume, ambients do not respond to volume) +"noise" sound to play +"channel" channel on which to play sound\ +(0 auto, 1 weapon, 2 voice, 3 item, 4 body, 8 don't use PHS) (voice is default) +"key" The item needed to activate this. (default nothing) +"thread" name of thread to trigger. This can be in a different script file as well\ +by using the '::' notation. + +Normal sounds play each time the target is used. + +Ambient Looped sounds have a volume 1, and the use function toggles it on/off. + +If NOT_PLAYERS is set, the trigger does not respond to players +If MONSTERS is set, the trigger will respond to monsters +If PROJECTILES is set, the trigger will respond to projectiles (rockets, grenades, etc.) + +******************************************************************************/ + + +/*QUAKED sound_randomspeaker (0 0.75 0.75) (-8 -8 -8) (8 8 8) x x NOT_PLAYERS MONSTERS PROJECTILES x x + +play a sound at random times + +"mindelay" minimum delay between sound triggers (default 3) +"maxdelay" maximum delay between sound triggers (default 10) +"chance" chance that sound will play when fired (default 1) +"volume" how loud 0-4 (1 default full volume) +"noise" sound to play +"channel" channel on which to play sound\ +(0 auto, 1 weapon, 2 voice, 3 item, 4 body, 8 don't use PHS) (voice is default) +"key" The item needed to activate this. (default nothing) + +Normal sounds play each time the target is used. + +If NOT_PLAYERS is set, the trigger does not respond to players +If MONSTERS is set, the trigger will respond to monsters +If PROJECTILES is set, the trigger will respond to projectiles (rockets, grenades, etc.) + +******************************************************************************/ + + +/*QUAKED trigger_changelevel (1 0 0) ? NO_INTERMISSION x NOT_PLAYERS MONSTERS PROJECTILES + +When the player touches this, he gets sent to the map listed in the "map" variable. +Unless the NO_INTERMISSION flag is set, the view will go to the info_intermission +spot and display stats. + +"spawnspot" name of the spawn location to start at in next map. +"key" The item needed to activate this. (default nothing) +"thread" This defaults to "LevelComplete" and should point to a thread that is called just +before the level ends. + +"triggerable" turn trigger on +"nottriggerable" turn trigger off + +If NOT_PLAYERS is set, the trigger does not respond to players +If MONSTERS is set, the trigger will respond to monsters +If PROJECTILES is set, the trigger will respond to projectiles (rockets, grenades, etc.) + +******************************************************************************/ + + +/*QUAKED trigger_use (1 0 0) ? VISIBLE x NOT_PLAYERS MONSTERS + +Activates targets when 'used' by an entity +"key" The item needed to activate this. (default nothing) +"thread" name of thread to trigger. This can be in a different script file as well\ +by using the '::' notation. + +"triggerable" turn trigger on +"nottriggerable" turn trigger off + +If NOT_PLAYERS is set, the trigger does not respond to players +If MONSTERS is set, the trigger will respond to monsters + +******************************************************************************/ + + +/*QUAKED trigger_useonce (1 0 0) ? VISIBLE x NOT_PLAYERS MONSTERS + +Activates targets when 'used' by an entity, but only once +"key" The item needed to activate this. (default nothing) +"thread" name of thread to trigger. This can be in a different script file as well\ +by using the '::' notation. + +"triggerable" turn trigger on +"nottriggerable" turn trigger off + +If NOT_PLAYERS is set, the trigger does not respond to players +If MONSTERS is set, the trigger will respond to monsters + +******************************************************************************/ + + +/*QUAKED trigger_hurt (1 0 0) ? x x NOT_PLAYERS NOT_MONSTERS PROJECTILES + +"damage" amount of damage to cause. (default 10) +"key" The item needed to activate this. (default nothing) +"damagetype" what kind of damage should be given to the player. (default CRUSH) + +"triggerable" turn trigger on +"nottriggerable" turn trigger off + +If NOT_PLAYERS is set, the trigger does not hurt players +If NOT_MONSTERS is set, the trigger does not hurt monsters +If PROJECTILES is set, the trigger will hurt projectiles (rockets, grenades, etc.) + +******************************************************************************/ + + +/*QUAKED trigger_damagetargets (1 0 0) ? SOLID x NOT_PLAYERS NOT_MONSTERS PROJECTILES + +"damage" amount of damage to cause. If no damage is specified, objects\ +are damaged by the current health+1 + +"key" The item needed to activate this. (default nothing) + +if a trigger_damagetargets is shot at and the SOLID flag is set,\ +the damage is passed on to the targets + +"triggerable" turn trigger on +"nottriggerable" turn trigger off + +If NOT_PLAYERS is set, the trigger does not hurt players +If NOT_MONSTERS is set, the trigger does not hurt monsters +If PROJECTILES is set, the trigger will hurt projectiles (rockets, grenades, etc.) + +******************************************************************************/ + + +/*QUAKED trigger_camerause (1 0 0) ? VISIBLE x NOT_PLAYERS MONSTERS + +Activates 'targeted' camera when 'used' +If activated, toggles through cameras +"key" The item needed to activate this. (default nothing) +"thread" name of thread to trigger. This can be in a different script file as well\ +by using the '::' notation. + +"triggerable" turn trigger on +"nottriggerable" turn trigger off + +If NOT_PLAYERS is set, the trigger does not respond to players +If MONSTERS is set, the trigger will respond to monsters + +******************************************************************************/ + + +/*QUAKED trigger_exit (1 0 0) ? + +When the player touches this, an exit icon will be displayed in his hud. +This is to inform him that he is near an exit. + +"triggerable" turn trigger on +"nottriggerable" turn trigger off + +******************************************************************************/ + + +/*QUAKED trigger_music (1 0 0) ? NORMAL ACTION NOT_PLAYERS MONSTERS PROJECTILES SUSPENSE MYSTERY SURPRISE + +Variable sized repeatable trigger to change the music mood. + +If "delay" is set, the trigger waits some time after activating before firing. +"current" can be used to set the current mood +"fallback" can be used to set the fallback mood +"altcurrent" can be used to set the current mood of the opposite face, if multiFaceted +"altfallback" can be used to set the fallback mood of the opposite face, if multiFaceted +"edgeTriggerable" trigger only fires when entering a trigger +"multiFaceted" if 1, then trigger is North/South separate triggerable\ +if 2, then trigger East/West separate triggerable + +"thread" name of thread to trigger. This can be in a different script file as well\ +by using the '::' notation. +"wait" : Seconds between triggerings. (1.0 default) +"cnt" how many times it can be triggered (infinite default) +"oneshot" make this a one time trigger + +"triggerable" turn trigger on +"nottriggerable" turn trigger off + +If NOT_PLAYERS is set, the trigger does not respond to players +If MONSTERS is set, the trigger will respond to monsters +If PROJECTILES is set, the trigger will respond to projectiles (rockets, grenades, etc.) + +NORMAL, ACTION, SUSPENSE, MYSTERY, and SURPRISE are the moods that can be triggered + +******************************************************************************/ + + +/*QUAKED trigger_reverb (1 0 0) ? x x NOT_PLAYERS MONSTERS PROJECTILES + +Variable sized repeatable trigger to change the reverb level in the game + +If "delay" is set, the trigger waits some time after activating before firing. +"reverbtype" what kind of reverb should be used +"reverblevel" how much of the reverb effect should be applied +"altreverbtype" what kind of reverb should be used +"altreverblevel" how much of the reverb effect should be applied +"edgeTriggerable" trigger only fires when entering a trigger +"multiFaceted" if 1, then trigger is North/South separate triggerable\ +if 2, then trigger East/West separate triggerable + +"thread" name of thread to trigger. This can be in a different script file as well\ +by using the '::' notation. +"wait" : Seconds between triggerings. (1.0 default) +"cnt" how many times it can be triggered (infinite default) +"oneshot" make this a one time trigger + +"triggerable" turn trigger on +"nottriggerable" turn trigger off + +If NOT_PLAYERS is set, the trigger does not respond to players +If MONSTERS is set, the trigger will respond to monsters +If PROJECTILES is set, the trigger will respond to projectiles (rockets, grenades, etc.) + +******************************************************************************/ + + +/*QUAKED trigger_pushobject (1 0 0) ? +Special trigger that can only be triggered by a push object. + +"triggername" if set, trigger only responds to objects with a targetname the same as triggername. +"cnt" how many times it can be triggered (default 1, use -1 for infinite) +******************************************************************************/ + + +/*QUAKED trigger_givepowerup (1 0 0) ? x x NOT_PLAYERS MONSTERS x + +Variable sized repeatable trigger to give a powerup to the player + +"oneshot" makes this triggerable only once +"powerupname" sets the name of the powerup to give to the player + +If NOT_PLAYERS is set, the trigger does not respond to players +If MONSTERS is set, the trigger will respond to monsters + +******************************************************************************/ + + +/*QUAKED worldspawn (0 0 0) ? CINEMATIC + +Only used for the world. + +"soundtrack" the soundtrack to use on the map +"gravity" 800 is default gravity +"skipthread" thread that is activated to skip this level (if cinematic) +"nextmap" map to goto when player exits +"message" text to print at user logon +"script" script to run on start of map +"watercolor" view color when underwater +"wateralpha" view alpha when underwater +"lavacolor" view alpha when in lava +"lavaalpha" view alpha when in lava +"farplane_color" color to fade to when the far clip plane is on +"farplane_cull" whether or not the far plane should cull, default is yes +"farplane" distance from the viewer that the far clip plane is +"ambientlight" ambient lighting to be applied to all entities +"ambient" ambient lighting to be applied to all entities, use _color to specify color +"suncolor" color of the sun in the level +"sunlight" intensity of the sun in the level +"sundirection" direction of the sun in the level +"sunflare" worldspace position of the sun flare +"sunflare_inportalsky" whether or not the flare is in the portal sky +"lightmapdensity" default lightmap density to be used for all surfaces +"skyalpha" initial value of the sky's alpha, defaults to 1 + +******************************************************************************/ + + diff --git a/fakk/maps/example/CameraScript.bsp b/fakk/maps/example/CameraScript.bsp new file mode 100644 index 0000000..33d89f9 Binary files /dev/null and b/fakk/maps/example/CameraScript.bsp differ diff --git a/fakk/maps/example/CameraScript.map b/fakk/maps/example/CameraScript.map new file mode 100644 index 0000000..065c2da --- /dev/null +++ b/fakk/maps/example/CameraScript.map @@ -0,0 +1,406 @@ +{ +"classname" "worldspawn" +// brush 0 +{ +( 224 192 0 ) ( 224 224 0 ) ( -480 224 0 ) eden/bedtrim -224 -32 90.00 1 1 0 0 0 +( -480 224 64 ) ( 224 224 64 ) ( 224 192 64 ) eden/bedtrim -224 -32 90.00 1 1 0 0 0 +( -480 224 256 ) ( -480 192 256 ) ( -480 192 0 ) eden/bedtrim -224 0 0.00 1 1 0 0 0 +( -480 192 256 ) ( 224 192 256 ) ( 224 192 0 ) common/skip 0 0 0.00 1 1 805306368 16512 0 +( 224 224 256 ) ( -480 224 256 ) ( -480 224 0 ) eden/bedtrim 224 0 -180.00 1 -1 0 0 0 +( -416 224 0 ) ( -416 192 0 ) ( -416 208 64 ) eden/bedtrim 224 0 -180.00 1 -1 0 0 0 +} +// brush 1 +{ +( 224 192 0 ) ( 224 224 0 ) ( -480 224 0 ) eden/bedtrim -224 -32 90.00 1 1 0 0 0 +( -480 224 64 ) ( 224 224 64 ) ( 224 192 64 ) eden/bedtrim -224 -32 90.00 1 1 0 0 0 +( -480 192 256 ) ( 224 192 256 ) ( 224 192 0 ) eden/bedtrim 224 0 -180.00 1 -1 0 0 0 +( 224 192 256 ) ( 224 224 256 ) ( 224 224 0 ) eden/bedtrim -224 0 0.00 1 1 0 0 0 +( 224 224 256 ) ( -480 224 256 ) ( -480 224 0 ) eden/bedtrim 224 0 -180.00 1 -1 0 0 0 +( -480 192 0 ) ( -480 224 0 ) ( -480 208 64 ) eden/bedtrim 224 0 -180.00 1 -1 0 0 0 +} +// brush 2 +{ +( 224 192 64 ) ( 224 224 64 ) ( -480 224 64 ) eden/edenmetalwall -224 -224 90.00 1 1 0 0 0 +( -480 224 320 ) ( 224 224 320 ) ( 224 192 320 ) eden/edenmetalwall -224 -224 90.00 1 1 0 0 0 +( -480 224 96 ) ( -480 192 96 ) ( -480 192 64 ) eden/edenmetalwall -224 64 0.00 1 1 0 0 0 +( -480 192 96 ) ( 224 192 96 ) ( 224 192 64 ) common/skip 0 0 0.00 1 1 805306368 16512 0 +( 224 224 96 ) ( -480 224 96 ) ( -480 224 64 ) eden/edenmetalwall 224 63 -180.00 1 -1 0 0 0 +( -416 224 64 ) ( -416 192 64 ) ( -416 208 320 ) eden/edenmetalwall 224 63 -180.00 1 -1 0 0 0 +} +// brush 3 +{ +( 224 192 64 ) ( 224 224 64 ) ( -480 224 64 ) eden/edenmetalwall -224 -224 90.00 1 1 0 0 0 +( -480 224 640 ) ( 224 224 640 ) ( 224 192 640 ) eden/edenmetalwall -224 -224 90.00 1 1 0 0 0 +( -480 192 96 ) ( 224 192 96 ) ( 224 192 64 ) eden/edenmetalwall 224 63 -180.00 1 -1 0 0 0 +( 224 192 96 ) ( 224 224 96 ) ( 224 224 64 ) eden/edenmetalwall -224 64 0.00 1 1 0 0 0 +( 224 224 96 ) ( -480 224 96 ) ( -480 224 64 ) eden/edenmetalwall 224 63 -180.00 1 -1 0 0 0 +( -480 192 384 ) ( -480 224 384 ) ( -480 208 640 ) eden/edenmetalwall 224 63 -180.00 1 -1 0 0 0 +} +// brush 4 + { + patchDef2 + { + eden/edenmetalwall + ( 3 3 0 536870912 0 ) +( +( ( -480 96 63.999981 0 0 ) ( -480 96 352.000061 0 0.500000 ) ( -480 96 640 0 1 ) ) +( ( -384 96 63.999981 0.500000 0 ) ( -384 96 352.000061 0.500000 0.500000 ) ( -384 96 640 0.500000 1 ) ) +( ( -384 192 63.999981 1 0 ) ( -384 192 352.000061 1 0.500000 ) ( -384 192 640 1 1 ) ) +) + } + } +// brush 5 +{ +( -480 192 0 ) ( -512 192 0 ) ( -512 -512 0 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +( -512 -512 64 ) ( -512 192 64 ) ( -480 192 64 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +( -480 -512 256 ) ( -480 192 256 ) ( -480 192 0 ) common/skip 0 0 0.00 1 1 805306368 16512 0 +( -480 192 256 ) ( -512 192 256 ) ( -512 192 0 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +( -512 192 256 ) ( -512 -512 256 ) ( -512 -512 0 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +( -480 128 0 ) ( -512 128 0 ) ( -496 128 64 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +} +// brush 6 +{ +( -480 192 0 ) ( -512 192 0 ) ( -512 -512 0 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +( -512 -512 64 ) ( -512 192 64 ) ( -480 192 64 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +( -512 -512 256 ) ( -480 -512 256 ) ( -480 -512 0 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +( -480 -512 256 ) ( -480 192 256 ) ( -480 192 0 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +( -512 192 256 ) ( -512 -512 256 ) ( -512 -512 0 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +( -512 192 0 ) ( -480 192 0 ) ( -496 192 64 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +} +// brush 7 +{ +( -480 192 64 ) ( -512 192 64 ) ( -512 -512 64 ) eden/edenmetalwall 0 0 0.00 1 1 0 0 0 +( -512 -512 320 ) ( -512 192 320 ) ( -480 192 320 ) eden/edenmetalwall 0 0 0.00 1 1 0 0 0 +( -480 -512 96 ) ( -480 192 96 ) ( -480 192 64 ) common/skip 0 0 0.00 1 1 805306368 16512 0 +( -480 192 96 ) ( -512 192 96 ) ( -512 192 64 ) eden/edenmetalwall 0 64 0.00 1 1 0 0 0 +( -512 192 96 ) ( -512 -512 96 ) ( -512 -512 64 ) eden/edenmetalwall 0 64 0.00 1 1 0 0 0 +( -480 128 64 ) ( -512 128 64 ) ( -496 128 320 ) eden/edenmetalwall 0 64 0.00 1 1 0 0 0 +} +// brush 8 +{ +( -480 192 64 ) ( -512 192 64 ) ( -512 -512 64 ) eden/edenmetalwall 0 0 0.00 1 1 0 0 0 +( -512 -512 640 ) ( -512 192 640 ) ( -480 192 640 ) eden/edenmetalwall 0 0 0.00 1 1 0 0 0 +( -512 -512 96 ) ( -480 -512 96 ) ( -480 -512 64 ) eden/edenmetalwall 0 64 0.00 1 1 0 0 0 +( -480 -512 416 ) ( -480 192 416 ) ( -480 192 384 ) eden/edenmetalwall 0 64 0.00 1 1 0 0 0 +( -512 192 96 ) ( -512 -512 96 ) ( -512 -512 64 ) eden/edenmetalwall 0 64 0.00 1 1 0 0 0 +( -512 192 64 ) ( -480 192 64 ) ( -496 192 320 ) eden/edenmetalwall 0 64 0.00 1 1 0 0 0 +} +// brush 9 + { + patchDef2 + { + eden/bedtrim + ( 3 3 0 536870912 0 ) +( +( ( -480 96 0 0 0 ) ( -480 96 32 0 0.500000 ) ( -480 96 64 0 1 ) ) +( ( -384 96 0 0.500000 0 ) ( -384 96 32 0.500000 0.500000 ) ( -384 96 64 0.500000 1 ) ) +( ( -384 192 0 1 0 ) ( -384 192 32 1 0.500000 ) ( -384 192 64 1 1 ) ) +) + } + } +// brush 10 +{ +( 192 192 608 ) ( -480 192 608 ) ( -480 -512 608 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( -480 -512 640 ) ( -480 192 640 ) ( 192 192 640 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( -480 -512 640 ) ( 192 -512 640 ) ( 192 -512 608 ) eden/CL_edenroof3 0 -96 0.00 1 1 0 0 0 +( 192 192 640 ) ( -480 192 640 ) ( -480 192 608 ) eden/CL_edenroof3 0 -96 0.00 1 1 0 0 0 +( -480 192 640 ) ( -480 -512 640 ) ( -480 -512 608 ) eden/CL_edenroof3 0 -96 0.00 1 1 0 0 0 +( 216 -112 608 ) ( 216 -240 608 ) ( 216 -176 640 ) eden/CL_edenroof3 0 -96 0.00 1 1 0 0 0 +} +// brush 11 +{ +( 192 192 -32 ) ( -480 192 -32 ) ( -480 -512 -32 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( -480 -512 0 ) ( -480 192 0 ) ( 192 192 0 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( -480 -512 224 ) ( 192 -512 224 ) ( 192 -512 -32 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 192 -512 224 ) ( 192 192 224 ) ( 192 192 -32 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 192 192 224 ) ( -480 192 224 ) ( -480 192 -32 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( -480 192 224 ) ( -480 -512 224 ) ( -480 -512 -32 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +} +// brush 12 +{ +( -480 -512 64 ) ( -480 -544 64 ) ( 224 -544 64 ) eden/edenmetalwall -31 31 -90.00 1 1 0 0 0 +( 224 -544 640 ) ( -480 -544 640 ) ( -480 -512 640 ) eden/edenmetalwall -31 31 -90.00 1 1 0 0 0 +( 224 -544 96 ) ( 224 -512 96 ) ( 224 -512 64 ) eden/edenmetalwall -32 63 -180.00 1 -1 0 0 0 +( 224 -512 96 ) ( -480 -512 96 ) ( -480 -512 64 ) eden/edenmetalwall -32 62 0.00 1.000008 1 0 0 0 +( -480 -512 416 ) ( -480 -544 416 ) ( -480 -544 384 ) eden/edenmetalwall -33 63 -180.00 1 -1 0 0 0 +( -480 -544 96 ) ( 224 -544 96 ) ( 224 -544 64 ) eden/edenmetalwall -32 62 0.00 1.000008 1 0 0 0 +} +// brush 13 +{ +( -480 -512 0 ) ( -480 -544 0 ) ( 224 -544 0 ) eden/bedtrim -31 32 -90.00 1 1 0 0 0 +( 224 -544 64 ) ( -480 -544 64 ) ( -480 -512 64 ) eden/bedtrim -31 32 -90.00 1 1 0 0 0 +( 224 -544 256 ) ( 224 -512 256 ) ( 224 -512 0 ) eden/bedtrim -32 0 -180.00 1 -1 0 0 0 +( 224 -512 256 ) ( -480 -512 256 ) ( -480 -512 0 ) eden/bedtrim -32 0 0.00 1 1 0 0 0 +( -480 -512 256 ) ( -480 -544 256 ) ( -480 -544 0 ) eden/bedtrim -33 0 -180.00 1 -1 0 0 0 +( -480 -544 256 ) ( 224 -544 256 ) ( 224 -544 0 ) eden/bedtrim -32 0 0.00 1 1 0 0 0 +} +// brush 14 +{ +( 192 -512 0 ) ( 224 -512 0 ) ( 224 192 0 ) eden/bedtrim 160 0 -180.00 1 1 0 0 0 +( 224 192 64 ) ( 224 -512 64 ) ( 192 -512 64 ) eden/bedtrim 160 0 -180.00 1 1 0 0 0 +( 224 192 256 ) ( 192 192 256 ) ( 192 192 0 ) eden/bedtrim 160 0 -180.00 1 -1 0 0 0 +( 192 192 256 ) ( 192 -512 256 ) ( 192 -512 0 ) eden/bedtrim -64 0 -180.00 1 -1 0 0 0 +( 192 -512 256 ) ( 224 -512 256 ) ( 224 -512 0 ) eden/bedtrim 159 0 -180.00 1 -1 0 0 0 +( 224 -512 256 ) ( 224 192 256 ) ( 224 192 0 ) eden/bedtrim -64 0 -180.00 1 -1 0 0 0 +} +// brush 15 +{ +( 192 -512 64 ) ( 224 -512 64 ) ( 224 192 64 ) eden/edenmetalwall 160 63 -180.00 1 1 0 0 0 +( 224 192 640 ) ( 224 -512 640 ) ( 192 -512 640 ) eden/edenmetalwall 160 63 -180.00 1 1 0 0 0 +( 224 192 96 ) ( 192 192 96 ) ( 192 192 64 ) eden/edenmetalwall 160 64 -180.00 1 -1 0 0 0 +( 192 192 416 ) ( 192 -512 416 ) ( 192 -512 384 ) eden/edenmetalwall -64 62 -180.00 1 -1 0 0 0 +( 192 -512 96 ) ( 224 -512 96 ) ( 224 -512 64 ) eden/edenmetalwall 159 64 -180.00 1 -1 0 0 0 +( 224 -512 96 ) ( 224 192 96 ) ( 224 192 64 ) eden/edenmetalwall -64 62 -180.00 1 -1 0 0 0 +} +} +// entity 1 +{ +"classname" "Characters_Gruff" +"scale" "1.0" +"model" "gruff.tik" +"targetname" "gruff" +"angle" "90" +"origin" "-148.00 -364.00 0.00" +} +// entity 2 +{ +"classname" "func_camera" +"scale" "1.0" +"model" "func_camera.tik" +"targetname" "camera1" +"origin" "-144.00 -216.00 0.00" +} +// entity 3 +{ +"classname" "info_splinepath" +"scale" "1.0" +"model" "func_spline.tik" +"angles" " 0.0 22.5 0" +"origin" "-389.55 -69.55 136.00" +"target" "t1" +"targetname" "campath1" +} +// entity 4 +{ +"classname" "Characters_EdenMale_Random2" +"scale" "1.0" +"model" "edenmale_random2.tik" +"angle" "225" +"origin" "-105.37 86.63 0.00" +"targetname" "edenmale" +} +// entity 5 +{ +"targetname" "movinlight2" +"classname" "script_object" +// brush 0 +{ +( 16 -368 144 ) ( 0 -368 144 ) ( 0 -384 144 ) common/skip 32 16 0.00 1 1 805306368 16512 0 +( 0 -384 160 ) ( 0 -368 160 ) ( 16 -368 160 ) common/skip 32 16 0.00 1 1 805306368 16512 0 +( 0 -384 240 ) ( 16 -384 240 ) ( 16 -384 144 ) common/skip 32 -48 0.00 1 1 805306368 16512 0 +( 16 -384 240 ) ( 16 -368 240 ) ( 16 -368 144 ) common/skip -16 -48 0.00 1 1 805306368 16512 0 +( 16 -368 240 ) ( 0 -368 240 ) ( 0 -368 144 ) common/skip 32 -48 0.00 1 1 805306368 16512 0 +( 0 -368 240 ) ( 0 -384 240 ) ( 0 -384 144 ) common/skip -16 -48 0.00 1 1 805306368 16512 0 +} +} +// entity 6 +{ +"targetname" "movinlight1" +"classname" "script_object" +// brush 0 +{ +( -344 64 144 ) ( -360 64 144 ) ( -360 48 144 ) common/skip 0 0 0.00 1 1 805306368 16512 0 +( -360 48 160 ) ( -360 64 160 ) ( -344 64 160 ) common/skip 0 0 0.00 1 1 805306368 16512 0 +( -360 48 240 ) ( -344 48 240 ) ( -344 48 144 ) common/skip 0 -48 0.00 1 1 805306368 16512 0 +( -344 48 240 ) ( -344 64 240 ) ( -344 64 144 ) common/skip 0 -48 0.00 1 1 805306368 16512 0 +( -344 64 240 ) ( -360 64 240 ) ( -360 64 144 ) common/skip 0 -48 0.00 1 1 805306368 16512 0 +( -360 64 240 ) ( -360 48 240 ) ( -360 48 144 ) common/skip 0 -48 0.00 1 1 805306368 16512 0 +} +} +// entity 7 +{ +"classname" "light" +"spawnflags" "0" +"origin" "-352 56 168" +"light" "200" +"_color" "1.000000 0.724409 0.523622" +} +// entity 8 +{ +"classname" "info_player_start" +"angle" "0" +"origin" "-416 -176 24" +} +// entity 9 +{ +"origin" "8 56 168" +"spawnflags" "0" +"classname" "light" +"light" "200" +"_color" "0.629921 0.846457 1.000000" +} +// entity 10 +{ +"origin" "-344 -376 168" +"spawnflags" "0" +"classname" "light" +"light" "200" +} +// entity 11 +{ +"classname" "light" +"spawnflags" "0" +"origin" "8 -376 168" +"light" "200" +} +// entity 12 +{ +"light" "200" +"classname" "light" +"spawnflags" "0" +"origin" "-168 -160 168" +} +// entity 13 +{ +"_color" "1.000000 0.724409 0.523622" +"light" "200" +"origin" "-352 56 384" +"spawnflags" "0" +"classname" "light" +} +// entity 14 +{ +"_color" "0.629921 0.846457 1.000000" +"light" "200" +"classname" "light" +"spawnflags" "0" +"origin" "8 56 384" +} +// entity 15 +{ +"light" "200" +"classname" "light" +"spawnflags" "0" +"origin" "-344 -376 384" +} +// entity 16 +{ +"light" "200" +"origin" "8 -376 384" +"spawnflags" "0" +"classname" "light" +} +// entity 17 +{ +"origin" "-168 -160 384" +"spawnflags" "0" +"classname" "light" +"light" "200" +} +// entity 18 +{ +"origin" "-349.55 24.00 178.45" +"angles" "22.5 0.0 0" +"model" "func_spline.tik" +"scale" "1.0" +"classname" "info_splinepath" +"targetname" "t1" +"target" "t2" +} +// entity 19 +{ +"classname" "info_splinepath" +"scale" "1.0" +"model" "func_spline.tik" +"angles" "22 337 0" +"origin" "-315.29 99.43 178.41" +"targetname" "t2" +"target" "t3" +} +// entity 20 +{ +"origin" "-178.96 125.10 42.49" +"angles" "337 314 0" +"model" "func_spline.tik" +"scale" "1.0" +"classname" "info_splinepath" +"targetname" "t3" +"target" "t4" +} +// entity 21 +{ +"classname" "info_splinepath" +"scale" "1.0" +"model" "func_spline.tik" +"angles" "314.5 359.0 0" +"origin" "-164.55 64.20 43.31" +"targetname" "t4" +"target" "t5" +} +// entity 22 +{ +"origin" "-103.80 35.45 43.31" +"angles" "314 89 0" +"model" "func_spline.tik" +"scale" "1.0" +"classname" "info_splinepath" +"targetname" "t5" +"target" "t6" +} +// entity 23 +{ +"classname" "info_splinepath" +"scale" "1.0" +"model" "func_spline.tik" +"angles" "355 179 0" +"origin" "-47.19 80.15 40.67" +"targetname" "t6" +"target" "t7" +} +// entity 24 +{ +"origin" " 0.15 128.81 40.67" +"angles" "355 269 0" +"model" "func_spline.tik" +"scale" "1.0" +"classname" "info_splinepath" +"targetname" "t7" +"target" "t8" +} +// entity 25 +{ +"classname" "info_splinepath" +"scale" "1.0" +"model" "func_spline.tik" +"angles" "355.0 179.0 0" +"origin" "64.81 -15.85 40.67" +"targetname" "t8" +"target" "t9" +} +// entity 26 +{ +"origin" "-151.85 -63.19 40.67" +"angles" "355.0 89.0 0" +"model" "func_spline.tik" +"scale" "1.0" +"classname" "info_splinepath" +"targetname" "t9" +"target" "t10" +} +// entity 27 +{ +"classname" "info_splinepath" +"scale" "1.0" +"model" "func_spline.tik" +"angles" "355.0 134.0 0" +"origin" "-340.22 -132.21 40.67" +"targetname" "t10" +} +// entity 28 +{ +"origin" "-144.00 -248.00 0.00" +"targetname" "camera2" +"model" "func_camera.tik" +"scale" "1.0" +"classname" "func_camera" +} \ No newline at end of file diff --git a/fakk/maps/example/CameraScript.prt b/fakk/maps/example/CameraScript.prt new file mode 100644 index 0000000..ff1e3bb --- /dev/null +++ b/fakk/maps/example/CameraScript.prt @@ -0,0 +1,24 @@ +PRT1 +4 +4 +16 +4 0 2 0 (0 0 0 ) (0 0 608 ) (0 192 608 ) (0 192 0 ) +4 0 1 0 (0 0 608 ) (0 0 0 ) (192 0 0 ) (192 0 608 ) +4 1 3 0 (0 -512 0 ) (0 -512 608 ) (0 0 608 ) (0 0 0 ) +4 2 3 0 (0 0 0 ) (0 0 608 ) (-480 0 608 ) (-480 0 0 ) +4 0 (0 0 608 ) (192 0 608 ) (192 192 608 ) (0 192 608 ) +4 0 (192 192 608 ) (192 192 0 ) (0 192 0 ) (0 192 608 ) +4 0 (192 0 608 ) (192 0 0 ) (192 192 0 ) (192 192 608 ) +4 0 (0 192 0 ) (192 192 0 ) (192 0 0 ) (0 0 0 ) +4 1 (0 -512 608 ) (192 -512 608 ) (192 0 608 ) (0 0 608 ) +4 1 (0 -512 608 ) (0 -512 0 ) (192 -512 0 ) (192 -512 608 ) +4 1 (192 -512 608 ) (192 -512 0 ) (192 0 0 ) (192 0 608 ) +4 1 (0 0 0 ) (192 0 0 ) (192 -512 0 ) (0 -512 0 ) +4 2 (0 192 608 ) (-480 192 608 ) (-480 0 608 ) (0 0 608 ) +4 2 (-480 192 0 ) (-480 192 608 ) (0 192 608 ) (0 192 0 ) +4 2 (-480 192 608 ) (-480 192 0 ) (-480 0 0 ) (-480 0 608 ) +4 2 (0 0 0 ) (-480 0 0 ) (-480 192 0 ) (0 192 0 ) +4 3 (0 0 608 ) (-480 0 608 ) (-480 -512 608 ) (0 -512 608 ) +4 3 (-480 0 608 ) (-480 0 0 ) (-480 -512 0 ) (-480 -512 608 ) +4 3 (-480 -512 608 ) (-480 -512 0 ) (0 -512 0 ) (0 -512 608 ) +4 3 (0 -512 0 ) (-480 -512 0 ) (-480 0 0 ) (0 0 0 ) diff --git a/fakk/maps/example/CameraScript.scr b/fakk/maps/example/CameraScript.scr new file mode 100644 index 0000000..2bab2d7 --- /dev/null +++ b/fakk/maps/example/CameraScript.scr @@ -0,0 +1,47 @@ +// +// Camera Script Map script +// by Mark Dochtermann +// + +// wait for the player to join +waitforplayer +// wait 5 seconds +wait 5 + +// setup camera 1 +// follow the path called campath1 +$camera1 orbit $campath1 +// no transition, the camera should start immediately +$camera1 cut + +// setup camera 2 +// orbit $gruff +$camera2 follow_distance 180 +$camera2 orbit_height 8 +$camera2 orbit $gruff +$camera2 cut + +loop: +// tell the user we are going to switch +print "Following a Camera Path\n" +//wait a second +wait 1 +// cue to the camera over 1 second +cuecamera $camera1 0 +// wait until the camera is done +wait 5 +// tell the user we are going to orbit the other character +print "Orbiting a character\n" +// wait a second +wait 1 +cuecamera $camera2 0 +// wait a while +wait 5 + +cueplayer 0 +end +// loop ad infinitum +goto loop + +// finished +end \ No newline at end of file diff --git a/fakk/maps/example/autocamera.bsp b/fakk/maps/example/autocamera.bsp new file mode 100644 index 0000000..31aee1e Binary files /dev/null and b/fakk/maps/example/autocamera.bsp differ diff --git a/fakk/maps/example/autocamera.map b/fakk/maps/example/autocamera.map new file mode 100644 index 0000000..19a256e --- /dev/null +++ b/fakk/maps/example/autocamera.map @@ -0,0 +1,2116 @@ +{ +"classname" "worldspawn" +// brush 0 +{ +( 152 -592 328 ) ( 56 -592 328 ) ( 56 -632 328 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( 56 -632 368 ) ( 56 -592 368 ) ( 152 -592 368 ) eden/FL_edenhouse3bak 16 -8 0.00 1 1 0 0 0 +( 56 -632 296 ) ( 152 -632 296 ) ( 152 -632 288 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( 152 -632 296 ) ( 152 -592 296 ) ( 152 -592 288 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( 152 -576 296 ) ( 56 -576 296 ) ( 56 -576 288 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( 56 -592 296 ) ( 56 -632 296 ) ( 56 -632 288 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +} +// brush 1 +{ +( -16 -800 0 ) ( -16 -832 0 ) ( 16 -848 0 ) eden/edenrockdark 0 64 0.00 1 1 0 0 0 +( -16 -832 256 ) ( -16 -800 256 ) ( 16 -816 256 ) eden/edenrockdark 0 64 0.00 1 1 0 0 0 +( -16 -800 256 ) ( -16 -800 0 ) ( 16 -816 0 ) eden/edenrockdark 0 0 0.00 1 1 0 0 0 +( -144 -832 256 ) ( -144 -864 256 ) ( -144 -864 0 ) eden/edenrockdark -64 0 0.00 1 1 0 0 0 +( 16 -960 0 ) ( -16 -960 0 ) ( 0 -960 256 ) eden/edenrockdark 0 0 0.00 1 1 0 0 0 +( 16 -896 0 ) ( 16 -928 0 ) ( 16 -912 256 ) eden/edenrockdark -64 0 0.00 1 1 0 0 0 +( -128 -768 0 ) ( -80 -768 0 ) ( -104 -768 256 ) eden/edenrockdark -64 0 0.00 1 1 0 0 0 +} +// brush 2 +{ +( -128 -704 0 ) ( -448 -704 0 ) ( -448 -960 0 ) eden/edenrockdark 0 0 0.00 1 1 0 0 0 +( -448 -960 256 ) ( -448 -704 256 ) ( -128 -704 256 ) eden/edenrockdark 0 0 0.00 1 1 0 0 0 +( -448 -960 256 ) ( -128 -960 256 ) ( -128 -960 0 ) eden/edenrockdark 0 0 0.00 1 1 0 0 0 +( -80 -976 256 ) ( -80 -720 256 ) ( -80 -720 0 ) eden/edenrockdark 0 0 0.00 1 1 0 0 0 +( -128 -704 256 ) ( -448 -704 256 ) ( -448 -704 0 ) eden/edenrockdark 0 0 0.00 1 1 0 0 0 +( -448 -704 256 ) ( -448 -960 256 ) ( -448 -960 0 ) eden/edenrockdark 0 0 0.00 1 1 0 0 0 +( -448 -880 0 ) ( -416 -816 0 ) ( -432 -848 256 ) eden/edenrockdark 0 0 0.00 1 1 0 0 0 +( -416 -816 0 ) ( -352 -752 0 ) ( -384 -784 256 ) eden/edenrockdark 0 0 0.00 1 1 0 0 0 +( -352 -752 0 ) ( -256 -704 0 ) ( -304 -728 256 ) eden/edenrockdark 0 0 0.00 1 1 0 0 0 +( -192 -704 0 ) ( -128 -768 0 ) ( -160 -736 256 ) eden/edenrockdark 0 0 0.00 1 1 0 0 0 +} +// brush 3 +{ +( 512 638 64 ) ( 512 446 64 ) ( 512 446 0 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( 512 446 64 ) ( 672 446 64 ) ( 672 446 0 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( 512 446 127 ) ( 512 638 127 ) ( 672 638 127 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( 672 638 0 ) ( 512 638 0 ) ( 512 446 0 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( 608 446 64 ) ( 608 638 48 ) ( 608 446 32 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( -182 448 0 ) ( -176 448 0 ) ( -179 448 127 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +} +// brush 4 +{ +( 704 446 64 ) ( 704 638 64 ) ( 704 638 0 ) common/clip 0 0 0.00 1 1 65536 16529 0 +( 512 446 64 ) ( 672 446 64 ) ( 672 446 0 ) common/clip 0 0 0.00 1 1 65536 16529 0 +( 512 446 128 ) ( 512 638 128 ) ( 672 638 128 ) common/clip 0 0 0.00 1 1 65536 16529 0 +( 672 638 0 ) ( 512 638 0 ) ( 512 446 0 ) common/clip 0 0 0.00 1 1 65536 16529 0 +( 608 638 48 ) ( 608 446 64 ) ( 608 446 32 ) common/clip 0 0 0.00 1 1 65536 16529 0 +( -182 448 0 ) ( -176 448 0 ) ( -179 448 128 ) common/clip 0 0 0.00 1 1 65536 16529 0 +} +// brush 5 +{ +( 256 638 80 ) ( 256 638 0 ) ( 256 446 0 ) common/clip 0 0 0.00 1 1 65536 16529 0 +( 256 446 80 ) ( 256 446 0 ) ( 192 446 0 ) common/clip 0 0 0.00 1 1 65536 16529 0 +( 256 638 80 ) ( 256 446 80 ) ( 192 446 80 ) common/clip 0 0 0.00 1 1 65536 16529 0 +( 256 446 0 ) ( 256 638 0 ) ( 192 638 0 ) common/clip 0 0 0.00 1 1 65536 16529 0 +( 192 638 0 ) ( 192 638 80 ) ( 192 446 80 ) common/clip 0 0 0.00 1 1 65536 16529 0 +( -182 448 0 ) ( -176 448 0 ) ( -179 448 80 ) common/clip 0 0 0.00 1 1 65536 16529 0 +} +// brush 6 +{ +( 192 638 79 ) ( 192 638 0 ) ( 192 446 0 ) common/clip 0 0 0.00 1 1 65536 16529 0 +( 192 446 79 ) ( 192 446 0 ) ( 128 446 0 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( 192 638 79 ) ( 192 446 79 ) ( 128 446 79 ) common/clip 0 0 0.00 1 1 65536 16529 0 +( 192 446 0 ) ( 192 638 0 ) ( 128 638 0 ) common/clip 0 0 0.00 1 1 65536 16529 0 +( 128 638 0 ) ( 128 638 79 ) ( 128 446 79 ) common/clip 0 0 0.00 1 1 65536 16529 0 +( -182 448 0 ) ( -176 448 0 ) ( -179 448 79 ) common/clip 0 0 0.00 1 1 65536 16529 0 +} +// brush 7 +{ +( -224 638 47 ) ( -224 638 0 ) ( -224 446 0 ) common/clip 0 0 0.00 1 1 65536 16529 0 +( -224 446 47 ) ( -224 446 0 ) ( -288 446 0 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( -224 638 47 ) ( -224 446 47 ) ( -288 446 47 ) common/clip 0 0 0.00 1 1 65536 16529 0 +( -224 446 0 ) ( -224 638 0 ) ( -288 638 0 ) common/clip 0 0 0.00 1 1 65536 16529 0 +( -288 638 0 ) ( -288 638 47 ) ( -288 446 47 ) common/clip 0 0 0.00 1 1 65536 16529 0 +( -182 448 0 ) ( -176 448 0 ) ( -179 448 47 ) common/clip 0 0 0.00 1 1 65536 16529 0 +} +// brush 8 +{ +( -160 638 48 ) ( -160 638 0 ) ( -160 446 0 ) common/clip 0 0 0.00 1 1 65536 16529 0 +( -224 446 0 ) ( -224 446 48 ) ( -160 446 48 ) common/clip 0 0 0.00 1 1 65536 16529 0 +( -224 446 48 ) ( -224 638 48 ) ( -160 638 48 ) common/clip 0 0 0.00 1 1 65536 16529 0 +( -224 638 0 ) ( -224 446 0 ) ( -160 446 0 ) common/clip 0 0 0.00 1 1 65536 16529 0 +( -224 638 0 ) ( -224 638 48 ) ( -224 446 48 ) common/clip 0 0 0.00 1 1 65536 16529 0 +( -182 448 0 ) ( -176 448 0 ) ( -179 448 48 ) common/clip 0 0 0.00 1 1 65536 16529 0 +} +// brush 9 +{ +( 448 638 96 ) ( 448 638 0 ) ( 448 446 0 ) common/clip 0 0 0.00 1 1 65536 16529 0 +( 384 446 0 ) ( 384 446 96 ) ( 448 446 96 ) common/clip 0 0 0.00 1 1 65536 16529 0 +( 384 446 96 ) ( 384 638 96 ) ( 448 638 96 ) common/clip 0 0 0.00 1 1 65536 16529 0 +( 384 638 0 ) ( 384 446 0 ) ( 448 446 0 ) common/clip 0 0 0.00 1 1 65536 16529 0 +( 384 638 0 ) ( 384 638 96 ) ( 384 446 96 ) common/clip 0 0 0.00 1 1 65536 16529 0 +( -182 448 0 ) ( -176 448 0 ) ( -179 448 96 ) common/clip 0 0 0.00 1 1 65536 16529 0 +} +// brush 10 +{ +( 320 638 0 ) ( 320 638 95 ) ( 320 446 95 ) common/clip 0 0 0.00 1 1 65536 16529 0 +( 384 446 95 ) ( 384 446 0 ) ( 320 446 0 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( 384 638 95 ) ( 384 446 95 ) ( 320 446 95 ) common/clip 0 0 0.00 1 1 65536 16529 0 +( 384 446 0 ) ( 384 638 0 ) ( 320 638 0 ) common/clip 0 0 0.00 1 1 65536 16529 0 +( 384 638 95 ) ( 384 638 0 ) ( 384 446 0 ) common/clip 0 0 0.00 1 1 65536 16529 0 +( -182 448 0 ) ( -176 448 0 ) ( -179 448 95 ) common/clip 0 0 0.00 1 1 65536 16529 0 +} +// brush 11 +{ +( -64 638 0 ) ( -64 638 63 ) ( -64 446 63 ) common/clip 0 0 0.00 1 1 65536 16529 0 +( 0 446 63 ) ( 0 446 0 ) ( -64 446 0 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( 0 638 63 ) ( 0 446 63 ) ( -64 446 63 ) common/clip 0 0 0.00 1 1 65536 16529 0 +( 0 446 0 ) ( 0 638 0 ) ( -64 638 0 ) common/clip 0 0 0.00 1 1 65536 16529 0 +( 0 638 63 ) ( 0 638 0 ) ( 0 446 0 ) common/clip 0 0 0.00 1 1 65536 16529 0 +( -182 448 0 ) ( -176 448 0 ) ( -179 448 63 ) common/clip 0 0 0.00 1 1 65536 16529 0 +} +// brush 12 +{ +( 64 638 64 ) ( 64 638 0 ) ( 64 446 0 ) common/clip 0 0 0.00 1 1 65536 16529 0 +( 64 446 64 ) ( 64 446 0 ) ( 0 446 0 ) common/clip 0 0 0.00 1 1 65536 16529 0 +( 64 638 64 ) ( 64 446 64 ) ( 0 446 64 ) common/clip 0 0 0.00 1 1 65536 16529 0 +( 64 446 0 ) ( 64 638 0 ) ( 0 638 0 ) common/clip 0 0 0.00 1 1 65536 16529 0 +( 0 638 0 ) ( 0 638 64 ) ( 0 446 64 ) common/clip 0 0 0.00 1 1 65536 16529 0 +( -182 448 0 ) ( -176 448 0 ) ( -179 448 64 ) common/clip 0 0 0.00 1 1 65536 16529 0 +} +// brush 13 +{ +( -384 638 32 ) ( -384 638 0 ) ( -384 446 0 ) common/clip 0 0 0.00 1 1 65536 16529 0 +( -448 446 0 ) ( -448 446 32 ) ( -384 446 32 ) common/clip 0 0 0.00 1 1 65536 16529 0 +( -448 446 32 ) ( -448 638 32 ) ( -384 638 32 ) common/clip 0 0 0.00 1 1 65536 16529 0 +( -448 638 0 ) ( -448 446 0 ) ( -384 446 0 ) common/clip 0 0 0.00 1 1 65536 16529 0 +( -448 638 0 ) ( -448 638 32 ) ( -448 446 32 ) common/clip 0 0 0.00 1 1 65536 16529 0 +( -182 448 0 ) ( -176 448 0 ) ( -179 448 32 ) common/clip 0 0 0.00 1 1 65536 16529 0 +} +// brush 14 +{ +( -512 638 0 ) ( -512 638 31 ) ( -512 446 31 ) common/clip 0 0 0.00 1 1 65536 16529 0 +( -448 446 31 ) ( -448 446 0 ) ( -512 446 0 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( -448 638 31 ) ( -448 446 31 ) ( -512 446 31 ) common/clip 0 0 0.00 1 1 65536 16529 0 +( -448 446 0 ) ( -448 638 0 ) ( -512 638 0 ) common/clip 0 0 0.00 1 1 65536 16529 0 +( -448 638 31 ) ( -448 638 0 ) ( -448 446 0 ) common/clip 0 0 0.00 1 1 65536 16529 0 +( -182 448 0 ) ( -176 448 0 ) ( -179 448 31 ) common/clip 0 0 0.00 1 1 65536 16529 0 +} +// brush 15 +{ +( -480 -192 0 ) ( -544 -192 0 ) ( -544 -256 0 ) eden/edenwalltest 0 0 0.00 1 1 0 0 0 +( -544 -256 256 ) ( -544 -192 256 ) ( -480 -192 256 ) eden/WL_brick 0 0 0.00 1 1 0 0 0 +( -528 -704 16 ) ( -464 -704 16 ) ( -464 -704 0 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( -480 -256 16 ) ( -480 -192 16 ) ( -480 -192 0 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( -640 -192 16 ) ( -704 -192 16 ) ( -704 -192 0 ) eden/edenwalltest 0 -160 0.00 1 1 0 0 0 +( -704 -192 16 ) ( -704 -256 16 ) ( -704 -256 0 ) eden/edenwalltest 0 -160 0.00 1 1 0 0 0 +( -480 -656 0 ) ( -496 -672 0 ) ( -488 -664 256 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +} +// brush 16 +{ +( -448 -876 0 ) ( -456 -876 0 ) ( -456 -960 0 ) eden/edenwalltest -40 0 -180.00 1 -1 0 0 0 +( -456 -960 128 ) ( -456 -876 128 ) ( -448 -876 128 ) eden/WL_brick -16 -23 90.00 1 1 0 0 0 +( -456 -960 128 ) ( -448 -960 128 ) ( -448 -960 0 ) eden/edenwalltest -40 0 -180.00 1 -1 0 0 0 +( -448 -880 128 ) ( -448 -880 0 ) ( -448 -960 0 ) eden/edenwalltest -40 0 -180.00 1 -1 0 0 0 +( -448 -880 0 ) ( -448 -880 128 ) ( -456 -876 128 ) eden/edenwalltest -40 0 -180.00 1 -1 0 0 0 +( -456 -876 128 ) ( -456 -960 128 ) ( -456 -960 0 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +} +// brush 17 +{ +( -456 -875.999756 0 ) ( -448 -879.999756 0 ) ( -416 -816 0 ) eden/edenwalltest -40 0 -180.00 1 -1 0 0 0 +( -448 -879.999756 128 ) ( -456 -875.999756 128 ) ( -424 -812 128 ) eden/WL_brick -16 -23 90.00 1 1 0 0 0 +( -448 -880 128 ) ( -448 -880 0 ) ( -456 -876 0 ) eden/edenwalltest -40 0 -180.00 1 -1 0 0 0 +( -448 -880.000427 0 ) ( -448 -880.000427 128 ) ( -416 -816 128 ) eden/edenwalltest -40 0 -180.00 1 -1 0 0 0 +( -416 -816 0 ) ( -416 -816 128 ) ( -424 -812 128 ) eden/edenwalltest -40 0 -180.00 1 -1 0 0 0 +( -456 -875.999939 128 ) ( -456 -875.999939 0 ) ( -424 -812 0 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +} +// brush 18 +{ +( -420 -808 0 ) ( -416 -816 0 ) ( -352 -752 0 ) eden/edenwalltest -40 0 -180.00 1 -1 0 0 0 +( -416 -816 128 ) ( -420 -808 128 ) ( -356 -744 128 ) eden/WL_brick -16 -23 90.00 1 1 0 0 0 +( -424 -812 0 ) ( -424 -812 128 ) ( -416 -816 128 ) eden/edenwalltest -40 0 -180.00 1 -1 0 0 0 +( -416 -816.000427 0 ) ( -416 -816.000427 128 ) ( -352 -752 128 ) eden/edenwalltest -40 0 -180.00 1 -1 0 0 0 +( -356 -744 128 ) ( -356 -744 0 ) ( -352 -752 0 ) eden/edenwalltest -40 0 -180.00 1 -1 0 0 0 +( -424 -812 128 ) ( -424 -812 0 ) ( -356 -744 0 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +} +// brush 19 +{ +( -356 -744 0 ) ( -352 -752 0 ) ( -256.000305 -704 0 ) eden/edenwalltest -40 0 -180.00 1 -1 0 0 0 +( -352 -752 128 ) ( -356 -744 128 ) ( -260.000305 -696 128 ) eden/WL_brick -16 -23 90.00 1 1 0 0 0 +( -352 -752 0 ) ( -352 -752 128 ) ( -256.000305 -704 128 ) eden/edenwalltest -40 0 -180.00 1 -1 0 0 0 +( -256 -704 0 ) ( -256 -704 128 ) ( -260 -696 128 ) eden/edenwalltest -40 0 -180.00 1 -1 0 0 0 +( -356 -744 128 ) ( -356 -744 0 ) ( -259.999695 -696 0 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( -352 -752 128 ) ( -352 -752 0 ) ( -356 -744 0 ) eden/edenwalltest -40 0 -180.00 1 -1 0 0 0 +} +// brush 20 +{ +( -188 -696 0 ) ( -256 -696 0 ) ( -256 -704 0 ) eden/edenwalltest -40 0 -180.00 1 -1 0 0 0 +( -256 -704 128 ) ( -256 -696 128 ) ( -188 -696 128 ) eden/WL_brick -16 -23 90.00 1 1 0 0 0 +( -256 -704 128 ) ( -188 -704 128 ) ( -188 -704 0 ) eden/edenwalltest -40 0 -180.00 1 -1 0 0 0 +( -188 -696 128 ) ( -188 -696 0 ) ( -192 -704 0 ) eden/edenwalltest -40 0 -180.00 1 -1 0 0 0 +( -260 -696 128 ) ( -260 -696 0 ) ( -188 -696 0 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( -260 -696 0 ) ( -260 -696 128 ) ( -256 -704 128 ) eden/edenwalltest -40 0 -180.00 1 -1 0 0 0 +} +// brush 21 +{ +( -140.000015 -744.000488 0 ) ( -144.000015 -752 0 ) ( -128.000015 -768 0 ) eden/edenwalltest -40 0 -180.00 1 -1 0 0 0 +( -144.000015 -752 128 ) ( -140.000015 -744.000488 128 ) ( -124.000168 -760.000305 128 ) eden/WL_brick -16 -23 90.00 1 1 0 0 0 +( -128 -768 0 ) ( -128 -768 128 ) ( -124 -760 128 ) eden/edenwalltest -40 0 -180.00 1 -1 0 0 0 +( -139.999878 -744.000244 128 ) ( -139.999878 -744.000244 0 ) ( -123.999908 -760.000183 0 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( -188 -696 128 ) ( -192 -704 128 ) ( -192 -704 0 ) eden/edenwalltest -40 0 -180.00 1 -1 0 0 0 +( -143.999802 -751.999573 0 ) ( -143.999802 -751.999573 128 ) ( -127.999763 -767.999634 128 ) eden/edenwalltest -40 0 -180.00 1 -1 0 0 0 +} +// brush 22 +{ +( -80 -760 0 ) ( -136 -760 0 ) ( -136 -768 0 ) eden/edenwalltest -40 0 -180.00 1 -1 0 0 0 +( -136 -768 128 ) ( -136 -760 128 ) ( -80 -760 128 ) eden/WL_brick -16 -23 90.00 1 1 0 0 0 +( -136 -768 128 ) ( -80 -768 128 ) ( -80 -768 0 ) eden/edenwalltest -40 0 -180.00 1 -1 0 0 0 +( -76 -760 128 ) ( -76 -760 0 ) ( -80 -768 0 ) eden/edenwalltest -40 0 -180.00 1 -1 0 0 0 +( -124 -760 128 ) ( -124 -760 0 ) ( -76 -760 0 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( -124 -760 0 ) ( -124 -760 128 ) ( -128 -768 128 ) eden/edenwalltest -40 0 -180.00 1 -1 0 0 0 +} +// brush 23 +{ +( -76.000465 -760 128 ) ( -76.000465 -760 0 ) ( 20 -808 0 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( -79.999840 -768 0 ) ( -79.999840 -768 128 ) ( 16 -816 128 ) eden/edenwalltest -40 0 -180.00 1 -1 0 0 0 +( -79.999840 -768 128 ) ( -76.000465 -760 128 ) ( 20 -808 128 ) eden/WL_brick -16 -23 90.00 1 1 0 0 0 +( -76.000465 -760 0 ) ( -79.999840 -768 0 ) ( 16 -816 0 ) eden/edenwalltest -80 -88 90.00 1 1 0 0 0 +( -76 -760 0 ) ( -76 -760 128 ) ( -80 -768 128 ) eden/edenwalltest 63 -112 90.00 1 1 0 0 0 +( 24 -800 0 ) ( 16 -816 0 ) ( 20 -808 128 ) eden/edenwalltest 63 -112 90.00 1 1 0 0 0 +} +// brush 24 +{ +( 96 -816 0 ) ( 16 -816 0 ) ( 16 -896 0 ) eden/edenrockdark 0 64 0.00 1 1 0 0 0 +( 16 -896 256 ) ( 16 -816 256 ) ( 96 -816 256 ) eden/edenrockdark 0 64 0.00 1 1 0 0 0 +( 16 -960 128 ) ( 96 -960 128 ) ( 96 -960 0 ) eden/edenrockdark 0 0 0.00 1 1 0 0 0 +( 160 -896 128 ) ( 160 -816 128 ) ( 160 -816 0 ) eden/edenrockdark -64 0 0.00 1 1 0 0 0 +( 96 -816 128 ) ( 16 -816 128 ) ( 16 -816 0 ) eden/edenrockdark 0 0 0.00 1 1 0 0 0 +( 16 -880 128 ) ( 16 -960 128 ) ( 16 -960 0 ) eden/edenrockdark -64 0 0.00 1 1 0 0 0 +} +// brush 25 +{ +( 20 -808 128 ) ( 20 -808 0 ) ( 176 -808 0 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( -432 -816 160 ) ( 272 -816 160 ) ( 272 -816 0 ) eden/edenwalltest -16 0 -180.00 1 -1 0 0 0 +( -144 -800 128 ) ( 560 -800 128 ) ( 560 -816 128 ) eden/WL_brick -16 -47 90.00 1 1 0 0 0 +( 560 -816 0 ) ( 560 -800 0 ) ( -144 -800 0 ) eden/edenwalltest -80 -112 90.00 1 1 0 0 0 +( 20 -808 0 ) ( 20 -808 128 ) ( 16 -816 128 ) eden/edenwalltest 63 -112 90.00 1 1 0 0 0 +( 96 -784 0 ) ( 96 -832 0 ) ( 96 -808 128 ) eden/edenwalltest 63 -112 90.00 1 1 0 0 0 +} +// brush 26 +{ +( 160 -896 0 ) ( 160 -768 0 ) ( 32 -768 0 ) eden/edenwalltest 0 160 90.00 1 1 0 0 0 +( 32 -768 128 ) ( 160 -768 128 ) ( 160 -896 128 ) eden/WL_brick 0 -31 90.00 1 1 0 0 0 +( 96 -688 112 ) ( 96 -816 112 ) ( 96 -816 0 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( 32 -816 112 ) ( 160 -816 112 ) ( 160 -816 0 ) eden/edenwalltest -32 0 -180.00 1 -1 0 0 0 +( 160 -896 112 ) ( 160 -768 112 ) ( 160 -768 0 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( 160 -752 112 ) ( 32 -752 112 ) ( 32 -752 0 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +} +// brush 27 +{ +( 664 638 60 ) ( 664 446 60 ) ( 668 446 60 ) creeperpens/wl_astroid -4 -106 0.00 1 1 0 0 0 +( 668 446 64 ) ( 664 446 64 ) ( 664 638 64 ) creeperpens/wl_astroid -4 -106 0.00 1 1 0 0 0 +( 668 446 60 ) ( 668 446 64 ) ( 668 638 64 ) creeperpens/wl_astroid 106 -44 0.00 1 1 0 0 0 +( 664 446 60 ) ( 664 446 64 ) ( 668 446 64 ) creeperpens/wl_astroid -4 -44 0.00 1 1 0 0 0 +( 664 638 60 ) ( 664 638 64 ) ( 664 446 64 ) creeperpens/wl_astroid 106 -44 0.00 1 1 0 0 0 +( 730 448 60 ) ( 727 448 64 ) ( 724 448 60 ) creeperpens/wl_astroid -4 -44 0.00 1 1 0 0 0 +} +// brush 28 +{ +( 672 638 60 ) ( 672 446 60 ) ( 676 446 60 ) creeperpens/wl_astroid -4 -106 0.00 1 1 0 0 0 +( 676 446 64 ) ( 672 446 64 ) ( 672 638 64 ) creeperpens/wl_astroid -4 -106 0.00 1 1 0 0 0 +( 676 446 60 ) ( 676 446 64 ) ( 676 638 64 ) creeperpens/wl_astroid 106 -44 0.00 1 1 0 0 0 +( 672 446 60 ) ( 672 446 64 ) ( 676 446 64 ) creeperpens/wl_astroid -4 -44 0.00 1 1 0 0 0 +( 672 638 60 ) ( 672 638 64 ) ( 672 446 64 ) creeperpens/wl_astroid 106 -44 0.00 1 1 0 0 0 +( 730 448 60 ) ( 727 448 64 ) ( 724 448 60 ) creeperpens/wl_astroid -4 -44 0.00 1 1 0 0 0 +} +// brush 29 +{ +( 664 638 56 ) ( 664 446 56 ) ( 676 446 56 ) creeperpens/wl_astroid -4 -106 0.00 1 1 0 0 0 +( 676 446 60 ) ( 664 446 60 ) ( 664 638 60 ) creeperpens/wl_astroid -4 -106 0.00 1 1 0 0 0 +( 676 446 56 ) ( 676 446 60 ) ( 676 638 60 ) creeperpens/wl_astroid 106 -44 0.00 1 1 0 0 0 +( 664 446 56 ) ( 664 446 60 ) ( 676 446 60 ) creeperpens/wl_astroid -4 -44 0.00 1 1 0 0 0 +( 664 638 56 ) ( 664 638 60 ) ( 664 446 60 ) creeperpens/wl_astroid 106 -44 0.00 1 1 0 0 0 +( 730 448 56 ) ( 727 448 60 ) ( 724 448 56 ) creeperpens/wl_astroid -4 -44 0.00 1 1 0 0 0 +} +// brush 30 +{ +( 664 638 64 ) ( 664 446 64 ) ( 676 446 64 ) creeperpens/wl_astroid -4 -106 0.00 1 1 0 0 0 +( 676 446 68 ) ( 664 446 68 ) ( 664 638 68 ) creeperpens/wl_astroid -4 -106 0.00 1 1 0 0 0 +( 676 446 64 ) ( 676 446 68 ) ( 676 638 68 ) creeperpens/wl_astroid 106 -44 0.00 1 1 0 0 0 +( 664 446 64 ) ( 664 446 68 ) ( 676 446 68 ) creeperpens/wl_astroid -4 -44 0.00 1 1 0 0 0 +( 664 638 64 ) ( 664 638 68 ) ( 664 446 68 ) creeperpens/wl_astroid 106 -44 0.00 1 1 0 0 0 +( 730 448 64 ) ( 727 448 68 ) ( 724 448 64 ) creeperpens/wl_astroid -4 -44 0.00 1 1 0 0 0 +} +// brush 31 +{ +( 672 638 68 ) ( 672 446 68 ) ( 676 446 68 ) creeperpens/wl_astroid -4 -106 0.00 1 1 0 0 0 +( 676 446 72 ) ( 672 446 72 ) ( 672 638 72 ) creeperpens/wl_astroid -4 -106 0.00 1 1 0 0 0 +( 676 446 68 ) ( 676 446 72 ) ( 676 638 72 ) creeperpens/wl_astroid 106 -44 0.00 1 1 0 0 0 +( 672 446 68 ) ( 672 446 72 ) ( 676 446 72 ) creeperpens/wl_astroid -4 -44 0.00 1 1 0 0 0 +( 672 638 68 ) ( 672 638 72 ) ( 672 446 72 ) creeperpens/wl_astroid 106 -44 0.00 1 1 0 0 0 +( 730 448 68 ) ( 727 448 72 ) ( 724 448 68 ) creeperpens/wl_astroid -4 -44 0.00 1 1 0 0 0 +} +// brush 32 +{ +( 664 638 68 ) ( 664 446 68 ) ( 668 446 68 ) creeperpens/wl_astroid -4 -106 0.00 1 1 0 0 0 +( 668 446 76 ) ( 664 446 76 ) ( 664 638 76 ) creeperpens/wl_astroid -4 -106 0.00 1 1 0 0 0 +( 668 446 68 ) ( 668 446 76 ) ( 668 638 76 ) creeperpens/wl_astroid 106 -44 0.00 1 1 0 0 0 +( 664 446 68 ) ( 664 446 76 ) ( 668 446 76 ) creeperpens/wl_astroid -4 -44 0.00 1 1 0 0 0 +( 664 638 68 ) ( 664 638 76 ) ( 664 446 76 ) creeperpens/wl_astroid 106 -44 0.00 1 1 0 0 0 +( 730 448 68 ) ( 727 448 76 ) ( 724 448 68 ) creeperpens/wl_astroid -4 -44 0.00 1 1 0 0 0 +} +// brush 33 +{ +( 668 638 72 ) ( 668 446 72 ) ( 676 446 72 ) creeperpens/wl_astroid -4 -106 0.00 1 1 0 0 0 +( 676 446 76 ) ( 668 446 76 ) ( 668 638 76 ) creeperpens/wl_astroid -4 -106 0.00 1 1 0 0 0 +( 676 446 72 ) ( 676 446 76 ) ( 676 638 76 ) creeperpens/wl_astroid 106 -44 0.00 1 1 0 0 0 +( 668 446 72 ) ( 668 446 76 ) ( 676 446 76 ) creeperpens/wl_astroid -4 -44 0.00 1 1 0 0 0 +( 668 638 72 ) ( 668 638 76 ) ( 668 446 76 ) creeperpens/wl_astroid 106 -44 0.00 1 1 0 0 0 +( 730 448 72 ) ( 727 448 76 ) ( 724 448 72 ) creeperpens/wl_astroid -4 -44 0.00 1 1 0 0 0 +} +// brush 34 +{ +( 648 638 72 ) ( 648 446 72 ) ( 656 446 72 ) creeperpens/wl_astroid 0 -106 0.00 1 1 0 0 0 +( 656 446 76 ) ( 648 446 76 ) ( 648 638 76 ) creeperpens/wl_astroid 0 -106 0.00 1 1 0 0 0 +( 656 446 72 ) ( 656 446 76 ) ( 656 638 76 ) creeperpens/wl_astroid 106 44 0.00 1 1 0 0 0 +( 648 446 72 ) ( 648 446 76 ) ( 656 446 76 ) creeperpens/wl_astroid 0 44 0.00 1 1 0 0 0 +( 648 638 72 ) ( 648 638 76 ) ( 648 446 76 ) creeperpens/wl_astroid 106 44 0.00 1 1 0 0 0 +( 726 448 72 ) ( 723 448 76 ) ( 720 448 72 ) creeperpens/wl_astroid 0 44 0.00 1 1 0 0 0 +} +// brush 35 +{ +( 656 446 68 ) ( 660 446 68 ) ( 660 638 68 ) creeperpens/wl_astroid 0 -106 0.00 1 1 0 0 0 +( 656 638 76 ) ( 660 638 72 ) ( 660 446 72 ) creeperpens/wl_astroid 0 -106 0.00 1 1 0 0 0 +( 660 446 68 ) ( 660 446 72 ) ( 660 638 72 ) creeperpens/wl_astroid 106 44 0.00 1 1 0 0 0 +( 656 446 68 ) ( 656 446 76 ) ( 660 446 76 ) creeperpens/wl_astroid 0 44 0.00 1 1 0 0 0 +( 656 638 68 ) ( 656 638 76 ) ( 656 446 76 ) creeperpens/wl_astroid 106 44 0.00 1 1 0 0 0 +( 726 448 68 ) ( 723 448 76 ) ( 720 448 68 ) creeperpens/wl_astroid 0 44 0.00 1 1 0 0 0 +} +// brush 36 +{ +( 648 638 60 ) ( 648 446 60 ) ( 652 446 60 ) creeperpens/wl_astroid 0 -106 0.00 1 1 0 0 0 +( 660 446 68 ) ( 656 446 68 ) ( 656 638 68 ) creeperpens/wl_astroid 0 -106 0.00 1 1 0 0 0 +( 660 638 68 ) ( 652 638 60 ) ( 652 446 60 ) creeperpens/wl_astroid 0 -106 0.00 1 1 0 0 0 +( 660 446 68 ) ( 652 446 60 ) ( 648 446 60 ) creeperpens/wl_astroid 0 44 0.00 1 1 0 0 0 +( 656 446 68 ) ( 648 446 60 ) ( 648 638 60 ) creeperpens/wl_astroid 0 -106 0.00 1 1 0 0 0 +( 726 448 60 ) ( 723 448 68 ) ( 720 448 60 ) creeperpens/wl_astroid 0 44 0.00 1 1 0 0 0 +} +// brush 37 +{ +( 648 638 56 ) ( 648 446 56 ) ( 660 446 56 ) creeperpens/wl_astroid 0 -106 0.00 1 1 0 0 0 +( 660 446 60 ) ( 648 446 60 ) ( 648 638 60 ) creeperpens/wl_astroid 0 -106 0.00 1 1 0 0 0 +( 660 446 56 ) ( 660 446 60 ) ( 660 638 60 ) creeperpens/wl_astroid 106 44 0.00 1 1 0 0 0 +( 648 446 56 ) ( 648 446 60 ) ( 660 446 60 ) creeperpens/wl_astroid 0 44 0.00 1 1 0 0 0 +( 648 638 56 ) ( 648 638 60 ) ( 648 446 60 ) creeperpens/wl_astroid 106 44 0.00 1 1 0 0 0 +( 726 448 56 ) ( 723 448 60 ) ( 720 448 56 ) creeperpens/wl_astroid 0 44 0.00 1 1 0 0 0 +} +// brush 38 +{ +( 640 638 56 ) ( 640 446 56 ) ( 644 446 56 ) creeperpens/wl_astroid -28 0 0.00 1 1 0 0 0 +( 644 446 76 ) ( 640 446 76 ) ( 640 638 76 ) creeperpens/wl_astroid -28 0 0.00 1 1 0 0 0 +( 644 446 56 ) ( 644 446 76 ) ( 644 638 76 ) creeperpens/wl_astroid 0 52 0.00 1 1 0 0 0 +( 640 446 56 ) ( 640 446 76 ) ( 644 446 76 ) creeperpens/wl_astroid -28 52 0.00 1 1 0 0 0 +( 640 638 56 ) ( 640 638 76 ) ( 640 446 76 ) creeperpens/wl_astroid 0 52 0.00 1 1 0 0 0 +( 750 448 56 ) ( 747 448 76 ) ( 744 448 56 ) creeperpens/wl_astroid -28 52 0.00 1 1 0 0 0 +} +// brush 39 +{ +( 568 638 72 ) ( 568 446 72 ) ( 580 446 72 ) creeperpens/wl_astroid -80 -106 0.00 1 1 0 0 0 +( 580 446 76 ) ( 568 446 76 ) ( 568 638 76 ) creeperpens/wl_astroid -80 -106 0.00 1 1 0 0 0 +( 580 446 72 ) ( 580 446 76 ) ( 580 638 76 ) creeperpens/wl_astroid 106 -44 0.00 1 1 0 0 0 +( 568 446 72 ) ( 568 446 76 ) ( 580 446 76 ) creeperpens/wl_astroid -80 -44 0.00 1 1 0 0 0 +( 568 638 72 ) ( 568 638 76 ) ( 568 446 76 ) creeperpens/wl_astroid 106 -44 0.00 1 1 0 0 0 +( 678 448 72 ) ( 675 448 76 ) ( 672 448 72 ) creeperpens/wl_astroid -80 -44 0.00 1 1 0 0 0 +} +// brush 40 +{ +( 568 638 56 ) ( 568 446 56 ) ( 572 446 56 ) creeperpens/wl_astroid -80 -106 0.00 1 1 0 0 0 +( 580 446 72 ) ( 576 446 72 ) ( 576 638 72 ) creeperpens/wl_astroid -80 -106 0.00 1 1 0 0 0 +( 580 638 72 ) ( 572 638 56 ) ( 572 446 56 ) creeperpens/wl_astroid 106 -44 0.00 1 1 0 0 0 +( 580 446 72 ) ( 572 446 56 ) ( 568 446 56 ) creeperpens/wl_astroid -80 -44 0.00 1 1 0 0 0 +( 576 446 72 ) ( 568 446 56 ) ( 568 638 56 ) creeperpens/wl_astroid 106 -44 0.00 1 1 0 0 0 +( 678 448 56 ) ( 675 448 72 ) ( 672 448 56 ) creeperpens/wl_astroid -80 -44 0.00 1 1 0 0 0 +} +// brush 41 +{ +( 544 638 56 ) ( 544 446 56 ) ( 548 446 56 ) creeperpens/wl_astroid -60 0 0.00 1 1 0 0 0 +( 548 446 76 ) ( 544 446 76 ) ( 544 638 76 ) creeperpens/wl_astroid -60 0 0.00 1 1 0 0 0 +( 548 446 56 ) ( 548 446 76 ) ( 548 638 76 ) creeperpens/wl_astroid 0 52 0.00 1 1 0 0 0 +( 544 446 56 ) ( 544 446 76 ) ( 548 446 76 ) creeperpens/wl_astroid -60 52 0.00 1 1 0 0 0 +( 544 638 56 ) ( 544 638 76 ) ( 544 446 76 ) creeperpens/wl_astroid 0 52 0.00 1 1 0 0 0 +( 654 448 56 ) ( 651 448 76 ) ( 648 448 56 ) creeperpens/wl_astroid -60 52 0.00 1 1 0 0 0 +} +// brush 42 +{ +( 552 638 56 ) ( 552 446 56 ) ( 564 446 56 ) creeperpens/wl_astroid -32 -106 0.00 1 1 0 0 0 +( 564 446 60 ) ( 552 446 60 ) ( 552 638 60 ) creeperpens/wl_astroid -32 -106 0.00 1 1 0 0 0 +( 564 446 56 ) ( 564 446 60 ) ( 564 638 60 ) creeperpens/wl_astroid 106 44 0.00 1 1 0 0 0 +( 552 446 56 ) ( 552 446 60 ) ( 564 446 60 ) creeperpens/wl_astroid -32 44 0.00 1 1 0 0 0 +( 552 638 56 ) ( 552 638 60 ) ( 552 446 60 ) creeperpens/wl_astroid 106 44 0.00 1 1 0 0 0 +( 630 448 56 ) ( 627 448 60 ) ( 624 448 56 ) creeperpens/wl_astroid -32 44 0.00 1 1 0 0 0 +} +// brush 43 +{ +( 552 638 60 ) ( 552 446 60 ) ( 556 446 60 ) creeperpens/wl_astroid -32 -106 0.00 1 1 0 0 0 +( 564 446 68 ) ( 560 446 68 ) ( 560 638 68 ) creeperpens/wl_astroid -32 -106 0.00 1 1 0 0 0 +( 564 638 68 ) ( 556 638 60 ) ( 556 446 60 ) creeperpens/wl_astroid -32 -106 0.00 1 1 0 0 0 +( 564 446 68 ) ( 556 446 60 ) ( 552 446 60 ) creeperpens/wl_astroid -32 44 0.00 1 1 0 0 0 +( 560 446 68 ) ( 552 446 60 ) ( 552 638 60 ) creeperpens/wl_astroid -32 -106 0.00 1 1 0 0 0 +( 630 448 60 ) ( 627 448 68 ) ( 624 448 60 ) creeperpens/wl_astroid -32 44 0.00 1 1 0 0 0 +} +// brush 44 +{ +( 560 446 68 ) ( 564 446 68 ) ( 564 638 68 ) creeperpens/wl_astroid -32 -106 0.00 1 1 0 0 0 +( 560 638 76 ) ( 564 638 72 ) ( 564 446 72 ) creeperpens/wl_astroid -32 -106 0.00 1 1 0 0 0 +( 564 446 68 ) ( 564 446 72 ) ( 564 638 72 ) creeperpens/wl_astroid 106 44 0.00 1 1 0 0 0 +( 560 446 68 ) ( 560 446 76 ) ( 564 446 76 ) creeperpens/wl_astroid -32 44 0.00 1 1 0 0 0 +( 560 638 68 ) ( 560 638 76 ) ( 560 446 76 ) creeperpens/wl_astroid 106 44 0.00 1 1 0 0 0 +( 630 448 68 ) ( 627 448 76 ) ( 624 448 68 ) creeperpens/wl_astroid -32 44 0.00 1 1 0 0 0 +} +// brush 45 +{ +( 552 638 72 ) ( 552 446 72 ) ( 560 446 72 ) creeperpens/wl_astroid -32 -106 0.00 1 1 0 0 0 +( 560 446 76 ) ( 552 446 76 ) ( 552 638 76 ) creeperpens/wl_astroid -32 -106 0.00 1 1 0 0 0 +( 560 446 72 ) ( 560 446 76 ) ( 560 638 76 ) creeperpens/wl_astroid 106 44 0.00 1 1 0 0 0 +( 552 446 72 ) ( 552 446 76 ) ( 560 446 76 ) creeperpens/wl_astroid -32 44 0.00 1 1 0 0 0 +( 552 638 72 ) ( 552 638 76 ) ( 552 446 76 ) creeperpens/wl_astroid 106 44 0.00 1 1 0 0 0 +( 630 448 72 ) ( 627 448 76 ) ( 624 448 72 ) creeperpens/wl_astroid -32 44 0.00 1 1 0 0 0 +} +// brush 46 +{ +( 512 640 64 ) ( 512 448 64 ) ( 512 448 0 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( 672 640 64 ) ( 512 640 64 ) ( 512 640 0 ) eden/edenwalltest -64 0 0.00 1 1 0 0 0 +( 512 448 64 ) ( 672 448 64 ) ( 672 448 0 ) eden/edenwalltest -64 0 0.00 1 1 0 0 0 +( 512 448 127 ) ( 512 640 127 ) ( 672 640 127 ) eden/WL_brick 0 0 0.00 1 1 0 0 0 +( 672 640 0 ) ( 512 640 0 ) ( 512 448 0 ) eden/edenwalltest -64 192 0.00 1 1 0 0 0 +( 608 448 64 ) ( 608 640 48 ) ( 608 448 32 ) eden/edenwalltest -64 192 0.00 1 1 0 0 0 +} +// brush 47 +{ +( 672 640 64 ) ( 512 640 64 ) ( 512 640 0 ) eden/WL_basement_2w -64 0 0.00 1 1 0 0 0 +( 704 448 64 ) ( 704 640 64 ) ( 704 640 0 ) eden/WL_basement_2w -64 0 0.00 1 1 0 0 0 +( 512 448 64 ) ( 672 448 64 ) ( 672 448 0 ) eden/WL_basement_2w -64 0 0.00 1 1 0 0 0 +( 512 448 128 ) ( 512 640 128 ) ( 672 640 128 ) eden/WL_basement_2w -64 0 0.00 1 1 0 0 0 +( 672 640 0 ) ( 512 640 0 ) ( 512 448 0 ) eden/WL_basement_2w -64 0 0.00 1 1 0 0 0 +( 608 640 48 ) ( 608 448 64 ) ( 608 448 32 ) eden/WL_basement_2w -64 0 0.00 1 1 0 0 0 +} +// brush 48 +{ +( 360 638 38 ) ( 360 446 38 ) ( 352 446 38 ) creeperpens/wl_astroid 52 -106 0.00 1 1 0 0 0 +( 352 446 34 ) ( 360 446 34 ) ( 360 638 34 ) creeperpens/wl_astroid 52 -106 0.00 1 1 0 0 0 +( 352 446 38 ) ( 352 446 34 ) ( 352 638 34 ) creeperpens/wl_astroid 106 -66 0.00 1 1 0 0 0 +( 360 446 38 ) ( 360 446 34 ) ( 352 446 34 ) creeperpens/wl_astroid 52 -66 0.00 1 1 0 0 0 +( 360 638 38 ) ( 360 638 34 ) ( 360 446 34 ) creeperpens/wl_astroid 106 -66 0.00 1 1 0 0 0 +( 298 448 38 ) ( 301 448 34 ) ( 304 448 38 ) creeperpens/wl_astroid 52 -66 0.00 1 1 0 0 0 +} +// brush 49 +{ +( 364 638 42 ) ( 364 446 42 ) ( 360 446 42 ) creeperpens/wl_astroid 52 -106 0.00 1 1 0 0 0 +( 364 446 38 ) ( 364 448 38 ) ( 360 448 34 ) creeperpens/wl_astroid 52 -106 0.00 1 1 0 0 0 +( 360 446 42 ) ( 360 446 34 ) ( 360 638 34 ) creeperpens/wl_astroid 106 -66 0.00 1 1 0 0 0 +( 364 446 42 ) ( 364 446 34 ) ( 360 446 34 ) creeperpens/wl_astroid 52 -66 0.00 1 1 0 0 0 +( 364 448 38 ) ( 364 446 38 ) ( 364 446 42 ) creeperpens/wl_astroid 106 -66 0.00 1 1 0 0 0 +( 298 448 42 ) ( 301 448 34 ) ( 304 448 42 ) creeperpens/wl_astroid 52 -66 0.00 1 1 0 0 0 +} +// brush 50 +{ +( 360 448 46 ) ( 360 446 46 ) ( 352 446 46 ) creeperpens/wl_astroid 52 -106 0.00 1 1 0 0 0 +( 356 448 42 ) ( 356 446 42 ) ( 364 446 42 ) creeperpens/wl_astroid 52 -106 0.00 1 1 0 0 0 +( 356 446 42 ) ( 356 448 42 ) ( 352 448 46 ) creeperpens/wl_astroid 106 -66 0.00 1 1 0 0 0 +( 364 446 46 ) ( 364 446 42 ) ( 352 446 42 ) creeperpens/wl_astroid 52 -66 0.00 1 1 0 0 0 +( 360 446 46 ) ( 360 448 46 ) ( 364 448 42 ) creeperpens/wl_astroid 106 -66 0.00 1 1 0 0 0 +( 298 448 46 ) ( 301 448 42 ) ( 304 448 46 ) creeperpens/wl_astroid 52 -66 0.00 1 1 0 0 0 +} +// brush 51 +{ +( 352 446 54 ) ( 352 448 54 ) ( 364 448 54 ) creeperpens/wl_astroid 52 -106 0.00 1 1 0 0 0 +( 352 446 50 ) ( 364 446 50 ) ( 364 638 50 ) creeperpens/wl_astroid 52 -106 0.00 1 1 0 0 0 +( 352 448 54 ) ( 352 446 54 ) ( 352 446 50 ) creeperpens/wl_astroid 106 -66 0.00 1 1 0 0 0 +( 364 446 54 ) ( 364 446 50 ) ( 352 446 50 ) creeperpens/wl_astroid 52 -66 0.00 1 1 0 0 0 +( 364 638 54 ) ( 364 638 50 ) ( 364 446 50 ) creeperpens/wl_astroid 106 -66 0.00 1 1 0 0 0 +( 298 448 54 ) ( 301 448 50 ) ( 304 448 54 ) creeperpens/wl_astroid 52 -66 0.00 1 1 0 0 0 +} +// brush 52 +{ +( 356 638 50 ) ( 356 446 50 ) ( 352 446 50 ) creeperpens/wl_astroid 52 -106 0.00 1 1 0 0 0 +( 352 446 46 ) ( 356 446 46 ) ( 356 638 46 ) creeperpens/wl_astroid 52 -106 0.00 1 1 0 0 0 +( 352 446 50 ) ( 352 446 46 ) ( 352 638 46 ) creeperpens/wl_astroid 106 -66 0.00 1 1 0 0 0 +( 356 446 50 ) ( 356 446 46 ) ( 352 446 46 ) creeperpens/wl_astroid 52 -66 0.00 1 1 0 0 0 +( 356 638 50 ) ( 356 638 46 ) ( 356 446 46 ) creeperpens/wl_astroid 106 -66 0.00 1 1 0 0 0 +( 298 448 50 ) ( 301 448 46 ) ( 304 448 50 ) creeperpens/wl_astroid 52 -66 0.00 1 1 0 0 0 +} +// brush 53 +{ +( 420 638 56 ) ( 420 446 56 ) ( 416 446 56 ) creeperpens/wl_astroid -12 -106 0.00 1 1 0 0 0 +( 416 446 52 ) ( 420 446 52 ) ( 420 638 52 ) creeperpens/wl_astroid -12 -106 0.00 1 1 0 0 0 +( 416 446 56 ) ( 416 446 52 ) ( 416 638 52 ) creeperpens/wl_astroid 106 -60 0.00 1 1 0 0 0 +( 420 446 56 ) ( 420 446 52 ) ( 416 446 52 ) creeperpens/wl_astroid -12 -60 0.00 1 1 0 0 0 +( 420 638 56 ) ( 420 638 52 ) ( 420 446 52 ) creeperpens/wl_astroid 106 -60 0.00 1 1 0 0 0 +( 362 448 56 ) ( 365 448 52 ) ( 368 448 56 ) creeperpens/wl_astroid -12 -60 0.00 1 1 0 0 0 +} +// brush 54 +{ +( 428 638 60 ) ( 428 446 60 ) ( 416 446 60 ) creeperpens/wl_astroid -12 -106 0.00 1 1 0 0 0 +( 416 446 56 ) ( 428 446 56 ) ( 428 638 56 ) creeperpens/wl_astroid -12 -106 0.00 1 1 0 0 0 +( 416 446 60 ) ( 416 446 56 ) ( 416 638 56 ) creeperpens/wl_astroid 106 -60 0.00 1 1 0 0 0 +( 428 446 60 ) ( 428 446 56 ) ( 416 446 56 ) creeperpens/wl_astroid -12 -60 0.00 1 1 0 0 0 +( 428 638 60 ) ( 428 638 56 ) ( 428 446 56 ) creeperpens/wl_astroid 106 -60 0.00 1 1 0 0 0 +( 362 448 60 ) ( 365 448 56 ) ( 368 448 60 ) creeperpens/wl_astroid -12 -60 0.00 1 1 0 0 0 +} +// brush 55 +{ +( 428 638 52 ) ( 428 446 52 ) ( 416 446 52 ) creeperpens/wl_astroid -12 -106 0.00 1 1 0 0 0 +( 416 446 48 ) ( 428 446 48 ) ( 428 638 48 ) creeperpens/wl_astroid -12 -106 0.00 1 1 0 0 0 +( 416 446 52 ) ( 416 446 48 ) ( 416 638 48 ) creeperpens/wl_astroid 106 -60 0.00 1 1 0 0 0 +( 428 446 52 ) ( 428 446 48 ) ( 416 446 48 ) creeperpens/wl_astroid -12 -60 0.00 1 1 0 0 0 +( 428 638 52 ) ( 428 638 48 ) ( 428 446 48 ) creeperpens/wl_astroid 106 -60 0.00 1 1 0 0 0 +( 362 448 52 ) ( 365 448 48 ) ( 368 448 52 ) creeperpens/wl_astroid -12 -60 0.00 1 1 0 0 0 +} +// brush 56 +{ +( 420 638 48 ) ( 420 446 48 ) ( 416 446 48 ) creeperpens/wl_astroid -12 -106 0.00 1 1 0 0 0 +( 416 446 44 ) ( 420 446 44 ) ( 420 638 44 ) creeperpens/wl_astroid -12 -106 0.00 1 1 0 0 0 +( 416 446 48 ) ( 416 446 44 ) ( 416 638 44 ) creeperpens/wl_astroid 106 -60 0.00 1 1 0 0 0 +( 420 446 48 ) ( 420 446 44 ) ( 416 446 44 ) creeperpens/wl_astroid -12 -60 0.00 1 1 0 0 0 +( 420 638 48 ) ( 420 638 44 ) ( 420 446 44 ) creeperpens/wl_astroid 106 -60 0.00 1 1 0 0 0 +( 362 448 48 ) ( 365 448 44 ) ( 368 448 48 ) creeperpens/wl_astroid -12 -60 0.00 1 1 0 0 0 +} +// brush 57 +{ +( 428 638 48 ) ( 428 446 48 ) ( 424 446 48 ) creeperpens/wl_astroid -12 -106 0.00 1 1 0 0 0 +( 424 446 40 ) ( 428 446 40 ) ( 428 638 40 ) creeperpens/wl_astroid -12 -106 0.00 1 1 0 0 0 +( 424 446 48 ) ( 424 446 40 ) ( 424 638 40 ) creeperpens/wl_astroid 106 -60 0.00 1 1 0 0 0 +( 428 446 48 ) ( 428 446 40 ) ( 424 446 40 ) creeperpens/wl_astroid -12 -60 0.00 1 1 0 0 0 +( 428 638 48 ) ( 428 638 40 ) ( 428 446 40 ) creeperpens/wl_astroid 106 -60 0.00 1 1 0 0 0 +( 362 448 48 ) ( 365 448 40 ) ( 368 448 48 ) creeperpens/wl_astroid -12 -60 0.00 1 1 0 0 0 +} +// brush 58 +{ +( 424 638 44 ) ( 424 446 44 ) ( 416 446 44 ) creeperpens/wl_astroid -12 -106 0.00 1 1 0 0 0 +( 416 446 40 ) ( 424 446 40 ) ( 424 638 40 ) creeperpens/wl_astroid -12 -106 0.00 1 1 0 0 0 +( 416 446 44 ) ( 416 446 40 ) ( 416 638 40 ) creeperpens/wl_astroid 106 -60 0.00 1 1 0 0 0 +( 424 446 44 ) ( 424 446 40 ) ( 416 446 40 ) creeperpens/wl_astroid -12 -60 0.00 1 1 0 0 0 +( 424 638 44 ) ( 424 638 40 ) ( 424 446 40 ) creeperpens/wl_astroid 106 -60 0.00 1 1 0 0 0 +( 362 448 44 ) ( 365 448 40 ) ( 368 448 44 ) creeperpens/wl_astroid -12 -60 0.00 1 1 0 0 0 +} +// brush 59 +{ +( 340 638 50 ) ( 340 446 50 ) ( 348 446 50 ) creeperpens/wl_astroid -60 -106 0.00 1 1 0 0 0 +( 348 446 54 ) ( 340 446 54 ) ( 340 638 54 ) creeperpens/wl_astroid -60 -106 0.00 1 1 0 0 0 +( 348 446 50 ) ( 348 446 54 ) ( 348 638 54 ) creeperpens/wl_astroid 106 -66 0.00 1 1 0 0 0 +( 340 446 50 ) ( 340 446 54 ) ( 348 446 54 ) creeperpens/wl_astroid -60 -66 0.00 1 1 0 0 0 +( 340 638 50 ) ( 340 638 54 ) ( 340 446 54 ) creeperpens/wl_astroid 106 -66 0.00 1 1 0 0 0 +( 402 448 50 ) ( 399 448 54 ) ( 396 448 50 ) creeperpens/wl_astroid -60 -66 0.00 1 1 0 0 0 +} +// brush 60 +{ +( 336 638 46 ) ( 336 446 46 ) ( 340 446 46 ) creeperpens/wl_astroid -60 -106 0.00 1 1 0 0 0 +( 340 446 54 ) ( 336 446 54 ) ( 336 638 54 ) creeperpens/wl_astroid -60 -106 0.00 1 1 0 0 0 +( 340 446 46 ) ( 340 446 54 ) ( 340 638 54 ) creeperpens/wl_astroid 106 -66 0.00 1 1 0 0 0 +( 336 446 46 ) ( 336 446 54 ) ( 340 446 54 ) creeperpens/wl_astroid -60 -66 0.00 1 1 0 0 0 +( 336 638 46 ) ( 336 638 54 ) ( 336 446 54 ) creeperpens/wl_astroid 106 -66 0.00 1 1 0 0 0 +( 402 448 46 ) ( 399 448 54 ) ( 396 448 46 ) creeperpens/wl_astroid -60 -66 0.00 1 1 0 0 0 +} +// brush 61 +{ +( 344 638 46 ) ( 344 446 46 ) ( 348 446 46 ) creeperpens/wl_astroid -60 -106 0.00 1 1 0 0 0 +( 348 446 50 ) ( 344 446 50 ) ( 344 638 50 ) creeperpens/wl_astroid -60 -106 0.00 1 1 0 0 0 +( 348 446 46 ) ( 348 446 50 ) ( 348 638 50 ) creeperpens/wl_astroid 106 -66 0.00 1 1 0 0 0 +( 344 446 46 ) ( 344 446 50 ) ( 348 446 50 ) creeperpens/wl_astroid -60 -66 0.00 1 1 0 0 0 +( 344 638 46 ) ( 344 638 50 ) ( 344 446 50 ) creeperpens/wl_astroid 106 -66 0.00 1 1 0 0 0 +( 402 448 46 ) ( 399 448 50 ) ( 396 448 46 ) creeperpens/wl_astroid -60 -66 0.00 1 1 0 0 0 +} +// brush 62 +{ +( 336 638 42 ) ( 336 446 42 ) ( 348 446 42 ) creeperpens/wl_astroid -60 -106 0.00 1 1 0 0 0 +( 348 446 46 ) ( 336 446 46 ) ( 336 638 46 ) creeperpens/wl_astroid -60 -106 0.00 1 1 0 0 0 +( 348 446 42 ) ( 348 446 46 ) ( 348 638 46 ) creeperpens/wl_astroid 106 -66 0.00 1 1 0 0 0 +( 336 446 42 ) ( 336 446 46 ) ( 348 446 46 ) creeperpens/wl_astroid -60 -66 0.00 1 1 0 0 0 +( 336 638 42 ) ( 336 638 46 ) ( 336 446 46 ) creeperpens/wl_astroid 106 -66 0.00 1 1 0 0 0 +( 402 448 42 ) ( 399 448 46 ) ( 396 448 42 ) creeperpens/wl_astroid -60 -66 0.00 1 1 0 0 0 +} +// brush 63 +{ +( 336 638 34 ) ( 336 446 34 ) ( 348 446 34 ) creeperpens/wl_astroid -60 -106 0.00 1 1 0 0 0 +( 348 446 38 ) ( 336 446 38 ) ( 336 638 38 ) creeperpens/wl_astroid -60 -106 0.00 1 1 0 0 0 +( 348 446 34 ) ( 348 446 38 ) ( 348 638 38 ) creeperpens/wl_astroid 106 -66 0.00 1 1 0 0 0 +( 336 446 34 ) ( 336 446 38 ) ( 348 446 38 ) creeperpens/wl_astroid -60 -66 0.00 1 1 0 0 0 +( 336 638 34 ) ( 336 638 38 ) ( 336 446 38 ) creeperpens/wl_astroid 106 -66 0.00 1 1 0 0 0 +( 402 448 34 ) ( 399 448 38 ) ( 396 448 34 ) creeperpens/wl_astroid -60 -66 0.00 1 1 0 0 0 +} +// brush 64 +{ +( 344 638 38 ) ( 344 446 38 ) ( 348 446 38 ) creeperpens/wl_astroid -60 -106 0.00 1 1 0 0 0 +( 348 446 42 ) ( 344 446 42 ) ( 344 638 42 ) creeperpens/wl_astroid -60 -106 0.00 1 1 0 0 0 +( 348 446 38 ) ( 348 446 42 ) ( 348 638 42 ) creeperpens/wl_astroid 106 -66 0.00 1 1 0 0 0 +( 344 446 38 ) ( 344 446 42 ) ( 348 446 42 ) creeperpens/wl_astroid -60 -66 0.00 1 1 0 0 0 +( 344 638 38 ) ( 344 638 42 ) ( 344 446 42 ) creeperpens/wl_astroid 106 -66 0.00 1 1 0 0 0 +( 402 448 38 ) ( 399 448 42 ) ( 396 448 38 ) creeperpens/wl_astroid -60 -66 0.00 1 1 0 0 0 +} +// brush 65 +{ +( 408 638 44 ) ( 408 446 44 ) ( 412 446 44 ) creeperpens/wl_astroid -124 -106 0.00 1 1 0 0 0 +( 412 446 48 ) ( 408 446 48 ) ( 408 638 48 ) creeperpens/wl_astroid -124 -106 0.00 1 1 0 0 0 +( 412 446 44 ) ( 412 446 48 ) ( 412 638 48 ) creeperpens/wl_astroid 106 -60 0.00 1 1 0 0 0 +( 408 446 44 ) ( 408 446 48 ) ( 412 446 48 ) creeperpens/wl_astroid -124 -60 0.00 1 1 0 0 0 +( 408 638 44 ) ( 408 638 48 ) ( 408 446 48 ) creeperpens/wl_astroid 106 -60 0.00 1 1 0 0 0 +( 466 448 44 ) ( 463 448 48 ) ( 460 448 44 ) creeperpens/wl_astroid -124 -60 0.00 1 1 0 0 0 +} +// brush 66 +{ +( 400 638 40 ) ( 400 446 40 ) ( 412 446 40 ) creeperpens/wl_astroid -124 -106 0.00 1 1 0 0 0 +( 412 446 44 ) ( 400 446 44 ) ( 400 638 44 ) creeperpens/wl_astroid -124 -106 0.00 1 1 0 0 0 +( 412 446 40 ) ( 412 446 44 ) ( 412 638 44 ) creeperpens/wl_astroid 106 -60 0.00 1 1 0 0 0 +( 400 446 40 ) ( 400 446 44 ) ( 412 446 44 ) creeperpens/wl_astroid -124 -60 0.00 1 1 0 0 0 +( 400 638 40 ) ( 400 638 44 ) ( 400 446 44 ) creeperpens/wl_astroid 106 -60 0.00 1 1 0 0 0 +( 466 448 40 ) ( 463 448 44 ) ( 460 448 40 ) creeperpens/wl_astroid -124 -60 0.00 1 1 0 0 0 +} +// brush 67 +{ +( 400 638 48 ) ( 400 446 48 ) ( 412 446 48 ) creeperpens/wl_astroid -124 -106 0.00 1 1 0 0 0 +( 412 446 52 ) ( 400 446 52 ) ( 400 638 52 ) creeperpens/wl_astroid -124 -106 0.00 1 1 0 0 0 +( 412 446 48 ) ( 412 446 52 ) ( 412 638 52 ) creeperpens/wl_astroid 106 -60 0.00 1 1 0 0 0 +( 400 446 48 ) ( 400 446 52 ) ( 412 446 52 ) creeperpens/wl_astroid -124 -60 0.00 1 1 0 0 0 +( 400 638 48 ) ( 400 638 52 ) ( 400 446 52 ) creeperpens/wl_astroid 106 -60 0.00 1 1 0 0 0 +( 466 448 48 ) ( 463 448 52 ) ( 460 448 48 ) creeperpens/wl_astroid -124 -60 0.00 1 1 0 0 0 +} +// brush 68 +{ +( 408 638 52 ) ( 408 446 52 ) ( 412 446 52 ) creeperpens/wl_astroid -124 -106 0.00 1 1 0 0 0 +( 412 446 56 ) ( 408 446 56 ) ( 408 638 56 ) creeperpens/wl_astroid -124 -106 0.00 1 1 0 0 0 +( 412 446 52 ) ( 412 446 56 ) ( 412 638 56 ) creeperpens/wl_astroid 106 -60 0.00 1 1 0 0 0 +( 408 446 52 ) ( 408 446 56 ) ( 412 446 56 ) creeperpens/wl_astroid -124 -60 0.00 1 1 0 0 0 +( 408 638 52 ) ( 408 638 56 ) ( 408 446 56 ) creeperpens/wl_astroid 106 -60 0.00 1 1 0 0 0 +( 466 448 52 ) ( 463 448 56 ) ( 460 448 52 ) creeperpens/wl_astroid -124 -60 0.00 1 1 0 0 0 +} +// brush 69 +{ +( 400 638 52 ) ( 400 446 52 ) ( 404 446 52 ) creeperpens/wl_astroid -124 -106 0.00 1 1 0 0 0 +( 404 446 60 ) ( 400 446 60 ) ( 400 638 60 ) creeperpens/wl_astroid -124 -106 0.00 1 1 0 0 0 +( 404 446 52 ) ( 404 446 60 ) ( 404 638 60 ) creeperpens/wl_astroid 106 -60 0.00 1 1 0 0 0 +( 400 446 52 ) ( 400 446 60 ) ( 404 446 60 ) creeperpens/wl_astroid -124 -60 0.00 1 1 0 0 0 +( 400 638 52 ) ( 400 638 60 ) ( 400 446 60 ) creeperpens/wl_astroid 106 -60 0.00 1 1 0 0 0 +( 466 448 52 ) ( 463 448 60 ) ( 460 448 52 ) creeperpens/wl_astroid -124 -60 0.00 1 1 0 0 0 +} +// brush 70 +{ +( 404 638 56 ) ( 404 446 56 ) ( 412 446 56 ) creeperpens/wl_astroid -124 -106 0.00 1 1 0 0 0 +( 412 446 60 ) ( 404 446 60 ) ( 404 638 60 ) creeperpens/wl_astroid -124 -106 0.00 1 1 0 0 0 +( 412 446 56 ) ( 412 446 60 ) ( 412 638 60 ) creeperpens/wl_astroid 106 -60 0.00 1 1 0 0 0 +( 404 446 56 ) ( 404 446 60 ) ( 412 446 60 ) creeperpens/wl_astroid -124 -60 0.00 1 1 0 0 0 +( 404 638 56 ) ( 404 638 60 ) ( 404 446 60 ) creeperpens/wl_astroid 106 -60 0.00 1 1 0 0 0 +( 466 448 56 ) ( 463 448 60 ) ( 460 448 56 ) creeperpens/wl_astroid -124 -60 0.00 1 1 0 0 0 +} +// brush 71 +{ +( 164 638 44 ) ( 164 446 44 ) ( 172 446 44 ) creeperpens/wl_astroid -12 -106 0.00 1 1 0 0 0 +( 172 446 48 ) ( 164 446 48 ) ( 164 638 48 ) creeperpens/wl_astroid -12 -106 0.00 1 1 0 0 0 +( 172 446 44 ) ( 172 446 48 ) ( 172 638 48 ) creeperpens/wl_astroid 106 -72 0.00 1 1 0 0 0 +( 164 446 44 ) ( 164 446 48 ) ( 172 446 48 ) creeperpens/wl_astroid -12 -72 0.00 1 1 0 0 0 +( 164 638 44 ) ( 164 638 48 ) ( 164 446 48 ) creeperpens/wl_astroid 106 -72 0.00 1 1 0 0 0 +( 226 448 44 ) ( 223 448 48 ) ( 220 448 44 ) creeperpens/wl_astroid -12 -72 0.00 1 1 0 0 0 +} +// brush 72 +{ +( 160 638 40 ) ( 160 446 40 ) ( 164 446 40 ) creeperpens/wl_astroid -12 -106 0.00 1 1 0 0 0 +( 164 446 48 ) ( 160 446 48 ) ( 160 638 48 ) creeperpens/wl_astroid -12 -106 0.00 1 1 0 0 0 +( 164 446 40 ) ( 164 446 48 ) ( 164 638 48 ) creeperpens/wl_astroid 106 -72 0.00 1 1 0 0 0 +( 160 446 40 ) ( 160 446 48 ) ( 164 446 48 ) creeperpens/wl_astroid -12 -72 0.00 1 1 0 0 0 +( 160 638 40 ) ( 160 638 48 ) ( 160 446 48 ) creeperpens/wl_astroid 106 -72 0.00 1 1 0 0 0 +( 226 448 40 ) ( 223 448 48 ) ( 220 448 40 ) creeperpens/wl_astroid -12 -72 0.00 1 1 0 0 0 +} +// brush 73 +{ +( 168 638 40 ) ( 168 446 40 ) ( 172 446 40 ) creeperpens/wl_astroid -12 -106 0.00 1 1 0 0 0 +( 172 446 44 ) ( 168 446 44 ) ( 168 638 44 ) creeperpens/wl_astroid -12 -106 0.00 1 1 0 0 0 +( 172 446 40 ) ( 172 446 44 ) ( 172 638 44 ) creeperpens/wl_astroid 106 -72 0.00 1 1 0 0 0 +( 168 446 40 ) ( 168 446 44 ) ( 172 446 44 ) creeperpens/wl_astroid -12 -72 0.00 1 1 0 0 0 +( 168 638 40 ) ( 168 638 44 ) ( 168 446 44 ) creeperpens/wl_astroid 106 -72 0.00 1 1 0 0 0 +( 226 448 40 ) ( 223 448 44 ) ( 220 448 40 ) creeperpens/wl_astroid -12 -72 0.00 1 1 0 0 0 +} +// brush 74 +{ +( 160 638 36 ) ( 160 446 36 ) ( 172 446 36 ) creeperpens/wl_astroid -12 -106 0.00 1 1 0 0 0 +( 172 446 40 ) ( 160 446 40 ) ( 160 638 40 ) creeperpens/wl_astroid -12 -106 0.00 1 1 0 0 0 +( 172 446 36 ) ( 172 446 40 ) ( 172 638 40 ) creeperpens/wl_astroid 106 -72 0.00 1 1 0 0 0 +( 160 446 36 ) ( 160 446 40 ) ( 172 446 40 ) creeperpens/wl_astroid -12 -72 0.00 1 1 0 0 0 +( 160 638 36 ) ( 160 638 40 ) ( 160 446 40 ) creeperpens/wl_astroid 106 -72 0.00 1 1 0 0 0 +( 226 448 36 ) ( 223 448 40 ) ( 220 448 36 ) creeperpens/wl_astroid -12 -72 0.00 1 1 0 0 0 +} +// brush 75 +{ +( 160 638 28 ) ( 160 446 28 ) ( 172 446 28 ) creeperpens/wl_astroid -12 -106 0.00 1 1 0 0 0 +( 172 446 32 ) ( 160 446 32 ) ( 160 638 32 ) creeperpens/wl_astroid -12 -106 0.00 1 1 0 0 0 +( 172 446 28 ) ( 172 446 32 ) ( 172 638 32 ) creeperpens/wl_astroid 106 -72 0.00 1 1 0 0 0 +( 160 446 28 ) ( 160 446 32 ) ( 172 446 32 ) creeperpens/wl_astroid -12 -72 0.00 1 1 0 0 0 +( 160 638 28 ) ( 160 638 32 ) ( 160 446 32 ) creeperpens/wl_astroid 106 -72 0.00 1 1 0 0 0 +( 226 448 28 ) ( 223 448 32 ) ( 220 448 28 ) creeperpens/wl_astroid -12 -72 0.00 1 1 0 0 0 +} +// brush 76 +{ +( 168 638 32 ) ( 168 446 32 ) ( 172 446 32 ) creeperpens/wl_astroid -12 -106 0.00 1 1 0 0 0 +( 172 446 36 ) ( 168 446 36 ) ( 168 638 36 ) creeperpens/wl_astroid -12 -106 0.00 1 1 0 0 0 +( 172 446 32 ) ( 172 446 36 ) ( 172 638 36 ) creeperpens/wl_astroid 106 -72 0.00 1 1 0 0 0 +( 168 446 32 ) ( 168 446 36 ) ( 172 446 36 ) creeperpens/wl_astroid -12 -72 0.00 1 1 0 0 0 +( 168 638 32 ) ( 168 638 36 ) ( 168 446 36 ) creeperpens/wl_astroid 106 -72 0.00 1 1 0 0 0 +( 226 448 32 ) ( 223 448 36 ) ( 220 448 32 ) creeperpens/wl_astroid -12 -72 0.00 1 1 0 0 0 +} +// brush 77 +{ +( 146 638 28 ) ( 146 446 28 ) ( 150 446 28 ) creeperpens/wl_astroid -42 -106 0.00 1 1 0 0 0 +( 158 446 44 ) ( 154 446 44 ) ( 154 638 44 ) creeperpens/wl_astroid -42 -106 0.00 1 1 0 0 0 +( 158 638 44 ) ( 150 638 28 ) ( 150 446 28 ) creeperpens/wl_astroid 106 -72 0.00 1 1 0 0 0 +( 158 446 44 ) ( 150 446 28 ) ( 146 446 28 ) creeperpens/wl_astroid -42 -72 0.00 1 1 0 0 0 +( 154 446 44 ) ( 146 446 28 ) ( 146 638 28 ) creeperpens/wl_astroid 106 -72 0.00 1 1 0 0 0 +( 256 448 28 ) ( 253 448 44 ) ( 250 448 28 ) creeperpens/wl_astroid -42 -72 0.00 1 1 0 0 0 +} +// brush 78 +{ +( 146 638 44 ) ( 146 446 44 ) ( 158 446 44 ) creeperpens/wl_astroid -42 -106 0.00 1 1 0 0 0 +( 158 446 48 ) ( 146 446 48 ) ( 146 638 48 ) creeperpens/wl_astroid -42 -106 0.00 1 1 0 0 0 +( 158 446 44 ) ( 158 446 48 ) ( 158 638 48 ) creeperpens/wl_astroid 106 -72 0.00 1 1 0 0 0 +( 146 446 44 ) ( 146 446 48 ) ( 158 446 48 ) creeperpens/wl_astroid -42 -72 0.00 1 1 0 0 0 +( 146 638 44 ) ( 146 638 48 ) ( 146 446 48 ) creeperpens/wl_astroid 106 -72 0.00 1 1 0 0 0 +( 256 448 44 ) ( 253 448 48 ) ( 250 448 44 ) creeperpens/wl_astroid -42 -72 0.00 1 1 0 0 0 +} +// brush 79 +{ +( 234 448 44 ) ( 230 448 44 ) ( 230 446 44 ) creeperpens/wl_astroid -64 -72 0.00 1 1 0 0 0 +( 230 446 48 ) ( 230 448 48 ) ( 234 448 48 ) creeperpens/wl_astroid -64 -72 0.00 1 1 0 0 0 +( 230 446 48 ) ( 234 446 48 ) ( 234 446 44 ) creeperpens/wl_astroid -64 -72 0.00 1 1 0 0 0 +( 234 446 48 ) ( 234 448 48 ) ( 234 448 44 ) creeperpens/wl_astroid -64 -72 0.00 1 1 0 0 0 +( 234 448 48 ) ( 230 448 48 ) ( 230 448 44 ) creeperpens/wl_astroid -64 -72 0.00 1 1 0 0 0 +( 230 448 48 ) ( 230 446 48 ) ( 230 446 44 ) creeperpens/wl_astroid -64 -72 0.00 1 1 0 0 0 +} +// brush 80 +{ +( 238 448 28 ) ( 234 448 28 ) ( 234 446 28 ) creeperpens/wl_astroid -64 -72 0.00 1 1 0 0 0 +( 234 446 48 ) ( 234 448 48 ) ( 238 448 48 ) creeperpens/wl_astroid -64 -72 0.00 1 1 0 0 0 +( 234 446 48 ) ( 238 446 48 ) ( 238 446 28 ) creeperpens/wl_astroid -64 -72 0.00 1 1 0 0 0 +( 238 446 48 ) ( 238 448 48 ) ( 238 448 28 ) creeperpens/wl_astroid -64 -72 0.00 1 1 0 0 0 +( 238 448 48 ) ( 234 448 48 ) ( 234 448 28 ) creeperpens/wl_astroid -64 -72 0.00 1 1 0 0 0 +( 234 448 48 ) ( 234 446 48 ) ( 234 446 28 ) creeperpens/wl_astroid -64 -72 0.00 1 1 0 0 0 +} +// brush 81 +{ +( 234 448 28 ) ( 230 448 28 ) ( 230 446 28 ) creeperpens/wl_astroid -64 -72 0.00 1 1 0 0 0 +( 230 446 32 ) ( 230 448 32 ) ( 234 448 32 ) creeperpens/wl_astroid -64 -72 0.00 1 1 0 0 0 +( 230 446 32 ) ( 234 446 32 ) ( 234 446 28 ) creeperpens/wl_astroid -64 -72 0.00 1 1 0 0 0 +( 234 446 32 ) ( 234 448 32 ) ( 234 448 28 ) creeperpens/wl_astroid -64 -72 0.00 1 1 0 0 0 +( 234 448 32 ) ( 230 448 32 ) ( 230 448 28 ) creeperpens/wl_astroid -64 -72 0.00 1 1 0 0 0 +( 230 448 32 ) ( 230 446 32 ) ( 230 446 28 ) creeperpens/wl_astroid -64 -72 0.00 1 1 0 0 0 +} +// brush 82 +{ +( 230 448 28 ) ( 226 448 28 ) ( 226 446 28 ) creeperpens/wl_astroid -64 -72 0.00 1 1 0 0 0 +( 226 446 48 ) ( 226 448 48 ) ( 230 448 48 ) creeperpens/wl_astroid -64 -72 0.00 1 1 0 0 0 +( 226 446 48 ) ( 230 446 48 ) ( 230 446 28 ) creeperpens/wl_astroid -64 -72 0.00 1 1 0 0 0 +( 230 446 48 ) ( 230 448 48 ) ( 230 448 28 ) creeperpens/wl_astroid -64 -72 0.00 1 1 0 0 0 +( 230 448 48 ) ( 226 448 48 ) ( 226 448 28 ) creeperpens/wl_astroid -64 -72 0.00 1 1 0 0 0 +( 226 448 48 ) ( 226 446 48 ) ( 226 446 28 ) creeperpens/wl_astroid -64 -72 0.00 1 1 0 0 0 +} +// brush 83 +{ +( 216 638 44 ) ( 216 446 44 ) ( 224 446 44 ) creeperpens/wl_astroid -64 -106 0.00 1 1 0 0 0 +( 224 446 48 ) ( 216 446 48 ) ( 216 638 48 ) creeperpens/wl_astroid -64 -106 0.00 1 1 0 0 0 +( 224 446 44 ) ( 224 446 48 ) ( 224 638 48 ) creeperpens/wl_astroid 106 -72 0.00 1 1 0 0 0 +( 216 446 44 ) ( 216 446 48 ) ( 224 446 48 ) creeperpens/wl_astroid -64 -72 0.00 1 1 0 0 0 +( 216 638 44 ) ( 216 638 48 ) ( 216 446 48 ) creeperpens/wl_astroid 106 -72 0.00 1 1 0 0 0 +( 278 448 44 ) ( 275 448 48 ) ( 272 448 44 ) creeperpens/wl_astroid -64 -72 0.00 1 1 0 0 0 +} +// brush 84 +{ +( 212 638 40 ) ( 212 446 40 ) ( 216 446 40 ) creeperpens/wl_astroid -64 -106 0.00 1 1 0 0 0 +( 216 446 48 ) ( 212 446 48 ) ( 212 638 48 ) creeperpens/wl_astroid -64 -106 0.00 1 1 0 0 0 +( 216 446 40 ) ( 216 446 48 ) ( 216 638 48 ) creeperpens/wl_astroid 106 -72 0.00 1 1 0 0 0 +( 212 446 40 ) ( 212 446 48 ) ( 216 446 48 ) creeperpens/wl_astroid -64 -72 0.00 1 1 0 0 0 +( 212 638 40 ) ( 212 638 48 ) ( 212 446 48 ) creeperpens/wl_astroid 106 -72 0.00 1 1 0 0 0 +( 278 448 40 ) ( 275 448 48 ) ( 272 448 40 ) creeperpens/wl_astroid -64 -72 0.00 1 1 0 0 0 +} +// brush 85 +{ +( 220 638 40 ) ( 220 446 40 ) ( 224 446 40 ) creeperpens/wl_astroid -64 -106 0.00 1 1 0 0 0 +( 224 446 44 ) ( 220 446 44 ) ( 220 638 44 ) creeperpens/wl_astroid -64 -106 0.00 1 1 0 0 0 +( 224 446 40 ) ( 224 446 44 ) ( 224 638 44 ) creeperpens/wl_astroid 106 -72 0.00 1 1 0 0 0 +( 220 446 40 ) ( 220 446 44 ) ( 224 446 44 ) creeperpens/wl_astroid -64 -72 0.00 1 1 0 0 0 +( 220 638 40 ) ( 220 638 44 ) ( 220 446 44 ) creeperpens/wl_astroid 106 -72 0.00 1 1 0 0 0 +( 278 448 40 ) ( 275 448 44 ) ( 272 448 40 ) creeperpens/wl_astroid -64 -72 0.00 1 1 0 0 0 +} +// brush 86 +{ +( 212 638 36 ) ( 212 446 36 ) ( 224 446 36 ) creeperpens/wl_astroid -64 -106 0.00 1 1 0 0 0 +( 224 446 40 ) ( 212 446 40 ) ( 212 638 40 ) creeperpens/wl_astroid -64 -106 0.00 1 1 0 0 0 +( 224 446 36 ) ( 224 446 40 ) ( 224 638 40 ) creeperpens/wl_astroid 106 -72 0.00 1 1 0 0 0 +( 212 446 36 ) ( 212 446 40 ) ( 224 446 40 ) creeperpens/wl_astroid -64 -72 0.00 1 1 0 0 0 +( 212 638 36 ) ( 212 638 40 ) ( 212 446 40 ) creeperpens/wl_astroid 106 -72 0.00 1 1 0 0 0 +( 278 448 36 ) ( 275 448 40 ) ( 272 448 36 ) creeperpens/wl_astroid -64 -72 0.00 1 1 0 0 0 +} +// brush 87 +{ +( 212 638 28 ) ( 212 446 28 ) ( 224 446 28 ) creeperpens/wl_astroid -64 -106 0.00 1 1 0 0 0 +( 224 446 32 ) ( 212 446 32 ) ( 212 638 32 ) creeperpens/wl_astroid -64 -106 0.00 1 1 0 0 0 +( 224 446 28 ) ( 224 446 32 ) ( 224 638 32 ) creeperpens/wl_astroid 106 -72 0.00 1 1 0 0 0 +( 212 446 28 ) ( 212 446 32 ) ( 224 446 32 ) creeperpens/wl_astroid -64 -72 0.00 1 1 0 0 0 +( 212 638 28 ) ( 212 638 32 ) ( 212 446 32 ) creeperpens/wl_astroid 106 -72 0.00 1 1 0 0 0 +( 278 448 28 ) ( 275 448 32 ) ( 272 448 28 ) creeperpens/wl_astroid -64 -72 0.00 1 1 0 0 0 +} +// brush 88 +{ +( 220 638 32 ) ( 220 446 32 ) ( 224 446 32 ) creeperpens/wl_astroid -64 -106 0.00 1 1 0 0 0 +( 224 446 36 ) ( 220 446 36 ) ( 220 638 36 ) creeperpens/wl_astroid -64 -106 0.00 1 1 0 0 0 +( 224 446 32 ) ( 224 446 36 ) ( 224 638 36 ) creeperpens/wl_astroid 106 -72 0.00 1 1 0 0 0 +( 220 446 32 ) ( 220 446 36 ) ( 224 446 36 ) creeperpens/wl_astroid -64 -72 0.00 1 1 0 0 0 +( 220 638 32 ) ( 220 638 36 ) ( 220 446 36 ) creeperpens/wl_astroid 106 -72 0.00 1 1 0 0 0 +( 278 448 32 ) ( 275 448 36 ) ( 272 448 32 ) creeperpens/wl_astroid -64 -72 0.00 1 1 0 0 0 +} +// brush 89 +{ +( 212 638 32 ) ( 212 446 32 ) ( 216 446 32 ) creeperpens/wl_astroid -64 -106 0.00 1 1 0 0 0 +( 216 446 36 ) ( 212 446 36 ) ( 212 638 36 ) creeperpens/wl_astroid -64 -106 0.00 1 1 0 0 0 +( 216 446 32 ) ( 216 446 36 ) ( 216 638 36 ) creeperpens/wl_astroid 106 -72 0.00 1 1 0 0 0 +( 212 446 32 ) ( 212 446 36 ) ( 216 446 36 ) creeperpens/wl_astroid -64 -72 0.00 1 1 0 0 0 +( 212 638 32 ) ( 212 638 36 ) ( 212 446 36 ) creeperpens/wl_astroid 106 -72 0.00 1 1 0 0 0 +( 278 448 32 ) ( 275 448 36 ) ( 272 448 32 ) creeperpens/wl_astroid -64 -72 0.00 1 1 0 0 0 +} +// brush 90 +{ +( 256 640 0 ) ( 256 640 80 ) ( 192 640 80 ) eden/WL_basement_2w -192 0 0.00 1 1 0 0 0 +( 256 640 80 ) ( 256 640 0 ) ( 256 448 0 ) eden/WL_basement_2w -192 0 0.00 1 1 0 0 0 +( 256 448 80 ) ( 256 448 0 ) ( 192 448 0 ) eden/WL_basement_2w -192 0 0.00 1 1 0 0 0 +( 256 640 80 ) ( 256 448 80 ) ( 192 448 80 ) eden/WL_basement_2w -192 192 0.00 1 1 0 0 0 +( 256 448 0 ) ( 256 640 0 ) ( 192 640 0 ) eden/WL_basement_2w -192 192 0.00 1 1 0 0 0 +( 192 640 0 ) ( 192 640 80 ) ( 192 448 80 ) eden/WL_basement_2w -192 0 0.00 1 1 0 0 0 +} +// brush 91 +{ +( 192 640 0 ) ( 192 640 79 ) ( 128 640 79 ) eden/edenwalltest 0 0 0.00 1 1 0 0 0 +( 192 640 79 ) ( 192 640 0 ) ( 192 448 0 ) eden/edenwalltest 0 0 0.00 1 1 0 0 0 +( 192 448 79 ) ( 192 448 0 ) ( 128 448 0 ) eden/edenwalltest 0 0 0.00 1 1 0 0 0 +( 192 640 79 ) ( 192 448 79 ) ( 128 448 79 ) eden/WL_brick 0 0 0.00 1 1 0 0 0 +( 192 448 0 ) ( 192 640 0 ) ( 128 640 0 ) eden/edenwalltest 0 0 0.00 1 1 0 0 0 +( 128 640 0 ) ( 128 640 79 ) ( 128 448 79 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +} +// brush 92 +{ +( -224 640 0 ) ( -224 640 47 ) ( -288 640 47 ) eden/edenwalltest 192 0 0.00 1 1 0 0 0 +( -224 640 47 ) ( -224 640 0 ) ( -224 448 0 ) eden/edenwalltest 192 0 0.00 1 1 0 0 0 +( -224 448 47 ) ( -224 448 0 ) ( -288 448 0 ) eden/edenwalltest 192 0 0.00 1 1 0 0 0 +( -224 640 47 ) ( -224 448 47 ) ( -288 448 47 ) eden/WL_brick 0 0 0.00 1 1 0 0 0 +( -224 448 0 ) ( -224 640 0 ) ( -288 640 0 ) eden/edenwalltest 192 0 0.00 1 1 0 0 0 +( -288 640 0 ) ( -288 640 47 ) ( -288 448 47 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +} +// brush 93 +{ +( -224 640 48 ) ( -224 640 0 ) ( -160 640 0 ) eden/WL_basement_2w -32 0 0.00 1 1 0 0 0 +( -160 640 48 ) ( -160 640 0 ) ( -160 448 0 ) eden/WL_basement_2w -192 0 0.00 1 1 0 0 0 +( -224 448 0 ) ( -224 448 48 ) ( -160 448 48 ) eden/WL_basement_2w -32 0 0.00 1 1 0 0 0 +( -224 448 48 ) ( -224 640 48 ) ( -160 640 48 ) eden/WL_basement_2w -32 192 0.00 1 1 0 0 0 +( -224 640 0 ) ( -224 448 0 ) ( -160 448 0 ) eden/WL_basement_2w -32 192 0.00 1 1 0 0 0 +( -224 640 0 ) ( -224 640 48 ) ( -224 448 48 ) eden/WL_basement_2w -192 0 0.00 1 1 0 0 0 +} +// brush 94 +{ +( -432 638 20 ) ( -432 446 20 ) ( -416 446 20 ) creeperpens/wl_astroid 36 -106 0.00 1 1 0 0 0 +( -428 638 24 ) ( -420 638 24 ) ( -420 446 24 ) creeperpens/wl_astroid 36 -106 0.00 1 1 0 0 0 +( -412 446 16 ) ( -420 446 24 ) ( -420 638 24 ) creeperpens/wl_astroid 36 -106 0.00 1 1 0 0 0 +( -428 446 16 ) ( -428 446 24 ) ( -412 446 24 ) creeperpens/wl_astroid 36 -8 0.00 1 1 0 0 0 +( -428 638 16 ) ( -428 638 24 ) ( -428 446 24 ) creeperpens/wl_astroid 106 -8 0.00 1 1 0 0 0 +( -334 448 20 ) ( -337 448 24 ) ( -340 448 20 ) creeperpens/wl_astroid 36 -8 0.00 1 1 0 0 0 +} +// brush 95 +{ +( -420 638 16 ) ( -420 446 16 ) ( -416 446 16 ) creeperpens/wl_astroid 36 -106 0.00 1 1 0 0 0 +( -416 446 20 ) ( -420 446 20 ) ( -420 638 20 ) creeperpens/wl_astroid 36 -106 0.00 1 1 0 0 0 +( -416 446 16 ) ( -416 446 20 ) ( -416 638 20 ) creeperpens/wl_astroid 106 -8 0.00 1 1 0 0 0 +( -420 446 16 ) ( -420 446 20 ) ( -416 446 20 ) creeperpens/wl_astroid 36 -8 0.00 1 1 0 0 0 +( -420 638 16 ) ( -420 638 20 ) ( -420 446 20 ) creeperpens/wl_astroid 106 -8 0.00 1 1 0 0 0 +( -334 448 16 ) ( -337 448 20 ) ( -340 448 16 ) creeperpens/wl_astroid 36 -8 0.00 1 1 0 0 0 +} +// brush 96 +{ +( -424 638 12 ) ( -424 446 12 ) ( -416 446 12 ) creeperpens/wl_astroid 36 -106 0.00 1 1 0 0 0 +( -416 446 16 ) ( -424 446 16 ) ( -424 638 16 ) creeperpens/wl_astroid 36 -106 0.00 1 1 0 0 0 +( -416 446 12 ) ( -416 446 16 ) ( -416 638 16 ) creeperpens/wl_astroid 106 -8 0.00 1 1 0 0 0 +( -424 446 12 ) ( -424 446 16 ) ( -416 446 16 ) creeperpens/wl_astroid 36 -8 0.00 1 1 0 0 0 +( -424 638 12 ) ( -424 638 16 ) ( -424 446 16 ) creeperpens/wl_astroid 106 -8 0.00 1 1 0 0 0 +( -334 448 12 ) ( -337 448 16 ) ( -340 448 12 ) creeperpens/wl_astroid 36 -8 0.00 1 1 0 0 0 +} +// brush 97 +{ +( -420 638 8 ) ( -420 446 8 ) ( -416 446 8 ) creeperpens/wl_astroid 36 -106 0.00 1 1 0 0 0 +( -416 446 12 ) ( -420 446 12 ) ( -420 638 12 ) creeperpens/wl_astroid 36 -106 0.00 1 1 0 0 0 +( -416 446 8 ) ( -416 446 12 ) ( -416 638 12 ) creeperpens/wl_astroid 106 -8 0.00 1 1 0 0 0 +( -420 446 8 ) ( -420 446 12 ) ( -416 446 12 ) creeperpens/wl_astroid 36 -8 0.00 1 1 0 0 0 +( -420 638 8 ) ( -420 638 12 ) ( -420 446 12 ) creeperpens/wl_astroid 106 -8 0.00 1 1 0 0 0 +( -334 448 8 ) ( -337 448 12 ) ( -340 448 8 ) creeperpens/wl_astroid 36 -8 0.00 1 1 0 0 0 +} +// brush 98 +{ +( -428 446 4 ) ( -420 446 4 ) ( -420 638 4 ) creeperpens/wl_astroid 36 -106 0.00 1 1 0 0 0 +( -416 446 8 ) ( -428 446 8 ) ( -428 638 8 ) creeperpens/wl_astroid 36 -106 0.00 1 1 0 0 0 +( -416 638 8 ) ( -420 638 4 ) ( -420 446 4 ) creeperpens/wl_astroid 36 -106 0.00 1 1 0 0 0 +( -428 446 4 ) ( -428 446 8 ) ( -416 446 8 ) creeperpens/wl_astroid 36 -8 0.00 1 1 0 0 0 +( -428 638 4 ) ( -428 638 8 ) ( -428 446 8 ) creeperpens/wl_astroid 106 -8 0.00 1 1 0 0 0 +( -334 448 4 ) ( -337 448 8 ) ( -340 448 4 ) creeperpens/wl_astroid 36 -8 0.00 1 1 0 0 0 +} +// brush 99 +{ +( -412 638 20 ) ( -412 446 20 ) ( -404 446 20 ) creeperpens/wl_astroid 36 -106 0.00 1 1 0 0 0 +( -404 446 24 ) ( -412 446 24 ) ( -412 638 24 ) creeperpens/wl_astroid 36 -106 0.00 1 1 0 0 0 +( -404 446 20 ) ( -404 446 24 ) ( -404 638 24 ) creeperpens/wl_astroid 106 -8 0.00 1 1 0 0 0 +( -412 446 20 ) ( -412 446 24 ) ( -404 446 24 ) creeperpens/wl_astroid 36 -8 0.00 1 1 0 0 0 +( -412 638 20 ) ( -412 638 24 ) ( -412 446 24 ) creeperpens/wl_astroid 106 -8 0.00 1 1 0 0 0 +( -334 448 20 ) ( -337 448 24 ) ( -340 448 20 ) creeperpens/wl_astroid 36 -8 0.00 1 1 0 0 0 +} +// brush 100 +{ +( -404 446 16 ) ( -400 446 16 ) ( -400 638 16 ) creeperpens/wl_astroid 36 -106 0.00 1 1 0 0 0 +( -404 638 24 ) ( -400 638 20 ) ( -400 446 20 ) creeperpens/wl_astroid 36 -106 0.00 1 1 0 0 0 +( -400 446 16 ) ( -400 446 20 ) ( -400 638 20 ) creeperpens/wl_astroid 106 -8 0.00 1 1 0 0 0 +( -404 446 16 ) ( -404 446 24 ) ( -400 446 24 ) creeperpens/wl_astroid 36 -8 0.00 1 1 0 0 0 +( -404 638 16 ) ( -404 638 24 ) ( -404 446 24 ) creeperpens/wl_astroid 106 -8 0.00 1 1 0 0 0 +( -334 448 16 ) ( -337 448 24 ) ( -340 448 16 ) creeperpens/wl_astroid 36 -8 0.00 1 1 0 0 0 +} +// brush 101 +{ +( -412 638 8 ) ( -412 446 8 ) ( -408 446 8 ) creeperpens/wl_astroid 36 -106 0.00 1 1 0 0 0 +( -400 446 16 ) ( -404 446 16 ) ( -404 638 16 ) creeperpens/wl_astroid 36 -106 0.00 1 1 0 0 0 +( -400 638 16 ) ( -408 638 8 ) ( -408 446 8 ) creeperpens/wl_astroid 36 -106 0.00 1 1 0 0 0 +( -400 446 16 ) ( -408 446 8 ) ( -412 446 8 ) creeperpens/wl_astroid 36 -8 0.00 1 1 0 0 0 +( -404 446 16 ) ( -412 446 8 ) ( -412 638 8 ) creeperpens/wl_astroid 36 -106 0.00 1 1 0 0 0 +( -334 448 8 ) ( -337 448 16 ) ( -340 448 8 ) creeperpens/wl_astroid 36 -8 0.00 1 1 0 0 0 +} +// brush 102 +{ +( -412 638 4 ) ( -412 446 4 ) ( -400 446 4 ) creeperpens/wl_astroid 36 -106 0.00 1 1 0 0 0 +( -400 446 8 ) ( -412 446 8 ) ( -412 638 8 ) creeperpens/wl_astroid 36 -106 0.00 1 1 0 0 0 +( -400 446 4 ) ( -400 446 8 ) ( -400 638 8 ) creeperpens/wl_astroid 106 -8 0.00 1 1 0 0 0 +( -412 446 4 ) ( -412 446 8 ) ( -400 446 8 ) creeperpens/wl_astroid 36 -8 0.00 1 1 0 0 0 +( -412 638 4 ) ( -412 638 8 ) ( -412 446 8 ) creeperpens/wl_astroid 106 -8 0.00 1 1 0 0 0 +( -334 448 4 ) ( -337 448 8 ) ( -340 448 4 ) creeperpens/wl_astroid 36 -8 0.00 1 1 0 0 0 +} +// brush 103 +{ +( -496 638 20 ) ( -496 446 20 ) ( -480 446 20 ) creeperpens/wl_astroid 64 0 0.00 1 1 0 0 0 +( -492 638 24 ) ( -484 638 24 ) ( -484 446 24 ) creeperpens/wl_astroid 64 0 0.00 1 1 0 0 0 +( -476 446 16 ) ( -484 446 24 ) ( -484 638 24 ) creeperpens/wl_astroid 64 0 0.00 1 1 0 0 0 +( -492 446 16 ) ( -492 446 24 ) ( -476 446 24 ) creeperpens/wl_astroid 64 0 0.00 1 1 0 0 0 +( -492 638 16 ) ( -492 638 24 ) ( -492 446 24 ) creeperpens/wl_astroid 0 0 0.00 1 1 0 0 0 +( -366 448 20 ) ( -369 448 24 ) ( -372 448 20 ) creeperpens/wl_astroid 64 0 0.00 1 1 0 0 0 +} +// brush 104 +{ +( -476 638 4 ) ( -476 446 4 ) ( -472 446 4 ) creeperpens/wl_astroid 64 0 0.00 1 1 0 0 0 +( -472 446 24 ) ( -476 446 24 ) ( -476 638 24 ) creeperpens/wl_astroid 64 0 0.00 1 1 0 0 0 +( -472 446 4 ) ( -472 446 24 ) ( -472 638 24 ) creeperpens/wl_astroid 0 0 0.00 1 1 0 0 0 +( -476 446 4 ) ( -476 446 24 ) ( -472 446 24 ) creeperpens/wl_astroid 64 0 0.00 1 1 0 0 0 +( -476 638 4 ) ( -476 638 24 ) ( -476 446 24 ) creeperpens/wl_astroid 0 0 0.00 1 1 0 0 0 +( -366 448 4 ) ( -369 448 24 ) ( -372 448 4 ) creeperpens/wl_astroid 64 0 0.00 1 1 0 0 0 +} +// brush 105 +{ +( -252 638 28 ) ( -252 446 28 ) ( -240 446 28 ) creeperpens/wl_astroid -28 -106 0.00 1 1 0 0 0 +( -240 446 32 ) ( -252 446 32 ) ( -252 638 32 ) creeperpens/wl_astroid -28 -106 0.00 1 1 0 0 0 +( -240 446 28 ) ( -240 446 32 ) ( -240 638 32 ) creeperpens/wl_astroid 106 -88 0.00 1 1 0 0 0 +( -252 446 28 ) ( -252 446 32 ) ( -240 446 32 ) creeperpens/wl_astroid -28 -88 0.00 1 1 0 0 0 +( -252 638 28 ) ( -252 638 32 ) ( -252 446 32 ) creeperpens/wl_astroid 106 -88 0.00 1 1 0 0 0 +( -142 448 28 ) ( -145 448 32 ) ( -148 448 28 ) creeperpens/wl_astroid -28 -88 0.00 1 1 0 0 0 +} +// brush 106 +{ +( -252 638 12 ) ( -252 446 12 ) ( -248 446 12 ) creeperpens/wl_astroid -28 -106 0.00 1 1 0 0 0 +( -240 446 28 ) ( -244 446 28 ) ( -244 638 28 ) creeperpens/wl_astroid -28 -106 0.00 1 1 0 0 0 +( -240 638 28 ) ( -248 638 12 ) ( -248 446 12 ) creeperpens/wl_astroid 106 -88 0.00 1 1 0 0 0 +( -240 446 28 ) ( -248 446 12 ) ( -252 446 12 ) creeperpens/wl_astroid -28 -88 0.00 1 1 0 0 0 +( -244 446 28 ) ( -252 446 12 ) ( -252 638 12 ) creeperpens/wl_astroid 106 -88 0.00 1 1 0 0 0 +( -142 448 12 ) ( -145 448 28 ) ( -148 448 12 ) creeperpens/wl_astroid -28 -88 0.00 1 1 0 0 0 +} +// brush 107 +{ +( -186 638 16 ) ( -186 446 16 ) ( -182 446 16 ) creeperpens/wl_astroid -50 -106 0.00 1 1 0 0 0 +( -182 446 20 ) ( -186 446 20 ) ( -186 638 20 ) creeperpens/wl_astroid -50 -106 0.00 1 1 0 0 0 +( -182 446 16 ) ( -182 446 20 ) ( -182 638 20 ) creeperpens/wl_astroid 106 -88 0.00 1 1 0 0 0 +( -186 446 16 ) ( -186 446 20 ) ( -182 446 20 ) creeperpens/wl_astroid -50 -88 0.00 1 1 0 0 0 +( -186 638 16 ) ( -186 638 20 ) ( -186 446 20 ) creeperpens/wl_astroid 106 -88 0.00 1 1 0 0 0 +( -120 448 16 ) ( -123 448 20 ) ( -126 448 16 ) creeperpens/wl_astroid -50 -88 0.00 1 1 0 0 0 +} +// brush 108 +{ +( -178 638 16 ) ( -178 446 16 ) ( -174 446 16 ) creeperpens/wl_astroid -50 -106 0.00 1 1 0 0 0 +( -174 446 20 ) ( -178 446 20 ) ( -178 638 20 ) creeperpens/wl_astroid -50 -106 0.00 1 1 0 0 0 +( -174 446 16 ) ( -174 446 20 ) ( -174 638 20 ) creeperpens/wl_astroid 106 -88 0.00 1 1 0 0 0 +( -178 446 16 ) ( -178 446 20 ) ( -174 446 20 ) creeperpens/wl_astroid -50 -88 0.00 1 1 0 0 0 +( -178 638 16 ) ( -178 638 20 ) ( -178 446 20 ) creeperpens/wl_astroid 106 -88 0.00 1 1 0 0 0 +( -120 448 16 ) ( -123 448 20 ) ( -126 448 16 ) creeperpens/wl_astroid -50 -88 0.00 1 1 0 0 0 +} +// brush 109 +{ +( -186 638 12 ) ( -186 446 12 ) ( -174 446 12 ) creeperpens/wl_astroid -50 -106 0.00 1 1 0 0 0 +( -174 446 16 ) ( -186 446 16 ) ( -186 638 16 ) creeperpens/wl_astroid -50 -106 0.00 1 1 0 0 0 +( -174 446 12 ) ( -174 446 16 ) ( -174 638 16 ) creeperpens/wl_astroid 106 -88 0.00 1 1 0 0 0 +( -186 446 12 ) ( -186 446 16 ) ( -174 446 16 ) creeperpens/wl_astroid -50 -88 0.00 1 1 0 0 0 +( -186 638 12 ) ( -186 638 16 ) ( -186 446 16 ) creeperpens/wl_astroid 106 -88 0.00 1 1 0 0 0 +( -120 448 12 ) ( -123 448 16 ) ( -126 448 12 ) creeperpens/wl_astroid -50 -88 0.00 1 1 0 0 0 +} +// brush 110 +{ +( -186 638 20 ) ( -186 446 20 ) ( -174 446 20 ) creeperpens/wl_astroid -50 -106 0.00 1 1 0 0 0 +( -174 446 24 ) ( -186 446 24 ) ( -186 638 24 ) creeperpens/wl_astroid -50 -106 0.00 1 1 0 0 0 +( -174 446 20 ) ( -174 446 24 ) ( -174 638 24 ) creeperpens/wl_astroid 106 -88 0.00 1 1 0 0 0 +( -186 446 20 ) ( -186 446 24 ) ( -174 446 24 ) creeperpens/wl_astroid -50 -88 0.00 1 1 0 0 0 +( -186 638 20 ) ( -186 638 24 ) ( -186 446 24 ) creeperpens/wl_astroid 106 -88 0.00 1 1 0 0 0 +( -120 448 20 ) ( -123 448 24 ) ( -126 448 20 ) creeperpens/wl_astroid -50 -88 0.00 1 1 0 0 0 +} +// brush 111 +{ +( -178 638 24 ) ( -178 446 24 ) ( -174 446 24 ) creeperpens/wl_astroid -50 -106 0.00 1 1 0 0 0 +( -174 446 28 ) ( -178 446 28 ) ( -178 638 28 ) creeperpens/wl_astroid -50 -106 0.00 1 1 0 0 0 +( -174 446 24 ) ( -174 446 28 ) ( -174 638 28 ) creeperpens/wl_astroid 106 -88 0.00 1 1 0 0 0 +( -178 446 24 ) ( -178 446 28 ) ( -174 446 28 ) creeperpens/wl_astroid -50 -88 0.00 1 1 0 0 0 +( -178 638 24 ) ( -178 638 28 ) ( -178 446 28 ) creeperpens/wl_astroid 106 -88 0.00 1 1 0 0 0 +( -120 448 24 ) ( -123 448 28 ) ( -126 448 24 ) creeperpens/wl_astroid -50 -88 0.00 1 1 0 0 0 +} +// brush 112 +{ +( -186 638 24 ) ( -186 446 24 ) ( -182 446 24 ) creeperpens/wl_astroid -50 -106 0.00 1 1 0 0 0 +( -182 446 32 ) ( -186 446 32 ) ( -186 638 32 ) creeperpens/wl_astroid -50 -106 0.00 1 1 0 0 0 +( -182 446 24 ) ( -182 446 32 ) ( -182 638 32 ) creeperpens/wl_astroid 106 -88 0.00 1 1 0 0 0 +( -186 446 24 ) ( -186 446 32 ) ( -182 446 32 ) creeperpens/wl_astroid -50 -88 0.00 1 1 0 0 0 +( -186 638 24 ) ( -186 638 32 ) ( -186 446 32 ) creeperpens/wl_astroid 106 -88 0.00 1 1 0 0 0 +( -120 448 24 ) ( -123 448 32 ) ( -126 448 24 ) creeperpens/wl_astroid -50 -88 0.00 1 1 0 0 0 +} +// brush 113 +{ +( -182 638 28 ) ( -182 446 28 ) ( -174 446 28 ) creeperpens/wl_astroid -50 -106 0.00 1 1 0 0 0 +( -174 446 32 ) ( -182 446 32 ) ( -182 638 32 ) creeperpens/wl_astroid -50 -106 0.00 1 1 0 0 0 +( -174 446 28 ) ( -174 446 32 ) ( -174 638 32 ) creeperpens/wl_astroid 106 -88 0.00 1 1 0 0 0 +( -182 446 28 ) ( -182 446 32 ) ( -174 446 32 ) creeperpens/wl_astroid -50 -88 0.00 1 1 0 0 0 +( -182 638 28 ) ( -182 638 32 ) ( -182 446 32 ) creeperpens/wl_astroid 106 -88 0.00 1 1 0 0 0 +( -120 448 28 ) ( -123 448 32 ) ( -126 448 28 ) creeperpens/wl_astroid -50 -88 0.00 1 1 0 0 0 +} +// brush 114 +{ +( -202 638 24 ) ( -202 446 24 ) ( -198 446 24 ) creeperpens/wl_astroid -50 -106 0.00 1 1 0 0 0 +( -198 446 32 ) ( -202 446 32 ) ( -202 638 32 ) creeperpens/wl_astroid -50 -106 0.00 1 1 0 0 0 +( -198 446 24 ) ( -198 446 32 ) ( -198 638 32 ) creeperpens/wl_astroid 106 -88 0.00 1 1 0 0 0 +( -202 446 24 ) ( -202 446 32 ) ( -198 446 32 ) creeperpens/wl_astroid -50 -88 0.00 1 1 0 0 0 +( -202 638 24 ) ( -202 638 32 ) ( -202 446 32 ) creeperpens/wl_astroid 106 -88 0.00 1 1 0 0 0 +( -120 448 24 ) ( -123 448 32 ) ( -126 448 24 ) creeperpens/wl_astroid -50 -88 0.00 1 1 0 0 0 +} +// brush 115 +{ +( -202 638 20 ) ( -202 446 20 ) ( -190 446 20 ) creeperpens/wl_astroid -50 -106 0.00 1 1 0 0 0 +( -190 446 24 ) ( -202 446 24 ) ( -202 638 24 ) creeperpens/wl_astroid -50 -106 0.00 1 1 0 0 0 +( -190 446 20 ) ( -190 446 24 ) ( -190 638 24 ) creeperpens/wl_astroid 106 -88 0.00 1 1 0 0 0 +( -202 446 20 ) ( -202 446 24 ) ( -190 446 24 ) creeperpens/wl_astroid -50 -88 0.00 1 1 0 0 0 +( -202 638 20 ) ( -202 638 24 ) ( -202 446 24 ) creeperpens/wl_astroid 106 -88 0.00 1 1 0 0 0 +( -120 448 20 ) ( -123 448 24 ) ( -126 448 20 ) creeperpens/wl_astroid -50 -88 0.00 1 1 0 0 0 +} +// brush 116 +{ +( -194 638 24 ) ( -194 446 24 ) ( -190 446 24 ) creeperpens/wl_astroid -50 -106 0.00 1 1 0 0 0 +( -190 446 32 ) ( -194 446 32 ) ( -194 638 32 ) creeperpens/wl_astroid -50 -106 0.00 1 1 0 0 0 +( -190 446 28 ) ( -190 446 32 ) ( -190 638 32 ) creeperpens/wl_astroid 106 -88 0.00 1 1 0 0 0 +( -194 446 28 ) ( -194 446 32 ) ( -190 446 32 ) creeperpens/wl_astroid -50 -88 0.00 1 1 0 0 0 +( -194 638 28 ) ( -194 638 32 ) ( -194 446 32 ) creeperpens/wl_astroid 106 -88 0.00 1 1 0 0 0 +( -120 448 24 ) ( -123 448 32 ) ( -126 448 24 ) creeperpens/wl_astroid -50 -88 0.00 1 1 0 0 0 +} +// brush 117 +{ +( -194 638 12 ) ( -194 446 12 ) ( -190 446 12 ) creeperpens/wl_astroid -50 -106 0.00 1 1 0 0 0 +( -190 446 20 ) ( -194 446 20 ) ( -194 638 20 ) creeperpens/wl_astroid -50 -106 0.00 1 1 0 0 0 +( -190 446 12 ) ( -190 446 20 ) ( -190 638 20 ) creeperpens/wl_astroid 106 -88 0.00 1 1 0 0 0 +( -194 446 12 ) ( -194 446 20 ) ( -190 446 20 ) creeperpens/wl_astroid -50 -88 0.00 1 1 0 0 0 +( -194 638 12 ) ( -194 638 20 ) ( -194 446 20 ) creeperpens/wl_astroid 106 -88 0.00 1 1 0 0 0 +( -120 448 12 ) ( -123 448 20 ) ( -126 448 12 ) creeperpens/wl_astroid -50 -88 0.00 1 1 0 0 0 +} +// brush 118 +{ +( -268 638 24 ) ( -268 446 24 ) ( -264 446 24 ) creeperpens/wl_astroid -28 -106 0.00 1 1 0 0 0 +( -264 446 32 ) ( -268 446 32 ) ( -268 638 32 ) creeperpens/wl_astroid -28 -106 0.00 1 1 0 0 0 +( -264 446 24 ) ( -264 446 32 ) ( -264 638 32 ) creeperpens/wl_astroid 106 -88 0.00 1 1 0 0 0 +( -268 446 24 ) ( -268 446 32 ) ( -264 446 32 ) creeperpens/wl_astroid -28 -88 0.00 1 1 0 0 0 +( -268 638 24 ) ( -268 638 32 ) ( -268 446 32 ) creeperpens/wl_astroid 106 -88 0.00 1 1 0 0 0 +( -142 448 24 ) ( -145 448 32 ) ( -148 448 24 ) creeperpens/wl_astroid -28 -88 0.00 1 1 0 0 0 +} +// brush 119 +{ +( -268 638 20 ) ( -268 446 20 ) ( -256 446 20 ) creeperpens/wl_astroid -28 -106 0.00 1 1 0 0 0 +( -256 446 24 ) ( -268 446 24 ) ( -268 638 24 ) creeperpens/wl_astroid -28 -106 0.00 1 1 0 0 0 +( -256 446 20 ) ( -256 446 24 ) ( -256 638 24 ) creeperpens/wl_astroid 106 -88 0.00 1 1 0 0 0 +( -268 446 20 ) ( -268 446 24 ) ( -256 446 24 ) creeperpens/wl_astroid -28 -88 0.00 1 1 0 0 0 +( -268 638 20 ) ( -268 638 24 ) ( -268 446 24 ) creeperpens/wl_astroid 106 -88 0.00 1 1 0 0 0 +( -142 448 20 ) ( -145 448 24 ) ( -148 448 20 ) creeperpens/wl_astroid -28 -88 0.00 1 1 0 0 0 +} +// brush 120 +{ +( -260 638 24 ) ( -260 446 24 ) ( -256 446 24 ) creeperpens/wl_astroid -28 -106 0.00 1 1 0 0 0 +( -256 446 32 ) ( -260 446 32 ) ( -260 638 32 ) creeperpens/wl_astroid -28 -106 0.00 1 1 0 0 0 +( -256 446 28 ) ( -256 446 32 ) ( -256 638 32 ) creeperpens/wl_astroid 106 -88 0.00 1 1 0 0 0 +( -260 446 28 ) ( -260 446 32 ) ( -256 446 32 ) creeperpens/wl_astroid -28 -88 0.00 1 1 0 0 0 +( -260 638 28 ) ( -260 638 32 ) ( -260 446 32 ) creeperpens/wl_astroid 106 -88 0.00 1 1 0 0 0 +( -142 448 24 ) ( -145 448 32 ) ( -148 448 24 ) creeperpens/wl_astroid -28 -88 0.00 1 1 0 0 0 +} +// brush 121 +{ +( -260 638 12 ) ( -260 446 12 ) ( -256 446 12 ) creeperpens/wl_astroid -28 -106 0.00 1 1 0 0 0 +( -256 446 20 ) ( -260 446 20 ) ( -260 638 20 ) creeperpens/wl_astroid -28 -106 0.00 1 1 0 0 0 +( -256 446 12 ) ( -256 446 20 ) ( -256 638 20 ) creeperpens/wl_astroid 106 -88 0.00 1 1 0 0 0 +( -260 446 12 ) ( -260 446 20 ) ( -256 446 20 ) creeperpens/wl_astroid -28 -88 0.00 1 1 0 0 0 +( -260 638 12 ) ( -260 638 20 ) ( -260 446 20 ) creeperpens/wl_astroid 106 -88 0.00 1 1 0 0 0 +( -142 448 12 ) ( -145 448 20 ) ( -148 448 12 ) creeperpens/wl_astroid -28 -88 0.00 1 1 0 0 0 +} +// brush 122 +{ +( 36 638 28 ) ( 36 446 28 ) ( 48 446 28 ) creeperpens/wl_astroid -72 -106 0.00 1 1 0 0 0 +( 48 446 32 ) ( 36 446 32 ) ( 36 638 32 ) creeperpens/wl_astroid -72 -106 0.00 1 1 0 0 0 +( 48 446 28 ) ( 48 446 32 ) ( 48 638 32 ) creeperpens/wl_astroid 106 8 0.00 1 1 0 0 0 +( 36 446 28 ) ( 36 446 32 ) ( 48 446 32 ) creeperpens/wl_astroid -72 8 0.00 1 1 0 0 0 +( 36 638 28 ) ( 36 638 32 ) ( 36 446 32 ) creeperpens/wl_astroid 106 8 0.00 1 1 0 0 0 +( 30 448 28 ) ( 27 448 32 ) ( 24 448 28 ) creeperpens/wl_astroid -72 8 0.00 1 1 0 0 0 +} +// brush 123 +{ +( 36 638 32 ) ( 36 446 32 ) ( 40 446 32 ) creeperpens/wl_astroid -72 -106 0.00 1 1 0 0 0 +( 40 446 40 ) ( 36 446 40 ) ( 36 638 40 ) creeperpens/wl_astroid -72 -106 0.00 1 1 0 0 0 +( 40 446 32 ) ( 40 446 40 ) ( 40 638 40 ) creeperpens/wl_astroid 106 8 0.00 1 1 0 0 0 +( 36 446 32 ) ( 36 446 40 ) ( 40 446 40 ) creeperpens/wl_astroid -72 8 0.00 1 1 0 0 0 +( 36 638 32 ) ( 36 638 40 ) ( 36 446 40 ) creeperpens/wl_astroid 106 8 0.00 1 1 0 0 0 +( 30 448 32 ) ( 27 448 40 ) ( 24 448 32 ) creeperpens/wl_astroid -72 8 0.00 1 1 0 0 0 +} +// brush 124 +{ +( 44 638 32 ) ( 44 446 32 ) ( 48 446 32 ) creeperpens/wl_astroid -72 -106 0.00 1 1 0 0 0 +( 48 446 40 ) ( 44 446 40 ) ( 44 638 40 ) creeperpens/wl_astroid -72 -106 0.00 1 1 0 0 0 +( 48 446 36 ) ( 48 446 40 ) ( 48 638 40 ) creeperpens/wl_astroid 106 8 0.00 1 1 0 0 0 +( 44 446 36 ) ( 44 446 40 ) ( 48 446 40 ) creeperpens/wl_astroid -72 8 0.00 1 1 0 0 0 +( 44 638 36 ) ( 44 638 40 ) ( 44 446 40 ) creeperpens/wl_astroid 106 8 0.00 1 1 0 0 0 +( 30 448 32 ) ( 27 448 40 ) ( 24 448 32 ) creeperpens/wl_astroid -72 8 0.00 1 1 0 0 0 +} +// brush 125 +{ +( 44 638 20 ) ( 44 446 20 ) ( 48 446 20 ) creeperpens/wl_astroid -72 -106 0.00 1 1 0 0 0 +( 48 446 28 ) ( 44 446 28 ) ( 44 638 28 ) creeperpens/wl_astroid -72 -106 0.00 1 1 0 0 0 +( 48 446 20 ) ( 48 446 28 ) ( 48 638 28 ) creeperpens/wl_astroid 106 8 0.00 1 1 0 0 0 +( 44 446 20 ) ( 44 446 28 ) ( 48 446 28 ) creeperpens/wl_astroid -72 8 0.00 1 1 0 0 0 +( 44 638 20 ) ( 44 638 28 ) ( 44 446 28 ) creeperpens/wl_astroid 106 8 0.00 1 1 0 0 0 +( 30 448 20 ) ( 27 448 28 ) ( 24 448 20 ) creeperpens/wl_astroid -72 8 0.00 1 1 0 0 0 +} +// brush 126 +{ +( 24 638 28 ) ( 24 446 28 ) ( 32 446 28 ) creeperpens/wl_astroid -72 -106 0.00 1 1 0 0 0 +( 32 446 32 ) ( 24 446 32 ) ( 24 638 32 ) creeperpens/wl_astroid -72 -106 0.00 1 1 0 0 0 +( 32 446 28 ) ( 32 446 32 ) ( 32 638 32 ) creeperpens/wl_astroid 106 8 0.00 1 1 0 0 0 +( 24 446 28 ) ( 24 446 32 ) ( 32 446 32 ) creeperpens/wl_astroid -72 8 0.00 1 1 0 0 0 +( 24 638 28 ) ( 24 638 32 ) ( 24 446 32 ) creeperpens/wl_astroid 106 8 0.00 1 1 0 0 0 +( 30 448 28 ) ( 27 448 32 ) ( 24 448 28 ) creeperpens/wl_astroid -72 8 0.00 1 1 0 0 0 +} +// brush 127 +{ +( 28 638 24 ) ( 28 446 24 ) ( 32 446 24 ) creeperpens/wl_astroid -72 -106 0.00 1 1 0 0 0 +( 32 446 28 ) ( 28 446 28 ) ( 28 638 28 ) creeperpens/wl_astroid -72 -106 0.00 1 1 0 0 0 +( 32 446 24 ) ( 32 446 28 ) ( 32 638 28 ) creeperpens/wl_astroid 106 8 0.00 1 1 0 0 0 +( 28 446 24 ) ( 28 446 28 ) ( 32 446 28 ) creeperpens/wl_astroid -72 8 0.00 1 1 0 0 0 +( 28 638 24 ) ( 28 638 28 ) ( 28 446 28 ) creeperpens/wl_astroid 106 8 0.00 1 1 0 0 0 +( 30 448 24 ) ( 27 448 28 ) ( 24 448 24 ) creeperpens/wl_astroid -72 8 0.00 1 1 0 0 0 +} +// brush 128 +{ +( 24 638 20 ) ( 24 446 20 ) ( 32 446 20 ) creeperpens/wl_astroid -72 -106 0.00 1 1 0 0 0 +( 32 446 24 ) ( 24 446 24 ) ( 24 638 24 ) creeperpens/wl_astroid -72 -106 0.00 1 1 0 0 0 +( 32 446 20 ) ( 32 446 24 ) ( 32 638 24 ) creeperpens/wl_astroid 106 8 0.00 1 1 0 0 0 +( 24 446 20 ) ( 24 446 24 ) ( 32 446 24 ) creeperpens/wl_astroid -72 8 0.00 1 1 0 0 0 +( 24 638 20 ) ( 24 638 24 ) ( 24 446 24 ) creeperpens/wl_astroid 106 8 0.00 1 1 0 0 0 +( 30 448 20 ) ( 27 448 24 ) ( 24 448 20 ) creeperpens/wl_astroid -72 8 0.00 1 1 0 0 0 +} +// brush 129 +{ +( 20 638 20 ) ( 20 446 20 ) ( 24 446 20 ) creeperpens/wl_astroid -72 -106 0.00 1 1 0 0 0 +( 24 446 40 ) ( 20 446 40 ) ( 20 638 40 ) creeperpens/wl_astroid -72 -106 0.00 1 1 0 0 0 +( 24 446 20 ) ( 24 446 40 ) ( 24 638 40 ) creeperpens/wl_astroid 106 8 0.00 1 1 0 0 0 +( 20 446 20 ) ( 20 446 40 ) ( 24 446 40 ) creeperpens/wl_astroid -72 8 0.00 1 1 0 0 0 +( 20 638 20 ) ( 20 638 40 ) ( 20 446 40 ) creeperpens/wl_astroid 106 8 0.00 1 1 0 0 0 +( 30 448 20 ) ( 27 448 40 ) ( 24 448 20 ) creeperpens/wl_astroid -72 8 0.00 1 1 0 0 0 +} +// brush 130 +{ +( -44 638 28 ) ( -44 446 28 ) ( -36 446 28 ) creeperpens/wl_astroid -48 -106 0.00 1 1 0 0 0 +( -36 446 32 ) ( -44 446 32 ) ( -44 638 32 ) creeperpens/wl_astroid -48 -106 0.00 1 1 0 0 0 +( -36 446 28 ) ( -36 446 32 ) ( -36 638 32 ) creeperpens/wl_astroid 106 8 0.00 1 1 0 0 0 +( -44 446 28 ) ( -44 446 32 ) ( -36 446 32 ) creeperpens/wl_astroid -48 8 0.00 1 1 0 0 0 +( -44 638 28 ) ( -44 638 32 ) ( -44 446 32 ) creeperpens/wl_astroid 106 8 0.00 1 1 0 0 0 +( 6 448 28 ) ( 3 448 32 ) ( 0 448 28 ) creeperpens/wl_astroid -48 8 0.00 1 1 0 0 0 +} +// brush 131 +{ +( -40 638 24 ) ( -40 446 24 ) ( -36 446 24 ) creeperpens/wl_astroid -48 -106 0.00 1 1 0 0 0 +( -36 446 28 ) ( -40 446 28 ) ( -40 638 28 ) creeperpens/wl_astroid -48 -106 0.00 1 1 0 0 0 +( -36 446 24 ) ( -36 446 28 ) ( -36 638 28 ) creeperpens/wl_astroid 106 8 0.00 1 1 0 0 0 +( -40 446 24 ) ( -40 446 28 ) ( -36 446 28 ) creeperpens/wl_astroid -48 8 0.00 1 1 0 0 0 +( -40 638 24 ) ( -40 638 28 ) ( -40 446 28 ) creeperpens/wl_astroid 106 8 0.00 1 1 0 0 0 +( 6 448 24 ) ( 3 448 28 ) ( 0 448 24 ) creeperpens/wl_astroid -48 8 0.00 1 1 0 0 0 +} +// brush 132 +{ +( -44 638 20 ) ( -44 446 20 ) ( -36 446 20 ) creeperpens/wl_astroid -48 -106 0.00 1 1 0 0 0 +( -36 446 24 ) ( -44 446 24 ) ( -44 638 24 ) creeperpens/wl_astroid -48 -106 0.00 1 1 0 0 0 +( -36 446 20 ) ( -36 446 24 ) ( -36 638 24 ) creeperpens/wl_astroid 106 8 0.00 1 1 0 0 0 +( -44 446 20 ) ( -44 446 24 ) ( -36 446 24 ) creeperpens/wl_astroid -48 8 0.00 1 1 0 0 0 +( -44 638 20 ) ( -44 638 24 ) ( -44 446 24 ) creeperpens/wl_astroid 106 8 0.00 1 1 0 0 0 +( 6 448 20 ) ( 3 448 24 ) ( 0 448 20 ) creeperpens/wl_astroid -48 8 0.00 1 1 0 0 0 +} +// brush 133 +{ +( -48 638 20 ) ( -48 446 20 ) ( -44 446 20 ) creeperpens/wl_astroid -48 -106 0.00 1 1 0 0 0 +( -44 446 40 ) ( -48 446 40 ) ( -48 638 40 ) creeperpens/wl_astroid -48 -106 0.00 1 1 0 0 0 +( -44 446 20 ) ( -44 446 40 ) ( -44 638 40 ) creeperpens/wl_astroid 106 8 0.00 1 1 0 0 0 +( -48 446 20 ) ( -48 446 40 ) ( -44 446 40 ) creeperpens/wl_astroid -48 8 0.00 1 1 0 0 0 +( -48 638 20 ) ( -48 638 40 ) ( -48 446 40 ) creeperpens/wl_astroid 106 8 0.00 1 1 0 0 0 +( 6 448 20 ) ( 3 448 40 ) ( 0 448 20 ) creeperpens/wl_astroid -48 8 0.00 1 1 0 0 0 +} +// brush 134 +{ +( -32 446 20 ) ( -24 446 20 ) ( -24 638 20 ) creeperpens/wl_astroid -48 -106 0.00 1 1 0 0 0 +( -20 446 24 ) ( -32 446 24 ) ( -32 638 24 ) creeperpens/wl_astroid -48 -106 0.00 1 1 0 0 0 +( -20 638 24 ) ( -24 638 20 ) ( -24 446 20 ) creeperpens/wl_astroid -48 -106 0.00 1 1 0 0 0 +( -32 446 20 ) ( -32 446 24 ) ( -20 446 24 ) creeperpens/wl_astroid -48 8 0.00 1 1 0 0 0 +( -32 638 20 ) ( -32 638 24 ) ( -32 446 24 ) creeperpens/wl_astroid 106 8 0.00 1 1 0 0 0 +( 6 448 20 ) ( 3 448 24 ) ( 0 448 20 ) creeperpens/wl_astroid -48 8 0.00 1 1 0 0 0 +} +// brush 135 +{ +( -24 638 24 ) ( -24 446 24 ) ( -20 446 24 ) creeperpens/wl_astroid -48 -106 0.00 1 1 0 0 0 +( -20 446 28 ) ( -24 446 28 ) ( -24 638 28 ) creeperpens/wl_astroid -48 -106 0.00 1 1 0 0 0 +( -20 446 24 ) ( -20 446 28 ) ( -20 638 28 ) creeperpens/wl_astroid 106 8 0.00 1 1 0 0 0 +( -24 446 24 ) ( -24 446 28 ) ( -20 446 28 ) creeperpens/wl_astroid -48 8 0.00 1 1 0 0 0 +( -24 638 24 ) ( -24 638 28 ) ( -24 446 28 ) creeperpens/wl_astroid 106 8 0.00 1 1 0 0 0 +( 6 448 24 ) ( 3 448 28 ) ( 0 448 24 ) creeperpens/wl_astroid -48 8 0.00 1 1 0 0 0 +} +// brush 136 +{ +( -28 638 28 ) ( -28 446 28 ) ( -20 446 28 ) creeperpens/wl_astroid -48 -106 0.00 1 1 0 0 0 +( -20 446 32 ) ( -28 446 32 ) ( -28 638 32 ) creeperpens/wl_astroid -48 -106 0.00 1 1 0 0 0 +( -20 446 28 ) ( -20 446 32 ) ( -20 638 32 ) creeperpens/wl_astroid 106 8 0.00 1 1 0 0 0 +( -28 446 28 ) ( -28 446 32 ) ( -20 446 32 ) creeperpens/wl_astroid -48 8 0.00 1 1 0 0 0 +( -28 638 28 ) ( -28 638 32 ) ( -28 446 32 ) creeperpens/wl_astroid 106 8 0.00 1 1 0 0 0 +( 6 448 28 ) ( 3 448 32 ) ( 0 448 28 ) creeperpens/wl_astroid -48 8 0.00 1 1 0 0 0 +} +// brush 137 +{ +( -24 638 32 ) ( -24 446 32 ) ( -20 446 32 ) creeperpens/wl_astroid -48 -106 0.00 1 1 0 0 0 +( -20 446 36 ) ( -24 446 36 ) ( -24 638 36 ) creeperpens/wl_astroid -48 -106 0.00 1 1 0 0 0 +( -20 446 32 ) ( -20 446 36 ) ( -20 638 36 ) creeperpens/wl_astroid 106 8 0.00 1 1 0 0 0 +( -24 446 32 ) ( -24 446 36 ) ( -20 446 36 ) creeperpens/wl_astroid -48 8 0.00 1 1 0 0 0 +( -24 638 32 ) ( -24 638 36 ) ( -24 446 36 ) creeperpens/wl_astroid 106 8 0.00 1 1 0 0 0 +( 6 448 32 ) ( 3 448 36 ) ( 0 448 32 ) creeperpens/wl_astroid -48 8 0.00 1 1 0 0 0 +} +// brush 138 +{ +( -36 638 36 ) ( -36 446 36 ) ( -20 446 36 ) creeperpens/wl_astroid -48 -106 0.00 1 1 0 0 0 +( -32 638 40 ) ( -24 638 40 ) ( -24 446 40 ) creeperpens/wl_astroid -48 -106 0.00 1 1 0 0 0 +( -16 446 32 ) ( -24 446 40 ) ( -24 638 40 ) creeperpens/wl_astroid -48 -106 0.00 1 1 0 0 0 +( -32 446 32 ) ( -32 446 40 ) ( -16 446 40 ) creeperpens/wl_astroid -48 8 0.00 1 1 0 0 0 +( -32 638 32 ) ( -32 638 40 ) ( -32 446 40 ) creeperpens/wl_astroid 106 8 0.00 1 1 0 0 0 +( 6 448 36 ) ( 3 448 40 ) ( 0 448 36 ) creeperpens/wl_astroid -48 8 0.00 1 1 0 0 0 +} +// brush 139 +{ +( -484 638 16 ) ( -484 446 16 ) ( -480 446 16 ) creeperpens/wl_astroid 64 0 0.00 1 1 0 0 0 +( -480 446 20 ) ( -484 446 20 ) ( -484 638 20 ) creeperpens/wl_astroid 64 0 0.00 1 1 0 0 0 +( -480 446 16 ) ( -480 446 20 ) ( -480 638 20 ) creeperpens/wl_astroid 0 0 0.00 1 1 0 0 0 +( -484 446 16 ) ( -484 446 20 ) ( -480 446 20 ) creeperpens/wl_astroid 64 0 0.00 1 1 0 0 0 +( -484 638 16 ) ( -484 638 20 ) ( -484 446 20 ) creeperpens/wl_astroid 0 0 0.00 1 1 0 0 0 +( -366 448 16 ) ( -369 448 20 ) ( -372 448 16 ) creeperpens/wl_astroid 64 0 0.00 1 1 0 0 0 +} +// brush 140 +{ +( -488 638 12 ) ( -488 446 12 ) ( -480 446 12 ) creeperpens/wl_astroid 64 0 0.00 1 1 0 0 0 +( -480 446 16 ) ( -488 446 16 ) ( -488 638 16 ) creeperpens/wl_astroid 64 0 0.00 1 1 0 0 0 +( -480 446 12 ) ( -480 446 16 ) ( -480 638 16 ) creeperpens/wl_astroid 0 0 0.00 1 1 0 0 0 +( -488 446 12 ) ( -488 446 16 ) ( -480 446 16 ) creeperpens/wl_astroid 64 0 0.00 1 1 0 0 0 +( -488 638 12 ) ( -488 638 16 ) ( -488 446 16 ) creeperpens/wl_astroid 0 0 0.00 1 1 0 0 0 +( -366 448 12 ) ( -369 448 16 ) ( -372 448 12 ) creeperpens/wl_astroid 64 0 0.00 1 1 0 0 0 +} +// brush 141 +{ +( -484 638 8 ) ( -484 446 8 ) ( -480 446 8 ) creeperpens/wl_astroid 64 0 0.00 1 1 0 0 0 +( -480 446 12 ) ( -484 446 12 ) ( -484 638 12 ) creeperpens/wl_astroid 64 0 0.00 1 1 0 0 0 +( -480 446 8 ) ( -480 446 12 ) ( -480 638 12 ) creeperpens/wl_astroid 0 0 0.00 1 1 0 0 0 +( -484 446 8 ) ( -484 446 12 ) ( -480 446 12 ) creeperpens/wl_astroid 64 0 0.00 1 1 0 0 0 +( -484 638 8 ) ( -484 638 12 ) ( -484 446 12 ) creeperpens/wl_astroid 0 0 0.00 1 1 0 0 0 +( -366 448 8 ) ( -369 448 12 ) ( -372 448 8 ) creeperpens/wl_astroid 64 0 0.00 1 1 0 0 0 +} +// brush 142 +{ +( -492 446 4 ) ( -484 446 4 ) ( -484 638 4 ) creeperpens/wl_astroid 64 0 0.00 1 1 0 0 0 +( -480 446 8 ) ( -492 446 8 ) ( -492 638 8 ) creeperpens/wl_astroid 64 0 0.00 1 1 0 0 0 +( -480 638 8 ) ( -484 638 4 ) ( -484 446 4 ) creeperpens/wl_astroid 64 0 0.00 1 1 0 0 0 +( -492 446 4 ) ( -492 446 8 ) ( -480 446 8 ) creeperpens/wl_astroid 64 0 0.00 1 1 0 0 0 +( -492 638 4 ) ( -492 638 8 ) ( -492 446 8 ) creeperpens/wl_astroid 0 0 0.00 1 1 0 0 0 +( -366 448 4 ) ( -369 448 8 ) ( -372 448 4 ) creeperpens/wl_astroid 64 0 0.00 1 1 0 0 0 +} +// brush 143 +{ +( 832 -320 0 ) ( 576 -320 0 ) ( 576 -576 0 ) eden/edenfloor 64 32 0.00 1 1 0 0 0 +( 576 -576 160 ) ( 576 -320 160 ) ( 832 -320 160 ) eden/WL_brick 0 0 0.00 1 1 0 0 0 +( 576 -640 160 ) ( 832 -640 160 ) ( 832 -640 0 ) eden/edenfloor 64 32 0.00 1 1 0 0 0 +( 896 -576 160 ) ( 896 -320 160 ) ( 896 -320 0 ) eden/edenfloor 64 32 0.00 1 1 0 0 0 +( 832 -256 160 ) ( 576 -256 160 ) ( 576 -256 0 ) eden/edenfloor 64 32 0.00 1 1 0 0 0 +( 512 -320 160 ) ( 512 -576 160 ) ( 512 -576 0 ) eden/edenfloor 64 32 0.00 1 1 0 0 0 +( 512 -448 0 ) ( 544 -384 0 ) ( 528 -416 160 ) eden/edenfloor 64 32 0.00 1 1 0 0 0 +( 544 -384 0 ) ( 576 -352 0 ) ( 560 -368 160 ) eden/edenfloor 64 32 0.00 1 1 0 0 0 +( 640 -288 0 ) ( 768 -256 0 ) ( 704 -272 160 ) eden/edenfloor 64 32 0.00 1 1 0 0 0 +( 896 -448 0 ) ( 864 -480 0 ) ( 880 -464 160 ) eden/edenfloor 64 32 0.00 1 1 0 0 0 +( 832 -256 0 ) ( 864 -288 0 ) ( 848 -272 160 ) eden/edenfloor 64 32 0.00 1 1 0 0 0 +} +// brush 144 +{ +( -384 128 256 ) ( -384 0 256 ) ( -384 0 0 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( -128 128 256 ) ( -192 128 256 ) ( -192 128 0 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( -192 0 256 ) ( -128 0 256 ) ( -128 0 0 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( -192 0 64 ) ( -192 128 64 ) ( -128 128 64 ) eden/WL_brick 0 0 0.00 1 1 0 0 0 +( -128 128 0 ) ( -192 128 0 ) ( -192 0 0 ) eden/edenwalltest -128 192 0.00 1 1 0 0 0 +( -320 0 0 ) ( -320 128 -8 ) ( -320 0 -16 ) eden/edenwalltest -128 192 0.00 1 1 0 0 0 +} +// brush 145 +{ +( -128 128 256 ) ( -192 128 256 ) ( -192 128 0 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( -192 0 304 ) ( -192 128 304 ) ( -192 128 48 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( -192 0 256 ) ( -128 0 256 ) ( -128 0 0 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( -192 0 192 ) ( -192 128 192 ) ( -128 128 192 ) eden/WL_brick 0 0 0.00 1 1 0 0 0 +( -128 128 0 ) ( -192 128 0 ) ( -192 0 0 ) eden/edenwalltest -128 192 0.00 1 1 0 0 0 +( -320 128 120 ) ( -320 0 128 ) ( -320 0 112 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +} +// brush 146 +{ +( 384 640 96 ) ( 384 640 0 ) ( 448 640 0 ) eden/WL_basement_2w -64 0 0.00 1 1 0 0 0 +( 448 640 96 ) ( 448 640 0 ) ( 448 448 0 ) eden/WL_basement_2w -192 0 0.00 1 1 0 0 0 +( 384 448 0 ) ( 384 448 96 ) ( 448 448 96 ) eden/WL_basement_2w -64 0 0.00 1 1 0 0 0 +( 384 448 96 ) ( 384 640 96 ) ( 448 640 96 ) eden/WL_basement_2w -64 192 0.00 1 1 0 0 0 +( 384 640 0 ) ( 384 448 0 ) ( 448 448 0 ) eden/WL_basement_2w -64 192 0.00 1 1 0 0 0 +( 384 640 0 ) ( 384 640 96 ) ( 384 448 96 ) eden/WL_basement_2w -192 0 0.00 1 1 0 0 0 +} +// brush 147 +{ +( 320 640 0 ) ( 320 640 95 ) ( 320 448 95 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( 384 640 0 ) ( 384 640 95 ) ( 320 640 95 ) eden/edenwalltest -128 0 0.00 1 1 0 0 0 +( 384 448 95 ) ( 384 448 0 ) ( 320 448 0 ) eden/edenwalltest -128 0 0.00 1 1 0 0 0 +( 384 640 95 ) ( 384 448 95 ) ( 320 448 95 ) eden/WL_brick 0 0 0.00 1 1 0 0 0 +( 384 448 0 ) ( 384 640 0 ) ( 320 640 0 ) eden/edenwalltest -128 192 0.00 1 1 0 0 0 +( 384 640 95 ) ( 384 640 0 ) ( 384 448 0 ) eden/edenwalltest -192 0 0.00 1 1 0 0 0 +} +// brush 148 +{ +( -64 640 0 ) ( -64 640 63 ) ( -64 448 63 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( 0 640 0 ) ( 0 640 63 ) ( -64 640 63 ) eden/edenwalltest 0 0 0.00 1 1 0 0 0 +( 0 448 63 ) ( 0 448 0 ) ( -64 448 0 ) eden/edenwalltest 0 0 0.00 1 1 0 0 0 +( 0 640 63 ) ( 0 448 63 ) ( -64 448 63 ) eden/WL_brick 0 0 0.00 1 1 0 0 0 +( 0 448 0 ) ( 0 640 0 ) ( -64 640 0 ) eden/edenwalltest 0 192 0.00 1 1 0 0 0 +( 0 640 63 ) ( 0 640 0 ) ( 0 448 0 ) eden/edenwalltest -192 0 0.00 1 1 0 0 0 +} +// brush 149 +{ +( 64 640 0 ) ( 64 640 64 ) ( 0 640 64 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( 64 640 64 ) ( 64 640 0 ) ( 64 448 0 ) eden/WL_basement_2w -192 0 0.00 1 1 0 0 0 +( 64 448 64 ) ( 64 448 0 ) ( 0 448 0 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( 64 640 64 ) ( 64 448 64 ) ( 0 448 64 ) eden/WL_basement_2w 0 192 0.00 1 1 0 0 0 +( 64 448 0 ) ( 64 640 0 ) ( 0 640 0 ) eden/WL_basement_2w 0 192 0.00 1 1 0 0 0 +( 0 640 0 ) ( 0 640 64 ) ( 0 448 64 ) eden/WL_basement_2w -192 0 0.00 1 1 0 0 0 +} +// brush 150 +{ +( -448 640 32 ) ( -448 640 0 ) ( -384 640 0 ) eden/WL_basement_2w 192 0 0.00 1 1 0 0 0 +( -384 640 32 ) ( -384 640 0 ) ( -384 448 0 ) eden/WL_basement_2w -192 0 0.00 1 1 0 0 0 +( -448 448 0 ) ( -448 448 32 ) ( -384 448 32 ) eden/WL_basement_2w 192 0 0.00 1 1 0 0 0 +( -448 448 32 ) ( -448 640 32 ) ( -384 640 32 ) eden/WL_basement_2w 192 192 0.00 1 1 0 0 0 +( -448 640 0 ) ( -448 448 0 ) ( -384 448 0 ) eden/WL_basement_2w 192 192 0.00 1 1 0 0 0 +( -448 640 0 ) ( -448 640 32 ) ( -448 448 32 ) eden/WL_basement_2w -192 0 0.00 1 1 0 0 0 +} +// brush 151 +{ +( -512 640 0 ) ( -512 640 31 ) ( -512 448 31 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( -448 640 0 ) ( -448 640 31 ) ( -512 640 31 ) eden/edenwalltest 192 0 0.00 1 1 0 0 0 +( -448 448 31 ) ( -448 448 0 ) ( -512 448 0 ) eden/edenwalltest 192 0 0.00 1 1 0 0 0 +( -448 640 31 ) ( -448 448 31 ) ( -512 448 31 ) eden/WL_brick 0 0 0.00 1 1 0 0 0 +( -448 448 0 ) ( -448 640 0 ) ( -512 640 0 ) eden/edenwalltest 192 192 0.00 1 1 0 0 0 +( -448 640 31 ) ( -448 640 0 ) ( -448 448 0 ) eden/edenwalltest -192 0 0.00 1 1 0 0 0 +} +// brush 152 +{ +( 1120 -896 192 ) ( 960 -896 192 ) ( 960 -1088 192 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( 960 -1088 528 ) ( 960 -896 528 ) ( 1120 -896 528 ) eden/edenwalltest 0 -64 0.00 1 1 0 0 0 +( 960 -960 240 ) ( 1120 -960 240 ) ( 1120 -960 176 ) eden/edenwalltest 0 176 0.00 1 1 0 0 0 +( 1152 -1008 240 ) ( 1152 -816 240 ) ( 1152 -816 176 ) eden/edenwalltest 64 176 0.00 1 1 0 0 0 +( 1072 -576 240 ) ( 912 -576 240 ) ( 912 -576 176 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( 1104 -912 240 ) ( 1104 -1104 240 ) ( 1104 -1104 176 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +} +// brush 153 +{ +( 1264 -356 416 ) ( 1264 -352 420 ) ( -432 -354 418 ) metals/dark_combo_dark 0 0 0.00 1 1 0 0 0 +( 1328 -364 432 ) ( 1328 -368 428 ) ( -368 -366 430 ) metals/dark_combo_dark 0 0 0.00 1 1 0 0 0 +( 368 -368 432 ) ( 1328 -368 432 ) ( 1328 -368 304 ) metals/dark_combo_dark 0 0 0.00 1 1 0 0 0 +( 768 -352 432 ) ( -192 -352 432 ) ( -192 -352 304 ) metals/dark_combo_dark 0 0 0.00 1 1 0 0 0 +( 1264 -352 432 ) ( 1264 -368 432 ) ( 304 -368 432 ) metals/dark_combo_dark 0 0 0.00 1 1 0 0 0 +( 368 -368 416 ) ( 1328 -368 416 ) ( 1328 -352 416 ) metals/dark_combo_dark 0 0 0.00 1 1 0 0 0 +( 1264 -352 428 ) ( 1264 -356 432 ) ( -432 -354 430 ) metals/dark_combo_dark 0 0 0.00 1 1 0 0 0 +( 1328 -368 420 ) ( 1328 -364 416 ) ( -368 -366 418 ) metals/dark_combo_dark 0 0 0.00 1 1 0 0 0 +( 368 -368 416 ) ( 384 -352 416 ) ( 376 -360 432 ) metals/dark_combo_dark 0 0 0.00 1 1 0 0 0 +( 1120 -336 416 ) ( 1120 -368 416 ) ( 1120 -352 432 ) metals/dark_combo_dark 0 0 0.00 1 1 0 0 0 +} +// brush 154 +{ +( 382 -1168 418 ) ( 384 528 420 ) ( 380 528 416 ) metals/dark_combo_dark 0 0 0.00 1 1 0 0 0 +( 370 -1104 430 ) ( 368 592 428 ) ( 372 592 432 ) metals/dark_combo_dark 0 0 0.00 1 1 0 0 0 +( 368 592 304 ) ( 368 592 432 ) ( 368 -368 432 ) metals/dark_combo_dark 0 0 0.00 1 1 0 0 0 +( 384 -928 304 ) ( 384 -928 432 ) ( 384 32 432 ) metals/dark_combo_dark 0 0 0.00 1 1 0 0 0 +( 368 -432 432 ) ( 368 528 432 ) ( 384 528 432 ) metals/dark_combo_dark 0 0 0.00 1 1 0 0 0 +( 384 592 416 ) ( 368 592 416 ) ( 368 -368 416 ) metals/dark_combo_dark 0 0 0.00 1 1 0 0 0 +( 382 -1168 430 ) ( 380 528 432 ) ( 384 528 428 ) metals/dark_combo_dark 0 0 0.00 1 1 0 0 0 +( 370 -1104 418 ) ( 372 592 416 ) ( 368 592 420 ) metals/dark_combo_dark 0 0 0.00 1 1 0 0 0 +( 376 -360 432 ) ( 384 -352 416 ) ( 368 -368 416 ) metals/dark_combo_dark 0 0 0.00 1 1 0 0 0 +( 376 -264 432 ) ( 368 -272 416 ) ( 384 -256 416 ) metals/dark_combo_dark 0 0 0.00 1 1 0 0 0 +} +// brush 155 +{ +( -544 -268 416 ) ( -544 -272 420 ) ( 1152 -270 418 ) metals/dark_combo_dark 0 0 0.00 1 1 0 0 0 +( -608 -260 432 ) ( -608 -256 428 ) ( 1088 -258 430 ) metals/dark_combo_dark 0 0 0.00 1 1 0 0 0 +( -576 -256 432 ) ( -576 -272 432 ) ( -576 -272 304 ) metals/dark_combo_dark 0 0 0.00 1 1 0 0 0 +( 352 -256 432 ) ( -608 -256 432 ) ( -608 -256 304 ) metals/dark_combo_dark 0 0 0.00 1 1 0 0 0 +( -48 -272 432 ) ( 912 -272 432 ) ( 912 -272 304 ) metals/dark_combo_dark 0 0 0.00 1 1 0 0 0 +( -544 -272 432 ) ( -544 -256 432 ) ( 416 -256 432 ) metals/dark_combo_dark 0 0 0.00 1 1 0 0 0 +( 352 -256 416 ) ( -608 -256 416 ) ( -608 -272 416 ) metals/dark_combo_dark 0 0 0.00 1 1 0 0 0 +( -544 -272 428 ) ( -544 -268 432 ) ( 1152 -270 430 ) metals/dark_combo_dark 0 0 0.00 1 1 0 0 0 +( -608 -256 420 ) ( -608 -260 416 ) ( 1088 -258 418 ) metals/dark_combo_dark 0 0 0.00 1 1 0 0 0 +( 384 -256 416 ) ( 368 -272 416 ) ( 376 -264 432 ) metals/dark_combo_dark 0 0 0.00 1 1 0 0 0 +} +// brush 156 +{ +( -704 -128 16 ) ( -704 -192 16 ) ( -704 -192 0 ) eden/edenwalltest -64 -160 0.00 1 1 0 0 0 +( -480 -192 16 ) ( -480 -128 16 ) ( -480 -128 0 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( -704 -192 16 ) ( -640 -192 16 ) ( -640 -192 0 ) eden/edenwalltest 0 -160 0.00 1 1 0 0 0 +( -544 192 0 ) ( -480 192 0 ) ( -480 -192 256 ) eden/WL_brick 0 0 0.00 1 1 0 0 0 +( -544 192 0 ) ( -544 144 0 ) ( -480 168 0 ) eden/edenwalltest 0 64 0.00 1 1 0 0 0 +} +// brush 157 +{ +( 1120 -160 432 ) ( 1120 -176 432 ) ( 1120 -176 416 ) eden/ornatewallweathered -240 0 0.00 1 1 0 0 0 +( 1152 -152 440 ) ( 1120 -152 440 ) ( 1120 -152 424 ) eden/ornatewallweathered -128 0 0.00 1 1 0 0 0 +( 1152 -176 432 ) ( 1152 -160 432 ) ( 1152 -160 416 ) eden/ornatewallweathered -240 0 0.00 1 1 0 0 0 +( 1120 -184 432 ) ( 1152 -184 432 ) ( 1152 -184 416 ) eden/ornatewallweathered -128 0 0.00 1 1 0 0 0 +( 1120 -176 440 ) ( 1120 -160 440 ) ( 1152 -160 440 ) eden/ornatewallweathered -128 240 0.00 1 1 0 0 0 +( 1152 -160 408 ) ( 1120 -160 408 ) ( 1120 -176 408 ) eden/ornatewallweathered -128 240 0.00 1 1 0 0 0 +} +// brush 158 +{ +( -704 -176 432 ) ( -704 -192 432 ) ( -704 -192 416 ) eden/ornatewallweathered 32 0 0.00 1 1 0 0 0 +( -576 -168 440 ) ( -608 -168 440 ) ( -608 -168 424 ) eden/ornatewallweathered 64 0 0.00 1 1 0 0 0 +( -576 -192 432 ) ( -576 -176 432 ) ( -576 -176 416 ) eden/ornatewallweathered 32 0 0.00 1 1 0 0 0 +( -608 -200 432 ) ( -576 -200 432 ) ( -576 -200 416 ) eden/ornatewallweathered 64 0 0.00 1 1 0 0 0 +( -608 -192 440 ) ( -608 -176 440 ) ( -576 -176 440 ) eden/ornatewallweathered 64 -32 0.00 1 1 0 0 0 +( -576 -176 408 ) ( -608 -176 408 ) ( -608 -192 408 ) eden/ornatewallweathered 64 -32 0.00 1 1 0 0 0 +} +// brush 159 +{ +( -544 -188 416 ) ( -544 -192 420 ) ( 1152 -190 418 ) metals/dark_combo_dark 0 0 0.00 1 1 0 0 0 +( -544 -180 432 ) ( -544 -176 428 ) ( 1152 -178 430 ) metals/dark_combo_dark 0 0 0.00 1 1 0 0 0 +( -576 -176 432 ) ( -576 -192 432 ) ( -576 -192 304 ) metals/dark_combo_dark 0 0 0.00 1 1 0 0 0 +( 352 -176 432 ) ( -608 -176 432 ) ( -608 -176 304 ) metals/dark_combo_dark 0 0 0.00 1 1 0 0 0 +( 1120 -208 432 ) ( 1120 -192 432 ) ( 1120 -192 304 ) metals/dark_combo_dark 0 0 0.00 1 1 0 0 0 +( -112 -192 432 ) ( 848 -192 432 ) ( 848 -192 304 ) metals/dark_combo_dark 0 0 0.00 1 1 0 0 0 +( -544 -192 432 ) ( -544 -176 432 ) ( 416 -176 432 ) metals/dark_combo_dark 0 0 0.00 1 1 0 0 0 +( 352 -176 416 ) ( -608 -176 416 ) ( -608 -192 416 ) metals/dark_combo_dark 0 0 0.00 1 1 0 0 0 +( -544 -192 428 ) ( -544 -188 432 ) ( 1152 -190 430 ) metals/dark_combo_dark 0 0 0.00 1 1 0 0 0 +( -544 -176 420 ) ( -544 -180 416 ) ( 1152 -178 418 ) metals/dark_combo_dark 0 0 0.00 1 1 0 0 0 +} +// brush 160 +{ +( -704 -256 432 ) ( -704 -272 432 ) ( -704 -272 416 ) eden/ornatewallweathered -144 0 0.00 1 1 0 0 0 +( -672 -248 440 ) ( -704 -248 440 ) ( -704 -248 424 ) eden/ornatewallweathered 64 0 0.00 1 1 0 0 0 +( -576 -272 432 ) ( -576 -256 432 ) ( -576 -256 416 ) eden/ornatewallweathered -144 0 0.00 1 1 0 0 0 +( -608 -280 432 ) ( -576 -280 432 ) ( -576 -280 416 ) eden/ornatewallweathered 64 0 0.00 1 1 0 0 0 +( -608 -272 440 ) ( -608 -256 440 ) ( -576 -256 440 ) eden/ornatewallweathered 64 144 0.00 1 1 0 0 0 +( -576 -256 408 ) ( -608 -256 408 ) ( -608 -272 408 ) eden/ornatewallweathered 64 144 0.00 1 1 0 0 0 +} +// brush 161 +{ +( 1120 -352 432 ) ( 1120 -368 432 ) ( 1120 -368 416 ) eden/ornatewallweathered -48 0 0.00 1 1 0 0 0 +( 1152 -344 440 ) ( 1120 -344 440 ) ( 1120 -344 424 ) eden/ornatewallweathered -128 0 0.00 1 1 0 0 0 +( 1152 -368 432 ) ( 1152 -352 432 ) ( 1152 -352 416 ) eden/ornatewallweathered -48 0 0.00 1 1 0 0 0 +( 1120 -376 432 ) ( 1152 -376 432 ) ( 1152 -376 416 ) eden/ornatewallweathered -128 0 0.00 1 1 0 0 0 +( 1120 -368 440 ) ( 1120 -352 440 ) ( 1152 -352 440 ) eden/ornatewallweathered -128 48 0.00 1 1 0 0 0 +( 1152 -352 408 ) ( 1120 -352 408 ) ( 1120 -368 408 ) eden/ornatewallweathered -128 48 0.00 1 1 0 0 0 +} +// brush 162 +{ +( 1128 -600 432 ) ( 1128 -616 432 ) ( 1128 -616 416 ) eden/ornatewallweathered 192 0 0.00 1 1 0 0 0 +( 1152 -584 440 ) ( 1120 -584 440 ) ( 1120 -584 424 ) eden/ornatewallweathered -128 0 0.00 1 1 0 0 0 +( 1152 -608 432 ) ( 1152 -592 432 ) ( 1152 -592 416 ) eden/ornatewallweathered 192 0 0.00 1 1 0 0 0 +( 1128 -616 432 ) ( 1160 -616 432 ) ( 1160 -616 416 ) eden/ornatewallweathered -128 0 0.00 1 1 0 0 0 +( 1120 -608 440 ) ( 1120 -592 440 ) ( 1152 -592 440 ) eden/ornatewallweathered -128 -192 0.00 1 1 0 0 0 +( 1152 -592 408 ) ( 1120 -592 408 ) ( 1120 -608 408 ) eden/ornatewallweathered -128 -192 0.00 1 1 0 0 0 +} +// brush 163 +{ +( -704 -592 432 ) ( -704 -608 432 ) ( -704 -608 416 ) eden/ornatewallweathered 192 0 0.00 1 1 0 0 0 +( -672 -584 440 ) ( -704 -584 440 ) ( -704 -584 424 ) eden/ornatewallweathered 64 0 0.00 1 1 0 0 0 +( -632 -616 432 ) ( -632 -600 432 ) ( -632 -600 416 ) eden/ornatewallweathered 192 0 0.00 1 1 0 0 0 +( -600 -616 432 ) ( -568 -616 432 ) ( -568 -616 416 ) eden/ornatewallweathered 64 0 0.00 1 1 0 0 0 +( -608 -608 440 ) ( -608 -592 440 ) ( -576 -592 440 ) eden/ornatewallweathered 64 -192 0.00 1 1 0 0 0 +( -576 -592 408 ) ( -608 -592 408 ) ( -608 -608 408 ) eden/ornatewallweathered 64 -192 0.00 1 1 0 0 0 +} +// brush 164 +{ +( 448 -96 384 ) ( 320 -96 384 ) ( 320 -96 192 ) eden/edenfloor 64 0 0.00 1 1 0 0 0 +( 448 -224 384 ) ( 448 -96 384 ) ( 448 -96 192 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( 320 -224 384 ) ( 448 -224 384 ) ( 448 -224 192 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( 448 -96 192 ) ( 320 -96 192 ) ( 320 -224 192 ) eden/edenfloor 64 32 0.00 1 1 0 0 0 +( 320 -224 192 ) ( 328 -96 200 ) ( 336 -224 208 ) eden/edenfloor 64 32 0.00 1 1 0 0 0 +} +// brush 165 +{ +( 448 160 384 ) ( 320 160 384 ) ( 320 160 192 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( 448 32 384 ) ( 448 160 384 ) ( 448 160 192 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( 320 32 384 ) ( 448 32 384 ) ( 448 32 192 ) eden/edenfloor 64 0 0.00 1 1 0 0 0 +( 448 160 192 ) ( 320 160 192 ) ( 320 32 192 ) eden/edenfloor 64 32 0.00 1 1 0 0 0 +( 320 32 192 ) ( 328 160 200 ) ( 336 32 208 ) eden/edenfloor 64 32 0.00 1 1 0 0 0 +} +// brush 166 +{ +( 448 32 160 ) ( 384 32 160 ) ( 384 -96 160 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( 384 -96 320 ) ( 384 32 320 ) ( 448 32 320 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( 384 -96 416 ) ( 448 -96 416 ) ( 448 -96 160 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( 448 176 416 ) ( 448 304 416 ) ( 448 304 160 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( 448 32 416 ) ( 384 32 416 ) ( 384 32 160 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( 384 32 384 ) ( 384 -96 384 ) ( 384 -96 128 ) eden/WL_neweden_ivy 0 64 0.00 1 1 0 0 0 +surfaceparm ladder +} +// brush 167 +{ +( 448 -96 0 ) ( 384 -96 0 ) ( 384 -224 0 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( 384 -224 192 ) ( 384 -96 192 ) ( 448 -96 192 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( 384 -224 256 ) ( 448 -224 256 ) ( 448 -224 0 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( 448 48 256 ) ( 448 176 256 ) ( 448 176 0 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( 448 -96 256 ) ( 384 -96 256 ) ( 384 -96 0 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( 384 -96 256 ) ( 384 -224 256 ) ( 384 -224 0 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +} +// brush 168 +{ +( 448 160 0 ) ( 384 160 0 ) ( 384 32 0 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( 384 32 192 ) ( 384 160 192 ) ( 448 160 192 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( 384 32 256 ) ( 448 32 256 ) ( 448 32 0 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( 448 304 256 ) ( 448 432 256 ) ( 448 432 0 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( 448 160 256 ) ( 384 160 256 ) ( 384 160 0 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( 384 160 256 ) ( 384 32 256 ) ( 384 32 0 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +} +// brush 169 +{ +( -384 -448 256 ) ( -384 -576 256 ) ( -384 -576 0 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( -320 -448 256 ) ( -384 -448 256 ) ( -384 -448 0 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( -320 -576 256 ) ( -320 -448 256 ) ( -320 -448 0 ) eden/edenwalltest 0 0 0.00 1 1 0 0 0 +( -320 -576 256 ) ( -256 -576 256 ) ( -256 -576 0 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( -320 -576 64 ) ( -320 -448 64 ) ( -256 -448 64 ) eden/WL_brick 0 0 0.00 1 1 0 0 0 +( -256 -448 0 ) ( -320 -448 0 ) ( -320 -576 0 ) eden/edenwalltest 0 -128 0.00 1 1 0 0 0 +} +// brush 170 +{ +( -320 -448 256 ) ( -320 -576 256 ) ( -320 -576 0 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( -192 -448 256 ) ( -256 -448 256 ) ( -256 -448 0 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( -128 -576 256 ) ( -128 -448 256 ) ( -128 -448 0 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( -192 -576 256 ) ( -128 -576 256 ) ( -128 -576 0 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( -192 -576 192 ) ( -192 -448 192 ) ( -128 -448 192 ) eden/WL_brick 0 0 0.00 1 1 0 0 0 +( -128 -448 0 ) ( -192 -448 0 ) ( -192 -576 0 ) eden/edenwalltest -128 -128 0.00 1 1 0 0 0 +} +// brush 171 +{ +( 192 -448 256 ) ( 192 -576 256 ) ( 192 -576 0 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( 256 -448 256 ) ( 192 -448 256 ) ( 192 -448 0 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( 256 -576 256 ) ( 256 -448 256 ) ( 256 -448 0 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( 192 -576 256 ) ( 256 -576 256 ) ( 256 -576 0 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( 192 -576 192 ) ( 192 -448 192 ) ( 256 -448 192 ) eden/WL_brick 0 0 0.00 1 1 0 0 0 +( 256 -448 0 ) ( 192 -448 0 ) ( 192 -576 0 ) eden/edenwalltest 0 -128 0.00 1 1 0 0 0 +} +// brush 172 +{ +( 32 -464 0 ) ( -128 -464 0 ) ( -128 -560 0 ) eden/edenrockdark 0 -64 0.00 1 1 0 0 0 +( -128 -560 16 ) ( -128 -464 16 ) ( 32 -464 16 ) eden/edenrockdark 0 -64 0.00 1 1 0 0 0 +( -128 -560 64 ) ( 32 -560 64 ) ( 32 -560 0 ) eden/edenrockdark 0 0 0.00 1 1 0 0 0 +( 192 -544 64 ) ( 192 -448 64 ) ( 192 -448 0 ) eden/edenrockdark 64 0 0.00 1 1 0 0 0 +( 32 -464 64 ) ( -128 -464 64 ) ( -128 -464 0 ) eden/edenrockdark 0 0 0.00 1 1 0 0 0 +( -128 -464 64 ) ( -128 -560 64 ) ( -128 -560 0 ) eden/edenrockdark 64 0 0.00 1 1 0 0 0 +} +// brush 173 +{ +( -128 -272 64 ) ( -128 -368 64 ) ( -128 -368 0 ) eden/edenrockdark 0 0 0.00 1 1 0 0 0 +( 32 -272 64 ) ( -128 -272 64 ) ( -128 -272 0 ) eden/edenrockdark 0 0 0.00 1 1 0 0 0 +( 128 -368 64 ) ( 128 -272 64 ) ( 128 -272 0 ) eden/edenrockdark 0 0 0.00 1 1 0 0 0 +( -128 -368 64 ) ( 32 -368 64 ) ( 32 -368 0 ) eden/edenrockdark 0 0 0.00 1 1 0 0 0 +( -128 -368 16 ) ( -128 -272 16 ) ( 32 -272 16 ) eden/edenrockdark 0 0 0.00 1 1 0 0 0 +( 32 -272 0 ) ( -128 -272 0 ) ( -128 -368 0 ) eden/edenrockdark 0 0 0.00 1 1 0 0 0 +} +// brush 174 +{ +( 192 -256 0 ) ( 128 -256 0 ) ( 128 -384 0 ) eden/edenwalltest 64 -192 0.00 1 1 0 0 0 +( 128 -384 192 ) ( 128 -256 192 ) ( 192 -256 192 ) eden/WL_brick 0 0 0.00 1 1 0 0 0 +( 128 -384 256 ) ( 192 -384 256 ) ( 192 -384 0 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( 192 -384 256 ) ( 192 -256 256 ) ( 192 -256 0 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( 192 -256 256 ) ( 128 -256 256 ) ( 128 -256 0 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( 128 -256 256 ) ( 128 -384 256 ) ( 128 -384 0 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +} +// brush 175 +{ +( -128 -256 0 ) ( -192 -256 0 ) ( -192 -384 0 ) eden/edenwalltest -128 -192 0.00 1 1 0 0 0 +( -192 -384 192 ) ( -192 -256 192 ) ( -128 -256 192 ) eden/WL_brick 0 0 0.00 1 1 0 0 0 +( -192 -384 256 ) ( -128 -384 256 ) ( -128 -384 0 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( -128 -384 256 ) ( -128 -256 256 ) ( -128 -256 0 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( -128 -256 256 ) ( -192 -256 256 ) ( -192 -256 0 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( -320 -256 256 ) ( -320 -384 256 ) ( -320 -384 0 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +} +// brush 176 +{ +( -256 -256 0 ) ( -320 -256 0 ) ( -320 -384 0 ) eden/edenwalltest 0 -192 0.00 1 1 0 0 0 +( -320 -384 64 ) ( -320 -256 64 ) ( -256 -256 64 ) eden/WL_brick 0 0 0.00 1 1 0 0 0 +( -320 -384 256 ) ( -256 -384 256 ) ( -256 -384 0 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( -320 -384 256 ) ( -320 -256 256 ) ( -320 -256 0 ) eden/edenwalltest 64 0 0.00 1 1 0 0 0 +( -256 -256 256 ) ( -320 -256 256 ) ( -320 -256 0 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( -384 -256 256 ) ( -384 -384 256 ) ( -384 -384 0 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +} +// brush 177 +{ +( -192 -80 64 ) ( -192 -176 64 ) ( -192 -176 0 ) eden/edenrockdark 64 0 0.00 1 1 0 0 0 +( -32 -80 64 ) ( -192 -80 64 ) ( -192 -80 0 ) eden/edenrockdark 64 0 0.00 1 1 0 0 0 +( 0 -176 64 ) ( 0 -80 64 ) ( 0 -80 0 ) eden/edenrockdark 64 0 0.00 1 1 0 0 0 +( -192 -176 64 ) ( -32 -176 64 ) ( -32 -176 0 ) eden/edenrockdark 64 0 0.00 1 1 0 0 0 +( -192 -176 16 ) ( -192 -80 16 ) ( -32 -80 16 ) eden/edenrockdark 64 -64 0.00 1 1 0 0 0 +( -32 -80 0 ) ( -192 -80 0 ) ( -192 -176 0 ) eden/edenrockdark 64 -64 0.00 1 1 0 0 0 +} +// brush 178 +{ +( -192 112 64 ) ( -192 16 64 ) ( -192 16 0 ) eden/edenrockdark 0 0 0.00 1 1 0 0 0 +( -32 112 64 ) ( -192 112 64 ) ( -192 112 0 ) eden/edenrockdark 64 0 0.00 1 1 0 0 0 +( -32 16 64 ) ( -32 112 64 ) ( -32 112 0 ) eden/edenrockdark 0 0 0.00 1 1 0 0 0 +( -192 16 64 ) ( -32 16 64 ) ( -32 16 0 ) eden/edenrockdark 64 0 0.00 1 1 0 0 0 +( -192 16 16 ) ( -192 112 16 ) ( -32 112 16 ) eden/edenrockdark 64 0 0.00 1 1 0 0 0 +( -32 112 0 ) ( -192 112 0 ) ( -192 16 0 ) eden/edenrockdark 64 0 0.00 1 1 0 0 0 +} +// brush 179 +{ +( -256 -64 0 ) ( -320 -64 0 ) ( -320 -192 0 ) eden/edenwalltest 0 0 0.00 1 1 0 0 0 +( -320 -192 64 ) ( -320 -64 64 ) ( -256 -64 64 ) eden/WL_brick 0 0 0.00 1 1 0 0 0 +( -320 -192 256 ) ( -256 -192 256 ) ( -256 -192 0 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( -320 -192 256 ) ( -320 -64 256 ) ( -320 -64 0 ) eden/edenwalltest 128 0 0.00 1 1 0 0 0 +( -256 -64 256 ) ( -320 -64 256 ) ( -320 -64 0 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( -384 -64 256 ) ( -384 -192 256 ) ( -384 -192 0 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +} +// brush 180 +{ +( -320 -64 256 ) ( -320 -192 256 ) ( -320 -192 0 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( -128 -64 256 ) ( -192 -64 256 ) ( -192 -64 0 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( -192 -192 256 ) ( -192 -64 256 ) ( -192 -64 0 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( -192 -192 256 ) ( -128 -192 256 ) ( -128 -192 0 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( -192 -192 192 ) ( -192 -64 192 ) ( -128 -64 192 ) eden/WL_brick 0 0 0.00 1 1 0 0 0 +( -128 -64 0 ) ( -192 -64 0 ) ( -192 -192 0 ) eden/edenwalltest -128 0 0.00 1 1 0 0 0 +} +// brush 181 +{ +( 0 -64 256 ) ( 0 -192 256 ) ( 0 -192 0 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( 64 -64 256 ) ( 0 -64 256 ) ( 0 -64 0 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( 64 -192 256 ) ( 64 -64 256 ) ( 64 -64 0 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( 0 -192 256 ) ( 64 -192 256 ) ( 64 -192 0 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( 0 -192 192 ) ( 0 -64 192 ) ( 64 -64 192 ) eden/WL_brick 0 0 0.00 1 1 0 0 0 +( 64 -64 0 ) ( 0 -64 0 ) ( 0 -192 0 ) eden/edenwalltest -64 0 0.00 1 1 0 0 0 +} +// brush 182 +{ +( -32 128 384 ) ( -32 0 384 ) ( -32 0 128 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( 32 128 256 ) ( -32 128 256 ) ( -32 128 0 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( 32 16 256 ) ( 32 144 256 ) ( 32 144 0 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( -32 0 256 ) ( 32 0 256 ) ( 32 0 0 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( -32 0 192 ) ( -32 128 192 ) ( 32 128 192 ) eden/WL_brick 0 0 0.00 1 1 0 0 0 +( 32 128 0 ) ( -32 128 0 ) ( -32 0 0 ) eden/edenwalltest -32 192 0.00 1 1 0 0 0 +} +// brush 183 +{ +( 1136 -656 0 ) ( 848 -656 0 ) ( 848 -960 0 ) eden/edenwalltest 16 -32 0.00 1 1 0 0 0 +( 848 -960 128 ) ( 1136 -960 128 ) ( 1136 -960 0 ) eden/edenwalltest 16 0 0.00 1 1 0 0 0 +( 1104 -960 128 ) ( 1104 -656 128 ) ( 1104 -656 0 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( 848 -656 128 ) ( 848 -960 128 ) ( 848 -960 0 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( 848 -960 128 ) ( 848 -896 96 ) ( 1136 -928 112 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +} +// brush 184 +{ +( 208 -864 64 ) ( 208 -832 0 ) ( 496 -848 32 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( 496 -832 0 ) ( 208 -832 0 ) ( 208 -960 0 ) eden/edenwalltest -112 -32 0.00 1 1 0 0 0 +( 208 -960 256 ) ( 496 -960 256 ) ( 496 -960 0 ) eden/edenwalltest -112 0 0.00 1 1 0 0 0 +( 464 -960 256 ) ( 464 -832 256 ) ( 464 -832 0 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( 208 -832 256 ) ( 208 -960 256 ) ( 208 -960 0 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +} +// brush 185 +{ +( 528 -960 128 ) ( 528 -944 112 ) ( 816 -952 120 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( 816 -672 0 ) ( 528 -672 0 ) ( 528 -960 0 ) eden/edenwalltest -176 -32 0.00 1 1 0 0 0 +( 528 -960 128 ) ( 816 -960 128 ) ( 816 -960 0 ) eden/edenwalltest -176 0 0.00 1 1 0 0 0 +( 784 -960 128 ) ( 784 -672 128 ) ( 784 -672 0 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( 528 -672 128 ) ( 528 -960 128 ) ( 528 -960 0 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +} +// brush 186 +{ +( 1152 -192 0 ) ( 1024 -192 0 ) ( 1024 -320 0 ) eden/edenwalltest -128 -128 0.00 1 1 0 0 0 +( 1024 -320 128 ) ( 1024 -192 128 ) ( 1152 -192 128 ) eden/WL_brick 0 0 0.00 1 1 0 0 0 +( 1024 -320 112 ) ( 1152 -320 112 ) ( 1152 -320 0 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( 1152 -320 112 ) ( 1152 -192 112 ) ( 1152 -192 0 ) eden/edenwalltest 0 0 0.00 1 1 0 0 0 +( 1152 -192 112 ) ( 1024 -192 112 ) ( 1024 -192 0 ) eden/edenwalltest -128 0 0.00 1 1 0 0 0 +( 1024 -192 112 ) ( 1024 -320 112 ) ( 1024 -320 0 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +} +// brush 187 +{ +( 1144 72 160 ) ( 1144 -632 160 ) ( 1144 -632 0 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( 1152 -320 160 ) ( 1136 -320 160 ) ( 1136 -320 0 ) eden/edenwalltest -128 0 0.00 1 1 0 0 0 +( 1152 -928 160 ) ( 1152 -224 160 ) ( 1152 -224 0 ) eden/edenwalltest -128 0 0.00 1 1 0 0 0 +( 1136 -960 160 ) ( 1152 -960 160 ) ( 1152 -960 0 ) eden/edenwalltest -128 0 0.00 1 1 0 0 0 +( 1136 -640 128 ) ( 1136 64 128 ) ( 1152 64 128 ) eden/WL_brick 0 0 0.00 1 1 0 0 0 +( 1152 64 0 ) ( 1136 64 0 ) ( 1136 -640 0 ) eden/edenwalltest -128 0 0.00 1 1 0 0 0 +} +// brush 188 +{ +( 992 448 0 ) ( 832 448 0 ) ( 832 256 0 ) eden/edenwalltest -128 0 0.00 1 1 0 0 0 +( 832 256 160 ) ( 832 448 160 ) ( 992 448 160 ) eden/WL_brick 0 0 0.00 1 1 0 0 0 +( 832 256 64 ) ( 992 256 64 ) ( 992 256 0 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( 1088 448 64 ) ( 1088 640 64 ) ( 1088 640 0 ) eden/edenwalltest 0 0 0.00 1 1 0 0 0 +( 992 640 64 ) ( 832 640 64 ) ( 832 640 0 ) eden/edenwalltest -128 0 0.00 1 1 0 0 0 +( 832 448 64 ) ( 832 256 64 ) ( 832 256 0 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +} +// brush 189 +{ +( 1152 448 512 ) ( -544 448 512 ) ( -544 -672 512 ) creeperpens/edenwoodfloor 0 0 0.00 1 1 0 0 0 +( -544 -672 544 ) ( -544 448 544 ) ( 1152 448 544 ) creeperpens/edenwoodfloor 0 0 0.00 1 1 0 0 0 +( -704 -960 736 ) ( 992 -960 736 ) ( 992 -960 480 ) creeperpens/edenwoodfloor 0 0 0.00 1 1 0 0 0 +( 1152 -864 736 ) ( 1152 256 736 ) ( 1152 256 480 ) creeperpens/edenwoodfloor 0 0 0.00 1 1 0 0 0 +( 992 640 736 ) ( -704 640 736 ) ( -704 640 480 ) creeperpens/edenwoodfloor 0 0 0.00 1 1 0 0 0 +( -704 256 736 ) ( -704 -864 736 ) ( -704 -864 480 ) creeperpens/edenwoodfloor 0 0 0.00 1 1 0 0 0 +} +// brush 190 +{ +( 1152 448 -32 ) ( -544 448 -32 ) ( -544 -672 -32 ) creeperpens/fl_pens_base 0 0 0.00 1 1 0 0 0 +( -544 -672 0 ) ( -544 448 0 ) ( 1152 448 0 ) creeperpens/fl_pens_base 0 0 0.00 1 1 0 0 0 +( -704 -960 192 ) ( 992 -960 192 ) ( 992 -960 -64 ) creeperpens/fl_pens_base 0 0 0.00 1 1 0 0 0 +( 1152 -864 192 ) ( 1152 256 192 ) ( 1152 256 -64 ) creeperpens/fl_pens_base 0 0 0.00 1 1 0 0 0 +( 992 640 192 ) ( -704 640 192 ) ( -704 640 -64 ) creeperpens/fl_pens_base 0 0 0.00 1 1 0 0 0 +( -704 256 192 ) ( -704 -864 192 ) ( -704 -864 -64 ) creeperpens/fl_pens_base 0 0 0.00 1 1 0 0 0 +} +// brush 191 +{ +( 1152 384 512 ) ( 1152 -768 512 ) ( 1152 -768 480 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( 1184 640 32 ) ( 1152 640 32 ) ( 1152 640 0 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( 1184 -672 32 ) ( 1184 480 32 ) ( 1184 480 0 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( 1152 -960 32 ) ( 1184 -960 32 ) ( 1184 -960 0 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( 1184 480 0 ) ( 1152 480 0 ) ( 1152 -672 0 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( -480 -672 256 ) ( -448 448 256 ) ( -416 -672 256 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +} +// brush 192 +{ +( -448 448 256 ) ( -480 -672 256 ) ( -416 -672 256 ) eden/ornatewallweathered 0 0 0.00 1 1 0 0 0 +( 1152 -672 512 ) ( 1152 480 512 ) ( 1184 480 512 ) eden/ornatewallweathered 0 0 0.00 1 1 0 0 0 +( 1152 -960 32 ) ( 1184 -960 32 ) ( 1184 -960 0 ) eden/ornatewallweathered 0 0 0.00 1 1 0 0 0 +( 1184 -672 32 ) ( 1184 480 32 ) ( 1184 480 0 ) eden/ornatewallweathered 0 0 0.00 1 1 0 0 0 +( 1184 640 32 ) ( 1152 640 32 ) ( 1152 640 0 ) eden/ornatewallweathered 0 0 0.00 1 1 0 0 0 +( 1152 384 512 ) ( 1152 -768 512 ) ( 1152 -768 480 ) eden/ornatewallweathered 0 0 0.00 1 1 0 0 0 +} +// brush 193 +{ +( -480 -992 256 ) ( -448 -960 256 ) ( -416 -992 256 ) eden/WL_basement_2w 0 -192 0.00 1 1 0 0 0 +( 1120 -960 0 ) ( -544 -960 0 ) ( -544 -992 0 ) eden/WL_basement_2w 0 -192 0.00 1 1 0 0 0 +( -544 -992 32 ) ( 1120 -992 32 ) ( 1120 -992 0 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( 1152 -992 512 ) ( 1152 -960 512 ) ( 1152 -960 480 ) eden/WL_basement_2w 192 0 0.00 1 1 0 0 0 +( 960 -960 32 ) ( -704 -960 32 ) ( -704 -960 0 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( -704 -960 512 ) ( -704 -992 512 ) ( -704 -992 480 ) eden/WL_basement_2w 192 0 0.00 1 1 0 0 0 +} +// brush 194 +{ +( -704 -960 512 ) ( -704 -992 512 ) ( -704 -992 480 ) eden/ornatewallweathered 192 0 0.00 1 1 0 0 0 +( 960 -960 32 ) ( -704 -960 32 ) ( -704 -960 0 ) eden/ornatewallweathered 0 0 0.00 1 1 0 0 0 +( 1152 -992 512 ) ( 1152 -960 512 ) ( 1152 -960 480 ) eden/ornatewallweathered 192 0 0.00 1 1 0 0 0 +( -544 -992 32 ) ( 1120 -992 32 ) ( 1120 -992 0 ) eden/ornatewallweathered 0 0 0.00 1 1 0 0 0 +( -544 -992 512 ) ( -544 -960 512 ) ( 1120 -960 512 ) eden/ornatewallweathered 0 -192 0.00 1 1 0 0 0 +( -448 -960 256 ) ( -480 -992 256 ) ( -416 -992 256 ) eden/ornatewallweathered 0 -192 0.00 1 1 0 0 0 +} +// brush 195 +{ +( -480 640 256 ) ( -448 672 256 ) ( -416 640 256 ) eden/WL_basement_2w 0 192 0.00 1 1 0 0 0 +( -704 672 512 ) ( -704 640 512 ) ( -704 640 480 ) eden/WL_basement_2w -192 0 0.00 1 1 0 0 0 +( 1152 672 32 ) ( -544 672 32 ) ( -544 672 0 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( 1152 640 512 ) ( 1152 672 512 ) ( 1152 672 480 ) eden/WL_basement_2w -192 0 0.00 1 1 0 0 0 +( -704 640 32 ) ( 992 640 32 ) ( 992 640 0 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( 1152 672 0 ) ( -544 672 0 ) ( -544 640 0 ) eden/WL_basement_2w 0 192 0.00 1 1 0 0 0 +} +// brush 196 +{ +( -544 640 512 ) ( -544 672 512 ) ( 1152 672 512 ) eden/ornatewallweathered 0 192 0.00 1 1 0 0 0 +( -704 640 32 ) ( 992 640 32 ) ( 992 640 0 ) eden/ornatewallweathered 0 0 0.00 1 1 0 0 0 +( 1152 640 512 ) ( 1152 672 512 ) ( 1152 672 480 ) eden/ornatewallweathered -192 0 0.00 1 1 0 0 0 +( 1152 672 32 ) ( -544 672 32 ) ( -544 672 0 ) eden/ornatewallweathered 0 0 0.00 1 1 0 0 0 +( -704 672 512 ) ( -704 640 512 ) ( -704 640 480 ) eden/ornatewallweathered -192 0 0.00 1 1 0 0 0 +( -448 672 256 ) ( -480 640 256 ) ( -416 640 256 ) eden/ornatewallweathered 0 192 0.00 1 1 0 0 0 +} +// brush 197 +{ +( -640 -672 256 ) ( -608 448 256 ) ( -576 -672 256 ) eden/WL_basement_2w 160 0 0.00 1 1 0 0 0 +( -704 448 0 ) ( -736 448 0 ) ( -736 -704 0 ) eden/WL_basement_2w 160 0 0.00 1 1 0 0 0 +( -736 -960 32 ) ( -704 -960 32 ) ( -704 -960 0 ) eden/WL_basement_2w 160 0 0.00 1 1 0 0 0 +( -704 -800 512 ) ( -704 352 512 ) ( -704 352 480 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( -704 640 32 ) ( -736 640 32 ) ( -736 640 0 ) eden/WL_basement_2w 160 0 0.00 1 1 0 0 0 +( -736 448 32 ) ( -736 -704 32 ) ( -736 -704 0 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +} +// brush 198 +{ +( -736 448 32 ) ( -736 -704 32 ) ( -736 -704 0 ) eden/ornatewallweathered 0 0 0.00 1 1 0 0 0 +( -704 640 32 ) ( -736 640 32 ) ( -736 640 0 ) eden/ornatewallweathered 160 0 0.00 1 1 0 0 0 +( -704 -800 512 ) ( -704 352 512 ) ( -704 352 480 ) eden/ornatewallweathered 0 0 0.00 1 1 0 0 0 +( -736 -960 32 ) ( -704 -960 32 ) ( -704 -960 0 ) eden/ornatewallweathered 160 0 0.00 1 1 0 0 0 +( -736 -704 512 ) ( -736 448 512 ) ( -704 448 512 ) eden/ornatewallweathered 160 0 0.00 1 1 0 0 0 +( -608 448 256 ) ( -640 -672 256 ) ( -576 -672 256 ) eden/ornatewallweathered 160 0 0.00 1 1 0 0 0 +} +// brush 199 +{ +( 1120 128 0 ) ( 960 128 0 ) ( 960 -64 0 ) eden/edenwalltest 0 -64 0.00 1 1 0 0 0 +( 960 -64 160 ) ( 960 128 160 ) ( 1120 128 160 ) eden/WL_brick 0 0 0.00 1 1 0 0 0 +( 960 -64 64 ) ( 1120 -64 64 ) ( 1120 -64 0 ) eden/edenwalltest 0 0 0.00 1 1 0 0 0 +( 1152 128 64 ) ( 1152 320 64 ) ( 1152 320 0 ) eden/edenwalltest 64 0 0.00 1 1 0 0 0 +( 1312 640 64 ) ( 1152 640 64 ) ( 1152 640 0 ) eden/edenwalltest 0 0 0.00 1 1 0 0 0 +( 1088 336 64 ) ( 1088 144 64 ) ( 1088 144 0 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +} +// brush 200 +{ +( 1120 128 176 ) ( 960 128 176 ) ( 960 -64 176 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( 960 -64 528 ) ( 960 128 528 ) ( 1120 128 528 ) eden/edenwalltest 0 -64 0.00 1 1 0 0 0 +( 960 -64 240 ) ( 1120 -64 240 ) ( 1120 -64 176 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( 1152 128 240 ) ( 1152 320 240 ) ( 1152 320 176 ) eden/edenwalltest 64 176 0.00 1 1 0 0 0 +( 1072 640 240 ) ( 912 640 240 ) ( 912 640 176 ) eden/edenwalltest 0 176 0.00 1 1 0 0 0 +( 1056 144 240 ) ( 1056 -48 240 ) ( 1056 -48 176 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +} +// brush 201 +{ +( 1120 -64 0 ) ( 960 -64 0 ) ( 960 -256 0 ) eden/edenwalltest 0 0 0.00 1 1 0 0 0 +( 960 -256 160 ) ( 960 -64 160 ) ( 1120 -64 160 ) eden/WL_brick 0 0 0.00 1 1 0 0 0 +( 960 -128 64 ) ( 1120 -128 64 ) ( 1120 -128 0 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( 1152 -256 64 ) ( 1152 -64 64 ) ( 1152 -64 0 ) eden/edenwalltest 0 0 0.00 1 1 0 0 0 +( 1120 -64 64 ) ( 960 -64 64 ) ( 960 -64 0 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( 896 -48 64 ) ( 896 -240 64 ) ( 896 -240 0 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +} +// brush 202 +{ +( 1120 -64 224 ) ( 960 -64 224 ) ( 960 -256 224 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( 960 -256 528 ) ( 960 -64 528 ) ( 1120 -64 528 ) eden/edenwalltest 0 0 0.00 1 1 0 0 0 +( 960 -128 240 ) ( 1120 -128 240 ) ( 1120 -128 176 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( 1152 -256 240 ) ( 1152 -64 240 ) ( 1152 -64 176 ) eden/edenwalltest 0 176 0.00 1 1 0 0 0 +( 1072 0 240 ) ( 912 0 240 ) ( 912 0 176 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( 896 -48 240 ) ( 896 -240 240 ) ( 896 -240 176 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +} +} +// entity 1 +{ +"classname" "func_camera" +"scale" "1.0" +"model" "func_camera.tik" +"spawnflags" "4" +"auto_radius" "512" +"origin" "304.00 280.00 344.00" +} +// entity 2 +{ +"classname" "func_horizontalpipe" +// brush 0 + { + patchDef2 + { + metals/dark_combo_dark + ( 9 3 0 536870912 0 ) +( +( ( -631.999695 -596 424 0 0 ) ( 248.000122 -596 424 0 6.624999 ) ( 1128 -596 424 0 13.249998 ) ) +( ( -631.999695 -596 427 0.023438 0 ) ( 248.000122 -596 427 0.023438 6.624999 ) ( 1128 -596 427 0.023438 13.249998 ) ) +( ( -631.999695 -600 428 0.055649 0 ) ( 248.000122 -600 428 0.055649 6.624999 ) ( 1128 -600 428 0.055649 13.249998 ) ) +( ( -631.999695 -603 428 0.079087 0 ) ( 248.000122 -603 428 0.079087 6.624999 ) ( 1128 -603 428 0.079087 13.249998 ) ) +( ( -631.999695 -604 424 0.111299 0 ) ( 248.000122 -604 424 0.111299 6.624999 ) ( 1128 -604 424 0.111299 13.249998 ) ) +( ( -631.999695 -603 420 0.143510 0 ) ( 248.000122 -603 420 0.143510 6.624999 ) ( 1128 -603 420 0.143510 13.249998 ) ) +( ( -631.999695 -600 420 0.166948 0 ) ( 248.000122 -600 420 0.166948 6.624999 ) ( 1128 -600 420 0.166948 13.249998 ) ) +( ( -631.999695 -596 421 0.199160 0 ) ( 248.000122 -596 421 0.199160 6.624999 ) ( 1128 -596 421 0.199160 13.249998 ) ) +( ( -631.999695 -596 424 0.222597 0 ) ( 248.000122 -596 424 0.222597 6.624999 ) ( 1128 -596 424 0.222597 13.249998 ) ) +) + } + } +} +// entity 3 +{ +"classname" "func_monkeybars" +// brush 0 +{ +( -312 -176 420 ) ( -504 -176 420 ) ( -504 -272 420 ) eden/edenfence 0 63 -90.00 1 0.250000 536870912 16 0 +( -504 -272 428 ) ( -504 -176 428 ) ( -312 -176 428 ) common/skip 0 0 0.00 1 1 805306368 16512 0 +( -568 -256 432 ) ( -376 -256 432 ) ( -376 -256 416 ) common/skip 0 0 0.00 1 1 805306368 16512 0 +( 1120 -800 432 ) ( 1120 -704 432 ) ( 1120 -704 416 ) common/skip 0 0 0.00 1 1 805306368 16512 0 +( -376 -192 432 ) ( -568 -192 432 ) ( -568 -192 416 ) common/skip 0 0 0.00 1 1 805306368 16512 0 +( -576 -176 432 ) ( -576 -272 432 ) ( -576 -272 416 ) common/skip 0 0 0.00 1 1 805306368 16512 0 +} +// brush 1 +{ +( 648 -240 420 ) ( 456 -240 420 ) ( 456 -336 420 ) eden/edenfence -31 63 -90.00 1 0.250000 536870912 16 0 +( 456 -336 428 ) ( 456 -240 428 ) ( 648 -240 428 ) common/skip 0 0 0.00 1 1 805306368 16512 0 +( 392 -352 432 ) ( 584 -352 432 ) ( 584 -352 416 ) common/skip 0 0 0.00 1 1 805306368 16512 0 +( 1120 -880 432 ) ( 1120 -784 432 ) ( 1120 -784 416 ) common/skip 0 0 0.00 1 1 805306368 16512 0 +( 584 -256 432 ) ( 392 -256 432 ) ( 392 -256 416 ) common/skip 0 0 0.00 1 1 805306368 16512 0 +( 384 -240 432 ) ( 384 -336 432 ) ( 384 -336 416 ) common/skip 0 0 0.00 1 1 805306368 16512 0 +} +} +// entity 4 +{ +"origin" "-248 200 264" +"light" "400" +"classname" "light" +} +// entity 5 +{ +"origin" "-624 560 0" +"angle" "0" +"classname" "info_player_start" +} +// entity 6 +{ +"classname" "light" +"light" "400" +"origin" "200 200 264" +} +// entity 7 +{ +"origin" "648 200 264" +"light" "400" +"classname" "light" +} +// entity 8 +{ +"classname" "light" +"light" "400" +"origin" "-248 -600 264" +} +// entity 9 +{ +"origin" "200 -600 264" +"light" "400" +"classname" "light" +} +// entity 10 +{ +"classname" "light" +"light" "400" +"origin" "648 -600 264" +} +// entity 11 +{ +"classname" "light" +"light" "400" +"origin" "1000 200 264" +} +// entity 12 +{ +"origin" "1000 -600 264" +"light" "400" +"classname" "light" +} +// entity 13 +{ +"classname" "light" +"light" "400" +"origin" "392 -120 264" +} +// entity 14 +{ +"origin" "-56 -120 264" +"light" "400" +"classname" "light" +} +// entity 15 +{ +"classname" "light" +"light" "400" +"origin" "872 -120 264" +} +// entity 16 +{ +"classname" "light" +"light" "400" +"origin" "-600 200 264" +} +// entity 17 +{ +"_color" "1.000000 1.000000 1.000000" +"origin" "-600 -408 360" +"light" "100" +"classname" "light" +} +// entity 18 +{ +"classname" "light" +"light" "100" +"origin" "-600 -248 360" +"_color" "1.000000 1.000000 1.000000" +} +// entity 19 +{ +"origin" "1120 312 168" +"light" "100" +"classname" "light" +"_color" "0.500000 1.000000 1.000000" +} +// entity 20 +{ +"_color" "0.500000 1.000000 1.000000" +"classname" "light" +"light" "100" +"origin" "1120 200 168" +} +// entity 21 +{ +"origin" "1120 56 168" +"light" "100" +"classname" "light" +"_color" "0.500000 1.000000 1.000000" +} +// entity 22 +{ +"origin" "-8 -760 264" +"light" "400" +"classname" "light" +} +// entity 23 +{ +"classname" "light" +"light" "400" +"origin" "824 -808 264" +} +// entity 24 +{ +"classname" "light" +"light" "100" +"origin" "-584 -792 360" +"_color" "1.000000 1.000000 1.000000" +} +// entity 25 +{ +"classname" "light" +"light" "400" +"origin" "-24 424 264" +} +// entity 26 +{ +"origin" "-504 456 264" +"light" "400" +"classname" "light" +} +// entity 27 +{ +"classname" "light" +"light" "400" +"origin" "488 456 264" +} +// entity 28 +{ +"classname" "light" +"light" "100" +"origin" "-408 -408 168" +"_color" "1.000000 1.000000 1.000000" +} +// entity 29 +{ +"_color" "1.000000 1.000000 1.000000" +"origin" "-408 -56 168" +"light" "100" +"classname" "light" +} +// entity 30 +{ +"_color" "1.000000 1.000000 1.000000" +"origin" "-536 -792 200" +"light" "100" +"classname" "light" +} +// entity 31 +{ +"origin" "704.00 -72.00 344.00" +"auto_radius" "512" +"spawnflags" "4" +"model" "func_camera.tik" +"scale" "1.0" +"classname" "func_camera" +} +// entity 32 +{ +"origin" "184.00 -288.00 208.00" +"auto_radius" "1024" +"spawnflags" "4" +"model" "func_camera.tik" +"scale" "1.0" +"classname" "func_camera" +"auto_state" "MONKEY" +} +// entity 33 +{ +"auto_state" "PIPE" +"classname" "func_camera" +"scale" "1.0" +"model" "func_camera.tik" +"spawnflags" "4" +"auto_radius" "1024" +"origin" "-216.00 -800.00 416.00" +"fov" "0.5" +} +// entity 34 +{ +"origin" "1095.21 -941.12 491.06" +"auto_radius" "1024" +"spawnflags" "20" +"model" "func_camera.tik" +"scale" "1.0" +"classname" "func_camera" +"angles" "22.5 135.0 0" +} diff --git a/fakk/maps/example/autocamera.prt b/fakk/maps/example/autocamera.prt new file mode 100644 index 0000000..5bbdeb0 --- /dev/null +++ b/fakk/maps/example/autocamera.prt @@ -0,0 +1,2315 @@ +PRT1 +329 +1065 +1246 +4 0 5 0 (1056 0 160 ) (1152 0 160 ) (1152 0 176 ) (1056 0 176 ) +4 0 2 0 (1088 0 160 ) (1056 0 160 ) (1056 256 160 ) (1088 256 160 ) +4 0 1 0 (1056 640 160 ) (1056 0 160 ) (1056 0 176 ) (1056 640 176 ) +4 1 114 0 (1024 0 160 ) (1024 0 512 ) (1024 446 512 ) (1024 446 160 ) +4 1 43 0 (1024 446 512 ) (1024 448 512 ) (1024 448 160 ) (1024 446 160 ) +4 1 31 0 (1024 448 512 ) (1024 640 512 ) (1024 640 160 ) (1024 448 160 ) +4 1 3 0 (1024 0 224 ) (1024 0 176 ) (1056 0 176 ) (1056 0 224 ) +4 1 5 0 (1024 0 176 ) (1024 0 160 ) (1056 0 160 ) (1056 0 176 ) +4 1 2 0 (1056 0 160 ) (1024 0 160 ) (1024 256 160 ) (1056 256 160 ) +4 2 115 0 (1024 0 0 ) (1024 0 160 ) (1024 256 160 ) (1024 256 0 ) +4 2 26 0 (1024 0 160 ) (1024 0 0 ) (1088 0 0 ) (1088 0 160 ) +4 3 127 0 (1024 0 224 ) (1024 0 176 ) (1024 -64 176 ) (1024 -64 224 ) +4 3 4 0 (1024 -64 176 ) (1056 -64 176 ) (1056 -64 224 ) (1024 -64 224 ) +4 3 5 0 (1024 -64 176 ) (1024 0 176 ) (1056 0 176 ) (1056 -64 176 ) +4 4 127 0 (1024 -64 176 ) (1024 -128 176 ) (1024 -128 224 ) (1024 -64 224 ) +4 4 23 0 (1120 -128 224 ) (1024 -128 224 ) (1024 -128 192 ) (1120 -128 192 ) +4 4 10 0 (1152 -128 192 ) (1152 -128 224 ) (1120 -128 224 ) (1120 -128 192 ) +4 4 25 0 (1152 -128 176 ) (1152 -128 192 ) (1024 -128 192 ) (1024 -128 176 ) +4 4 5 0 (1152 -128 176 ) (1024 -128 176 ) (1024 -64 176 ) (1152 -64 176 ) +4 5 127 0 (1024 0 176 ) (1024 0 160 ) (1024 -128 160 ) (1024 -128 176 ) +4 5 26 0 (1024 0 160 ) (1088 0 160 ) (1088 -64 160 ) (1024 -64 160 ) +4 5 25 0 (1024 -128 160 ) (1152 -128 160 ) (1152 -128 176 ) (1024 -128 176 ) +4 6 11 0 (1120 -128 512 ) (1120 -128 440 ) (1120 -576 440 ) (1120 -576 512 ) +4 6 8 0 (1120 -344 440 ) (1120 -184 440 ) (1152 -184 440 ) (1152 -344 440 ) +4 6 7 0 (1120 -152 440 ) (1120 -128 440 ) (1152 -128 440 ) (1152 -152 440 ) +4 6 9 0 (1152 -576 440 ) (1120 -576 440 ) (1120 -376 440 ) (1152 -376 440 ) +4 7 12 0 (1120 -128 432 ) (1120 -128 416 ) (1120 -152 416 ) (1120 -152 432 ) +4 7 11 0 (1120 -128 440 ) (1120 -128 432 ) (1120 -152 432 ) (1120 -152 440 ) +4 7 23 0 (1120 -128 416 ) (1120 -128 408 ) (1120 -152 408 ) (1120 -152 416 ) +4 7 10 0 (1120 -152 408 ) (1120 -128 408 ) (1152 -128 408 ) (1152 -152 408 ) +4 8 17 0 (1120 -344 416 ) (1120 -344 432 ) (1120 -192 432 ) (1120 -192 416 ) +3 8 16 0 (1120 -192 432 ) (1120 -188 432 ) (1120 -192 428 ) +3 8 13 0 (1120 -188 416 ) (1120 -192 416 ) (1120 -192 420 ) +4 8 11 0 (1120 -344 432 ) (1120 -344 440 ) (1120 -184 440 ) (1120 -184 432 ) +4 8 23 0 (1120 -184 408 ) (1120 -344 408 ) (1120 -344 416 ) (1120 -184 416 ) +4 8 10 0 (1120 -344 408 ) (1120 -184 408 ) (1152 -184 408 ) (1152 -344 408 ) +4 9 22 0 (1120 -576 416 ) (1120 -576 432 ) (1120 -376 432 ) (1120 -376 416 ) +4 9 11 0 (1120 -576 432 ) (1120 -576 440 ) (1120 -376 440 ) (1120 -376 432 ) +4 9 23 0 (1120 -376 408 ) (1120 -576 408 ) (1120 -576 416 ) (1120 -376 416 ) +4 9 10 0 (1152 -576 408 ) (1120 -576 408 ) (1120 -376 408 ) (1152 -376 408 ) +4 10 23 0 (1120 -128 408 ) (1120 -128 192 ) (1120 -576 192 ) (1120 -576 408 ) +4 10 25 0 (1120 -128 192 ) (1152 -128 192 ) (1152 -576 192 ) (1120 -576 192 ) +4 11 126 0 (1024 -576 512 ) (1024 -128 512 ) (1024 -128 432 ) (1024 -576 432 ) +4 11 24 0 (1104 -576 512 ) (1024 -576 512 ) (1024 -576 432 ) (1104 -576 432 ) +4 11 20 0 (1024 -368 432 ) (1024 -364 432 ) (1120 -364 432 ) (1120 -368 432 ) +4 11 19 0 (1024 -356 432 ) (1024 -352 432 ) (1120 -352 432 ) (1120 -356 432 ) +4 11 22 0 (1120 -576 432 ) (1024 -576 432 ) (1024 -368 432 ) (1120 -368 432 ) +4 11 17 0 (1024 -352 432 ) (1024 -192 432 ) (1120 -192 432 ) (1120 -352 432 ) +4 11 16 0 (1024 -192 432 ) (1024 -188 432 ) (1120 -188 432 ) (1120 -192 432 ) +4 11 15 0 (1024 -180 432 ) (1024 -176 432 ) (1120 -176 432 ) (1120 -180 432 ) +4 11 12 0 (1024 -176 432 ) (1024 -128 432 ) (1120 -128 432 ) (1120 -176 432 ) +3 12 138 0 (1024 -176 420 ) (1024 -176 432 ) (1024 -164 432 ) +5 12 130 0 (1024 -128 432 ) (1024 -128 416 ) (1024 -176 416 ) (1024 -176 420 ) (1024 -164 432 ) +4 12 15 0 (1120 -176 428 ) (1120 -176 432 ) (1024 -176 432 ) (1024 -176 428 ) +4 12 14 0 (1024 -176 416 ) (1120 -176 416 ) (1120 -176 420 ) (1024 -176 420 ) +4 12 23 0 (1024 -176 416 ) (1024 -128 416 ) (1120 -128 416 ) (1120 -176 416 ) +3 13 140 0 (1024 -188 416 ) (1024 -192 416 ) (1024 -192 420 ) +4 13 17 0 (1024 -192 416 ) (1120 -192 416 ) (1120 -192 420 ) (1024 -192 420 ) +4 13 23 0 (1024 -192 416 ) (1024 -188 416 ) (1120 -188 416 ) (1120 -192 416 ) +3 14 130 0 (1024 -176 416 ) (1024 -180 416 ) (1024 -176 420 ) +4 14 23 0 (1024 -180 416 ) (1024 -176 416 ) (1120 -176 416 ) (1120 -180 416 ) +3 15 141 0 (1024 -180 432 ) (1024 -176 432 ) (1024 -176 428 ) +3 16 139 0 (1024 -192 428 ) (1024 -192 432 ) (1024 -188 432 ) +4 16 17 0 (1120 -192 428 ) (1120 -192 432 ) (1024 -192 432 ) (1024 -192 428 ) +6 17 149 0 (1024 -259.994049 416 ) (1024 -352 416 ) (1024 -352 432 ) (1024 -260 432 ) (1024 -256 428 ) (1024 -256 419.994049 ) +3 17 148 0 (1024 -260 432 ) (1024 -256 432 ) (1024 -256 428 ) +3 17 146 0 (1024 -256 416 ) (1024 -259.994049 416 ) (1024 -256 419.994049 ) +4 17 144 0 (1024 -224 416 ) (1024 -256 416 ) (1024 -256 432 ) (1024 -224 432 ) +4 17 143 0 (1024 -192 416 ) (1024 -224 416 ) (1024 -224 432 ) (1024 -192 432 ) +4 17 19 0 (1120 -352 428 ) (1120 -352 432 ) (1024 -352 432 ) (1024 -352 428 ) +4 17 18 0 (1024 -352 416 ) (1120 -352 416 ) (1120 -352 420 ) (1024 -352 420 ) +4 17 23 0 (1024 -352 416 ) (1024 -192 416 ) (1120 -192 416 ) (1120 -352 416 ) +3 18 150 0 (1024 -352 416 ) (1024 -356 416 ) (1024 -352 420 ) +4 18 23 0 (1024 -356 416 ) (1024 -352 416 ) (1120 -352 416 ) (1120 -356 416 ) +3 19 151 0 (1024 -356 432 ) (1024 -352 432 ) (1024 -352 428 ) +3 20 145 0 (1024 -368 428 ) (1024 -368 432 ) (1024 -364 432 ) +4 20 22 0 (1120 -368 428 ) (1120 -368 432 ) (1024 -368 432 ) (1024 -368 428 ) +3 21 147 0 (1024 -364 416 ) (1024 -368 416 ) (1024 -368 420 ) +4 21 23 0 (1024 -368 416 ) (1024 -364 416 ) (1120 -364 416 ) (1120 -368 416 ) +4 21 22 0 (1024 -368 416 ) (1120 -368 416 ) (1120 -368 420 ) (1024 -368 420 ) +4 22 159 0 (1024 -368 416 ) (1024 -576 416 ) (1024 -576 432 ) (1024 -368 432 ) +4 22 24 0 (1104 -576 432 ) (1024 -576 432 ) (1024 -576 416 ) (1104 -576 416 ) +4 22 23 0 (1120 -576 416 ) (1024 -576 416 ) (1024 -368 416 ) (1120 -368 416 ) +4 23 166 0 (1024 -256 192 ) (1024 -576 192 ) (1024 -576 256 ) (1024 -256 256 ) +4 23 161 0 (1024 -576 328 ) (1024 -576 368 ) (1024 -256 368 ) (1024 -256 328 ) +4 23 164 0 (1024 -576 256 ) (1024 -576 328 ) (1024 -256 328 ) (1024 -256 256 ) +4 23 160 0 (1024 -576 368 ) (1024 -576 416 ) (1024 -256 416 ) (1024 -256 368 ) +4 23 144 0 (1024 -224 192 ) (1024 -256 192 ) (1024 -256 416 ) (1024 -224 416 ) +3 23 142 0 (1024 -192 416 ) (1024 -180 416 ) (1024 -192 404 ) +4 23 143 0 (1024 -224 372 ) (1024 -224 416 ) (1024 -192 416 ) (1024 -192 404 ) +5 23 130 0 (1024 -128 416 ) (1024 -128 192 ) (1024 -224 192 ) (1024 -224 372 ) (1024 -180 416 ) +4 23 24 0 (1024 -576 192 ) (1104 -576 192 ) (1104 -576 416 ) (1024 -576 416 ) +4 23 25 0 (1024 -128 192 ) (1120 -128 192 ) (1120 -576 192 ) (1024 -576 192 ) +4 24 177 0 (1024 -960 192 ) (1024 -960 256 ) (1024 -640 256 ) (1024 -640 192 ) +4 24 166 0 (1024 -640 256 ) (1024 -576 256 ) (1024 -576 192 ) (1024 -640 192 ) +4 24 161 0 (1024 -960 328 ) (1024 -960 368 ) (1024 -576 368 ) (1024 -576 328 ) +4 24 164 0 (1024 -960 256 ) (1024 -960 328 ) (1024 -576 328 ) (1024 -576 256 ) +4 24 160 0 (1024 -960 368 ) (1024 -960 416 ) (1024 -576 416 ) (1024 -576 368 ) +4 24 159 0 (1024 -960 416 ) (1024 -960 432 ) (1024 -576 432 ) (1024 -576 416 ) +4 24 126 0 (1024 -960 432 ) (1024 -960 512 ) (1024 -576 512 ) (1024 -576 432 ) +4 24 25 0 (1104 -960 192 ) (1024 -960 192 ) (1024 -576 192 ) (1104 -576 192 ) +4 25 177 0 (1024 -960 160 ) (1024 -960 192 ) (1024 -640 192 ) (1024 -640 160 ) +4 25 166 0 (1024 -640 192 ) (1024 -256 192 ) (1024 -256 160 ) (1024 -640 160 ) +4 25 144 0 (1024 -256 192 ) (1024 -224 192 ) (1024 -224 160 ) (1024 -256 160 ) +4 25 130 0 (1024 -224 192 ) (1024 -128 192 ) (1024 -128 160 ) (1024 -224 160 ) +4 25 27 0 (1152 -128 160 ) (1152 -960 160 ) (1024 -960 160 ) (1024 -128 160 ) +4 26 128 0 (1024 -64 160 ) (1024 0 160 ) (1024 0 0 ) (1024 -64 0 ) +4 27 177 0 (1024 -960 128 ) (1024 -960 160 ) (1024 -640 160 ) (1024 -640 128 ) +4 27 167 0 (1024 -640 160 ) (1024 -256 160 ) (1024 -256 128 ) (1024 -640 128 ) +4 27 144 0 (1024 -256 160 ) (1024 -224 160 ) (1024 -224 128 ) (1024 -256 128 ) +4 27 130 0 (1024 -224 160 ) (1024 -128 160 ) (1024 -128 128 ) (1024 -224 128 ) +4 27 30 0 (1104 -960 128 ) (1024 -960 128 ) (1024 -320 128 ) (1104 -320 128 ) +4 27 29 0 (1144 -960 128 ) (1104 -960 128 ) (1104 -320 128 ) (1144 -320 128 ) +4 27 28 0 (1024 -128 128 ) (1152 -128 128 ) (1152 -192 128 ) (1024 -192 128 ) +4 28 130 0 (1024 -192 128 ) (1024 -128 128 ) (1024 -128 0 ) (1024 -192 0 ) +4 29 30 0 (1104 -320 128 ) (1104 -320 0 ) (1104 -704 0 ) (1104 -960 128 ) +4 30 177 0 (1024 -960 128 ) (1024 -640 128 ) (1024 -640 0 ) (1024 -704 0 ) +4 30 167 0 (1024 -640 128 ) (1024 -320 128 ) (1024 -320 0 ) (1024 -640 0 ) +4 31 194 0 (0 448 160 ) (0 448 512 ) (0 640 512 ) (0 640 160 ) +4 31 92 0 (0 448 512 ) (0 448 160 ) (224 448 160 ) (224 448 512 ) +4 31 88 0 (224 448 160 ) (336 448 160 ) (336 448 512 ) (224 448 512 ) +4 31 83 0 (336 448 160 ) (348 448 160 ) (348 448 512 ) (336 448 512 ) +4 31 69 0 (348 448 160 ) (412 448 160 ) (412 448 512 ) (348 448 512 ) +4 31 68 0 (412 448 160 ) (416 448 160 ) (416 448 512 ) (412 448 512 ) +4 31 64 0 (416 448 160 ) (428 448 160 ) (428 448 512 ) (416 448 512 ) +4 31 61 0 (428 448 160 ) (640 448 160 ) (640 448 512 ) (428 448 512 ) +4 31 58 0 (640 448 160 ) (648 448 160 ) (648 448 512 ) (640 448 512 ) +4 31 52 0 (648 448 160 ) (660 448 160 ) (660 448 512 ) (648 448 512 ) +4 31 51 0 (660 448 160 ) (664 448 160 ) (664 448 512 ) (660 448 512 ) +4 31 45 0 (664 448 160 ) (676 448 160 ) (676 448 512 ) (664 448 512 ) +4 31 43 0 (676 448 160 ) (1024 448 160 ) (1024 448 512 ) (676 448 512 ) +4 31 42 0 (64 448 160 ) (0 448 160 ) (0 640 160 ) (64 640 160 ) +4 31 39 0 (256 448 160 ) (128 448 160 ) (128 640 160 ) (256 640 160 ) +4 31 41 0 (128 448 160 ) (64 448 160 ) (64 640 160 ) (128 640 160 ) +4 31 35 0 (512 448 160 ) (320 448 160 ) (320 640 160 ) (512 640 160 ) +4 31 38 0 (320 448 160 ) (256 448 160 ) (256 640 160 ) (320 640 160 ) +4 31 32 0 (832 448 160 ) (512 448 160 ) (512 640 160 ) (832 640 160 ) +4 32 61 0 (640 448 160 ) (512 448 160 ) (512 448 128 ) (640 448 128 ) +4 32 58 0 (648 448 160 ) (640 448 160 ) (640 448 128 ) (648 448 128 ) +4 32 52 0 (660 448 160 ) (648 448 160 ) (648 448 128 ) (660 448 128 ) +4 32 51 0 (664 448 160 ) (660 448 160 ) (660 448 128 ) (664 448 128 ) +4 32 45 0 (676 448 160 ) (664 448 160 ) (664 448 128 ) (676 448 128 ) +4 32 44 0 (832 448 128 ) (832 448 160 ) (676 448 160 ) (676 448 128 ) +4 32 35 0 (512 448 128 ) (512 448 160 ) (512 640 160 ) (512 640 128 ) +4 32 34 0 (512 448 128 ) (512 640 128 ) (608 640 128 ) (608 448 128 ) +4 32 33 0 (704 640 128 ) (832 640 128 ) (832 448 128 ) (704 448 128 ) +4 33 107 0 (704 448 0 ) (832 448 0 ) (832 448 28 ) (704 448 28 ) +4 33 44 0 (832 448 28 ) (832 448 128 ) (704 448 128 ) (704 448 28 ) +4 34 61 0 (608 448 127 ) (608 448 128 ) (512 448 128 ) (512 448 127 ) +4 34 35 0 (512 448 127 ) (512 448 128 ) (512 640 128 ) (512 640 127 ) +4 35 88 0 (336 448 160 ) (320 448 160 ) (320 448 96 ) (336 448 96 ) +4 35 83 0 (348 448 160 ) (336 448 160 ) (336 448 96 ) (348 448 96 ) +4 35 69 0 (412 448 160 ) (348 448 160 ) (348 448 96 ) (412 448 96 ) +4 35 68 0 (416 448 160 ) (412 448 160 ) (412 448 96 ) (416 448 96 ) +4 35 64 0 (428 448 160 ) (416 448 160 ) (416 448 96 ) (428 448 96 ) +4 35 63 0 (512 448 96 ) (512 448 127 ) (428 448 127 ) (428 448 96 ) +4 35 61 0 (512 448 127 ) (512 448 160 ) (428 448 160 ) (428 448 127 ) +4 35 37 0 (320 448 96 ) (320 640 96 ) (384 640 96 ) (384 448 96 ) +4 35 36 0 (448 640 96 ) (512 640 96 ) (512 448 96 ) (448 448 96 ) +4 35 38 0 (320 448 96 ) (320 448 160 ) (320 640 160 ) (320 640 96 ) +4 36 108 0 (448 448 0 ) (512 448 0 ) (512 448 28 ) (448 448 28 ) +4 36 63 0 (512 448 28 ) (512 448 96 ) (448 448 96 ) (448 448 28 ) +4 37 88 0 (336 448 96 ) (320 448 96 ) (320 448 95 ) (336 448 95 ) +4 37 83 0 (348 448 96 ) (336 448 96 ) (336 448 95 ) (348 448 95 ) +4 37 69 0 (384 448 95 ) (384 448 96 ) (348 448 96 ) (348 448 95 ) +4 37 38 0 (320 448 95 ) (320 448 96 ) (320 640 96 ) (320 640 95 ) +4 38 108 0 (256 448 0 ) (320 448 0 ) (320 448 28 ) (256 448 28 ) +4 38 89 0 (320 448 28 ) (320 448 48 ) (256 448 48 ) (256 448 28 ) +4 38 88 0 (320 448 48 ) (320 448 160 ) (256 448 160 ) (256 448 48 ) +4 38 39 0 (256 448 80 ) (256 448 160 ) (256 640 160 ) (256 640 80 ) +4 39 92 0 (224 448 160 ) (128 448 160 ) (128 448 80 ) (224 448 80 ) +4 39 88 0 (256 448 80 ) (256 448 160 ) (224 448 160 ) (224 448 80 ) +4 39 40 0 (128 448 80 ) (128 640 80 ) (192 640 80 ) (192 448 80 ) +4 39 41 0 (128 448 80 ) (128 448 160 ) (128 640 160 ) (128 640 80 ) +4 40 92 0 (192 448 80 ) (128 448 80 ) (128 448 79 ) (192 448 79 ) +4 40 41 0 (128 448 79 ) (128 448 80 ) (128 640 80 ) (128 640 79 ) +4 41 108 0 (64 448 0 ) (128 448 0 ) (128 448 28 ) (64 448 28 ) +4 41 100 0 (128 448 28 ) (128 448 44 ) (64 448 44 ) (64 448 28 ) +4 41 99 0 (128 448 44 ) (128 448 48 ) (64 448 48 ) (64 448 44 ) +4 41 92 0 (128 448 48 ) (128 448 160 ) (64 448 160 ) (64 448 48 ) +4 41 42 0 (64 448 64 ) (64 448 160 ) (64 640 160 ) (64 640 64 ) +4 42 194 0 (0 448 64 ) (0 448 160 ) (0 640 160 ) (0 640 64 ) +4 42 92 0 (0 448 160 ) (0 448 64 ) (64 448 64 ) (64 448 160 ) +4 43 114 0 (1024 446 160 ) (1024 446 512 ) (676 446 512 ) (676 446 160 ) +4 43 45 0 (676 448 512 ) (676 448 160 ) (676 446 160 ) (676 446 512 ) +4 43 44 0 (832 446 160 ) (676 446 160 ) (676 448 160 ) (832 448 160 ) +4 44 116 0 (676 446 28 ) (832 446 28 ) (832 446 160 ) (676 446 160 ) +4 44 107 0 (832 446 28 ) (676 446 28 ) (676 448 28 ) (832 448 28 ) +4 44 46 0 (676 448 56 ) (676 448 28 ) (676 446 28 ) (676 446 56 ) +4 44 45 0 (676 448 160 ) (676 448 76 ) (676 446 76 ) (676 446 160 ) +4 45 116 0 (676 446 76 ) (676 446 160 ) (664 446 160 ) (664 446 76 ) +4 45 114 0 (676 446 160 ) (676 446 512 ) (664 446 512 ) (664 446 160 ) +4 45 51 0 (664 448 512 ) (664 448 76 ) (664 446 76 ) (664 446 512 ) +4 46 116 0 (672 446 28 ) (676 446 28 ) (676 446 56 ) (672 446 56 ) +4 46 107 0 (676 446 28 ) (672 446 28 ) (672 448 28 ) (676 448 28 ) +4 46 49 0 (672 448 28 ) (672 446 28 ) (672 446 56 ) (672 448 56 ) +4 47 116 0 (672 446 68 ) (672 446 72 ) (668 446 72 ) (668 446 68 ) +4 48 116 0 (672 446 60 ) (672 446 64 ) (668 446 64 ) (668 446 60 ) +4 49 116 0 (668 446 28 ) (672 446 28 ) (672 446 56 ) (668 446 56 ) +4 49 107 0 (672 446 28 ) (668 446 28 ) (668 448 28 ) (672 448 28 ) +4 49 50 0 (668 448 28 ) (668 446 28 ) (668 446 56 ) (668 448 56 ) +4 50 116 0 (664 446 28 ) (668 446 28 ) (668 446 56 ) (664 446 56 ) +4 50 107 0 (668 446 28 ) (664 446 28 ) (664 448 28 ) (668 448 28 ) +4 50 51 0 (664 448 56 ) (664 448 28 ) (664 446 28 ) (664 446 56 ) +4 51 116 0 (660 446 28 ) (664 446 28 ) (664 446 160 ) (660 446 160 ) +4 51 114 0 (664 446 160 ) (664 446 512 ) (660 446 512 ) (660 446 160 ) +4 51 107 0 (664 446 28 ) (660 446 28 ) (660 448 28 ) (664 448 28 ) +4 51 54 0 (660 446 60 ) (660 446 68 ) (660 448 68 ) (660 448 60 ) +4 51 53 0 (660 446 72 ) (660 446 76 ) (660 448 76 ) (660 448 72 ) +4 51 57 0 (660 448 28 ) (660 446 28 ) (660 446 56 ) (660 448 56 ) +4 51 52 0 (660 446 76 ) (660 446 512 ) (660 448 512 ) (660 448 76 ) +4 52 116 0 (660 446 76 ) (660 446 160 ) (648 446 160 ) (648 446 76 ) +4 52 114 0 (660 446 160 ) (660 446 512 ) (648 446 512 ) (648 446 160 ) +4 52 58 0 (648 446 76 ) (648 446 512 ) (648 448 512 ) (648 448 76 ) +4 52 53 0 (656 448 76 ) (660 448 76 ) (660 446 76 ) (656 446 76 ) +3 53 116 0 (660 446 72 ) (660 446 76 ) (656 446 76 ) +4 54 116 0 (660 446 60 ) (660 446 68 ) (656 446 64 ) (656 446 60 ) +4 54 56 0 (656 448 60 ) (656 446 60 ) (656 446 64 ) (656 448 64 ) +4 55 116 0 (656 446 72 ) (648 446 72 ) (648 446 60 ) (656 446 68 ) +4 55 59 0 (648 446 60 ) (648 446 72 ) (648 448 72 ) (648 448 60 ) +3 56 116 0 (652 446 60 ) (656 446 60 ) (656 446 64 ) +4 57 116 0 (648 446 28 ) (660 446 28 ) (660 446 56 ) (648 446 56 ) +4 57 107 0 (660 446 28 ) (648 446 28 ) (648 448 28 ) (660 448 28 ) +4 57 59 0 (648 448 28 ) (648 446 28 ) (648 446 56 ) (648 448 56 ) +4 58 116 0 (648 446 76 ) (648 446 160 ) (640 446 160 ) (640 446 76 ) +4 58 114 0 (648 446 160 ) (648 446 512 ) (640 446 512 ) (640 446 160 ) +4 58 62 0 (640 446 76 ) (640 446 127 ) (640 448 127 ) (640 448 76 ) +4 58 61 0 (640 446 127 ) (640 446 512 ) (640 448 512 ) (640 448 127 ) +4 58 59 0 (644 448 76 ) (648 448 76 ) (648 446 76 ) (644 446 76 ) +4 59 116 0 (644 446 28 ) (648 446 28 ) (648 446 76 ) (644 446 76 ) +4 59 107 0 (648 446 28 ) (644 446 28 ) (644 448 28 ) (648 448 28 ) +4 59 60 0 (644 448 28 ) (644 446 28 ) (644 446 56 ) (644 448 56 ) +4 60 116 0 (640 446 28 ) (644 446 28 ) (644 446 56 ) (640 446 56 ) +4 60 107 0 (644 446 28 ) (640 446 28 ) (640 448 28 ) (644 448 28 ) +4 60 62 0 (640 448 28 ) (640 446 28 ) (640 446 56 ) (640 448 56 ) +4 61 121 0 (428 446 192 ) (428 446 127 ) (448 446 127 ) (448 446 192 ) +4 61 117 0 (448 446 512 ) (428 446 512 ) (428 446 192 ) (448 446 192 ) +4 61 116 0 (640 446 127 ) (640 446 160 ) (448 446 160 ) (448 446 127 ) +4 61 114 0 (640 446 160 ) (640 446 512 ) (448 446 512 ) (448 446 160 ) +4 61 64 0 (428 448 512 ) (428 448 127 ) (428 446 127 ) (428 446 512 ) +4 61 62 0 (608 448 127 ) (640 448 127 ) (640 446 127 ) (608 446 127 ) +4 61 63 0 (428 446 127 ) (428 448 127 ) (512 448 127 ) (512 446 127 ) +4 62 116 0 (608 446 28 ) (640 446 28 ) (640 446 127 ) (608 446 127 ) +4 62 107 0 (640 446 28 ) (608 446 28 ) (608 448 28 ) (640 448 28 ) +4 63 121 0 (428 446 28 ) (448 446 28 ) (448 446 127 ) (428 446 127 ) +4 63 116 0 (448 446 28 ) (512 446 28 ) (512 446 127 ) (448 446 127 ) +4 63 108 0 (512 446 28 ) (428 446 28 ) (428 448 28 ) (512 448 28 ) +4 63 65 0 (428 448 56 ) (428 448 52 ) (428 446 52 ) (428 446 56 ) +4 63 64 0 (428 448 127 ) (428 448 60 ) (428 446 60 ) (428 446 127 ) +4 63 67 0 (428 448 40 ) (428 448 28 ) (428 446 28 ) (428 446 40 ) +4 64 121 0 (428 446 60 ) (428 446 192 ) (416 446 192 ) (416 446 60 ) +4 64 117 0 (428 446 192 ) (428 446 512 ) (416 446 512 ) (416 446 192 ) +4 64 68 0 (416 448 512 ) (416 448 60 ) (416 446 60 ) (416 446 512 ) +4 65 121 0 (428 446 52 ) (428 446 56 ) (420 446 56 ) (420 446 52 ) +4 66 121 0 (420 446 48 ) (420 446 44 ) (424 446 44 ) (424 446 48 ) +4 67 121 0 (416 446 28 ) (428 446 28 ) (428 446 40 ) (416 446 40 ) +4 67 108 0 (428 446 28 ) (416 446 28 ) (416 448 28 ) (428 448 28 ) +4 67 68 0 (416 448 40 ) (416 448 28 ) (416 446 28 ) (416 446 40 ) +4 68 121 0 (412 446 28 ) (416 446 28 ) (416 446 192 ) (412 446 192 ) +4 68 117 0 (416 446 192 ) (416 446 512 ) (412 446 512 ) (412 446 192 ) +4 68 108 0 (416 446 28 ) (412 446 28 ) (412 448 28 ) (416 448 28 ) +4 68 70 0 (412 448 40 ) (412 448 28 ) (412 446 28 ) (412 446 40 ) +4 68 69 0 (412 448 512 ) (412 448 60 ) (412 446 60 ) (412 446 512 ) +4 69 123 0 (384 446 192 ) (348 446 192 ) (348 446 60 ) (384 446 60 ) +4 69 121 0 (412 446 60 ) (412 446 192 ) (384 446 192 ) (384 446 60 ) +4 69 117 0 (412 446 192 ) (412 446 512 ) (348 446 512 ) (348 446 192 ) +4 69 83 0 (348 448 512 ) (348 448 60 ) (348 446 60 ) (348 446 512 ) +4 69 75 0 (352 448 60 ) (364 448 60 ) (364 446 60 ) (352 446 60 ) +4 69 74 0 (364 448 60 ) (400 448 60 ) (400 446 60 ) (364 446 60 ) +4 69 82 0 (348 446 60 ) (348 448 60 ) (352 448 60 ) (352 446 60 ) +4 70 121 0 (408 446 28 ) (412 446 28 ) (412 446 40 ) (408 446 40 ) +4 70 108 0 (412 446 28 ) (408 446 28 ) (408 448 28 ) (412 448 28 ) +4 70 73 0 (408 448 28 ) (408 446 28 ) (408 446 40 ) (408 448 40 ) +4 71 121 0 (408 446 52 ) (408 446 56 ) (404 446 56 ) (404 446 52 ) +4 72 121 0 (408 446 44 ) (408 446 48 ) (400 446 48 ) (400 446 44 ) +4 72 74 0 (400 446 44 ) (400 446 48 ) (400 448 48 ) (400 448 44 ) +4 73 121 0 (400 446 28 ) (408 446 28 ) (408 446 40 ) (400 446 40 ) +4 73 108 0 (408 446 28 ) (400 446 28 ) (400 448 28 ) (408 448 28 ) +4 73 74 0 (400 448 28 ) (400 446 28 ) (400 446 40 ) (400 448 40 ) +4 74 123 0 (364 446 28 ) (384 446 28 ) (384 446 60 ) (364 446 60 ) +4 74 121 0 (384 446 28 ) (400 446 28 ) (400 446 60 ) (384 446 60 ) +4 74 108 0 (400 446 28 ) (364 446 28 ) (364 448 28 ) (400 448 28 ) +4 74 80 0 (364 446 34 ) (364 446 38 ) (364 448 38 ) (364 448 34 ) +4 74 81 0 (364 448 28 ) (364 446 28 ) (364 446 34 ) (364 448 34 ) +4 74 76 0 (364 446 42 ) (364 446 50 ) (364 448 50 ) (364 448 42 ) +4 74 75 0 (364 446 54 ) (364 446 60 ) (364 448 60 ) (364 448 54 ) +4 75 123 0 (364 446 54 ) (364 446 60 ) (352 446 60 ) (352 446 54 ) +4 75 82 0 (352 446 54 ) (352 446 60 ) (352 448 60 ) (352 448 54 ) +4 76 123 0 (364 446 42 ) (364 446 50 ) (360 446 50 ) (360 446 46 ) +4 76 77 0 (360 446 46 ) (360 446 50 ) (360 448 50 ) (360 448 46 ) +4 77 123 0 (360 446 50 ) (356 446 50 ) (356 446 46 ) (360 446 46 ) +4 78 123 0 (356 446 42 ) (356 446 38 ) (360 446 38 ) (360 446 42 ) +4 78 79 0 (356 448 38 ) (356 446 38 ) (356 446 42 ) (356 448 42 ) +4 79 123 0 (352 446 46 ) (352 446 38 ) (356 446 38 ) (356 446 42 ) +4 79 82 0 (352 446 38 ) (352 446 46 ) (352 448 46 ) (352 448 38 ) +3 80 123 0 (364 446 34 ) (364 446 38 ) (360 446 34 ) +4 80 81 0 (360 448 34 ) (364 448 34 ) (364 446 34 ) (360 446 34 ) +4 81 123 0 (352 446 28 ) (364 446 28 ) (364 446 34 ) (352 446 34 ) +4 81 108 0 (364 446 28 ) (352 446 28 ) (352 448 28 ) (364 448 28 ) +4 81 82 0 (352 448 28 ) (352 446 28 ) (352 446 34 ) (352 448 34 ) +4 82 123 0 (348 446 28 ) (352 446 28 ) (352 446 60 ) (348 446 60 ) +4 82 108 0 (352 446 28 ) (348 446 28 ) (348 448 28 ) (352 448 28 ) +4 82 84 0 (348 448 34 ) (348 448 28 ) (348 446 28 ) (348 446 34 ) +4 82 83 0 (348 448 60 ) (348 448 54 ) (348 446 54 ) (348 446 60 ) +4 83 123 0 (348 446 54 ) (348 446 192 ) (336 446 192 ) (336 446 54 ) +4 83 117 0 (348 446 192 ) (348 446 512 ) (336 446 512 ) (336 446 192 ) +4 83 88 0 (336 448 512 ) (336 448 54 ) (336 446 54 ) (336 446 512 ) +4 84 123 0 (344 446 28 ) (348 446 28 ) (348 446 34 ) (344 446 34 ) +4 84 108 0 (348 446 28 ) (344 446 28 ) (344 448 28 ) (348 448 28 ) +4 84 87 0 (344 448 28 ) (344 446 28 ) (344 446 34 ) (344 448 34 ) +4 85 123 0 (344 446 46 ) (344 446 50 ) (340 446 50 ) (340 446 46 ) +4 86 123 0 (344 446 38 ) (344 446 42 ) (336 446 42 ) (336 446 38 ) +4 86 89 0 (336 448 42 ) (336 448 38 ) (336 446 38 ) (336 446 42 ) +4 87 123 0 (336 446 28 ) (344 446 28 ) (344 446 34 ) (336 446 34 ) +4 87 108 0 (344 446 28 ) (336 446 28 ) (336 448 28 ) (344 448 28 ) +4 87 89 0 (336 448 34 ) (336 448 28 ) (336 446 28 ) (336 446 34 ) +4 88 123 0 (336 446 48 ) (336 446 192 ) (224 446 192 ) (224 446 48 ) +4 88 117 0 (336 446 192 ) (336 446 512 ) (224 446 512 ) (224 446 192 ) +4 88 92 0 (224 448 512 ) (224 448 48 ) (224 446 48 ) (224 446 512 ) +4 88 89 0 (238 448 48 ) (336 448 48 ) (336 446 48 ) (238 446 48 ) +4 88 91 0 (224 446 48 ) (224 448 48 ) (226 448 48 ) (226 446 48 ) +4 89 123 0 (238 446 28 ) (336 446 28 ) (336 446 48 ) (238 446 48 ) +4 89 108 0 (336 446 28 ) (238 446 28 ) (238 448 28 ) (336 448 28 ) +4 90 123 0 (234 446 44 ) (230 446 44 ) (230 446 32 ) (234 446 32 ) +4 91 123 0 (224 446 28 ) (226 446 28 ) (226 446 48 ) (224 446 48 ) +4 91 108 0 (226 446 28 ) (224 446 28 ) (224 448 28 ) (226 448 28 ) +4 92 202 0 (0 446 48 ) (0 446 512 ) (0 448 512 ) (0 448 48 ) +4 92 123 0 (0 446 192 ) (0 446 48 ) (224 446 48 ) (224 446 192 ) +4 92 117 0 (0 446 512 ) (0 446 192 ) (224 446 192 ) (224 446 512 ) +4 92 102 0 (0 448 48 ) (48 448 48 ) (48 446 48 ) (0 446 48 ) +4 92 98 0 (158 448 48 ) (160 448 48 ) (160 446 48 ) (158 446 48 ) +4 92 99 0 (48 448 48 ) (146 448 48 ) (146 446 48 ) (48 446 48 ) +4 92 95 0 (172 448 48 ) (212 448 48 ) (212 446 48 ) (172 446 48 ) +4 93 123 0 (220 446 40 ) (220 446 44 ) (216 446 44 ) (216 446 40 ) +4 94 123 0 (220 446 32 ) (220 446 36 ) (216 446 36 ) (216 446 32 ) +4 95 123 0 (172 446 28 ) (212 446 28 ) (212 446 48 ) (172 446 48 ) +4 95 108 0 (212 446 28 ) (172 446 28 ) (172 448 28 ) (212 448 28 ) +4 96 123 0 (168 446 40 ) (168 446 44 ) (164 446 44 ) (164 446 40 ) +4 97 123 0 (168 446 32 ) (168 446 36 ) (160 446 36 ) (160 446 32 ) +4 97 101 0 (160 446 32 ) (160 446 36 ) (160 448 36 ) (160 448 32 ) +4 98 123 0 (160 446 44 ) (160 446 48 ) (158 446 48 ) (158 446 44 ) +4 98 101 0 (158 448 44 ) (160 448 44 ) (160 446 44 ) (158 446 44 ) +4 99 123 0 (146 446 48 ) (48 446 48 ) (48 446 44 ) (146 446 44 ) +4 99 102 0 (48 446 44 ) (48 446 48 ) (48 448 48 ) (48 448 44 ) +4 99 100 0 (48 446 44 ) (48 448 44 ) (146 448 44 ) (146 446 44 ) +4 100 123 0 (48 446 28 ) (146 446 28 ) (154 446 44 ) (48 446 44 ) +4 100 108 0 (146 446 28 ) (48 446 28 ) (48 448 28 ) (146 448 28 ) +4 100 102 0 (48 446 40 ) (48 446 44 ) (48 448 44 ) (48 448 40 ) +4 101 123 0 (150 446 28 ) (160 446 28 ) (160 446 44 ) (158 446 44 ) +4 101 108 0 (160 446 28 ) (150 446 28 ) (150 448 28 ) (160 448 28 ) +4 102 202 0 (0 446 40 ) (0 446 48 ) (0 448 48 ) (0 448 40 ) +4 102 123 0 (0 446 48 ) (0 446 40 ) (48 446 40 ) (48 446 48 ) +4 102 105 0 (24 448 40 ) (32 448 40 ) (32 446 40 ) (24 446 40 ) +4 102 106 0 (0 448 40 ) (20 448 40 ) (20 446 40 ) (0 446 40 ) +4 102 104 0 (32 448 40 ) (36 448 40 ) (36 446 40 ) (32 446 40 ) +4 102 103 0 (40 448 40 ) (44 448 40 ) (44 446 40 ) (40 446 40 ) +4 103 123 0 (44 446 40 ) (40 446 40 ) (40 446 32 ) (44 446 32 ) +4 104 123 0 (32 446 28 ) (36 446 28 ) (36 446 40 ) (32 446 40 ) +4 104 110 0 (36 446 28 ) (32 446 28 ) (32 448 28 ) (36 448 28 ) +4 104 105 0 (32 446 32 ) (32 446 40 ) (32 448 40 ) (32 448 32 ) +4 105 123 0 (32 446 32 ) (32 446 40 ) (24 446 40 ) (24 446 32 ) +4 106 208 0 (0 446 28 ) (0 446 32 ) (0 448 32 ) (0 448 28 ) +4 106 203 0 (0 446 32 ) (0 446 40 ) (0 448 40 ) (0 448 32 ) +4 106 123 0 (0 446 40 ) (0 446 28 ) (20 446 28 ) (20 446 40 ) +4 106 112 0 (20 446 28 ) (0 446 28 ) (0 448 28 ) (20 448 28 ) +4 107 116 0 (832 446 28 ) (608 446 28 ) (608 446 0 ) (832 446 0 ) +4 108 123 0 (384 446 28 ) (48 446 28 ) (48 446 0 ) (384 446 0 ) +4 108 121 0 (448 446 28 ) (384 446 28 ) (384 446 0 ) (448 446 0 ) +4 108 116 0 (512 446 28 ) (448 446 28 ) (448 446 0 ) (512 446 0 ) +4 108 109 0 (48 448 0 ) (48 446 0 ) (48 446 20 ) (48 448 20 ) +4 109 123 0 (44 446 20 ) (44 446 0 ) (48 446 0 ) (48 446 20 ) +4 109 110 0 (44 448 0 ) (44 446 0 ) (44 446 20 ) (44 448 20 ) +4 110 123 0 (44 446 28 ) (32 446 28 ) (32 446 0 ) (44 446 0 ) +4 110 113 0 (32 446 0 ) (32 446 20 ) (32 448 20 ) (32 448 0 ) +4 111 123 0 (28 446 24 ) (28 446 28 ) (24 446 28 ) (24 446 24 ) +4 112 222 0 (0 446 20 ) (0 446 24 ) (0 448 24 ) (0 448 20 ) +4 112 208 0 (0 446 24 ) (0 446 28 ) (0 448 28 ) (0 448 24 ) +4 112 123 0 (0 446 28 ) (0 446 20 ) (20 446 20 ) (20 446 28 ) +4 112 113 0 (0 448 20 ) (20 448 20 ) (20 446 20 ) (0 446 20 ) +4 113 256 0 (0 446 0 ) (0 446 4 ) (0 448 4 ) (0 448 0 ) +4 113 243 0 (0 446 4 ) (0 446 8 ) (0 448 8 ) (0 448 4 ) +4 113 242 0 (0 446 8 ) (0 446 12 ) (0 448 12 ) (0 448 8 ) +4 113 233 0 (0 446 12 ) (0 446 20 ) (0 448 20 ) (0 448 12 ) +4 113 123 0 (0 446 20 ) (0 446 0 ) (32 446 0 ) (32 446 20 ) +4 114 127 0 (1024 0 160 ) (1024 0 224 ) (896 0 224 ) (896 0 160 ) +4 114 129 0 (896 0 432 ) (448 0 432 ) (448 0 160 ) (896 0 160 ) +4 114 125 0 (896 0 512 ) (448 0 512 ) (448 0 432 ) (896 0 432 ) +4 114 121 0 (448 446 192 ) (448 446 160 ) (448 160 160 ) (448 160 192 ) +4 114 119 0 (448 0 320 ) (448 0 512 ) (448 32 512 ) (448 32 320 ) +4 114 118 0 (448 32 320 ) (448 32 512 ) (448 160 512 ) (448 160 320 ) +4 114 117 0 (448 446 512 ) (448 446 192 ) (448 160 192 ) (448 160 512 ) +4 114 115 0 (1024 0 160 ) (832 0 160 ) (832 256 160 ) (1024 256 160 ) +4 114 116 0 (832 0 160 ) (448 0 160 ) (448 446 160 ) (832 446 160 ) +4 115 128 0 (1024 0 0 ) (1024 0 160 ) (896 0 160 ) (896 0 0 ) +4 115 129 0 (896 0 160 ) (832 0 160 ) (832 0 0 ) (896 0 0 ) +4 115 116 0 (832 256 0 ) (832 0 0 ) (832 0 160 ) (832 256 160 ) +4 116 129 0 (832 0 160 ) (448 0 160 ) (448 0 0 ) (832 0 0 ) +4 116 122 0 (448 32 0 ) (448 0 0 ) (448 0 160 ) (448 32 160 ) +4 116 121 0 (448 446 160 ) (448 446 0 ) (448 160 0 ) (448 160 160 ) +4 117 257 0 (0 160 512 ) (0 446 512 ) (0 446 192 ) (0 160 192 ) +4 117 123 0 (0 446 192 ) (384 446 192 ) (384 160 192 ) (0 160 192 ) +4 117 121 0 (384 446 192 ) (448 446 192 ) (448 160 192 ) (384 160 192 ) +5 117 118 0 (0 160 192 ) (320 160 192 ) (448 160 320 ) (448 160 512 ) (0 160 512 ) +4 118 257 0 (0 32 512 ) (0 160 512 ) (0 160 192 ) (0 32 192 ) +4 118 124 0 (320 32 192 ) (32 32 192 ) (32 128 192 ) (320 128 192 ) +4 118 123 0 (0 128 192 ) (0 160 192 ) (320 160 192 ) (320 128 192 ) +4 118 119 0 (448 32 320 ) (448 32 512 ) (384 32 512 ) (384 32 320 ) +5 118 120 0 (0 32 192 ) (320 32 192 ) (384 32 256 ) (384 32 512 ) (0 32 512 ) +4 119 131 0 (448 0 320 ) (448 0 432 ) (384 0 432 ) (384 0 320 ) +4 119 125 0 (448 0 432 ) (448 0 512 ) (384 0 512 ) (384 0 432 ) +4 119 120 0 (384 32 512 ) (384 32 320 ) (384 0 320 ) (384 0 512 ) +4 120 257 0 (0 0 192 ) (0 0 512 ) (0 32 512 ) (0 32 192 ) +4 120 132 0 (0 0 320 ) (0 0 192 ) (384 0 192 ) (384 0 320 ) +4 120 131 0 (0 0 432 ) (0 0 320 ) (384 0 320 ) (384 0 432 ) +4 120 125 0 (0 0 512 ) (0 0 432 ) (384 0 432 ) (384 0 512 ) +4 120 124 0 (384 0 192 ) (32 0 192 ) (32 32 192 ) (384 32 192 ) +4 121 123 0 (384 446 0 ) (384 160 0 ) (384 160 192 ) (384 446 192 ) +4 122 134 0 (384 0 0 ) (448 0 0 ) (448 0 160 ) (384 0 160 ) +4 122 124 0 (384 32 0 ) (384 0 0 ) (384 0 160 ) (384 32 160 ) +4 123 258 0 (0 128 192 ) (0 446 192 ) (0 446 0 ) (0 128 0 ) +4 123 124 0 (32 128 0 ) (384 128 0 ) (384 128 192 ) (32 128 192 ) +4 124 135 0 (32 0 0 ) (384 0 0 ) (384 0 192 ) (32 0 192 ) +4 125 267 0 (0 0 440 ) (0 0 432 ) (0 -128 432 ) (0 -128 440 ) +4 125 266 0 (0 -128 512 ) (0 0 512 ) (0 0 440 ) (0 -128 440 ) +4 125 133 0 (0 -128 432 ) (0 -96 432 ) (448 -96 432 ) (448 -128 432 ) +4 125 131 0 (0 -96 432 ) (0 0 432 ) (448 0 432 ) (448 -96 432 ) +4 125 129 0 (448 0 432 ) (896 0 432 ) (896 -128 432 ) (448 -128 432 ) +4 125 126 0 (0 -128 432 ) (896 -128 432 ) (896 -128 512 ) (0 -128 512 ) +4 126 268 0 (0 -960 432 ) (0 -960 440 ) (0 -168 440 ) (0 -168 432 ) +4 126 267 0 (0 -168 440 ) (0 -128 440 ) (0 -128 432 ) (0 -168 432 ) +4 126 266 0 (0 -960 440 ) (0 -960 512 ) (0 -128 512 ) (0 -128 440 ) +4 126 157 0 (368 -272 432 ) (372 -272 432 ) (372 -364 432 ) (368 -364 432 ) +4 126 158 0 (0 -364 432 ) (0 -272 432 ) (368 -272 432 ) (368 -364 432 ) +4 126 154 0 (0 -272 432 ) (0 -268 432 ) (372 -268 432 ) (372 -272 432 ) +4 126 152 0 (380 -260 432 ) (384 -260 432 ) (384 -356 432 ) (380 -356 432 ) +4 126 151 0 (1024 -352 432 ) (1024 -356 432 ) (384 -356 432 ) (384 -352 432 ) +4 126 149 0 (384 -260 432 ) (1024 -260 432 ) (1024 -352 432 ) (384 -352 432 ) +4 126 148 0 (0 -260 432 ) (0 -256 432 ) (1024 -256 432 ) (1024 -260 432 ) +4 126 145 0 (0 -368 432 ) (0 -364 432 ) (1024 -364 432 ) (1024 -368 432 ) +4 126 159 0 (1024 -960 432 ) (0 -960 432 ) (0 -368 432 ) (1024 -368 432 ) +4 126 144 0 (0 -256 432 ) (0 -224 432 ) (1024 -224 432 ) (1024 -256 432 ) +4 126 141 0 (0 -180 432 ) (0 -176 432 ) (1024 -176 432 ) (1024 -180 432 ) +4 126 139 0 (0 -192 432 ) (0 -188 432 ) (1024 -188 432 ) (1024 -192 432 ) +4 126 138 0 (0 -176 432 ) (0 -164 432 ) (1024 -164 432 ) (1024 -176 432 ) +4 126 143 0 (0 -224 432 ) (0 -192 432 ) (1024 -192 432 ) (1024 -224 432 ) +4 126 133 0 (0 -164 432 ) (0 -128 432 ) (448 -128 432 ) (448 -164 432 ) +4 126 130 0 (448 -128 432 ) (1024 -128 432 ) (1024 -164 432 ) (448 -164 432 ) +4 127 128 0 (896 -64 160 ) (896 0 160 ) (1024 0 160 ) (1024 -64 160 ) +4 127 130 0 (1024 -128 160 ) (1024 -128 224 ) (896 -128 224 ) (896 -128 160 ) +4 127 129 0 (896 -128 160 ) (896 -128 224 ) (896 0 224 ) (896 0 160 ) +4 128 129 0 (896 0 0 ) (896 -64 0 ) (896 -64 160 ) (896 0 160 ) +4 129 134 0 (448 0 0 ) (448 -96 0 ) (448 -96 160 ) (448 0 160 ) +4 129 133 0 (448 -128 320 ) (448 -128 432 ) (448 -96 432 ) (448 -96 320 ) +4 129 131 0 (448 -96 432 ) (448 0 432 ) (448 0 320 ) (448 -96 320 ) +4 129 130 0 (448 -128 432 ) (448 -128 0 ) (896 -128 0 ) (896 -128 432 ) +4 130 144 0 (1024 -224 0 ) (1024 -224 372 ) (448 -224 372 ) (448 -224 0 ) +4 130 138 0 (1024 -176 420 ) (1024 -164 432 ) (448 -164 432 ) (448 -176 420 ) +4 130 142 0 (1024 -192 404 ) (1024 -180 416 ) (448 -180 416 ) (448 -192 404 ) +4 130 143 0 (448 -224 372 ) (1024 -224 372 ) (1024 -192 404 ) (448 -192 404 ) +5 130 133 0 (448 -224 320 ) (448 -224 372 ) (448 -164 432 ) (448 -128 432 ) (448 -128 320 ) +4 131 285 0 (0 0 408 ) (0 0 320 ) (0 -96 320 ) (0 -96 408 ) +4 131 267 0 (0 -96 432 ) (0 0 432 ) (0 0 408 ) (0 -96 408 ) +4 131 133 0 (448 -96 320 ) (448 -96 432 ) (0 -96 432 ) (0 -96 320 ) +4 131 132 0 (384 -96 320 ) (0 -96 320 ) (0 0 320 ) (384 0 320 ) +4 132 287 0 (0 -64 192 ) (0 -96 192 ) (0 -96 256 ) (0 -64 256 ) +4 132 286 0 (0 0 256 ) (0 0 192 ) (0 -64 192 ) (0 -64 256 ) +4 132 285 0 (0 0 320 ) (0 0 256 ) (0 -96 256 ) (0 -96 320 ) +4 132 136 0 (384 -64 192 ) (384 -96 192 ) (64 -96 192 ) (64 -64 192 ) +4 132 135 0 (0 0 192 ) (384 0 192 ) (384 -64 192 ) (0 -64 192 ) +5 132 133 0 (0 -96 192 ) (320 -96 192 ) (384 -96 256 ) (384 -96 320 ) (0 -96 320 ) +4 133 294 0 (0 -224 192 ) (0 -224 256 ) (0 -192 256 ) (0 -192 192 ) +4 133 287 0 (0 -192 256 ) (0 -96 256 ) (0 -96 192 ) (0 -192 192 ) +5 133 285 0 (0 -224 256 ) (0 -224 372 ) (0 -188 408 ) (0 -96 408 ) (0 -96 256 ) +3 133 271 0 (0 -180 416 ) (0 -176 420 ) (0 -176 416 ) +4 133 269 0 (0 -176 420 ) (0 -168 428 ) (0 -168 416 ) (0 -176 416 ) +4 133 280 0 (0 -188 408 ) (0 -180 416 ) (0 -168 416 ) (0 -168 408 ) +5 133 267 0 (0 -168 428 ) (0 -164 432 ) (0 -96 432 ) (0 -96 408 ) (0 -168 408 ) +5 133 144 0 (448 -224 372 ) (0 -224 372 ) (0 -224 192 ) (320 -224 192 ) (448 -224 320 ) +4 133 138 0 (448 -176 420 ) (448 -164 432 ) (0 -164 432 ) (0 -176 420 ) +4 133 142 0 (448 -192 404 ) (448 -180 416 ) (0 -180 416 ) (0 -192 404 ) +4 133 143 0 (0 -224 372 ) (448 -224 372 ) (448 -192 404 ) (0 -192 404 ) +4 133 137 0 (64 -224 192 ) (0 -224 192 ) (0 -192 192 ) (64 -192 192 ) +4 133 136 0 (320 -224 192 ) (64 -224 192 ) (64 -96 192 ) (320 -96 192 ) +4 134 136 0 (384 -64 0 ) (384 -96 0 ) (384 -96 160 ) (384 -64 160 ) +4 134 135 0 (384 0 0 ) (384 -64 0 ) (384 -64 160 ) (384 0 160 ) +4 135 286 0 (0 -64 192 ) (0 0 192 ) (0 0 0 ) (0 -64 0 ) +4 135 136 0 (64 -64 0 ) (384 -64 0 ) (384 -64 192 ) (64 -64 192 ) +4 136 144 0 (64 -224 0 ) (384 -224 0 ) (384 -224 192 ) (64 -224 192 ) +4 136 137 0 (64 -192 0 ) (64 -224 0 ) (64 -224 192 ) (64 -192 192 ) +4 137 294 0 (0 -224 0 ) (0 -224 192 ) (0 -192 192 ) (0 -192 0 ) +4 137 144 0 (0 -224 192 ) (0 -224 0 ) (64 -224 0 ) (64 -224 192 ) +4 138 269 0 (0 -176 432 ) (0 -168 432 ) (0 -168 428 ) (0 -176 420 ) +3 138 267 0 (0 -168 432 ) (0 -164 432 ) (0 -168 428 ) +4 138 141 0 (1024 -176 428 ) (1024 -176 432 ) (0 -176 432 ) (0 -176 428 ) +3 139 273 0 (0 -192 432 ) (0 -188 432 ) (0 -192 428 ) +4 139 143 0 (1024 -192 428 ) (1024 -192 432 ) (0 -192 432 ) (0 -192 428 ) +3 140 270 0 (0 -188 416 ) (0 -192 416 ) (0 -192 420 ) +4 140 142 0 (1024 -192 416 ) (0 -192 416 ) (0 -188 416 ) (1024 -188 416 ) +4 140 143 0 (1024 -192 416 ) (1024 -192 420 ) (0 -192 420 ) (0 -192 416 ) +3 141 272 0 (0 -180 432 ) (0 -176 432 ) (0 -176 428 ) +3 142 285 0 (0 -188 408 ) (0 -192 404 ) (0 -192 408 ) +4 142 280 0 (0 -180 416 ) (0 -188 408 ) (0 -192 408 ) (0 -192 416 ) +4 142 143 0 (0 -192 404 ) (1024 -192 404 ) (1024 -192 416 ) (0 -192 416 ) +4 143 285 0 (0 -224 372 ) (0 -224 408 ) (0 -192 408 ) (0 -192 404 ) +4 143 274 0 (0 -224 416 ) (0 -224 432 ) (0 -192 432 ) (0 -192 416 ) +4 143 280 0 (0 -224 408 ) (0 -224 416 ) (0 -192 416 ) (0 -192 408 ) +4 143 144 0 (1024 -224 372 ) (1024 -224 432 ) (0 -224 432 ) (0 -224 372 ) +4 144 294 0 (0 -256 0 ) (0 -256 256 ) (0 -224 256 ) (0 -224 0 ) +4 144 285 0 (0 -256 256 ) (0 -256 408 ) (0 -224 408 ) (0 -224 256 ) +4 144 274 0 (0 -256 416 ) (0 -256 432 ) (0 -224 432 ) (0 -224 416 ) +4 144 280 0 (0 -256 408 ) (0 -256 416 ) (0 -224 416 ) (0 -224 408 ) +4 144 185 0 (0 -256 16 ) (0 -256 0 ) (128 -256 0 ) (128 -256 16 ) +4 144 184 0 (0 -256 192 ) (0 -256 16 ) (128 -256 16 ) (128 -256 192 ) +4 144 183 0 (192 -256 256 ) (0 -256 256 ) (0 -256 192 ) (192 -256 192 ) +4 144 175 0 (192 -256 192 ) (192 -256 0 ) (256 -256 0 ) (256 -256 192 ) +4 144 174 0 (256 -256 256 ) (192 -256 256 ) (192 -256 192 ) (256 -256 192 ) +4 144 172 0 (768 -256 160 ) (672 -256 160 ) (672 -256 0 ) (768 -256 0 ) +4 144 170 0 (672 -256 160 ) (608 -256 160 ) (608 -256 0 ) (672 -256 0 ) +4 144 169 0 (896 -256 160 ) (832 -256 160 ) (832 -256 0 ) (896 -256 0 ) +4 144 168 0 (608 -256 160 ) (512 -256 160 ) (512 -256 0 ) (608 -256 0 ) +4 144 167 0 (1024 -256 0 ) (1024 -256 160 ) (896 -256 160 ) (896 -256 0 ) +4 144 173 0 (512 -256 160 ) (256 -256 160 ) (256 -256 0 ) (512 -256 0 ) +4 144 166 0 (1024 -256 160 ) (1024 -256 256 ) (256 -256 256 ) (256 -256 160 ) +4 144 162 0 (152 -256 368 ) (56 -256 368 ) (56 -256 328 ) (152 -256 328 ) +4 144 161 0 (1024 -256 328 ) (1024 -256 368 ) (152 -256 368 ) (152 -256 328 ) +4 144 164 0 (1024 -256 256 ) (1024 -256 328 ) (56 -256 328 ) (56 -256 256 ) +4 144 165 0 (56 -256 368 ) (0 -256 368 ) (0 -256 256 ) (56 -256 256 ) +4 144 160 0 (1024 -256 368 ) (1024 -256 416 ) (0 -256 416 ) (0 -256 368 ) +4 144 149 0 (1024 -256 419.994049 ) (1024 -256 428 ) (384 -256 428 ) (384 -256 419.994049 ) +4 144 148 0 (1024 -256 428 ) (1024 -256 432 ) (0 -256 432 ) (0 -256 428 ) +4 144 146 0 (1024 -256 416 ) (1024 -256 419.994049 ) (0 -256 419.994049 ) (0 -256 416 ) +3 145 279 0 (0 -368 432 ) (0 -364 432 ) (0 -368 428 ) +3 145 157 0 (368 -368 428 ) (368 -364 432 ) (372 -364 432 ) +4 145 158 0 (368 -368 428 ) (0 -368 428 ) (0 -364 432 ) (368 -364 432 ) +4 145 159 0 (1024 -368 428 ) (1024 -368 432 ) (0 -368 432 ) (0 -368 428 ) +3 146 277 0 (0 -256 419.994049 ) (0 -256 416 ) (0 -259.994049 416 ) +4 146 160 0 (0 -259.994049 416 ) (0 -256 416 ) (1024 -256 416 ) (1024 -259.994049 416 ) +4 146 153 0 (380 -259.994476 416 ) (384 -259.994476 416 ) (384 -256 419.994324 ) (383.994324 -256 419.994324 ) +4 146 149 0 (384 -259.994476 416 ) (1024 -259.994446 416 ) (1024 -256 419.994293 ) (384 -256 419.994324 ) +3 147 279 0 (0 -364 416 ) (0 -368 416 ) (0 -368 420 ) +4 147 160 0 (0 -368 416 ) (0 -364 416 ) (1024 -364 416 ) (1024 -368 416 ) +3 147 156 0 (372 -364 416 ) (368 -364 416 ) (368 -368 420 ) +4 147 158 0 (368 -364 416 ) (0 -364 416 ) (0 -368 420 ) (368 -368 420 ) +4 147 159 0 (0 -368 416 ) (1024 -368 416 ) (1024 -368 420 ) (0 -368 420 ) +3 148 275 0 (0 -260 432 ) (0 -256 432 ) (0 -256 428 ) +3 148 152 0 (384 -256 428 ) (384 -260 432 ) (380 -260 432 ) +4 148 149 0 (384 -256 428 ) (1024 -256 428 ) (1024 -260 432 ) (384 -260 432 ) +4 149 160 0 (384 -259.994049 416 ) (1024 -259.994049 416 ) (1024 -352 416 ) (384 -352 416 ) +5 149 153 0 (384 -256 420 ) (384 -256 419.993683 ) (384 -259.993835 416 ) (384 -352 416 ) (384 -352 420 ) +4 149 152 0 (384 -260 432 ) (384 -256 428 ) (384 -352 428 ) (384 -352 432 ) +4 149 151 0 (384 -352 432 ) (384 -352 428 ) (1024 -352 428 ) (1024 -352 432 ) +4 149 150 0 (384 -352 420 ) (384 -352 416 ) (1024 -352 416 ) (1024 -352 420 ) +4 150 160 0 (1024 -352 416 ) (1024 -356 416 ) (384 -356 416 ) (384 -352 416 ) +3 150 153 0 (384 -352 416 ) (384 -356 416 ) (384 -352 420 ) +3 151 152 0 (384 -356 432 ) (384 -352 432 ) (384 -352 428 ) +4 153 160 0 (380 -259.994049 416 ) (384 -259.994049 416 ) (384 -356 416 ) (380 -356 416 ) +3 154 278 0 (0 -272 432 ) (0 -268 432 ) (0 -272 428 ) +3 154 157 0 (372 -272 432 ) (368 -272 432 ) (368 -272 428 ) +4 154 158 0 (368 -272 432 ) (0 -272 432 ) (0 -272 428 ) (368 -272 428 ) +3 155 276 0 (0 -268 416 ) (0 -272 416 ) (0 -272 420 ) +4 155 160 0 (0 -272 416 ) (0 -268 416 ) (372 -268 416 ) (372 -272 416 ) +3 155 156 0 (368 -272 416 ) (372 -272 416 ) (368 -272 420 ) +4 155 158 0 (0 -272 416 ) (368 -272 416 ) (368 -272 420 ) (0 -272 420 ) +4 156 160 0 (368 -272 416 ) (372 -272 416 ) (372 -364 416 ) (368 -364 416 ) +4 156 158 0 (368 -272 420 ) (368 -272 416 ) (368 -364 416 ) (368 -368 420 ) +4 157 158 0 (368 -272 432 ) (368 -272 428 ) (368 -368 428 ) (368 -364 432 ) +6 158 279 0 (0 -364 432 ) (0 -272 432 ) (0 -272 416 ) (0 -364 416 ) (0 -368 420 ) (0 -368 428 ) +4 158 160 0 (0 -364 416 ) (0 -272 416 ) (368 -272 416 ) (368 -364 416 ) +4 158 159 0 (368 -368 428 ) (0 -368 428 ) (0 -368 420 ) (368 -368 420 ) +4 159 279 0 (0 -960 416 ) (0 -960 432 ) (0 -368 432 ) (0 -368 416 ) +4 159 160 0 (1024 -960 416 ) (0 -960 416 ) (0 -368 416 ) (1024 -368 416 ) +4 160 285 0 (0 -960 368 ) (0 -960 408 ) (0 -256 408 ) (0 -256 368 ) +4 160 280 0 (0 -960 408 ) (0 -960 416 ) (0 -256 416 ) (0 -256 408 ) +4 160 163 0 (152 -960 368 ) (56 -960 368 ) (56 -632 368 ) (152 -632 368 ) +4 160 162 0 (56 -576 368 ) (56 -256 368 ) (152 -256 368 ) (152 -576 368 ) +4 160 161 0 (1024 -960 368 ) (152 -960 368 ) (152 -256 368 ) (1024 -256 368 ) +4 160 165 0 (56 -960 368 ) (0 -960 368 ) (0 -256 368 ) (56 -256 368 ) +4 161 163 0 (152 -632 328 ) (152 -960 328 ) (152 -960 368 ) (152 -632 368 ) +4 161 162 0 (152 -256 328 ) (152 -576 328 ) (152 -576 368 ) (152 -256 368 ) +4 161 164 0 (1024 -960 328 ) (152 -960 328 ) (152 -256 328 ) (1024 -256 328 ) +4 162 165 0 (56 -576 368 ) (56 -256 368 ) (56 -256 328 ) (56 -576 328 ) +4 162 164 0 (56 -576 328 ) (56 -256 328 ) (152 -256 328 ) (152 -576 328 ) +4 163 164 0 (152 -960 328 ) (56 -960 328 ) (56 -632 328 ) (152 -632 328 ) +4 163 165 0 (56 -960 328 ) (56 -960 368 ) (56 -632 368 ) (56 -632 328 ) +4 164 193 0 (192 -960 256 ) (160 -960 256 ) (160 -816 256 ) (192 -816 256 ) +4 164 187 0 (56 -816 256 ) (56 -384 256 ) (192 -384 256 ) (192 -816 256 ) +4 164 183 0 (56 -384 256 ) (56 -256 256 ) (192 -256 256 ) (192 -384 256 ) +4 164 181 0 (464 -960 256 ) (208 -960 256 ) (208 -640 256 ) (464 -640 256 ) +4 164 182 0 (208 -960 256 ) (192 -960 256 ) (192 -640 256 ) (208 -640 256 ) +4 164 180 0 (528 -960 256 ) (464 -960 256 ) (464 -640 256 ) (528 -640 256 ) +4 164 179 0 (784 -960 256 ) (528 -960 256 ) (528 -640 256 ) (784 -640 256 ) +4 164 178 0 (848 -960 256 ) (784 -960 256 ) (784 -640 256 ) (848 -640 256 ) +4 164 177 0 (1024 -960 256 ) (848 -960 256 ) (848 -640 256 ) (1024 -640 256 ) +4 164 174 0 (192 -640 256 ) (192 -256 256 ) (256 -256 256 ) (256 -640 256 ) +4 164 166 0 (256 -256 256 ) (1024 -256 256 ) (1024 -640 256 ) (256 -640 256 ) +4 164 165 0 (56 -256 256 ) (56 -960 256 ) (56 -960 328 ) (56 -256 328 ) +4 165 285 0 (0 -960 256 ) (0 -960 368 ) (0 -256 368 ) (0 -256 256 ) +5 165 187 0 (0 -808 256 ) (0 -384 256 ) (56 -384 256 ) (56 -816 256 ) (16 -816 256 ) +4 165 183 0 (0 -384 256 ) (0 -256 256 ) (56 -256 256 ) (56 -384 256 ) +4 166 181 0 (464 -640 256 ) (256 -640 256 ) (256 -640 160 ) (464 -640 160 ) +4 166 180 0 (528 -640 256 ) (464 -640 256 ) (464 -640 160 ) (528 -640 160 ) +4 166 179 0 (784 -640 256 ) (528 -640 256 ) (528 -640 160 ) (784 -640 160 ) +4 166 178 0 (848 -640 256 ) (784 -640 256 ) (784 -640 160 ) (848 -640 160 ) +4 166 177 0 (1024 -640 160 ) (1024 -640 256 ) (848 -640 256 ) (848 -640 160 ) +4 166 175 0 (256 -448 192 ) (256 -256 192 ) (256 -256 160 ) (256 -448 160 ) +4 166 176 0 (256 -640 160 ) (256 -640 192 ) (256 -576 192 ) (256 -576 160 ) +4 166 174 0 (256 -640 192 ) (256 -640 256 ) (256 -256 256 ) (256 -256 192 ) +3 166 172 0 (640 -288 160 ) (672 -256 160 ) (768 -256 160 ) +3 166 171 0 (896 -640 160 ) (704 -640 160 ) (896 -448 160 ) +3 166 170 0 (544 -384 160 ) (608 -256 160 ) (672 -256 160 ) +3 166 169 0 (832 -256 160 ) (896 -256 160 ) (896 -320 160 ) +3 166 168 0 (512 -448 160 ) (512 -256 160 ) (608 -256 160 ) +4 166 167 0 (1024 -640 160 ) (896 -640 160 ) (896 -256 160 ) (1024 -256 160 ) +4 166 173 0 (512 -640 160 ) (256 -640 160 ) (256 -256 160 ) (512 -256 160 ) +4 167 177 0 (896 -640 0 ) (1024 -640 0 ) (1024 -640 160 ) (896 -640 160 ) +4 167 171 0 (896 -448 0 ) (896 -640 0 ) (896 -640 160 ) (896 -448 160 ) +4 167 169 0 (896 -256 0 ) (896 -320 0 ) (896 -320 160 ) (896 -256 160 ) +4 168 170 0 (544 -384 0 ) (608 -256 0 ) (608 -256 160 ) (544 -384 160 ) +4 168 173 0 (512 -256 0 ) (512 -448 0 ) (512 -448 160 ) (512 -256 160 ) +4 170 172 0 (640 -288 0 ) (672 -256 0 ) (672 -256 160 ) (640 -288 160 ) +4 171 179 0 (704 -640 0 ) (784 -640 0 ) (784 -640 160 ) (704 -640 160 ) +4 171 178 0 (784 -640 0 ) (848 -640 0 ) (848 -640 160 ) (784 -640 160 ) +4 171 177 0 (848 -640 0 ) (896 -640 0 ) (896 -640 160 ) (848 -640 160 ) +4 173 181 0 (256 -640 0 ) (464 -640 0 ) (464 -640 160 ) (256 -640 160 ) +4 173 180 0 (464 -640 0 ) (512 -640 0 ) (512 -640 160 ) (464 -640 160 ) +4 173 175 0 (256 -256 0 ) (256 -448 0 ) (256 -448 160 ) (256 -256 160 ) +4 173 176 0 (256 -576 0 ) (256 -640 0 ) (256 -640 160 ) (256 -576 160 ) +4 174 187 0 (192 -640 256 ) (192 -384 256 ) (192 -384 192 ) (192 -640 192 ) +4 174 183 0 (192 -384 256 ) (192 -256 256 ) (192 -256 192 ) (192 -384 192 ) +4 174 181 0 (208 -640 192 ) (256 -640 192 ) (256 -640 256 ) (208 -640 256 ) +4 174 182 0 (192 -640 256 ) (192 -640 192 ) (208 -640 192 ) (208 -640 256 ) +4 174 175 0 (256 -256 192 ) (256 -448 192 ) (192 -448 192 ) (192 -256 192 ) +4 174 176 0 (256 -576 192 ) (256 -640 192 ) (192 -640 192 ) (192 -576 192 ) +4 175 189 0 (192 -384 0 ) (192 -448 0 ) (192 -448 16 ) (192 -384 16 ) +4 175 188 0 (192 -448 16 ) (192 -448 128 ) (192 -384 128 ) (192 -384 16 ) +4 175 187 0 (192 -448 128 ) (192 -448 192 ) (192 -384 192 ) (192 -384 128 ) +4 176 190 0 (192 -576 0 ) (192 -640 0 ) (192 -640 128 ) (192 -576 128 ) +4 176 187 0 (192 -640 128 ) (192 -640 192 ) (192 -576 192 ) (192 -576 128 ) +4 176 181 0 (208 -640 0 ) (256 -640 0 ) (256 -640 192 ) (208 -640 192 ) +4 176 182 0 (192 -640 192 ) (192 -640 0 ) (208 -640 0 ) (208 -640 192 ) +5 177 178 0 (848 -640 256 ) (848 -640 0 ) (848 -704 0 ) (848 -960 128 ) (848 -960 256 ) +5 178 179 0 (784 -640 256 ) (784 -640 0 ) (784 -832 0 ) (784 -960 128 ) (784 -960 256 ) +5 179 180 0 (528 -640 256 ) (528 -640 0 ) (528 -832 0 ) (528 -960 128 ) (528 -960 256 ) +4 180 181 0 (464 -640 256 ) (464 -640 0 ) (464 -832 0 ) (464 -960 256 ) +4 181 182 0 (208 -640 256 ) (208 -640 0 ) (208 -832 0 ) (208 -960 256 ) +4 182 193 0 (192 -960 0 ) (192 -960 256 ) (192 -816 256 ) (192 -816 0 ) +4 182 191 0 (192 -752 0 ) (192 -816 0 ) (192 -816 128 ) (192 -752 128 ) +4 182 190 0 (192 -640 128 ) (192 -640 0 ) (192 -752 0 ) (192 -752 128 ) +4 182 187 0 (192 -816 256 ) (192 -640 256 ) (192 -640 128 ) (192 -816 128 ) +4 183 295 0 (0 -384 256 ) (0 -256 256 ) (0 -256 192 ) (0 -384 192 ) +4 183 187 0 (192 -384 192 ) (192 -384 256 ) (0 -384 256 ) (0 -384 192 ) +4 183 184 0 (128 -384 192 ) (0 -384 192 ) (0 -256 192 ) (128 -256 192 ) +4 184 296 0 (0 -256 192 ) (0 -256 16 ) (0 -368 16 ) (0 -368 192 ) +4 184 298 0 (0 -368 16 ) (0 -384 16 ) (0 -384 192 ) (0 -368 192 ) +4 184 188 0 (128 -384 16 ) (128 -384 128 ) (0 -384 128 ) (0 -384 16 ) +4 184 187 0 (128 -384 128 ) (128 -384 192 ) (0 -384 192 ) (0 -384 128 ) +4 184 185 0 (0 -256 16 ) (128 -256 16 ) (128 -272 16 ) (0 -272 16 ) +4 184 186 0 (128 -368 16 ) (128 -384 16 ) (0 -384 16 ) (0 -368 16 ) +4 185 297 0 (0 -256 16 ) (0 -256 0 ) (0 -272 0 ) (0 -272 16 ) +4 186 298 0 (0 -368 0 ) (0 -384 0 ) (0 -384 16 ) (0 -368 16 ) +4 186 189 0 (0 -384 0 ) (128 -384 0 ) (128 -384 16 ) (0 -384 16 ) +4 187 310 0 (0 -808 256 ) (0 -768 256 ) (0 -768 128 ) (0 -808 128 ) +4 187 307 0 (0 -768 256 ) (0 -704 256 ) (0 -704 128 ) (0 -768 128 ) +4 187 302 0 (0 -384 192 ) (0 -384 128 ) (0 -704 128 ) (0 -704 192 ) +4 187 301 0 (0 -704 256 ) (0 -384 256 ) (0 -384 192 ) (0 -704 192 ) +4 187 193 0 (192 -816 128 ) (192 -816 256 ) (160 -816 256 ) (160 -816 128 ) +5 187 192 0 (0 -798 128 ) (0 -752 128 ) (96 -752 128 ) (96 -808 128 ) (20 -808 128 ) +4 187 191 0 (192 -816 128 ) (160 -816 128 ) (160 -752 128 ) (192 -752 128 ) +4 187 190 0 (0 -752 128 ) (0 -560 128 ) (192 -560 128 ) (192 -752 128 ) +4 187 188 0 (0 -560 128 ) (0 -384 128 ) (192 -384 128 ) (192 -560 128 ) +4 188 314 0 (0 -448 16 ) (0 -560 16 ) (0 -560 128 ) (0 -448 128 ) +4 188 313 0 (0 -384 128 ) (0 -384 16 ) (0 -448 16 ) (0 -448 128 ) +4 188 190 0 (192 -560 16 ) (192 -560 128 ) (0 -560 128 ) (0 -560 16 ) +4 188 189 0 (0 -464 16 ) (0 -384 16 ) (192 -384 16 ) (192 -464 16 ) +4 189 315 0 (0 -448 0 ) (0 -464 0 ) (0 -464 16 ) (0 -448 16 ) +4 189 313 0 (0 -384 16 ) (0 -384 0 ) (0 -448 0 ) (0 -448 16 ) +4 190 322 0 (0 -696 0 ) (0 -752 0 ) (0 -752 128 ) (0 -696 128 ) +4 190 319 0 (0 -576 0 ) (0 -696 0 ) (0 -696 128 ) (0 -576 128 ) +4 190 316 0 (0 -560 0 ) (0 -576 0 ) (0 -576 128 ) (0 -560 128 ) +4 190 192 0 (0 -752 0 ) (96 -752 0 ) (96 -752 128 ) (0 -752 128 ) +4 190 191 0 (160 -752 0 ) (192 -752 0 ) (192 -752 128 ) (160 -752 128 ) +4 191 193 0 (160 -816 0 ) (192 -816 0 ) (192 -816 128 ) (160 -816 128 ) +4 192 325 0 (0 -760 0 ) (0 -798 0 ) (0 -798 128 ) (0 -760 128 ) +4 192 322 0 (0 -752 0 ) (0 -760 0 ) (0 -760 128 ) (0 -752 128 ) +4 194 202 0 (-704 448 512 ) (-704 448 63 ) (0 448 63 ) (0 448 512 ) +4 194 198 0 (-288 448 63 ) (-512 448 63 ) (-512 640 63 ) (-288 640 63 ) +4 194 201 0 (-512 448 63 ) (-704 448 63 ) (-704 640 63 ) (-512 640 63 ) +4 194 195 0 (-64 448 63 ) (-288 448 63 ) (-288 640 63 ) (-64 640 63 ) +4 195 202 0 (-64 448 48 ) (-64 448 63 ) (-288 448 63 ) (-288 448 48 ) +4 195 198 0 (-288 448 48 ) (-288 448 63 ) (-288 640 63 ) (-288 640 48 ) +4 195 197 0 (-288 448 48 ) (-288 640 48 ) (-224 640 48 ) (-224 448 48 ) +4 195 196 0 (-160 640 48 ) (-64 640 48 ) (-64 448 48 ) (-160 448 48 ) +4 196 256 0 (-160 448 0 ) (-64 448 0 ) (-64 448 4 ) (-160 448 4 ) +4 196 243 0 (-64 448 4 ) (-64 448 8 ) (-160 448 8 ) (-160 448 4 ) +4 196 242 0 (-64 448 8 ) (-64 448 12 ) (-160 448 12 ) (-160 448 8 ) +4 196 233 0 (-64 448 12 ) (-64 448 20 ) (-160 448 20 ) (-160 448 12 ) +4 196 224 0 (-64 448 20 ) (-64 448 24 ) (-160 448 24 ) (-160 448 20 ) +4 196 212 0 (-64 448 24 ) (-64 448 32 ) (-160 448 32 ) (-160 448 24 ) +4 196 207 0 (-64 448 32 ) (-64 448 40 ) (-160 448 40 ) (-160 448 32 ) +4 196 202 0 (-64 448 40 ) (-64 448 48 ) (-160 448 48 ) (-160 448 40 ) +4 197 202 0 (-224 448 47 ) (-224 448 48 ) (-288 448 48 ) (-288 448 47 ) +4 197 198 0 (-288 448 47 ) (-288 448 48 ) (-288 640 48 ) (-288 640 47 ) +4 198 207 0 (-288 448 32 ) (-288 448 40 ) (-512 448 40 ) (-512 448 32 ) +4 198 202 0 (-288 448 40 ) (-288 448 63 ) (-512 448 63 ) (-512 448 40 ) +4 198 200 0 (-512 448 32 ) (-512 640 32 ) (-448 640 32 ) (-448 448 32 ) +4 198 199 0 (-384 640 32 ) (-288 640 32 ) (-288 448 32 ) (-384 448 32 ) +4 198 201 0 (-512 448 32 ) (-512 448 63 ) (-512 640 63 ) (-512 640 32 ) +4 199 256 0 (-384 448 0 ) (-288 448 0 ) (-288 448 4 ) (-384 448 4 ) +4 199 243 0 (-288 448 4 ) (-288 448 8 ) (-384 448 8 ) (-384 448 4 ) +4 199 242 0 (-288 448 8 ) (-288 448 12 ) (-384 448 12 ) (-384 448 8 ) +4 199 238 0 (-288 448 12 ) (-288 448 20 ) (-384 448 20 ) (-384 448 12 ) +4 199 228 0 (-288 448 20 ) (-288 448 24 ) (-384 448 24 ) (-384 448 20 ) +4 199 221 0 (-288 448 24 ) (-288 448 32 ) (-384 448 32 ) (-384 448 24 ) +4 200 221 0 (-448 448 31 ) (-448 448 32 ) (-512 448 32 ) (-512 448 31 ) +4 200 201 0 (-512 448 31 ) (-512 448 32 ) (-512 640 32 ) (-512 640 31 ) +4 201 256 0 (-704 448 4 ) (-704 448 0 ) (-512 448 0 ) (-512 448 4 ) +4 201 255 0 (-704 448 20 ) (-704 448 4 ) (-512 448 4 ) (-512 448 20 ) +4 201 232 0 (-704 448 24 ) (-704 448 20 ) (-512 448 20 ) (-512 448 24 ) +4 201 221 0 (-704 448 32 ) (-704 448 24 ) (-512 448 24 ) (-512 448 32 ) +4 201 207 0 (-704 448 40 ) (-704 448 32 ) (-512 448 32 ) (-512 448 40 ) +4 201 202 0 (-704 448 63 ) (-704 448 40 ) (-512 448 40 ) (-512 448 63 ) +4 202 259 0 (-480 446 192 ) (-704 446 192 ) (-704 446 40 ) (-480 446 40 ) +4 202 258 0 (0 446 40 ) (0 446 192 ) (-480 446 192 ) (-480 446 40 ) +4 202 257 0 (0 446 192 ) (0 446 512 ) (-704 446 512 ) (-704 446 192 ) +4 202 207 0 (-48 446 40 ) (-704 446 40 ) (-704 448 40 ) (-48 448 40 ) +4 202 206 0 (-32 446 40 ) (-44 446 40 ) (-44 448 40 ) (-32 448 40 ) +4 202 204 0 (-20 446 40 ) (-24 446 40 ) (-24 448 40 ) (-20 448 40 ) +4 202 203 0 (0 446 40 ) (-20 446 40 ) (-20 448 40 ) (0 448 40 ) +4 203 258 0 (0 446 32 ) (0 446 40 ) (-20 446 40 ) (-20 446 32 ) +4 203 208 0 (0 446 32 ) (-20 446 32 ) (-20 448 32 ) (0 448 32 ) +4 203 204 0 (-20 446 36 ) (-20 446 40 ) (-20 448 40 ) (-20 448 36 ) +3 204 258 0 (-20 446 40 ) (-24 446 40 ) (-20 446 36 ) +4 205 258 0 (-32 446 36 ) (-32 446 32 ) (-24 446 32 ) (-24 446 36 ) +4 205 210 0 (-28 446 32 ) (-32 446 32 ) (-32 448 32 ) (-28 448 32 ) +4 205 206 0 (-32 448 32 ) (-32 446 32 ) (-32 446 36 ) (-32 448 36 ) +4 206 258 0 (-32 446 40 ) (-44 446 40 ) (-44 446 32 ) (-32 446 32 ) +4 206 210 0 (-32 446 32 ) (-36 446 32 ) (-36 448 32 ) (-32 448 32 ) +4 207 259 0 (-480 446 40 ) (-704 446 40 ) (-704 446 32 ) (-480 446 32 ) +4 207 258 0 (-48 446 40 ) (-480 446 40 ) (-480 446 32 ) (-48 446 32 ) +4 207 221 0 (-268 446 32 ) (-704 446 32 ) (-704 448 32 ) (-268 448 32 ) +4 207 220 0 (-260 446 32 ) (-264 446 32 ) (-264 448 32 ) (-260 448 32 ) +4 207 217 0 (-252 446 32 ) (-256 446 32 ) (-256 448 32 ) (-252 448 32 ) +4 207 216 0 (-202 446 32 ) (-240 446 32 ) (-240 448 32 ) (-202 448 32 ) +4 207 215 0 (-194 446 32 ) (-198 446 32 ) (-198 448 32 ) (-194 448 32 ) +4 207 214 0 (-186 446 32 ) (-190 446 32 ) (-190 448 32 ) (-186 448 32 ) +4 207 212 0 (-48 446 32 ) (-174 446 32 ) (-174 448 32 ) (-48 448 32 ) +4 208 258 0 (0 446 24 ) (0 446 32 ) (-20 446 32 ) (-20 446 24 ) +4 208 222 0 (0 446 24 ) (-20 446 24 ) (-20 448 24 ) (0 448 24 ) +4 209 258 0 (-28 446 28 ) (-28 446 24 ) (-24 446 24 ) (-24 446 28 ) +4 209 210 0 (-28 448 24 ) (-28 446 24 ) (-28 446 28 ) (-28 448 28 ) +4 210 258 0 (-28 446 32 ) (-36 446 32 ) (-36 446 24 ) (-28 446 24 ) +4 210 223 0 (-32 446 24 ) (-36 446 24 ) (-36 448 24 ) (-32 448 24 ) +4 211 258 0 (-44 446 28 ) (-44 446 24 ) (-40 446 24 ) (-40 446 28 ) +4 212 258 0 (-48 446 32 ) (-174 446 32 ) (-174 446 24 ) (-48 446 24 ) +4 212 224 0 (-48 446 24 ) (-174 446 24 ) (-174 448 24 ) (-48 448 24 ) +4 213 258 0 (-182 446 28 ) (-182 446 24 ) (-178 446 24 ) (-178 446 28 ) +4 214 258 0 (-186 446 32 ) (-190 446 32 ) (-190 446 24 ) (-186 446 24 ) +4 214 225 0 (-186 446 24 ) (-190 446 24 ) (-190 448 24 ) (-186 448 24 ) +4 215 258 0 (-194 446 32 ) (-198 446 32 ) (-198 446 24 ) (-194 446 24 ) +4 216 258 0 (-202 446 32 ) (-240 446 32 ) (-240 446 24 ) (-202 446 24 ) +4 216 226 0 (-202 446 24 ) (-240 446 24 ) (-240 448 24 ) (-202 448 24 ) +4 216 219 0 (-240 448 24 ) (-240 446 24 ) (-240 446 28 ) (-240 448 28 ) +4 217 258 0 (-252 446 32 ) (-256 446 32 ) (-256 446 28 ) (-252 446 28 ) +4 217 218 0 (-256 446 28 ) (-256 448 28 ) (-252 448 28 ) (-252 446 28 ) +4 218 258 0 (-256 446 28 ) (-256 446 24 ) (-246 446 24 ) (-244 446 28 ) +4 218 227 0 (-246 446 24 ) (-256 446 24 ) (-256 448 24 ) (-246 448 24 ) +3 219 258 0 (-242 446 24 ) (-240 446 24 ) (-240 446 28 ) +4 219 226 0 (-240 446 24 ) (-242 446 24 ) (-242 448 24 ) (-240 448 24 ) +4 220 258 0 (-260 446 32 ) (-264 446 32 ) (-264 446 24 ) (-260 446 24 ) +4 221 259 0 (-480 446 32 ) (-704 446 32 ) (-704 446 24 ) (-480 446 24 ) +4 221 258 0 (-268 446 32 ) (-480 446 32 ) (-480 446 24 ) (-268 446 24 ) +4 221 231 0 (-476 446 24 ) (-484 446 24 ) (-484 448 24 ) (-476 448 24 ) +4 221 232 0 (-492 446 24 ) (-704 446 24 ) (-704 448 24 ) (-492 448 24 ) +4 221 230 0 (-428 446 24 ) (-472 446 24 ) (-472 448 24 ) (-428 448 24 ) +4 221 229 0 (-412 446 24 ) (-420 446 24 ) (-420 448 24 ) (-412 448 24 ) +4 221 228 0 (-268 446 24 ) (-404 446 24 ) (-404 448 24 ) (-268 448 24 ) +4 222 258 0 (0 446 20 ) (0 446 24 ) (-20 446 24 ) (-24 446 20 ) +4 222 233 0 (0 446 20 ) (-24 446 20 ) (-24 448 20 ) (0 448 20 ) +4 223 258 0 (-32 446 24 ) (-36 446 24 ) (-36 446 20 ) (-32 446 20 ) +4 223 233 0 (-32 446 20 ) (-36 446 20 ) (-36 448 20 ) (-32 448 20 ) +4 224 258 0 (-48 446 24 ) (-174 446 24 ) (-174 446 20 ) (-48 446 20 ) +4 224 233 0 (-48 446 20 ) (-174 446 20 ) (-174 448 20 ) (-48 448 20 ) +4 225 258 0 (-186 446 24 ) (-190 446 24 ) (-190 446 20 ) (-186 446 20 ) +4 225 235 0 (-186 446 20 ) (-190 446 20 ) (-190 448 20 ) (-186 448 20 ) +4 226 258 0 (-202 446 24 ) (-242 446 24 ) (-244 446 20 ) (-202 446 20 ) +4 226 237 0 (-202 446 20 ) (-244 446 20 ) (-244 448 20 ) (-202 448 20 ) +4 227 258 0 (-246 446 24 ) (-256 446 24 ) (-256 446 20 ) (-248 446 20 ) +4 227 236 0 (-248 446 20 ) (-256 446 20 ) (-256 448 20 ) (-248 448 20 ) +4 228 258 0 (-268 446 24 ) (-404 446 24 ) (-400 446 20 ) (-268 446 20 ) +4 228 238 0 (-268 446 20 ) (-400 446 20 ) (-400 448 20 ) (-268 448 20 ) +4 229 258 0 (-412 446 24 ) (-420 446 24 ) (-416 446 20 ) (-412 446 20 ) +4 229 240 0 (-412 446 20 ) (-416 446 20 ) (-416 448 20 ) (-412 448 20 ) +4 230 258 0 (-428 446 24 ) (-472 446 24 ) (-472 446 20 ) (-428 446 20 ) +4 230 249 0 (-428 446 20 ) (-472 446 20 ) (-472 448 20 ) (-428 448 20 ) +3 231 259 0 (-480 446 24 ) (-484 446 24 ) (-480 446 20 ) +4 231 258 0 (-476 446 24 ) (-480 446 24 ) (-480 446 20 ) (-476 446 20 ) +4 231 250 0 (-476 446 20 ) (-480 446 20 ) (-480 448 20 ) (-476 448 20 ) +4 232 259 0 (-492 446 24 ) (-704 446 24 ) (-704 446 20 ) (-492 446 20 ) +4 232 255 0 (-492 446 20 ) (-704 446 20 ) (-704 448 20 ) (-492 448 20 ) +4 233 258 0 (0 446 12 ) (0 446 20 ) (-174 446 20 ) (-174 446 12 ) +4 233 242 0 (0 446 12 ) (-174 446 12 ) (-174 448 12 ) (0 448 12 ) +4 234 258 0 (-178 446 20 ) (-182 446 20 ) (-182 446 16 ) (-178 446 16 ) +4 235 258 0 (-186 446 20 ) (-190 446 20 ) (-190 446 12 ) (-186 446 12 ) +4 235 242 0 (-186 446 12 ) (-190 446 12 ) (-190 448 12 ) (-186 448 12 ) +4 236 258 0 (-248 446 20 ) (-256 446 20 ) (-256 446 12 ) (-252 446 12 ) +4 236 242 0 (-252 446 12 ) (-256 446 12 ) (-256 448 12 ) (-252 448 12 ) +4 237 258 0 (-194 446 20 ) (-244 446 20 ) (-248 446 12 ) (-194 446 12 ) +4 237 242 0 (-194 446 12 ) (-248 446 12 ) (-248 448 12 ) (-194 448 12 ) +4 238 258 0 (-260 446 20 ) (-400 446 20 ) (-400 446 12 ) (-260 446 12 ) +4 238 242 0 (-260 446 12 ) (-400 446 12 ) (-400 448 12 ) (-260 448 12 ) +4 238 239 0 (-400 448 12 ) (-400 446 12 ) (-400 446 16 ) (-400 448 16 ) +3 239 258 0 (-404 446 12 ) (-400 446 12 ) (-400 446 16 ) +4 239 242 0 (-400 446 12 ) (-404 446 12 ) (-404 448 12 ) (-400 448 12 ) +5 240 258 0 (-404 446 20 ) (-416 446 20 ) (-416 446 12 ) (-408 446 12 ) (-404 446 16 ) +4 240 241 0 (-408 446 12 ) (-416 446 12 ) (-416 448 12 ) (-408 448 12 ) +4 241 258 0 (-408 446 12 ) (-416 446 12 ) (-416 446 8 ) (-412 446 8 ) +4 241 244 0 (-412 446 8 ) (-416 446 8 ) (-416 448 8 ) (-412 448 8 ) +4 242 258 0 (0 446 8 ) (0 446 12 ) (-404 446 12 ) (-408 446 8 ) +4 242 243 0 (0 446 8 ) (-400 446 8 ) (-400 448 8 ) (0 448 8 ) +4 243 258 0 (0 446 4 ) (0 446 8 ) (-400 446 8 ) (-400 446 4 ) +4 243 256 0 (0 446 4 ) (-400 446 4 ) (-400 448 4 ) (0 448 4 ) +4 244 258 0 (-412 446 8 ) (-416 446 8 ) (-416 446 4 ) (-412 446 4 ) +4 244 256 0 (-412 446 4 ) (-416 446 4 ) (-416 448 4 ) (-412 448 4 ) +4 244 245 0 (-416 448 4 ) (-416 446 4 ) (-416 446 8 ) (-416 448 8 ) +3 245 258 0 (-420 446 4 ) (-416 446 4 ) (-416 446 8 ) +4 245 256 0 (-416 446 4 ) (-420 446 4 ) (-420 448 4 ) (-416 448 4 ) +4 246 258 0 (-420 446 20 ) (-428 446 20 ) (-428 446 16 ) (-420 446 16 ) +4 246 249 0 (-428 446 16 ) (-428 446 20 ) (-428 448 20 ) (-428 448 16 ) +4 246 248 0 (-428 446 16 ) (-428 448 16 ) (-424 448 16 ) (-424 446 16 ) +4 247 258 0 (-424 446 8 ) (-420 446 8 ) (-420 446 12 ) (-424 446 12 ) +4 247 248 0 (-424 448 8 ) (-424 446 8 ) (-424 446 12 ) (-424 448 12 ) +4 248 258 0 (-428 446 16 ) (-428 446 8 ) (-424 446 8 ) (-424 446 16 ) +4 248 249 0 (-428 446 8 ) (-428 446 16 ) (-428 448 16 ) (-428 448 8 ) +4 249 258 0 (-428 446 20 ) (-472 446 20 ) (-472 446 4 ) (-428 446 4 ) +4 249 256 0 (-428 446 4 ) (-472 446 4 ) (-472 448 4 ) (-428 448 4 ) +4 250 258 0 (-476 446 20 ) (-480 446 20 ) (-480 446 4 ) (-476 446 4 ) +4 250 256 0 (-476 446 4 ) (-480 446 4 ) (-480 448 4 ) (-476 448 4 ) +4 250 251 0 (-480 448 4 ) (-480 446 4 ) (-480 446 8 ) (-480 448 8 ) +3 251 259 0 (-484 446 4 ) (-480 446 4 ) (-480 446 8 ) +4 251 256 0 (-480 446 4 ) (-484 446 4 ) (-484 448 4 ) (-480 448 4 ) +4 252 259 0 (-484 446 20 ) (-492 446 20 ) (-492 446 16 ) (-484 446 16 ) +4 252 253 0 (-492 446 16 ) (-492 448 16 ) (-488 448 16 ) (-488 446 16 ) +4 252 255 0 (-492 446 16 ) (-492 446 20 ) (-492 448 20 ) (-492 448 16 ) +4 253 259 0 (-492 446 16 ) (-492 446 12 ) (-488 446 12 ) (-488 446 16 ) +4 253 254 0 (-492 446 12 ) (-492 448 12 ) (-488 448 12 ) (-488 446 12 ) +4 253 255 0 (-492 446 12 ) (-492 446 16 ) (-492 448 16 ) (-492 448 12 ) +4 254 259 0 (-492 446 12 ) (-492 446 8 ) (-484 446 8 ) (-484 446 12 ) +4 254 255 0 (-492 446 8 ) (-492 446 12 ) (-492 448 12 ) (-492 448 8 ) +4 255 259 0 (-492 446 20 ) (-704 446 20 ) (-704 446 4 ) (-492 446 4 ) +4 255 256 0 (-492 446 4 ) (-704 446 4 ) (-704 448 4 ) (-492 448 4 ) +4 256 259 0 (-480 446 4 ) (-704 446 4 ) (-704 446 0 ) (-480 446 0 ) +4 256 258 0 (0 446 0 ) (0 446 4 ) (-480 446 4 ) (-480 446 0 ) +4 257 293 0 (-480 0 256 ) (-704 0 256 ) (-704 0 192 ) (-480 0 192 ) +4 257 286 0 (0 0 192 ) (0 0 256 ) (-480 0 256 ) (-480 0 192 ) +4 257 285 0 (0 0 256 ) (0 0 408 ) (-704 0 408 ) (-704 0 256 ) +4 257 267 0 (0 0 408 ) (0 0 440 ) (-704 0 440 ) (-704 0 408 ) +4 257 266 0 (0 0 440 ) (0 0 512 ) (-704 0 512 ) (-704 0 440 ) +4 257 265 0 (-480 0 192 ) (-704 0 192 ) (-704 128 192 ) (-480 128 192 ) +4 257 264 0 (-384 0 192 ) (-480 0 192 ) (-480 128 192 ) (-384 128 192 ) +4 257 263 0 (-320 0 192 ) (-384 0 192 ) (-384 128 192 ) (-320 128 192 ) +4 257 260 0 (-192 16 192 ) (-192 128 192 ) (-32 128 192 ) (-32 16 192 ) +4 257 262 0 (-32 0 192 ) (-192 0 192 ) (-192 16 192 ) (-32 16 192 ) +4 257 259 0 (-704 128 192 ) (-704 446 192 ) (-480 446 192 ) (-480 128 192 ) +4 257 258 0 (-480 446 192 ) (0 446 192 ) (0 128 192 ) (-480 128 192 ) +4 258 264 0 (-480 128 0 ) (-384 128 0 ) (-384 128 192 ) (-480 128 192 ) +4 258 263 0 (-320 128 64 ) (-320 128 192 ) (-384 128 192 ) (-384 128 64 ) +4 258 261 0 (-192 128 0 ) (-32 128 0 ) (-32 128 16 ) (-192 128 16 ) +4 258 260 0 (-32 128 16 ) (-32 128 192 ) (-192 128 192 ) (-192 128 16 ) +5 258 259 0 (-480 446 0 ) (-480 192 0 ) (-480 128 42.666672 ) (-480 128 192 ) (-480 446 192 ) +4 259 265 0 (-480 128 42.666672 ) (-480 128 192 ) (-704 128 192 ) (-704 128 42.666664 ) +4 260 261 0 (-192 112 16 ) (-192 128 16 ) (-32 128 16 ) (-32 112 16 ) +4 260 262 0 (-192 16 192 ) (-192 16 16 ) (-32 16 16 ) (-32 16 192 ) +4 262 286 0 (-32 0 192 ) (-192 0 192 ) (-192 0 0 ) (-32 0 0 ) +4 263 286 0 (-320 0 192 ) (-384 0 192 ) (-384 0 64 ) (-320 0 64 ) +4 263 264 0 (-384 128 192 ) (-384 128 64 ) (-384 0 64 ) (-384 0 192 ) +4 264 286 0 (-384 0 192 ) (-480 0 192 ) (-480 0 0 ) (-384 0 0 ) +4 264 265 0 (-480 128 192 ) (-480 128 42.666664 ) (-480 0 128 ) (-480 0 192 ) +4 265 293 0 (-480 0 192 ) (-704 0 192 ) (-704 0 128 ) (-480 0 128 ) +4 266 283 0 (-632 -584 440 ) (-576 -584 440 ) (-576 -616 440 ) (-632 -616 440 ) +4 266 282 0 (-704 -584 440 ) (-704 -280 440 ) (-576 -280 440 ) (-576 -584 440 ) +4 266 281 0 (-704 -248 440 ) (-704 -200 440 ) (-576 -200 440 ) (-576 -248 440 ) +4 266 284 0 (-704 -960 440 ) (-704 -616 440 ) (-576 -616 440 ) (-576 -960 440 ) +4 266 268 0 (-576 -168 440 ) (0 -168 440 ) (0 -960 440 ) (-576 -960 440 ) +4 266 267 0 (-704 -168 440 ) (-704 0 440 ) (0 0 440 ) (0 -168 440 ) +4 267 285 0 (-704 -168 408 ) (-704 0 408 ) (0 0 408 ) (0 -168 408 ) +4 267 269 0 (0 -168 416 ) (0 -168 432 ) (-576 -168 432 ) (-576 -168 416 ) +4 267 268 0 (0 -168 432 ) (0 -168 440 ) (-576 -168 440 ) (-576 -168 432 ) +4 267 280 0 (-576 -168 408 ) (0 -168 408 ) (0 -168 416 ) (-576 -168 416 ) +4 268 283 0 (-576 -584 432 ) (-576 -616 432 ) (-576 -616 440 ) (-576 -584 440 ) +4 268 282 0 (-576 -280 432 ) (-576 -584 432 ) (-576 -584 440 ) (-576 -280 440 ) +4 268 281 0 (-576 -200 432 ) (-576 -248 432 ) (-576 -248 440 ) (-576 -200 440 ) +4 268 284 0 (-576 -616 432 ) (-576 -960 432 ) (-576 -960 440 ) (-576 -616 440 ) +4 268 278 0 (-576 -272 432 ) (-576 -268 432 ) (0 -268 432 ) (0 -272 432 ) +4 268 275 0 (-576 -260 432 ) (-576 -256 432 ) (0 -256 432 ) (0 -260 432 ) +4 268 279 0 (0 -960 432 ) (-576 -960 432 ) (-576 -272 432 ) (0 -272 432 ) +4 268 274 0 (-576 -256 432 ) (-576 -192 432 ) (0 -192 432 ) (0 -256 432 ) +4 268 273 0 (-576 -192 432 ) (-576 -188 432 ) (0 -188 432 ) (0 -192 432 ) +4 268 272 0 (-576 -180 432 ) (-576 -176 432 ) (0 -176 432 ) (0 -180 432 ) +4 268 269 0 (-576 -176 432 ) (-576 -168 432 ) (0 -168 432 ) (0 -176 432 ) +4 269 272 0 (0 -176 428 ) (0 -176 432 ) (-576 -176 432 ) (-576 -176 428 ) +4 269 271 0 (-576 -176 416 ) (0 -176 416 ) (0 -176 420 ) (-576 -176 420 ) +4 269 280 0 (-576 -176 416 ) (-576 -168 416 ) (0 -168 416 ) (0 -176 416 ) +4 270 274 0 (-576 -192 416 ) (0 -192 416 ) (0 -192 420 ) (-576 -192 420 ) +4 270 280 0 (-576 -192 416 ) (-576 -188 416 ) (0 -188 416 ) (0 -192 416 ) +4 271 280 0 (-576 -180 416 ) (-576 -176 416 ) (0 -176 416 ) (0 -180 416 ) +4 273 274 0 (0 -192 428 ) (0 -192 432 ) (-576 -192 432 ) (-576 -192 428 ) +4 274 281 0 (-576 -200 416 ) (-576 -248 416 ) (-576 -248 432 ) (-576 -200 432 ) +4 274 277 0 (-576 -256 416 ) (0 -256 416 ) (0 -256 419.994049 ) (-576 -256 419.994049 ) +4 274 275 0 (0 -256 428 ) (0 -256 432 ) (-576 -256 432 ) (-576 -256 428 ) +4 274 280 0 (-576 -256 416 ) (-576 -192 416 ) (0 -192 416 ) (0 -256 416 ) +4 276 280 0 (-576 -272 416 ) (-576 -268 416 ) (0 -268 416 ) (0 -272 416 ) +4 276 279 0 (-576 -272 416 ) (0 -272 416 ) (0 -272 420 ) (-576 -272 420 ) +4 277 280 0 (-576 -259.994049 416 ) (-576 -256 416 ) (0 -256 416 ) (0 -259.994049 416 ) +4 278 279 0 (0 -272 428 ) (0 -272 432 ) (-576 -272 432 ) (-576 -272 428 ) +4 279 283 0 (-576 -584 416 ) (-576 -616 416 ) (-576 -616 432 ) (-576 -584 432 ) +4 279 282 0 (-576 -280 416 ) (-576 -584 416 ) (-576 -584 432 ) (-576 -280 432 ) +4 279 284 0 (-576 -616 416 ) (-576 -960 416 ) (-576 -960 432 ) (-576 -616 432 ) +4 279 280 0 (0 -960 416 ) (-576 -960 416 ) (-576 -272 416 ) (0 -272 416 ) +4 280 285 0 (-576 -168 408 ) (0 -168 408 ) (0 -960 408 ) (-576 -960 408 ) +4 280 283 0 (-576 -584 408 ) (-576 -616 408 ) (-576 -616 416 ) (-576 -584 416 ) +4 280 282 0 (-576 -280 408 ) (-576 -584 408 ) (-576 -584 416 ) (-576 -280 416 ) +4 280 281 0 (-576 -200 408 ) (-576 -248 408 ) (-576 -248 416 ) (-576 -200 416 ) +4 280 284 0 (-576 -616 408 ) (-576 -960 408 ) (-576 -960 416 ) (-576 -616 416 ) +4 281 285 0 (-704 -248 408 ) (-704 -200 408 ) (-576 -200 408 ) (-576 -248 408 ) +4 282 285 0 (-704 -584 408 ) (-704 -280 408 ) (-576 -280 408 ) (-576 -584 408 ) +4 282 283 0 (-632 -584 408 ) (-576 -584 408 ) (-576 -584 440 ) (-632 -584 440 ) +4 283 285 0 (-632 -584 408 ) (-576 -584 408 ) (-576 -616 408 ) (-632 -616 408 ) +4 283 284 0 (-632 -616 408 ) (-576 -616 408 ) (-576 -616 440 ) (-632 -616 440 ) +4 284 285 0 (-704 -960 408 ) (-704 -616 408 ) (-576 -616 408 ) (-576 -960 408 ) +3 285 327 0 (-480 -656 256 ) (-480 -704 256 ) (-528 -704 256 ) +4 285 328 0 (-480 -960 256 ) (-704 -960 256 ) (-704 -704 256 ) (-480 -704 256 ) +3 285 311 0 (-416 -816 256 ) (-392 -768 256 ) (-368 -768 256 ) +3 285 310 0 (0 -768 256 ) (0 -808 256 ) (-80 -768 256 ) +3 285 309 0 (-448 -880 256 ) (-448 -768 256 ) (-392 -768 256 ) +3 285 308 0 (-352 -752 256 ) (-304 -704 256 ) (-256 -704 256 ) +4 285 307 0 (0 -704 256 ) (0 -768 256 ) (-128 -768 256 ) (-192 -704 256 ) +4 285 306 0 (-368 -768 256 ) (-448 -768 256 ) (-448 -704 256 ) (-304 -704 256 ) +4 285 312 0 (-448 -960 256 ) (-480 -960 256 ) (-480 -704 256 ) (-448 -704 256 ) +4 285 301 0 (0 -384 256 ) (0 -704 256 ) (-320 -704 256 ) (-320 -384 256 ) +4 285 305 0 (-320 -704 256 ) (-480 -704 256 ) (-480 -384 256 ) (-320 -384 256 ) +4 285 295 0 (0 -256 256 ) (0 -384 256 ) (-480 -384 256 ) (-480 -256 256 ) +4 285 294 0 (0 -192 256 ) (0 -256 256 ) (-480 -256 256 ) (-480 -192 256 ) +4 285 293 0 (-704 0 256 ) (-480 0 256 ) (-480 -192 256 ) (-704 -192 256 ) +4 285 291 0 (-320 -192 256 ) (-384 -192 256 ) (-384 -64 256 ) (-320 -64 256 ) +4 285 287 0 (0 -64 256 ) (0 -192 256 ) (-320 -192 256 ) (-320 -64 256 ) +4 285 292 0 (-384 -192 256 ) (-480 -192 256 ) (-480 -64 256 ) (-384 -64 256 ) +4 285 286 0 (-480 0 256 ) (0 0 256 ) (0 -64 256 ) (-480 -64 256 ) +4 286 293 0 (-480 -64 170.666656 ) (-480 -64 256 ) (-480 0 256 ) (-480 0 128 ) +4 286 291 0 (-320 -64 64 ) (-320 -64 256 ) (-384 -64 256 ) (-384 -64 64 ) +4 286 289 0 (-192 -64 0 ) (0 -64 0 ) (0 -64 16 ) (-192 -64 16 ) +4 286 288 0 (0 -64 16 ) (0 -64 192 ) (-192 -64 192 ) (-192 -64 16 ) +4 286 287 0 (0 -64 192 ) (0 -64 256 ) (-320 -64 256 ) (-320 -64 192 ) +4 286 292 0 (-480 -64 256 ) (-480 -64 0 ) (-384 -64 0 ) (-384 -64 256 ) +4 287 294 0 (0 -192 192 ) (0 -192 256 ) (-320 -192 256 ) (-320 -192 192 ) +4 287 291 0 (-320 -64 256 ) (-320 -64 192 ) (-320 -192 192 ) (-320 -192 256 ) +4 287 288 0 (0 -192 192 ) (-192 -192 192 ) (-192 -64 192 ) (0 -64 192 ) +4 288 294 0 (0 -192 16 ) (0 -192 192 ) (-192 -192 192 ) (-192 -192 16 ) +4 288 289 0 (-192 -80 16 ) (-192 -64 16 ) (0 -64 16 ) (0 -80 16 ) +4 288 290 0 (0 -192 16 ) (-192 -192 16 ) (-192 -176 16 ) (0 -176 16 ) +4 290 294 0 (-192 -192 0 ) (0 -192 0 ) (0 -192 16 ) (-192 -192 16 ) +4 291 294 0 (-320 -192 64 ) (-320 -192 256 ) (-384 -192 256 ) (-384 -192 64 ) +4 291 292 0 (-384 -64 256 ) (-384 -64 64 ) (-384 -192 64 ) (-384 -192 256 ) +4 292 294 0 (-480 -192 0 ) (-384 -192 0 ) (-384 -192 256 ) (-480 -192 256 ) +3 292 293 0 (-480 -192 256 ) (-480 -64 256 ) (-480 -64 170.666656 ) +4 294 299 0 (-320 -256 192 ) (-384 -256 192 ) (-384 -256 64 ) (-320 -256 64 ) +4 294 297 0 (-128 -256 0 ) (0 -256 0 ) (0 -256 16 ) (-128 -256 16 ) +4 294 296 0 (0 -256 16 ) (0 -256 192 ) (-128 -256 192 ) (-128 -256 16 ) +4 294 300 0 (-480 -256 192 ) (-480 -256 0 ) (-384 -256 0 ) (-384 -256 192 ) +4 294 295 0 (-480 -256 256 ) (-480 -256 192 ) (0 -256 192 ) (0 -256 256 ) +4 295 301 0 (0 -384 192 ) (0 -384 256 ) (-320 -384 256 ) (-320 -384 192 ) +4 295 305 0 (-320 -384 256 ) (-480 -384 256 ) (-480 -384 192 ) (-320 -384 192 ) +4 295 299 0 (-320 -384 192 ) (-384 -384 192 ) (-384 -256 192 ) (-320 -256 192 ) +4 295 296 0 (-128 -368 192 ) (-128 -256 192 ) (0 -256 192 ) (0 -368 192 ) +4 295 298 0 (0 -384 192 ) (-128 -384 192 ) (-128 -368 192 ) (0 -368 192 ) +4 295 300 0 (-384 -384 192 ) (-480 -384 192 ) (-480 -256 192 ) (-384 -256 192 ) +4 296 297 0 (-128 -272 16 ) (-128 -256 16 ) (0 -256 16 ) (0 -272 16 ) +4 296 298 0 (-128 -368 192 ) (-128 -368 16 ) (0 -368 16 ) (0 -368 192 ) +4 298 313 0 (-128 -384 0 ) (0 -384 0 ) (0 -384 128 ) (-128 -384 128 ) +4 298 302 0 (0 -384 128 ) (0 -384 192 ) (-128 -384 192 ) (-128 -384 128 ) +4 299 313 0 (-384 -384 128 ) (-384 -384 64 ) (-320 -384 64 ) (-320 -384 128 ) +4 299 305 0 (-320 -384 192 ) (-384 -384 192 ) (-384 -384 128 ) (-320 -384 128 ) +4 299 300 0 (-384 -384 64 ) (-384 -384 192 ) (-384 -256 192 ) (-384 -256 64 ) +4 300 313 0 (-480 -384 0 ) (-384 -384 0 ) (-384 -384 128 ) (-480 -384 128 ) +4 300 305 0 (-384 -384 128 ) (-384 -384 192 ) (-480 -384 192 ) (-480 -384 128 ) +4 301 308 0 (-256 -704 256 ) (-304 -704 256 ) (-304 -704 192 ) (-256 -704 192 ) +4 301 307 0 (0 -704 192 ) (0 -704 256 ) (-192 -704 256 ) (-192 -704 192 ) +4 301 306 0 (-304 -704 256 ) (-320 -704 256 ) (-320 -704 192 ) (-304 -704 192 ) +4 301 304 0 (-128 -704 192 ) (-320 -704 192 ) (-320 -576 192 ) (-128 -576 192 ) +4 301 303 0 (-320 -448 192 ) (-320 -384 192 ) (-128 -384 192 ) (-128 -448 192 ) +4 301 302 0 (0 -704 192 ) (-128 -704 192 ) (-128 -384 192 ) (0 -384 192 ) +4 301 305 0 (-320 -384 256 ) (-320 -384 192 ) (-320 -704 192 ) (-320 -704 256 ) +4 302 322 0 (0 -696 128 ) (0 -704 128 ) (-128 -704 128 ) (-128 -696 128 ) +4 302 319 0 (0 -576 128 ) (0 -696 128 ) (-128 -696 128 ) (-128 -576 128 ) +4 302 314 0 (0 -448 128 ) (0 -560 128 ) (-128 -560 128 ) (-128 -448 128 ) +4 302 316 0 (0 -560 128 ) (0 -576 128 ) (-128 -576 128 ) (-128 -560 128 ) +4 302 313 0 (-128 -384 128 ) (0 -384 128 ) (0 -448 128 ) (-128 -448 128 ) +4 302 307 0 (-128 -704 128 ) (0 -704 128 ) (0 -704 192 ) (-128 -704 192 ) +4 302 304 0 (-128 -576 128 ) (-128 -704 128 ) (-128 -704 192 ) (-128 -576 192 ) +4 302 303 0 (-128 -384 128 ) (-128 -448 128 ) (-128 -448 192 ) (-128 -384 192 ) +4 303 313 0 (-320 -384 128 ) (-128 -384 128 ) (-128 -448 128 ) (-320 -448 128 ) +4 303 305 0 (-320 -384 192 ) (-320 -384 128 ) (-320 -448 128 ) (-320 -448 192 ) +4 304 323 0 (-276 -704 128 ) (-316 -704 128 ) (-308 -696 128 ) (-260 -696 128 ) +4 304 322 0 (-128 -696 128 ) (-128 -704 128 ) (-180 -704 128 ) (-188 -696 128 ) +4 304 321 0 (-316 -704 128 ) (-320 -704 128 ) (-320 -696 128 ) (-308 -696 128 ) +4 304 319 0 (-128 -576 128 ) (-128 -696 128 ) (-320 -696 128 ) (-320 -576 128 ) +4 304 308 0 (-304 -704 128 ) (-256 -704 128 ) (-256 -704 192 ) (-304 -704 192 ) +4 304 307 0 (-192 -704 128 ) (-128 -704 128 ) (-128 -704 192 ) (-192 -704 192 ) +4 304 306 0 (-320 -704 128 ) (-304 -704 128 ) (-304 -704 192 ) (-320 -704 192 ) +4 304 305 0 (-320 -576 128 ) (-320 -704 128 ) (-320 -704 192 ) (-320 -576 192 ) +4 305 327 0 (-480 -656 128 ) (-480 -704 128 ) (-480 -704 256 ) (-480 -656 256 ) +4 305 321 0 (-320 -696 128 ) (-320 -704 128 ) (-370 -704 128 ) (-366 -696 128 ) +4 305 320 0 (-370 -704 128 ) (-456 -704 128 ) (-456 -696 128 ) (-366 -696 128 ) +4 305 319 0 (-456 -576 128 ) (-320 -576 128 ) (-320 -696 128 ) (-456 -696 128 ) +4 305 326 0 (-480 -704 128 ) (-480 -576 128 ) (-456 -576 128 ) (-456 -704 128 ) +4 305 317 0 (-384 -448 128 ) (-320 -448 128 ) (-320 -576 128 ) (-384 -576 128 ) +4 305 318 0 (-480 -576 128 ) (-480 -448 128 ) (-384 -448 128 ) (-384 -576 128 ) +4 305 313 0 (-480 -448 128 ) (-480 -384 128 ) (-320 -384 128 ) (-320 -448 128 ) +4 305 306 0 (-448 -704 128 ) (-320 -704 128 ) (-320 -704 256 ) (-448 -704 256 ) +4 305 312 0 (-480 -704 256 ) (-480 -704 128 ) (-448 -704 128 ) (-448 -704 256 ) +4 306 324 0 (-380 -768 128 ) (-402 -768 128 ) (-398 -760 128 ) (-372 -760 128 ) +4 306 323 0 (-316 -704 128 ) (-304 -704 128 ) (-332 -732 128 ) (-356 -744 128 ) +4 306 321 0 (-370 -704 128 ) (-316 -704 128 ) (-372 -760 128 ) (-398 -760 128 ) +4 306 320 0 (-448 -768 128 ) (-448 -704 128 ) (-370 -704 128 ) (-402 -768 128 ) +4 306 311 0 (-392 -768 128 ) (-368 -768 128 ) (-368 -768 256 ) (-392 -768 256 ) +4 306 309 0 (-448 -768 256 ) (-448 -768 128 ) (-392 -768 128 ) (-392 -768 256 ) +4 306 308 0 (-352 -752 128 ) (-304 -704 128 ) (-304 -704 256 ) (-352 -752 256 ) +4 306 312 0 (-448 -704 256 ) (-448 -704 128 ) (-448 -768 128 ) (-448 -768 256 ) +4 307 325 0 (0 -760 128 ) (0 -768 128 ) (-60 -768 128 ) (-76 -760 128 ) +4 307 322 0 (-180 -704 128 ) (0 -704 128 ) (0 -760 128 ) (-124 -760 128 ) +4 307 310 0 (-80 -768 128 ) (0 -768 128 ) (0 -768 256 ) (-80 -768 256 ) +3 308 323 0 (-304 -704 128 ) (-276 -704 128 ) (-332 -732 128 ) +4 309 324 0 (-424 -812 128 ) (-402 -768 128 ) (-392 -768 128 ) (-404 -792 128 ) +3 309 320 0 (-448 -860 128 ) (-448 -768 128 ) (-402 -768 128 ) +4 309 311 0 (-416 -816 128 ) (-392 -768 128 ) (-392 -768 256 ) (-416 -816 256 ) +4 309 312 0 (-448 -768 128 ) (-448 -880 128 ) (-448 -880 256 ) (-448 -768 256 ) +3 310 325 0 (-60 -768 128 ) (0 -768 128 ) (0 -798 128 ) +3 311 324 0 (-404 -792 128 ) (-392 -768 128 ) (-380 -768 128 ) +4 312 328 0 (-480 -704 128 ) (-480 -960 128 ) (-480 -960 256 ) (-480 -704 256 ) +4 312 320 0 (-456 -876 128 ) (-456 -704 128 ) (-448 -704 128 ) (-448 -860 128 ) +4 312 326 0 (-456 -960 128 ) (-480 -960 128 ) (-480 -704 128 ) (-456 -704 128 ) +4 313 317 0 (-320 -448 128 ) (-384 -448 128 ) (-384 -448 64 ) (-320 -448 64 ) +4 313 315 0 (-128 -448 16 ) (-128 -448 0 ) (0 -448 0 ) (0 -448 16 ) +4 313 314 0 (0 -448 128 ) (-128 -448 128 ) (-128 -448 16 ) (0 -448 16 ) +4 313 318 0 (-384 -448 128 ) (-480 -448 128 ) (-480 -448 0 ) (-384 -448 0 ) +4 314 315 0 (-128 -464 16 ) (-128 -448 16 ) (0 -448 16 ) (0 -464 16 ) +4 314 316 0 (-128 -560 128 ) (-128 -560 16 ) (0 -560 16 ) (0 -560 128 ) +4 316 319 0 (0 -576 128 ) (-128 -576 128 ) (-128 -576 0 ) (0 -576 0 ) +4 317 319 0 (-320 -576 128 ) (-384 -576 128 ) (-384 -576 64 ) (-320 -576 64 ) +4 317 318 0 (-384 -448 128 ) (-384 -448 64 ) (-384 -576 64 ) (-384 -576 128 ) +4 318 319 0 (-384 -576 128 ) (-456 -576 128 ) (-456 -576 0 ) (-384 -576 0 ) +4 318 326 0 (-456 -576 128 ) (-480 -576 128 ) (-480 -576 0 ) (-456 -576 0 ) +4 319 323 0 (-308 -696 0 ) (-260 -696 0 ) (-260 -696 128 ) (-308 -696 128 ) +4 319 322 0 (-188 -696 0 ) (0 -696 0 ) (0 -696 128 ) (-188 -696 128 ) +4 319 321 0 (-366 -696 0 ) (-308 -696 0 ) (-308 -696 128 ) (-366 -696 128 ) +4 319 320 0 (-456 -696 128 ) (-456 -696 0 ) (-366 -696 0 ) (-366 -696 128 ) +4 319 326 0 (-456 -576 128 ) (-456 -576 0 ) (-456 -696 0 ) (-456 -696 128 ) +4 320 324 0 (-424 -812 0 ) (-398 -760 0 ) (-398 -760 128 ) (-424 -812 128 ) +4 320 321 0 (-398 -760 0 ) (-366 -696 0 ) (-366 -696 128 ) (-398 -760 128 ) +4 320 326 0 (-456 -696 0 ) (-456 -876 0 ) (-456 -876 128 ) (-456 -696 128 ) +4 321 324 0 (-398 -760 128 ) (-398 -760 0 ) (-372 -760 0 ) (-372 -760 128 ) +4 321 323 0 (-356 -744 0 ) (-308 -696 0 ) (-308 -696 128 ) (-356 -744 128 ) +4 322 325 0 (-76 -760 0 ) (0 -760 0 ) (0 -760 128 ) (-76 -760 128 ) +4 326 327 0 (-480 -656 0 ) (-480 -704 0 ) (-480 -704 128 ) (-480 -656 128 ) +4 326 328 0 (-480 -704 0 ) (-480 -960 0 ) (-480 -960 128 ) (-480 -704 128 ) +4 327 328 0 (-528 -704 0 ) (-480 -704 0 ) (-480 -704 256 ) (-528 -704 256 ) +4 0 (1056 256 160 ) (1056 640 160 ) (1088 640 160 ) (1088 256 160 ) +4 0 (1152 0 160 ) (1088 0 160 ) (1088 640 160 ) (1152 640 160 ) +4 0 (1152 0 176 ) (1152 0 160 ) (1152 640 160 ) (1152 640 176 ) +4 0 (1056 640 176 ) (1152 640 176 ) (1152 640 160 ) (1056 640 160 ) +4 0 (1152 0 176 ) (1152 640 176 ) (1056 640 176 ) (1056 0 176 ) +4 1 (1024 0 512 ) (1024 0 224 ) (1056 0 224 ) (1056 0 512 ) +4 1 (1024 256 160 ) (1024 640 160 ) (1056 640 160 ) (1056 256 160 ) +4 1 (1056 640 176 ) (1056 640 512 ) (1056 0 512 ) (1056 0 176 ) +4 1 (1024 0 512 ) (1056 0 512 ) (1056 640 512 ) (1024 640 512 ) +4 1 (1056 640 512 ) (1056 640 160 ) (1024 640 160 ) (1024 640 512 ) +4 2 (1088 256 160 ) (1088 0 160 ) (1088 0 0 ) (1088 256 0 ) +4 2 (1088 256 0 ) (1088 0 0 ) (1024 0 0 ) (1024 256 0 ) +4 2 (1024 256 160 ) (1088 256 160 ) (1088 256 0 ) (1024 256 0 ) +4 3 (1056 -64 224 ) (1056 0 224 ) (1024 0 224 ) (1024 -64 224 ) +4 3 (1056 0 224 ) (1056 -64 224 ) (1056 -64 176 ) (1056 0 176 ) +4 4 (1056 -64 224 ) (1152 -64 224 ) (1152 -64 176 ) (1056 -64 176 ) +4 4 (1152 -64 224 ) (1152 -128 224 ) (1152 -128 176 ) (1152 -64 176 ) +4 4 (1152 -64 224 ) (1056 -64 224 ) (1056 -128 224 ) (1152 -128 224 ) +4 4 (1056 -64 224 ) (1024 -64 224 ) (1024 -128 224 ) (1056 -128 224 ) +4 5 (1088 -64 160 ) (1088 -128 160 ) (1024 -128 160 ) (1024 -64 160 ) +4 5 (1088 0 160 ) (1152 0 160 ) (1152 -128 160 ) (1088 -128 160 ) +4 5 (1056 -64 176 ) (1152 -64 176 ) (1152 0 176 ) (1056 0 176 ) +4 5 (1152 -128 176 ) (1152 -128 160 ) (1152 0 160 ) (1152 0 176 ) +4 6 (1120 -184 440 ) (1120 -152 440 ) (1152 -152 440 ) (1152 -184 440 ) +4 6 (1120 -376 440 ) (1120 -344 440 ) (1152 -344 440 ) (1152 -376 440 ) +4 6 (1152 -576 440 ) (1152 -128 440 ) (1152 -128 512 ) (1152 -576 512 ) +4 6 (1120 -128 512 ) (1120 -576 512 ) (1152 -576 512 ) (1152 -128 512 ) +4 6 (1120 -128 440 ) (1120 -128 512 ) (1152 -128 512 ) (1152 -128 440 ) +4 6 (1120 -576 512 ) (1120 -576 440 ) (1152 -576 440 ) (1152 -576 512 ) +4 7 (1120 -152 408 ) (1152 -152 408 ) (1152 -152 440 ) (1120 -152 440 ) +4 7 (1152 -152 440 ) (1152 -152 408 ) (1152 -128 408 ) (1152 -128 440 ) +4 7 (1120 -128 408 ) (1120 -128 440 ) (1152 -128 440 ) (1152 -128 408 ) +6 8 (1120 -188 432 ) (1120 -184 432 ) (1120 -184 416 ) (1120 -188 416 ) (1120 -192 420 ) (1120 -192 428 ) +4 8 (1120 -344 408 ) (1152 -344 408 ) (1152 -344 440 ) (1120 -344 440 ) +4 8 (1152 -184 440 ) (1152 -344 440 ) (1152 -344 408 ) (1152 -184 408 ) +4 8 (1120 -184 440 ) (1152 -184 440 ) (1152 -184 408 ) (1120 -184 408 ) +4 9 (1120 -376 440 ) (1152 -376 440 ) (1152 -376 408 ) (1120 -376 408 ) +4 9 (1120 -576 440 ) (1120 -576 408 ) (1152 -576 408 ) (1152 -576 440 ) +4 9 (1152 -376 440 ) (1152 -576 440 ) (1152 -576 408 ) (1152 -376 408 ) +4 10 (1152 -184 408 ) (1152 -152 408 ) (1120 -152 408 ) (1120 -184 408 ) +4 10 (1152 -376 408 ) (1152 -344 408 ) (1120 -344 408 ) (1120 -376 408 ) +4 10 (1120 -576 408 ) (1120 -576 192 ) (1152 -576 192 ) (1152 -576 408 ) +4 10 (1120 -128 224 ) (1120 -128 408 ) (1152 -128 408 ) (1152 -128 224 ) +4 10 (1152 -576 408 ) (1152 -576 192 ) (1152 -128 192 ) (1152 -128 408 ) +4 11 (1120 -576 432 ) (1120 -576 512 ) (1104 -576 512 ) (1104 -576 432 ) +4 11 (1024 -364 432 ) (1024 -356 432 ) (1120 -356 432 ) (1120 -364 432 ) +4 11 (1024 -188 432 ) (1024 -180 432 ) (1120 -180 432 ) (1120 -188 432 ) +4 11 (1120 -576 512 ) (1120 -128 512 ) (1024 -128 512 ) (1024 -576 512 ) +4 11 (1120 -128 432 ) (1056 -128 432 ) (1056 -128 512 ) (1120 -128 512 ) +4 11 (1056 -128 432 ) (1024 -128 432 ) (1024 -128 512 ) (1056 -128 512 ) +4 11 (1120 -344 432 ) (1120 -344 440 ) (1120 -376 440 ) (1120 -376 432 ) +4 11 (1120 -152 432 ) (1120 -152 440 ) (1120 -184 440 ) (1120 -184 432 ) +4 12 (1120 -176 420 ) (1120 -176 428 ) (1024 -176 428 ) (1024 -176 420 ) +4 12 (1120 -128 432 ) (1120 -128 416 ) (1056 -128 416 ) (1056 -128 432 ) +4 12 (1056 -128 432 ) (1056 -128 416 ) (1024 -128 416 ) (1024 -128 432 ) +4 12 (1120 -176 416 ) (1120 -152 416 ) (1120 -152 432 ) (1120 -176 432 ) +4 13 (1120 -188 416 ) (1024 -188 416 ) (1024 -192 420 ) (1120 -192 420 ) +4 14 (1024 -180 416 ) (1120 -180 416 ) (1120 -176 420 ) (1024 -176 420 ) +3 14 (1120 -180 416 ) (1120 -176 416 ) (1120 -176 420 ) +4 15 (1024 -176 428 ) (1120 -176 428 ) (1120 -180 432 ) (1024 -180 432 ) +3 15 (1120 -176 428 ) (1120 -176 432 ) (1120 -180 432 ) +4 16 (1120 -192 428 ) (1024 -192 428 ) (1024 -188 432 ) (1120 -188 432 ) +4 17 (1120 -352 420 ) (1120 -352 428 ) (1024 -352 428 ) (1024 -352 420 ) +4 17 (1120 -352 416 ) (1120 -344 416 ) (1120 -344 432 ) (1120 -352 432 ) +4 17 (1024 -192 420 ) (1024 -192 428 ) (1120 -192 428 ) (1120 -192 420 ) +4 18 (1024 -356 416 ) (1120 -356 416 ) (1120 -352 420 ) (1024 -352 420 ) +3 18 (1120 -356 416 ) (1120 -352 416 ) (1120 -352 420 ) +4 19 (1024 -352 428 ) (1120 -352 428 ) (1120 -356 432 ) (1024 -356 432 ) +3 19 (1120 -352 428 ) (1120 -352 432 ) (1120 -356 432 ) +4 20 (1120 -368 428 ) (1024 -368 428 ) (1024 -364 432 ) (1120 -364 432 ) +3 20 (1120 -368 428 ) (1120 -364 432 ) (1120 -368 432 ) +3 21 (1120 -368 420 ) (1120 -368 416 ) (1120 -364 416 ) +4 21 (1120 -364 416 ) (1024 -364 416 ) (1024 -368 420 ) (1120 -368 420 ) +4 22 (1120 -576 416 ) (1120 -576 432 ) (1104 -576 432 ) (1104 -576 416 ) +4 22 (1024 -368 420 ) (1024 -368 428 ) (1120 -368 428 ) (1120 -368 420 ) +4 22 (1120 -368 416 ) (1120 -368 432 ) (1120 -376 432 ) (1120 -376 416 ) +4 23 (1104 -576 192 ) (1120 -576 192 ) (1120 -576 416 ) (1104 -576 416 ) +4 23 (1120 -364 416 ) (1120 -356 416 ) (1024 -356 416 ) (1024 -364 416 ) +4 23 (1120 -188 416 ) (1120 -180 416 ) (1024 -180 416 ) (1024 -188 416 ) +4 23 (1120 -152 416 ) (1120 -184 416 ) (1120 -184 408 ) (1120 -152 408 ) +4 23 (1120 -344 416 ) (1120 -376 416 ) (1120 -376 408 ) (1120 -344 408 ) +4 23 (1056 -128 416 ) (1056 -128 224 ) (1024 -128 224 ) (1024 -128 416 ) +4 23 (1120 -128 416 ) (1120 -128 224 ) (1056 -128 224 ) (1056 -128 416 ) +4 24 (1104 -576 512 ) (1024 -576 512 ) (1024 -960 512 ) (1104 -960 512 ) +4 24 (1024 -960 512 ) (1024 -960 192 ) (1104 -960 192 ) (1104 -960 512 ) +4 24 (1104 -960 512 ) (1104 -960 192 ) (1104 -576 192 ) (1104 -576 512 ) +4 25 (1104 -576 192 ) (1104 -960 192 ) (1120 -960 192 ) (1120 -576 192 ) +4 25 (1120 -576 192 ) (1120 -960 192 ) (1152 -960 192 ) (1152 -576 192 ) +4 25 (1024 -960 192 ) (1024 -960 160 ) (1152 -960 160 ) (1152 -960 192 ) +4 25 (1152 -128 192 ) (1152 -960 192 ) (1152 -960 160 ) (1152 -128 160 ) +4 26 (1088 0 160 ) (1088 -64 160 ) (1088 -64 0 ) (1088 0 0 ) +4 26 (1024 0 0 ) (1088 0 0 ) (1088 -64 0 ) (1024 -64 0 ) +4 26 (1024 -64 0 ) (1088 -64 0 ) (1088 -64 160 ) (1024 -64 160 ) +4 27 (1152 -320 128 ) (1152 -960 128 ) (1144 -960 128 ) (1144 -320 128 ) +4 27 (1152 -192 128 ) (1152 -320 128 ) (1024 -320 128 ) (1024 -192 128 ) +4 27 (1024 -960 160 ) (1024 -960 128 ) (1152 -960 128 ) (1152 -960 160 ) +4 27 (1152 -128 128 ) (1152 -128 160 ) (1152 -960 160 ) (1152 -960 128 ) +4 27 (1088 -128 128 ) (1088 -128 160 ) (1152 -128 160 ) (1152 -128 128 ) +4 27 (1024 -128 128 ) (1024 -128 160 ) (1088 -128 160 ) (1088 -128 128 ) +4 28 (1152 -128 128 ) (1152 -192 128 ) (1152 -192 0 ) (1152 -128 0 ) +4 28 (1152 -128 0 ) (1152 -192 0 ) (1024 -192 0 ) (1024 -128 0 ) +4 28 (1088 -128 128 ) (1152 -128 128 ) (1152 -128 0 ) (1088 -128 0 ) +4 28 (1024 -128 128 ) (1088 -128 128 ) (1088 -128 0 ) (1024 -128 0 ) +4 28 (1024 -192 0 ) (1152 -192 0 ) (1152 -192 128 ) (1024 -192 128 ) +3 29 (1104 -704 0 ) (1104 -960 0 ) (1104 -960 128 ) +4 29 (1104 -320 128 ) (1144 -320 128 ) (1144 -320 0 ) (1104 -320 0 ) +4 29 (1144 -960 0 ) (1104 -960 0 ) (1104 -320 0 ) (1144 -320 0 ) +4 29 (1104 -960 0 ) (1144 -960 0 ) (1144 -960 128 ) (1104 -960 128 ) +4 29 (1144 -960 128 ) (1144 -960 0 ) (1144 -320 0 ) (1144 -320 128 ) +4 30 (1024 -320 128 ) (1104 -320 128 ) (1104 -320 0 ) (1024 -320 0 ) +4 30 (1024 -704 0 ) (1024 -320 0 ) (1104 -320 0 ) (1104 -704 0 ) +4 30 (1024 -704 0 ) (1104 -704 0 ) (1104 -960 128 ) (1024 -960 128 ) +4 31 (1024 448 160 ) (832 448 160 ) (832 640 160 ) (1024 640 160 ) +4 31 (1024 640 512 ) (1024 640 160 ) (0 640 160 ) (0 640 512 ) +4 31 (1024 640 512 ) (0 640 512 ) (0 448 512 ) (1024 448 512 ) +4 32 (608 640 128 ) (704 640 128 ) (704 448 128 ) (608 448 128 ) +4 32 (832 640 128 ) (832 640 160 ) (832 448 160 ) (832 448 128 ) +4 32 (512 640 128 ) (512 640 160 ) (832 640 160 ) (832 640 128 ) +4 33 (832 640 128 ) (832 448 128 ) (832 448 0 ) (832 640 0 ) +4 33 (832 448 0 ) (704 448 0 ) (704 640 0 ) (832 640 0 ) +4 33 (704 640 128 ) (832 640 128 ) (832 640 0 ) (704 640 0 ) +4 33 (704 640 0 ) (704 448 0 ) (704 448 128 ) (704 640 128 ) +4 34 (512 640 127 ) (512 640 128 ) (608 640 128 ) (608 640 127 ) +4 34 (608 640 127 ) (608 640 128 ) (608 448 128 ) (608 448 127 ) +4 34 (512 448 127 ) (512 640 127 ) (608 640 127 ) (608 448 127 ) +4 35 (384 640 96 ) (448 640 96 ) (448 448 96 ) (384 448 96 ) +4 35 (512 640 96 ) (512 640 127 ) (512 448 127 ) (512 448 96 ) +4 35 (320 640 96 ) (320 640 160 ) (512 640 160 ) (512 640 96 ) +4 36 (512 640 96 ) (512 448 96 ) (512 448 0 ) (512 640 0 ) +4 36 (512 448 0 ) (448 448 0 ) (448 640 0 ) (512 640 0 ) +4 36 (448 640 96 ) (512 640 96 ) (512 640 0 ) (448 640 0 ) +4 36 (448 640 0 ) (448 448 0 ) (448 448 96 ) (448 640 96 ) +4 37 (320 640 95 ) (320 640 96 ) (384 640 96 ) (384 640 95 ) +4 37 (384 640 95 ) (384 640 96 ) (384 448 96 ) (384 448 95 ) +4 37 (320 448 95 ) (320 640 95 ) (384 640 95 ) (384 448 95 ) +4 38 (256 448 79 ) (256 448 80 ) (256 640 80 ) (256 640 79 ) +4 38 (256 640 0 ) (256 448 0 ) (256 448 79 ) (256 640 79 ) +4 38 (320 640 95 ) (320 448 95 ) (320 448 0 ) (320 640 0 ) +4 38 (256 640 160 ) (320 640 160 ) (320 640 0 ) (256 640 0 ) +4 38 (320 448 0 ) (256 448 0 ) (256 640 0 ) (320 640 0 ) +4 39 (192 640 80 ) (256 640 80 ) (256 448 80 ) (192 448 80 ) +4 39 (128 640 80 ) (128 640 160 ) (256 640 160 ) (256 640 80 ) +4 40 (128 448 79 ) (128 640 79 ) (192 640 79 ) (192 448 79 ) +4 40 (192 640 79 ) (128 640 79 ) (128 640 80 ) (192 640 80 ) +4 40 (192 640 80 ) (192 448 80 ) (192 448 79 ) (192 640 79 ) +4 41 (64 640 0 ) (64 448 0 ) (64 448 64 ) (64 640 64 ) +4 41 (128 640 79 ) (128 448 79 ) (128 448 0 ) (128 640 0 ) +4 41 (64 640 160 ) (128 640 160 ) (128 640 0 ) (64 640 0 ) +4 41 (128 448 0 ) (64 448 0 ) (64 640 0 ) (128 640 0 ) +4 42 (64 640 160 ) (64 640 64 ) (0 640 64 ) (0 640 160 ) +4 42 (0 640 64 ) (64 640 64 ) (64 448 64 ) (0 448 64 ) +4 43 (1024 446 160 ) (832 446 160 ) (832 448 160 ) (1024 448 160 ) +4 43 (1024 448 512 ) (676 448 512 ) (676 446 512 ) (1024 446 512 ) +4 44 (676 448 72 ) (676 448 56 ) (676 446 56 ) (676 446 72 ) +4 44 (676 448 76 ) (676 448 72 ) (676 446 72 ) (676 446 76 ) +4 44 (676 448 28 ) (676 448 128 ) (704 448 128 ) (704 448 28 ) +4 44 (832 448 160 ) (832 446 160 ) (832 446 28 ) (832 448 28 ) +4 45 (664 446 76 ) (664 448 76 ) (676 448 76 ) (676 446 76 ) +4 45 (676 448 76 ) (664 448 76 ) (664 448 128 ) (676 448 128 ) +4 45 (676 446 512 ) (676 448 512 ) (664 448 512 ) (664 446 512 ) +4 46 (672 448 56 ) (676 448 56 ) (676 448 28 ) (672 448 28 ) +4 46 (676 446 56 ) (676 448 56 ) (672 448 56 ) (672 446 56 ) +4 47 (668 446 68 ) (668 446 72 ) (668 448 72 ) (668 448 68 ) +4 47 (668 446 72 ) (672 446 72 ) (672 448 72 ) (668 448 72 ) +4 47 (668 448 68 ) (668 448 72 ) (672 448 72 ) (672 448 68 ) +4 47 (672 448 68 ) (672 448 72 ) (672 446 72 ) (672 446 68 ) +4 47 (668 446 68 ) (668 448 68 ) (672 448 68 ) (672 446 68 ) +4 48 (668 446 60 ) (668 446 64 ) (668 448 64 ) (668 448 60 ) +4 48 (668 446 60 ) (668 448 60 ) (672 448 60 ) (672 446 60 ) +4 48 (672 446 64 ) (672 448 64 ) (668 448 64 ) (668 446 64 ) +4 48 (672 448 60 ) (672 448 64 ) (672 446 64 ) (672 446 60 ) +4 48 (668 448 60 ) (668 448 64 ) (672 448 64 ) (672 448 60 ) +4 49 (668 448 56 ) (672 448 56 ) (672 448 28 ) (668 448 28 ) +4 49 (672 446 56 ) (672 448 56 ) (668 448 56 ) (668 446 56 ) +4 50 (668 448 56 ) (668 448 28 ) (664 448 28 ) (664 448 56 ) +4 50 (668 446 56 ) (668 448 56 ) (664 448 56 ) (664 446 56 ) +4 51 (660 446 68 ) (660 446 72 ) (660 448 72 ) (660 448 68 ) +4 51 (660 446 56 ) (660 446 60 ) (660 448 60 ) (660 448 56 ) +4 51 (664 446 72 ) (664 446 56 ) (664 448 56 ) (664 448 72 ) +4 51 (664 446 76 ) (664 446 72 ) (664 448 72 ) (664 448 76 ) +4 51 (664 448 28 ) (660 448 28 ) (660 448 128 ) (664 448 128 ) +4 51 (660 446 512 ) (664 446 512 ) (664 448 512 ) (660 448 512 ) +4 52 (648 446 76 ) (648 448 76 ) (656 448 76 ) (656 446 76 ) +4 52 (648 446 512 ) (660 446 512 ) (660 448 512 ) (648 448 512 ) +4 52 (660 448 76 ) (648 448 76 ) (648 448 128 ) (660 448 128 ) +3 53 (656 448 76 ) (660 448 76 ) (660 448 72 ) +4 53 (660 448 72 ) (660 446 72 ) (656 446 76 ) (656 448 76 ) +4 54 (656 448 64 ) (660 448 68 ) (660 448 60 ) (656 448 60 ) +4 54 (656 448 60 ) (660 448 60 ) (660 446 60 ) (656 446 60 ) +4 54 (656 448 64 ) (656 446 64 ) (660 446 68 ) (660 448 68 ) +4 55 (648 446 60 ) (648 448 60 ) (656 448 68 ) (656 446 68 ) +4 55 (656 448 72 ) (656 448 68 ) (648 448 60 ) (648 448 72 ) +4 55 (656 446 72 ) (656 448 72 ) (648 448 72 ) (648 446 72 ) +4 55 (656 448 68 ) (656 448 72 ) (656 446 72 ) (656 446 68 ) +4 56 (652 448 60 ) (656 448 60 ) (656 446 60 ) (652 446 60 ) +3 56 (656 448 64 ) (656 448 60 ) (652 448 60 ) +4 56 (652 448 60 ) (652 446 60 ) (656 446 64 ) (656 448 64 ) +4 57 (660 446 56 ) (660 448 56 ) (648 448 56 ) (648 446 56 ) +4 57 (660 448 56 ) (660 448 28 ) (648 448 28 ) (648 448 56 ) +4 58 (640 446 76 ) (640 448 76 ) (644 448 76 ) (644 446 76 ) +4 58 (640 446 512 ) (648 446 512 ) (648 448 512 ) (640 448 512 ) +4 58 (648 448 76 ) (640 448 76 ) (640 448 128 ) (648 448 128 ) +4 59 (644 446 56 ) (644 446 76 ) (644 448 76 ) (644 448 56 ) +4 59 (644 448 76 ) (648 448 76 ) (648 448 28 ) (644 448 28 ) +4 59 (648 448 72 ) (648 448 76 ) (648 446 76 ) (648 446 72 ) +4 59 (648 448 56 ) (648 448 60 ) (648 446 60 ) (648 446 56 ) +4 60 (644 448 56 ) (644 448 28 ) (640 448 28 ) (640 448 56 ) +4 60 (644 446 56 ) (644 448 56 ) (640 448 56 ) (640 446 56 ) +4 61 (512 448 127 ) (608 448 127 ) (608 446 127 ) (512 446 127 ) +4 61 (640 446 512 ) (640 448 512 ) (428 448 512 ) (428 446 512 ) +4 61 (640 448 127 ) (608 448 127 ) (608 448 128 ) (640 448 128 ) +4 62 (640 448 127 ) (640 448 28 ) (608 448 28 ) (608 448 127 ) +4 62 (640 448 56 ) (640 448 76 ) (640 446 76 ) (640 446 56 ) +4 62 (608 448 28 ) (608 446 28 ) (608 446 127 ) (608 448 127 ) +4 63 (428 448 52 ) (428 448 44 ) (428 446 44 ) (428 446 52 ) +4 63 (428 448 44 ) (428 448 40 ) (428 446 40 ) (428 446 44 ) +4 63 (428 448 60 ) (428 448 56 ) (428 446 56 ) (428 446 60 ) +4 63 (512 448 127 ) (512 446 127 ) (512 446 28 ) (512 448 28 ) +4 63 (428 448 28 ) (428 448 96 ) (448 448 96 ) (448 448 28 ) +4 64 (420 448 60 ) (428 448 60 ) (428 446 60 ) (420 446 60 ) +4 64 (416 446 60 ) (416 448 60 ) (420 448 60 ) (420 446 60 ) +4 64 (428 448 60 ) (416 448 60 ) (416 448 96 ) (428 448 96 ) +4 64 (428 446 512 ) (428 448 512 ) (416 448 512 ) (416 446 512 ) +4 65 (420 446 52 ) (420 448 52 ) (424 448 52 ) (424 446 52 ) +4 65 (424 448 52 ) (428 448 52 ) (428 446 52 ) (424 446 52 ) +4 65 (420 446 52 ) (420 446 56 ) (420 448 56 ) (420 448 52 ) +4 65 (420 448 52 ) (420 448 56 ) (428 448 56 ) (428 448 52 ) +4 65 (428 446 56 ) (428 448 56 ) (420 448 56 ) (420 446 56 ) +4 66 (424 448 48 ) (424 446 48 ) (424 446 44 ) (424 448 44 ) +4 66 (420 446 44 ) (420 448 44 ) (424 448 44 ) (424 446 44 ) +4 66 (420 446 44 ) (420 446 48 ) (420 448 48 ) (420 448 44 ) +4 66 (424 448 48 ) (424 448 44 ) (420 448 44 ) (420 448 48 ) +4 66 (424 446 48 ) (424 448 48 ) (420 448 48 ) (420 446 48 ) +4 67 (420 446 40 ) (428 446 40 ) (428 448 40 ) (420 448 40 ) +4 67 (420 446 40 ) (420 448 40 ) (416 448 40 ) (416 446 40 ) +4 67 (428 448 40 ) (428 448 28 ) (416 448 28 ) (416 448 40 ) +4 68 (412 448 60 ) (412 448 40 ) (412 446 40 ) (412 446 60 ) +4 68 (416 446 60 ) (416 446 40 ) (416 448 40 ) (416 448 60 ) +4 68 (416 448 28 ) (412 448 28 ) (412 448 96 ) (416 448 96 ) +4 68 (416 446 512 ) (416 448 512 ) (412 448 512 ) (412 446 512 ) +4 69 (400 448 60 ) (408 448 60 ) (408 446 60 ) (400 446 60 ) +4 69 (408 448 60 ) (412 448 60 ) (412 446 60 ) (408 446 60 ) +4 69 (348 448 60 ) (348 448 95 ) (384 448 95 ) (384 448 60 ) +4 69 (412 448 60 ) (384 448 60 ) (384 448 96 ) (412 448 96 ) +4 69 (412 446 512 ) (412 448 512 ) (348 448 512 ) (348 446 512 ) +4 70 (408 448 40 ) (412 448 40 ) (412 448 28 ) (408 448 28 ) +4 70 (412 446 40 ) (412 448 40 ) (408 448 40 ) (408 446 40 ) +4 71 (404 448 52 ) (408 448 52 ) (408 446 52 ) (404 446 52 ) +4 71 (404 448 52 ) (404 448 56 ) (408 448 56 ) (408 448 52 ) +4 71 (408 448 52 ) (408 448 56 ) (408 446 56 ) (408 446 52 ) +4 71 (404 446 56 ) (408 446 56 ) (408 448 56 ) (404 448 56 ) +4 71 (404 448 52 ) (404 446 52 ) (404 446 56 ) (404 448 56 ) +4 72 (400 446 44 ) (400 448 44 ) (408 448 44 ) (408 446 44 ) +4 72 (408 446 48 ) (408 448 48 ) (400 448 48 ) (400 446 48 ) +4 72 (400 448 44 ) (400 448 48 ) (408 448 48 ) (408 448 44 ) +4 72 (408 448 44 ) (408 448 48 ) (408 446 48 ) (408 446 44 ) +4 73 (400 448 40 ) (408 448 40 ) (408 448 28 ) (400 448 28 ) +4 73 (408 446 40 ) (408 448 40 ) (400 448 40 ) (400 446 40 ) +4 74 (364 446 38 ) (364 446 42 ) (364 448 42 ) (364 448 38 ) +4 74 (364 446 50 ) (364 446 54 ) (364 448 54 ) (364 448 50 ) +4 74 (364 448 28 ) (364 448 60 ) (384 448 60 ) (384 448 28 ) +4 74 (400 448 60 ) (400 448 28 ) (384 448 28 ) (384 448 60 ) +4 74 (400 448 56 ) (400 448 60 ) (400 446 60 ) (400 446 56 ) +4 74 (400 448 48 ) (400 448 52 ) (400 446 52 ) (400 446 48 ) +4 74 (400 448 52 ) (400 448 56 ) (400 446 56 ) (400 446 52 ) +4 74 (400 448 40 ) (400 448 44 ) (400 446 44 ) (400 446 40 ) +4 75 (364 448 54 ) (352 448 54 ) (352 448 60 ) (364 448 60 ) +4 75 (352 446 54 ) (352 448 54 ) (364 448 54 ) (364 446 54 ) +4 76 (360 446 50 ) (364 446 50 ) (364 448 50 ) (360 448 50 ) +4 76 (360 448 46 ) (360 448 50 ) (364 448 50 ) (364 448 42 ) +4 76 (364 448 42 ) (364 446 42 ) (360 446 46 ) (360 448 46 ) +4 77 (356 446 46 ) (356 446 50 ) (356 448 50 ) (356 448 46 ) +4 77 (356 448 46 ) (356 448 50 ) (360 448 50 ) (360 448 46 ) +4 77 (356 446 50 ) (360 446 50 ) (360 448 50 ) (356 448 50 ) +4 77 (356 446 46 ) (356 448 46 ) (360 448 46 ) (360 446 46 ) +4 78 (356 448 38 ) (360 448 38 ) (360 446 38 ) (356 446 38 ) +4 78 (360 446 42 ) (360 448 42 ) (356 448 42 ) (356 446 42 ) +4 78 (356 448 42 ) (360 448 42 ) (360 448 38 ) (356 448 38 ) +4 78 (360 448 42 ) (360 446 42 ) (360 446 38 ) (360 448 38 ) +4 79 (352 446 38 ) (352 448 38 ) (356 448 38 ) (356 446 38 ) +4 79 (356 448 42 ) (356 448 38 ) (352 448 38 ) (352 448 46 ) +4 79 (356 446 42 ) (356 448 42 ) (352 448 46 ) (352 446 46 ) +3 80 (364 448 38 ) (364 448 34 ) (360 448 34 ) +4 80 (360 448 34 ) (360 446 34 ) (364 446 38 ) (364 448 38 ) +4 81 (360 446 34 ) (360 448 34 ) (352 448 34 ) (352 446 34 ) +4 81 (364 448 34 ) (364 448 28 ) (352 448 28 ) (352 448 34 ) +4 82 (348 448 54 ) (348 448 34 ) (348 446 34 ) (348 446 54 ) +4 82 (352 448 34 ) (352 448 38 ) (352 446 38 ) (352 446 34 ) +4 82 (352 448 46 ) (352 448 50 ) (352 446 50 ) (352 446 46 ) +4 82 (352 448 50 ) (352 448 54 ) (352 446 54 ) (352 446 50 ) +4 82 (352 448 28 ) (348 448 28 ) (348 448 60 ) (352 448 60 ) +4 83 (336 446 54 ) (336 448 54 ) (344 448 54 ) (344 446 54 ) +4 83 (344 448 54 ) (348 448 54 ) (348 446 54 ) (344 446 54 ) +4 83 (348 448 54 ) (336 448 54 ) (336 448 95 ) (348 448 95 ) +4 83 (348 446 512 ) (348 448 512 ) (336 448 512 ) (336 446 512 ) +4 84 (344 448 34 ) (348 448 34 ) (348 448 28 ) (344 448 28 ) +4 84 (348 446 34 ) (348 448 34 ) (344 448 34 ) (344 446 34 ) +4 85 (340 448 46 ) (344 448 46 ) (344 446 46 ) (340 446 46 ) +4 85 (340 446 50 ) (344 446 50 ) (344 448 50 ) (340 448 50 ) +4 85 (344 448 46 ) (344 448 50 ) (344 446 50 ) (344 446 46 ) +4 85 (340 448 50 ) (344 448 50 ) (344 448 46 ) (340 448 46 ) +4 85 (340 448 46 ) (340 446 46 ) (340 446 50 ) (340 448 50 ) +4 86 (336 446 38 ) (336 448 38 ) (344 448 38 ) (344 446 38 ) +4 86 (344 448 42 ) (344 448 38 ) (336 448 38 ) (336 448 42 ) +4 86 (344 448 38 ) (344 448 42 ) (344 446 42 ) (344 446 38 ) +4 86 (344 446 42 ) (344 448 42 ) (336 448 42 ) (336 446 42 ) +4 87 (344 446 34 ) (344 448 34 ) (336 448 34 ) (336 446 34 ) +4 87 (344 448 34 ) (344 448 28 ) (336 448 28 ) (336 448 34 ) +4 88 (230 448 48 ) (238 448 48 ) (238 446 48 ) (230 446 48 ) +4 88 (226 448 48 ) (230 448 48 ) (230 446 48 ) (226 446 48 ) +4 88 (336 446 50 ) (336 446 48 ) (336 448 48 ) (336 448 50 ) +4 88 (336 446 54 ) (336 446 50 ) (336 448 50 ) (336 448 54 ) +4 88 (336 448 48 ) (320 448 48 ) (320 448 95 ) (336 448 95 ) +4 88 (224 448 48 ) (224 448 79 ) (256 448 79 ) (256 448 48 ) +4 88 (224 448 79 ) (224 448 80 ) (256 448 80 ) (256 448 79 ) +4 88 (336 446 512 ) (336 448 512 ) (224 448 512 ) (224 446 512 ) +4 89 (238 446 32 ) (238 446 44 ) (238 448 44 ) (238 448 32 ) +4 89 (238 448 28 ) (238 446 28 ) (238 446 32 ) (238 448 32 ) +4 89 (238 446 44 ) (238 446 48 ) (238 448 48 ) (238 448 44 ) +4 89 (238 448 28 ) (238 448 48 ) (256 448 48 ) (256 448 28 ) +4 89 (336 448 48 ) (336 448 28 ) (320 448 28 ) (320 448 48 ) +4 89 (336 446 48 ) (336 446 46 ) (336 448 46 ) (336 448 48 ) +4 89 (336 446 38 ) (336 446 34 ) (336 448 34 ) (336 448 38 ) +4 89 (336 446 46 ) (336 446 42 ) (336 448 42 ) (336 448 46 ) +4 90 (230 446 32 ) (230 448 32 ) (234 448 32 ) (234 446 32 ) +4 90 (230 446 32 ) (230 446 44 ) (230 448 44 ) (230 448 32 ) +4 90 (234 448 44 ) (234 448 32 ) (230 448 32 ) (230 448 44 ) +4 90 (234 446 44 ) (234 448 44 ) (230 448 44 ) (230 446 44 ) +4 90 (234 448 44 ) (234 446 44 ) (234 446 32 ) (234 448 32 ) +4 91 (224 448 48 ) (224 448 28 ) (224 446 28 ) (224 446 48 ) +4 91 (226 448 48 ) (226 446 48 ) (226 446 28 ) (226 448 28 ) +4 91 (226 448 28 ) (224 448 28 ) (224 448 48 ) (226 448 48 ) +4 92 (146 448 48 ) (158 448 48 ) (158 446 48 ) (146 446 48 ) +4 92 (160 448 48 ) (168 448 48 ) (168 446 48 ) (160 446 48 ) +4 92 (168 448 48 ) (172 448 48 ) (172 446 48 ) (168 446 48 ) +4 92 (216 448 48 ) (220 448 48 ) (220 446 48 ) (216 446 48 ) +4 92 (220 448 48 ) (224 448 48 ) (224 446 48 ) (220 446 48 ) +4 92 (212 448 48 ) (216 448 48 ) (216 446 48 ) (212 446 48 ) +4 92 (224 448 48 ) (128 448 48 ) (128 448 79 ) (224 448 79 ) +4 92 (224 448 79 ) (192 448 79 ) (192 448 80 ) (224 448 80 ) +4 92 (64 448 64 ) (64 448 48 ) (0 448 48 ) (0 448 64 ) +4 92 (0 446 512 ) (224 446 512 ) (224 448 512 ) (0 448 512 ) +4 93 (216 446 40 ) (216 446 44 ) (216 448 44 ) (216 448 40 ) +4 93 (216 448 40 ) (216 448 44 ) (220 448 44 ) (220 448 40 ) +4 93 (220 448 40 ) (220 448 44 ) (220 446 44 ) (220 446 40 ) +4 93 (220 446 44 ) (220 448 44 ) (216 448 44 ) (216 446 44 ) +4 93 (216 446 40 ) (216 448 40 ) (220 448 40 ) (220 446 40 ) +4 94 (220 446 36 ) (220 448 36 ) (216 448 36 ) (216 446 36 ) +4 94 (220 448 32 ) (220 448 36 ) (220 446 36 ) (220 446 32 ) +4 94 (216 448 32 ) (216 448 36 ) (220 448 36 ) (220 448 32 ) +4 94 (216 446 32 ) (216 446 36 ) (216 448 36 ) (216 448 32 ) +4 94 (216 446 32 ) (216 448 32 ) (220 448 32 ) (220 446 32 ) +4 95 (172 448 28 ) (172 446 28 ) (172 446 48 ) (172 448 48 ) +4 95 (212 448 48 ) (212 446 48 ) (212 446 28 ) (212 448 28 ) +4 95 (172 448 48 ) (212 448 48 ) (212 448 28 ) (172 448 28 ) +4 96 (164 448 40 ) (168 448 40 ) (168 446 40 ) (164 446 40 ) +4 96 (164 446 44 ) (168 446 44 ) (168 448 44 ) (164 448 44 ) +4 96 (164 448 40 ) (164 448 44 ) (168 448 44 ) (168 448 40 ) +4 96 (168 448 40 ) (168 448 44 ) (168 446 44 ) (168 446 40 ) +4 96 (164 448 40 ) (164 446 40 ) (164 446 44 ) (164 448 44 ) +4 97 (160 448 32 ) (160 448 36 ) (168 448 36 ) (168 448 32 ) +4 97 (168 448 32 ) (168 448 36 ) (168 446 36 ) (168 446 32 ) +4 97 (160 446 32 ) (160 448 32 ) (168 448 32 ) (168 446 32 ) +4 97 (168 446 36 ) (168 448 36 ) (160 448 36 ) (160 446 36 ) +4 98 (160 448 44 ) (160 448 48 ) (160 446 48 ) (160 446 44 ) +4 98 (158 448 48 ) (160 448 48 ) (160 448 44 ) (158 448 44 ) +4 98 (158 448 44 ) (158 446 44 ) (158 446 48 ) (158 448 48 ) +4 99 (146 448 48 ) (146 446 48 ) (146 446 44 ) (146 448 44 ) +4 99 (146 448 48 ) (146 448 44 ) (128 448 44 ) (128 448 48 ) +4 99 (48 448 44 ) (48 448 48 ) (64 448 48 ) (64 448 44 ) +4 100 (48 446 32 ) (48 446 40 ) (48 448 40 ) (48 448 32 ) +4 100 (48 448 28 ) (48 446 28 ) (48 446 32 ) (48 448 32 ) +4 100 (146 446 28 ) (146 448 28 ) (154 448 44 ) (154 446 44 ) +4 100 (154 448 44 ) (146 448 28 ) (128 448 28 ) (128 448 44 ) +4 100 (48 448 44 ) (64 448 44 ) (64 448 28 ) (48 448 28 ) +4 100 (146 446 44 ) (154 446 44 ) (154 448 44 ) (146 448 44 ) +4 101 (160 448 36 ) (160 448 40 ) (160 446 40 ) (160 446 36 ) +4 101 (160 448 40 ) (160 448 44 ) (160 446 44 ) (160 446 40 ) +4 101 (160 448 32 ) (160 446 32 ) (160 446 28 ) (160 448 28 ) +4 101 (158 448 44 ) (160 448 44 ) (160 448 28 ) (150 448 28 ) +4 101 (150 448 28 ) (150 446 28 ) (158 446 44 ) (158 448 44 ) +4 102 (20 448 40 ) (24 448 40 ) (24 446 40 ) (20 446 40 ) +4 102 (36 448 40 ) (40 448 40 ) (40 446 40 ) (36 446 40 ) +4 102 (44 448 40 ) (48 448 40 ) (48 446 40 ) (44 446 40 ) +4 102 (48 448 48 ) (48 448 40 ) (0 448 40 ) (0 448 48 ) +4 103 (44 448 40 ) (44 446 40 ) (44 446 32 ) (44 448 32 ) +4 103 (44 448 32 ) (40 448 32 ) (40 448 40 ) (44 448 40 ) +4 103 (40 448 32 ) (44 448 32 ) (44 446 32 ) (40 446 32 ) +4 103 (40 448 32 ) (40 446 32 ) (40 446 40 ) (40 448 40 ) +4 104 (32 448 28 ) (32 446 28 ) (32 446 32 ) (32 448 32 ) +4 104 (32 448 40 ) (36 448 40 ) (36 448 28 ) (32 448 28 ) +4 104 (36 448 32 ) (36 446 32 ) (36 446 28 ) (36 448 28 ) +4 104 (36 448 32 ) (36 448 40 ) (36 446 40 ) (36 446 32 ) +4 105 (24 446 32 ) (24 446 40 ) (24 448 40 ) (24 448 32 ) +4 105 (24 448 32 ) (24 448 40 ) (32 448 40 ) (32 448 32 ) +4 105 (24 446 32 ) (24 448 32 ) (32 448 32 ) (32 446 32 ) +4 106 (20 448 40 ) (20 446 40 ) (20 446 28 ) (20 448 28 ) +4 106 (20 448 40 ) (20 448 28 ) (0 448 28 ) (0 448 40 ) +4 107 (608 448 0 ) (608 446 0 ) (608 446 28 ) (608 448 28 ) +4 107 (608 448 28 ) (704 448 28 ) (704 448 0 ) (608 448 0 ) +4 107 (832 446 0 ) (608 446 0 ) (608 448 0 ) (832 448 0 ) +4 107 (832 448 28 ) (832 446 28 ) (832 446 0 ) (832 448 0 ) +4 108 (48 446 20 ) (48 446 28 ) (48 448 28 ) (48 448 20 ) +4 108 (512 448 28 ) (512 446 28 ) (512 446 0 ) (512 448 0 ) +4 108 (150 448 28 ) (146 448 28 ) (146 446 28 ) (150 446 28 ) +4 108 (168 448 28 ) (160 448 28 ) (160 446 28 ) (168 446 28 ) +4 108 (172 448 28 ) (168 448 28 ) (168 446 28 ) (172 446 28 ) +4 108 (220 448 28 ) (216 448 28 ) (216 446 28 ) (220 446 28 ) +4 108 (224 448 28 ) (220 448 28 ) (220 446 28 ) (224 446 28 ) +4 108 (216 448 28 ) (212 448 28 ) (212 446 28 ) (216 446 28 ) +4 108 (238 448 28 ) (230 448 28 ) (230 446 28 ) (238 446 28 ) +4 108 (230 448 28 ) (226 448 28 ) (226 446 28 ) (230 446 28 ) +4 108 (384 448 28 ) (448 448 28 ) (448 448 0 ) (384 448 0 ) +4 108 (320 448 28 ) (384 448 28 ) (384 448 0 ) (320 448 0 ) +4 108 (128 448 28 ) (256 448 28 ) (256 448 0 ) (128 448 0 ) +4 108 (48 448 28 ) (64 448 28 ) (64 448 0 ) (48 448 0 ) +4 108 (512 446 0 ) (48 446 0 ) (48 448 0 ) (512 448 0 ) +4 109 (48 446 0 ) (44 446 0 ) (44 448 0 ) (48 448 0 ) +4 109 (44 448 20 ) (48 448 20 ) (48 448 0 ) (44 448 0 ) +4 109 (48 446 20 ) (48 448 20 ) (44 448 20 ) (44 446 20 ) +4 110 (32 446 20 ) (32 446 28 ) (32 448 28 ) (32 448 20 ) +4 110 (44 448 20 ) (44 448 28 ) (44 446 28 ) (44 446 20 ) +4 110 (44 448 28 ) (36 448 28 ) (36 446 28 ) (44 446 28 ) +4 110 (32 448 28 ) (44 448 28 ) (44 448 0 ) (32 448 0 ) +4 110 (44 446 0 ) (32 446 0 ) (32 448 0 ) (44 448 0 ) +4 111 (24 448 24 ) (28 448 24 ) (28 446 24 ) (24 446 24 ) +4 111 (28 448 24 ) (28 448 28 ) (28 446 28 ) (28 446 24 ) +4 111 (28 448 28 ) (24 448 28 ) (24 446 28 ) (28 446 28 ) +4 111 (24 448 24 ) (24 448 28 ) (28 448 28 ) (28 448 24 ) +4 111 (24 448 24 ) (24 446 24 ) (24 446 28 ) (24 448 28 ) +4 112 (20 448 24 ) (20 448 28 ) (20 446 28 ) (20 446 24 ) +4 112 (20 448 24 ) (20 446 24 ) (20 446 20 ) (20 448 20 ) +4 112 (20 448 28 ) (20 448 20 ) (0 448 20 ) (0 448 28 ) +4 113 (32 448 20 ) (32 448 0 ) (0 448 0 ) (0 448 20 ) +4 113 (28 446 20 ) (32 446 20 ) (32 448 20 ) (28 448 20 ) +4 113 (20 446 20 ) (28 446 20 ) (28 448 20 ) (20 448 20 ) +4 113 (0 448 0 ) (32 448 0 ) (32 446 0 ) (0 446 0 ) +4 114 (1024 0 224 ) (1024 0 432 ) (896 0 432 ) (896 0 224 ) +4 114 (1024 0 432 ) (1024 0 512 ) (896 0 512 ) (896 0 432 ) +4 114 (448 32 160 ) (448 0 160 ) (448 0 192 ) (448 32 192 ) +4 114 (448 160 160 ) (448 32 160 ) (448 32 192 ) (448 160 192 ) +4 114 (448 32 192 ) (448 0 192 ) (448 0 320 ) (448 32 320 ) +4 114 (448 160 192 ) (448 32 192 ) (448 32 320 ) (448 160 320 ) +4 114 (832 256 160 ) (832 446 160 ) (1024 446 160 ) (1024 256 160 ) +4 114 (1024 446 512 ) (448 446 512 ) (448 0 512 ) (1024 0 512 ) +4 115 (1024 0 0 ) (832 0 0 ) (832 256 0 ) (1024 256 0 ) +4 115 (1024 256 160 ) (1024 256 0 ) (832 256 0 ) (832 256 160 ) +4 116 (448 160 0 ) (448 32 0 ) (448 32 160 ) (448 160 160 ) +4 116 (832 446 160 ) (832 256 160 ) (832 256 0 ) (832 446 0 ) +4 116 (608 446 0 ) (512 446 0 ) (512 446 28 ) (608 446 28 ) +4 116 (512 446 127 ) (608 446 127 ) (608 446 28 ) (512 446 28 ) +4 116 (640 446 56 ) (640 446 76 ) (644 446 76 ) (644 446 56 ) +4 116 (656 446 68 ) (656 446 64 ) (652 446 60 ) (648 446 60 ) +4 116 (656 446 64 ) (656 446 72 ) (660 446 72 ) (660 446 68 ) +4 116 (648 446 56 ) (648 446 60 ) (660 446 60 ) (660 446 56 ) +4 116 (648 446 72 ) (648 446 76 ) (656 446 76 ) (660 446 72 ) +4 116 (664 446 56 ) (664 446 72 ) (668 446 72 ) (668 446 56 ) +4 116 (668 446 56 ) (668 446 60 ) (672 446 60 ) (672 446 56 ) +4 116 (668 446 64 ) (668 446 68 ) (672 446 68 ) (672 446 64 ) +4 116 (672 446 56 ) (672 446 72 ) (676 446 72 ) (676 446 56 ) +4 116 (664 446 72 ) (664 446 76 ) (676 446 76 ) (676 446 72 ) +4 116 (832 0 0 ) (448 0 0 ) (448 446 0 ) (832 446 0 ) +3 117 (320 160 192 ) (448 160 192 ) (448 160 320 ) +4 117 (0 160 512 ) (448 160 512 ) (448 446 512 ) (0 446 512 ) +4 118 (32 32 192 ) (0 32 192 ) (0 128 192 ) (32 128 192 ) +3 118 (384 32 256 ) (448 32 320 ) (384 32 320 ) +4 118 (0 160 512 ) (0 32 512 ) (448 32 512 ) (448 160 512 ) +4 118 (448 32 320 ) (320 32 192 ) (320 160 192 ) (448 160 320 ) +4 119 (384 32 512 ) (384 0 512 ) (448 0 512 ) (448 32 512 ) +4 119 (384 0 320 ) (384 32 320 ) (448 32 320 ) (448 0 320 ) +4 120 (32 0 192 ) (0 0 192 ) (0 32 192 ) (32 32 192 ) +4 120 (384 0 320 ) (384 0 192 ) (384 32 192 ) (384 32 320 ) +4 120 (384 32 512 ) (0 32 512 ) (0 0 512 ) (384 0 512 ) +3 120 (384 32 256 ) (384 32 192 ) (320 32 192 ) +4 121 (384 160 192 ) (384 160 0 ) (448 160 0 ) (448 160 192 ) +4 121 (384 446 0 ) (448 446 0 ) (448 160 0 ) (384 160 0 ) +4 121 (420 446 40 ) (416 446 40 ) (416 446 60 ) (420 446 60 ) +4 121 (420 446 56 ) (420 446 60 ) (428 446 60 ) (428 446 56 ) +4 121 (420 446 40 ) (420 446 44 ) (428 446 44 ) (428 446 40 ) +4 121 (424 446 44 ) (424 446 52 ) (428 446 52 ) (428 446 44 ) +4 121 (424 446 48 ) (420 446 48 ) (420 446 52 ) (424 446 52 ) +4 121 (408 446 40 ) (408 446 60 ) (412 446 60 ) (412 446 40 ) +4 121 (400 446 56 ) (400 446 60 ) (408 446 60 ) (408 446 56 ) +4 121 (400 446 48 ) (400 446 52 ) (408 446 52 ) (408 446 48 ) +4 121 (404 446 52 ) (400 446 52 ) (400 446 56 ) (404 446 56 ) +4 121 (400 446 40 ) (400 446 44 ) (408 446 44 ) (408 446 40 ) +4 122 (448 32 160 ) (448 32 0 ) (384 32 0 ) (384 32 160 ) +4 122 (448 32 0 ) (448 0 0 ) (384 0 0 ) (384 32 0 ) +4 122 (448 0 160 ) (448 32 160 ) (384 32 160 ) (384 0 160 ) +4 123 (0 128 0 ) (32 128 0 ) (32 128 192 ) (0 128 192 ) +4 123 (384 128 192 ) (384 160 192 ) (320 160 192 ) (320 128 192 ) +4 123 (0 446 0 ) (384 446 0 ) (384 128 0 ) (0 128 0 ) +4 123 (352 446 50 ) (352 446 54 ) (364 446 54 ) (364 446 50 ) +4 123 (360 446 38 ) (360 446 46 ) (364 446 42 ) (364 446 38 ) +4 123 (360 446 46 ) (360 446 42 ) (356 446 42 ) (356 446 46 ) +4 123 (356 446 42 ) (352 446 46 ) (352 446 50 ) (356 446 50 ) +4 123 (360 446 34 ) (352 446 34 ) (352 446 38 ) (364 446 38 ) +4 123 (344 446 34 ) (344 446 54 ) (348 446 54 ) (348 446 34 ) +4 123 (336 446 50 ) (336 446 54 ) (344 446 54 ) (344 446 50 ) +4 123 (340 446 46 ) (336 446 46 ) (336 446 50 ) (340 446 50 ) +4 123 (336 446 34 ) (336 446 38 ) (344 446 38 ) (344 446 34 ) +4 123 (336 446 42 ) (336 446 46 ) (344 446 46 ) (344 446 42 ) +4 123 (226 446 48 ) (230 446 48 ) (230 446 28 ) (226 446 28 ) +4 123 (230 446 44 ) (230 446 48 ) (238 446 48 ) (238 446 44 ) +4 123 (230 446 32 ) (238 446 32 ) (238 446 28 ) (230 446 28 ) +4 123 (234 446 32 ) (234 446 44 ) (238 446 44 ) (238 446 32 ) +4 123 (212 446 48 ) (216 446 48 ) (216 446 28 ) (212 446 28 ) +4 123 (220 446 48 ) (224 446 48 ) (224 446 28 ) (220 446 28 ) +4 123 (216 446 32 ) (220 446 32 ) (220 446 28 ) (216 446 28 ) +4 123 (216 446 44 ) (216 446 48 ) (220 446 48 ) (220 446 44 ) +4 123 (216 446 36 ) (216 446 40 ) (220 446 40 ) (220 446 36 ) +4 123 (168 446 48 ) (172 446 48 ) (172 446 28 ) (168 446 28 ) +4 123 (160 446 44 ) (160 446 48 ) (168 446 48 ) (168 446 44 ) +4 123 (160 446 32 ) (168 446 32 ) (168 446 28 ) (160 446 28 ) +4 123 (164 446 40 ) (160 446 40 ) (160 446 44 ) (164 446 44 ) +4 123 (160 446 36 ) (160 446 40 ) (168 446 40 ) (168 446 36 ) +4 123 (158 446 44 ) (146 446 44 ) (146 446 48 ) (158 446 48 ) +4 123 (154 446 44 ) (158 446 44 ) (150 446 28 ) (146 446 28 ) +4 123 (36 446 32 ) (48 446 32 ) (48 446 28 ) (36 446 28 ) +4 123 (44 446 32 ) (44 446 40 ) (48 446 40 ) (48 446 32 ) +4 123 (40 446 32 ) (36 446 32 ) (36 446 40 ) (40 446 40 ) +4 123 (20 446 40 ) (24 446 40 ) (24 446 28 ) (20 446 28 ) +4 123 (24 446 32 ) (32 446 32 ) (32 446 28 ) (24 446 28 ) +4 123 (48 446 20 ) (44 446 20 ) (44 446 28 ) (48 446 28 ) +4 123 (28 446 28 ) (32 446 28 ) (32 446 20 ) (28 446 20 ) +4 123 (20 446 24 ) (28 446 24 ) (28 446 20 ) (20 446 20 ) +4 123 (24 446 24 ) (20 446 24 ) (20 446 28 ) (24 446 28 ) +4 123 (384 160 192 ) (384 128 192 ) (384 128 0 ) (384 160 0 ) +4 124 (384 32 160 ) (384 32 192 ) (384 0 192 ) (384 0 160 ) +4 124 (384 128 192 ) (384 32 192 ) (384 32 0 ) (384 128 0 ) +4 124 (384 128 0 ) (384 0 0 ) (32 0 0 ) (32 128 0 ) +4 124 (384 128 192 ) (320 128 192 ) (320 32 192 ) (384 32 192 ) +4 124 (32 128 192 ) (32 128 0 ) (32 0 0 ) (32 0 192 ) +4 125 (896 -128 512 ) (896 0 512 ) (0 0 512 ) (0 -128 512 ) +4 125 (896 0 512 ) (896 -128 512 ) (896 -128 432 ) (896 0 432 ) +4 126 (372 -272 432 ) (380 -272 432 ) (380 -364 432 ) (372 -364 432 ) +4 126 (0 -268 432 ) (0 -260 432 ) (380 -260 432 ) (380 -268 432 ) +4 126 (372 -268 432 ) (380 -268 432 ) (380 -272 432 ) (372 -272 432 ) +4 126 (384 -356 432 ) (384 -364 432 ) (380 -364 432 ) (380 -356 432 ) +4 126 (1024 -356 432 ) (1024 -364 432 ) (384 -364 432 ) (384 -356 432 ) +4 126 (0 -188 432 ) (0 -180 432 ) (1024 -180 432 ) (1024 -188 432 ) +4 126 (896 -128 512 ) (1024 -128 512 ) (1024 -128 432 ) (896 -128 432 ) +4 126 (1024 -128 512 ) (0 -128 512 ) (0 -960 512 ) (1024 -960 512 ) +4 126 (0 -960 512 ) (0 -960 432 ) (1024 -960 432 ) (1024 -960 512 ) +4 127 (1024 -128 160 ) (896 -128 160 ) (896 -64 160 ) (1024 -64 160 ) +4 127 (1024 0 224 ) (896 0 224 ) (896 -128 224 ) (1024 -128 224 ) +4 128 (896 0 0 ) (1024 0 0 ) (1024 -64 0 ) (896 -64 0 ) +4 128 (1024 -64 160 ) (896 -64 160 ) (896 -64 0 ) (1024 -64 0 ) +4 129 (448 -96 0 ) (448 -128 0 ) (448 -128 160 ) (448 -96 160 ) +4 129 (448 -128 160 ) (448 -128 192 ) (448 0 192 ) (448 0 160 ) +4 129 (448 -128 192 ) (448 -128 320 ) (448 -96 320 ) (448 -96 192 ) +4 129 (448 0 320 ) (448 0 192 ) (448 -96 192 ) (448 -96 320 ) +4 129 (896 -64 160 ) (896 -128 160 ) (896 -128 0 ) (896 -64 0 ) +4 129 (896 0 224 ) (896 0 432 ) (896 -128 432 ) (896 -128 224 ) +4 129 (448 -128 0 ) (448 0 0 ) (896 0 0 ) (896 -128 0 ) +4 130 (1024 -180 416 ) (1024 -176 420 ) (448 -176 420 ) (448 -180 416 ) +4 130 (448 -128 0 ) (448 -224 0 ) (448 -224 160 ) (448 -128 160 ) +4 130 (448 -224 160 ) (448 -224 192 ) (448 -128 192 ) (448 -128 160 ) +4 130 (448 -224 192 ) (448 -224 320 ) (448 -128 320 ) (448 -128 192 ) +4 130 (896 -128 160 ) (1024 -128 160 ) (1024 -128 0 ) (896 -128 0 ) +4 130 (896 -128 224 ) (896 -128 432 ) (1024 -128 432 ) (1024 -128 224 ) +4 130 (1024 -224 0 ) (448 -224 0 ) (448 -128 0 ) (1024 -128 0 ) +4 130 (1024 -224 0 ) (1024 -192 0 ) (1024 -192 128 ) (1024 -224 128 ) +4 131 (448 -96 320 ) (384 -96 320 ) (384 0 320 ) (448 0 320 ) +4 132 (64 -96 192 ) (0 -96 192 ) (0 -64 192 ) (64 -64 192 ) +3 132 (320 -96 192 ) (384 -96 192 ) (384 -96 256 ) +4 132 (384 0 320 ) (384 -96 320 ) (384 -96 192 ) (384 0 192 ) +4 133 (448 -180 416 ) (448 -176 420 ) (0 -176 420 ) (0 -180 416 ) +4 133 (0 -192 192 ) (0 -96 192 ) (64 -96 192 ) (64 -192 192 ) +3 133 (384 -96 256 ) (384 -96 320 ) (448 -96 320 ) +4 133 (320 -224 192 ) (320 -96 192 ) (448 -96 320 ) (448 -224 320 ) +4 134 (448 -96 160 ) (448 0 160 ) (384 0 160 ) (384 -96 160 ) +4 134 (384 -96 0 ) (384 0 0 ) (448 0 0 ) (448 -96 0 ) +4 134 (448 -96 0 ) (448 -96 160 ) (384 -96 160 ) (384 -96 0 ) +4 135 (0 -64 0 ) (64 -64 0 ) (64 -64 192 ) (0 -64 192 ) +4 135 (0 -64 0 ) (0 0 0 ) (384 0 0 ) (384 -64 0 ) +4 135 (32 0 192 ) (32 0 0 ) (0 0 0 ) (0 0 192 ) +4 135 (384 -64 160 ) (384 0 160 ) (384 0 192 ) (384 -64 192 ) +4 136 (64 -64 192 ) (64 -64 0 ) (64 -192 0 ) (64 -192 192 ) +4 136 (384 -96 160 ) (384 -224 160 ) (384 -224 0 ) (384 -96 0 ) +4 136 (384 -64 160 ) (384 -64 192 ) (384 -224 192 ) (384 -224 160 ) +4 136 (384 -224 0 ) (64 -224 0 ) (64 -64 0 ) (384 -64 0 ) +4 136 (384 -96 192 ) (320 -96 192 ) (320 -224 192 ) (384 -224 192 ) +4 137 (64 -224 0 ) (0 -224 0 ) (0 -192 0 ) (64 -192 0 ) +4 137 (0 -192 192 ) (64 -192 192 ) (64 -192 0 ) (0 -192 0 ) +4 138 (0 -176 420 ) (1024 -176 420 ) (1024 -176 428 ) (0 -176 428 ) +4 139 (1024 -192 428 ) (0 -192 428 ) (0 -188 432 ) (1024 -188 432 ) +4 140 (1024 -188 416 ) (0 -188 416 ) (0 -192 420 ) (1024 -192 420 ) +4 141 (0 -176 428 ) (1024 -176 428 ) (1024 -180 432 ) (0 -180 432 ) +4 142 (1024 -188 416 ) (1024 -180 416 ) (0 -180 416 ) (0 -188 416 ) +4 143 (0 -192 420 ) (0 -192 428 ) (1024 -192 428 ) (1024 -192 420 ) +4 144 (128 -256 0 ) (192 -256 0 ) (192 -256 192 ) (128 -256 192 ) +4 144 (832 -256 160 ) (768 -256 160 ) (768 -256 0 ) (832 -256 0 ) +4 144 (384 -256 428 ) (0 -256 428 ) (0 -256 419.994049 ) (384 -256 419.994049 ) +4 144 (1024 -256 0 ) (1024 -224 0 ) (1024 -224 128 ) (1024 -256 128 ) +3 144 (448 -224 320 ) (448 -224 192 ) (320 -224 192 ) +4 144 (384 -224 160 ) (384 -224 192 ) (448 -224 192 ) (448 -224 160 ) +4 144 (384 -224 160 ) (448 -224 160 ) (448 -224 0 ) (384 -224 0 ) +4 144 (1024 -256 0 ) (0 -256 0 ) (0 -224 0 ) (1024 -224 0 ) +4 145 (384 -368 428 ) (368 -368 428 ) (372 -364 432 ) (380 -364 432 ) +3 145 (384 -368 428 ) (380 -364 432 ) (384 -364 432 ) +4 145 (1024 -368 428 ) (384 -368 428 ) (384 -364 432 ) (1024 -364 432 ) +4 146 (0 -259.994476 416 ) (380 -259.994476 416 ) (383.994324 -256 419.994324 ) (0 -256 419.994324 ) +4 147 (380 -364 416 ) (372 -364 416 ) (368 -368 420 ) (384 -368 420 ) +3 147 (384 -364 416 ) (380 -364 416 ) (384 -368 420 ) +4 147 (1024 -364 416 ) (384 -364 416 ) (384 -368 420 ) (1024 -368 420 ) +4 148 (0 -256 428 ) (384 -256 428 ) (380 -260 432 ) (0 -260 432 ) +4 149 (384 -272 420 ) (384 -352 420 ) (384 -352 428 ) (384 -272 428 ) +4 149 (384 -256 428 ) (384 -256 420 ) (384 -272 420 ) (384 -272 428 ) +4 149 (384 -352 428 ) (384 -352 420 ) (1024 -352 420 ) (1024 -352 428 ) +4 150 (1024 -352 420 ) (384 -352 420 ) (384 -356 416 ) (1024 -356 416 ) +4 151 (384 -356 432 ) (384 -352 428 ) (1024 -352 428 ) (1024 -356 432 ) +4 152 (384 -272 428 ) (384 -352 428 ) (380 -356 432 ) (380 -272 432 ) +4 152 (380 -260 432 ) (384 -256 428 ) (384 -272 428 ) (380 -268 432 ) +3 152 (384 -272 428 ) (380 -272 432 ) (380 -268 432 ) +3 152 (380 -356 432 ) (384 -352 428 ) (384 -356 432 ) +4 153 (384 -352 420 ) (384 -272 420 ) (380 -272 416 ) (380 -356 416 ) +3 153 (384 -272 420 ) (380 -268 416 ) (380 -272 416 ) +5 153 (384 -272 420 ) (384 -256 420 ) (383.994171 -256 419.994019 ) (380 -259.994019 416 ) (380 -268 416 ) +3 153 (384 -352 420 ) (380 -356 416 ) (384 -356 416 ) +4 154 (368 -272 428 ) (0 -272 428 ) (0 -268 432 ) (372 -268 432 ) +3 154 (372 -272 432 ) (368 -272 428 ) (372 -268 432 ) +4 155 (0 -272 420 ) (368 -272 420 ) (372 -268 416 ) (0 -268 416 ) +3 155 (372 -268 416 ) (368 -272 420 ) (372 -272 416 ) +4 156 (372 -272 416 ) (368 -272 420 ) (368 -368 420 ) (372 -364 416 ) +4 157 (368 -368 428 ) (368 -272 428 ) (372 -272 432 ) (372 -364 432 ) +4 158 (368 -368 428 ) (368 -368 420 ) (368 -272 420 ) (368 -272 428 ) +4 158 (368 -272 420 ) (0 -272 420 ) (0 -272 428 ) (368 -272 428 ) +4 159 (384 -368 420 ) (368 -368 420 ) (368 -368 428 ) (384 -368 428 ) +4 159 (384 -368 420 ) (384 -368 428 ) (1024 -368 428 ) (1024 -368 420 ) +4 159 (0 -960 432 ) (0 -960 416 ) (1024 -960 416 ) (1024 -960 432 ) +4 160 (56 -632 368 ) (56 -576 368 ) (152 -576 368 ) (152 -632 368 ) +4 160 (372 -364 416 ) (380 -364 416 ) (380 -272 416 ) (372 -272 416 ) +4 160 (372 -272 416 ) (380 -272 416 ) (380 -268 416 ) (372 -268 416 ) +4 160 (380 -268 416 ) (380 -259.994049 416 ) (0 -259.994049 416 ) (0 -268 416 ) +4 160 (380 -356 416 ) (380 -364 416 ) (384 -364 416 ) (384 -356 416 ) +4 160 (384 -356 416 ) (384 -364 416 ) (1024 -364 416 ) (1024 -356 416 ) +4 160 (0 -960 416 ) (0 -960 368 ) (1024 -960 368 ) (1024 -960 416 ) +4 161 (152 -576 328 ) (152 -632 328 ) (152 -632 368 ) (152 -576 368 ) +4 161 (1024 -960 328 ) (1024 -960 368 ) (152 -960 368 ) (152 -960 328 ) +4 162 (56 -576 368 ) (56 -576 328 ) (152 -576 328 ) (152 -576 368 ) +4 163 (152 -960 368 ) (56 -960 368 ) (56 -960 328 ) (152 -960 328 ) +4 163 (152 -632 368 ) (152 -632 328 ) (56 -632 328 ) (56 -632 368 ) +4 164 (160 -960 256 ) (56 -960 256 ) (56 -816 256 ) (160 -816 256 ) +4 164 (152 -632 328 ) (152 -576 328 ) (56 -576 328 ) (56 -632 328 ) +4 164 (56 -960 256 ) (1024 -960 256 ) (1024 -960 328 ) (56 -960 328 ) +4 165 (56 -960 256 ) (0 -960 256 ) (0 -816 256 ) (56 -816 256 ) +3 165 (0 -816 256 ) (0 -808 256 ) (16 -816 256 ) +4 165 (56 -632 328 ) (56 -576 328 ) (56 -576 368 ) (56 -632 368 ) +4 165 (0 -960 368 ) (0 -960 256 ) (56 -960 256 ) (56 -960 368 ) +4 166 (256 -576 192 ) (256 -448 192 ) (256 -448 160 ) (256 -576 160 ) +9 166 (704 -640 160 ) (512 -640 160 ) (512 -448 160 ) (544 -384 160 ) (640 -288 160 ) (768 -256 160 ) (832 -256 160 ) (896 -320 160 ) (896 -448 160 ) +4 167 (896 -320 0 ) (896 -448 0 ) (896 -448 160 ) (896 -320 160 ) +4 167 (896 -256 0 ) (1024 -256 0 ) (1024 -640 0 ) (896 -640 0 ) +4 167 (1024 -320 0 ) (1024 -256 0 ) (1024 -256 128 ) (1024 -320 128 ) +4 168 (512 -448 160 ) (512 -448 0 ) (544 -384 0 ) (544 -384 160 ) +3 168 (512 -256 0 ) (608 -256 0 ) (512 -448 0 ) +4 169 (832 -256 0 ) (896 -320 0 ) (896 -320 160 ) (832 -256 160 ) +3 169 (832 -256 0 ) (896 -256 0 ) (896 -320 0 ) +4 170 (544 -384 160 ) (544 -384 0 ) (640 -288 0 ) (640 -288 160 ) +3 170 (608 -256 0 ) (672 -256 0 ) (544 -384 0 ) +4 171 (896 -448 160 ) (896 -448 0 ) (704 -640 0 ) (704 -640 160 ) +3 171 (896 -448 0 ) (896 -640 0 ) (704 -640 0 ) +3 172 (672 -256 0 ) (768 -256 0 ) (640 -288 0 ) +4 172 (640 -288 160 ) (640 -288 0 ) (768 -256 0 ) (768 -256 160 ) +4 173 (256 -448 0 ) (256 -576 0 ) (256 -576 160 ) (256 -448 160 ) +4 173 (512 -448 160 ) (512 -640 160 ) (512 -640 0 ) (512 -448 0 ) +4 173 (256 -256 0 ) (512 -256 0 ) (512 -640 0 ) (256 -640 0 ) +4 174 (256 -448 192 ) (256 -576 192 ) (192 -576 192 ) (192 -448 192 ) +4 175 (192 -256 192 ) (192 -256 0 ) (192 -384 0 ) (192 -384 192 ) +4 175 (192 -448 0 ) (192 -256 0 ) (256 -256 0 ) (256 -448 0 ) +4 175 (192 -448 0 ) (256 -448 0 ) (256 -448 192 ) (192 -448 192 ) +4 176 (192 -576 192 ) (256 -576 192 ) (256 -576 0 ) (192 -576 0 ) +4 176 (192 -640 0 ) (192 -576 0 ) (256 -576 0 ) (256 -640 0 ) +4 177 (1024 -960 128 ) (1024 -960 256 ) (848 -960 256 ) (848 -960 128 ) +4 177 (848 -704 0 ) (848 -640 0 ) (1024 -640 0 ) (1024 -704 0 ) +4 177 (1024 -960 128 ) (848 -960 128 ) (848 -704 0 ) (1024 -704 0 ) +3 178 (784 -832 0 ) (784 -960 0 ) (784 -960 128 ) +4 178 (848 -960 256 ) (784 -960 256 ) (784 -960 0 ) (848 -960 0 ) +4 178 (848 -960 0 ) (784 -960 0 ) (784 -640 0 ) (848 -640 0 ) +3 178 (848 -960 128 ) (848 -960 0 ) (848 -704 0 ) +4 179 (528 -640 160 ) (704 -640 160 ) (704 -640 0 ) (528 -640 0 ) +4 179 (528 -832 0 ) (528 -640 0 ) (784 -640 0 ) (784 -832 0 ) +4 179 (784 -960 256 ) (528 -960 256 ) (528 -960 128 ) (784 -960 128 ) +4 179 (528 -960 128 ) (528 -832 0 ) (784 -832 0 ) (784 -960 128 ) +3 180 (464 -832 0 ) (464 -960 0 ) (464 -960 256 ) +4 180 (512 -640 160 ) (528 -640 160 ) (528 -640 0 ) (512 -640 0 ) +4 180 (528 -960 0 ) (464 -960 0 ) (464 -640 0 ) (528 -640 0 ) +4 180 (528 -960 256 ) (464 -960 256 ) (464 -960 0 ) (528 -960 0 ) +3 180 (528 -960 128 ) (528 -960 0 ) (528 -832 0 ) +4 181 (208 -832 0 ) (208 -640 0 ) (464 -640 0 ) (464 -832 0 ) +4 181 (208 -960 256 ) (208 -832 0 ) (464 -832 0 ) (464 -960 256 ) +3 182 (208 -960 256 ) (208 -960 0 ) (208 -832 0 ) +4 182 (208 -960 256 ) (192 -960 256 ) (192 -960 0 ) (208 -960 0 ) +4 182 (208 -960 0 ) (192 -960 0 ) (192 -640 0 ) (208 -640 0 ) +4 183 (192 -384 192 ) (128 -384 192 ) (128 -256 192 ) (192 -256 192 ) +4 184 (128 -272 16 ) (128 -368 16 ) (0 -368 16 ) (0 -272 16 ) +4 184 (128 -256 16 ) (128 -256 192 ) (128 -384 192 ) (128 -384 16 ) +4 185 (128 -256 16 ) (128 -272 16 ) (128 -272 0 ) (128 -256 0 ) +4 185 (0 -256 0 ) (128 -256 0 ) (128 -272 0 ) (0 -272 0 ) +4 185 (0 -272 0 ) (128 -272 0 ) (128 -272 16 ) (0 -272 16 ) +4 186 (0 -368 16 ) (128 -368 16 ) (128 -368 0 ) (0 -368 0 ) +4 186 (128 -368 0 ) (128 -384 0 ) (0 -384 0 ) (0 -368 0 ) +4 186 (128 -368 16 ) (128 -384 16 ) (128 -384 0 ) (128 -368 0 ) +4 187 (160 -816 256 ) (16 -816 256 ) (16 -816 128 ) (160 -816 128 ) +3 187 (0 -808 128 ) (0 -798 128 ) (20 -808 128 ) +4 187 (96 -816 128 ) (16 -816 128 ) (0 -808 128 ) (96 -808 128 ) +4 187 (160 -816 128 ) (96 -816 128 ) (96 -752 128 ) (160 -752 128 ) +4 187 (128 -384 128 ) (128 -384 192 ) (192 -384 192 ) (192 -384 128 ) +4 187 (192 -448 128 ) (192 -448 192 ) (192 -576 192 ) (192 -576 128 ) +4 187 (0 -808 128 ) (16 -816 128 ) (16 -816 256 ) (0 -808 256 ) +4 188 (192 -560 16 ) (0 -560 16 ) (0 -464 16 ) (192 -464 16 ) +4 188 (192 -448 16 ) (192 -448 128 ) (192 -560 128 ) (192 -560 16 ) +4 188 (128 -384 16 ) (128 -384 128 ) (192 -384 128 ) (192 -384 16 ) +4 189 (128 -384 16 ) (192 -384 16 ) (192 -384 0 ) (128 -384 0 ) +4 189 (192 -448 16 ) (192 -464 16 ) (192 -464 0 ) (192 -448 0 ) +4 189 (192 -384 0 ) (192 -464 0 ) (0 -464 0 ) (0 -384 0 ) +4 189 (0 -464 0 ) (192 -464 0 ) (192 -464 16 ) (0 -464 16 ) +4 190 (96 -752 0 ) (160 -752 0 ) (160 -752 128 ) (96 -752 128 ) +4 190 (192 -560 0 ) (192 -752 0 ) (0 -752 0 ) (0 -560 0 ) +4 190 (192 -560 128 ) (192 -576 128 ) (192 -576 0 ) (192 -560 0 ) +4 190 (0 -560 16 ) (192 -560 16 ) (192 -560 0 ) (0 -560 0 ) +4 191 (192 -752 0 ) (192 -816 0 ) (160 -816 0 ) (160 -752 0 ) +4 191 (160 -752 128 ) (160 -752 0 ) (160 -816 0 ) (160 -816 128 ) +4 192 (20 -808 0 ) (96 -808 0 ) (96 -808 128 ) (20 -808 128 ) +4 192 (96 -808 128 ) (96 -808 0 ) (96 -752 0 ) (96 -752 128 ) +5 192 (0 -798 0 ) (0 -752 0 ) (96 -752 0 ) (96 -808 0 ) (20 -808 0 ) +4 192 (0 -798 0 ) (20 -808 0 ) (20 -808 128 ) (0 -798 128 ) +4 193 (160 -960 0 ) (192 -960 0 ) (192 -960 256 ) (160 -960 256 ) +4 193 (192 -816 0 ) (192 -960 0 ) (160 -960 0 ) (160 -816 0 ) +4 193 (160 -816 256 ) (160 -816 0 ) (160 -960 0 ) (160 -960 256 ) +4 194 (0 448 63 ) (-64 448 63 ) (-64 640 63 ) (0 640 63 ) +4 194 (0 640 63 ) (0 640 64 ) (0 448 64 ) (0 448 63 ) +4 194 (-704 448 63 ) (-704 448 512 ) (-704 640 512 ) (-704 640 63 ) +4 194 (0 640 512 ) (0 640 63 ) (-704 640 63 ) (-704 640 512 ) +4 194 (0 640 512 ) (-704 640 512 ) (-704 448 512 ) (0 448 512 ) +4 195 (-224 640 48 ) (-160 640 48 ) (-160 448 48 ) (-224 448 48 ) +4 195 (-64 640 48 ) (-64 640 63 ) (-64 448 63 ) (-64 448 48 ) +4 195 (-288 640 48 ) (-288 640 63 ) (-64 640 63 ) (-64 640 48 ) +4 196 (-64 640 48 ) (-64 448 48 ) (-64 448 0 ) (-64 640 0 ) +4 196 (-64 448 0 ) (-160 448 0 ) (-160 640 0 ) (-64 640 0 ) +4 196 (-160 640 48 ) (-64 640 48 ) (-64 640 0 ) (-160 640 0 ) +4 196 (-160 640 0 ) (-160 448 0 ) (-160 448 48 ) (-160 640 48 ) +4 197 (-288 640 47 ) (-288 640 48 ) (-224 640 48 ) (-224 640 47 ) +4 197 (-224 640 47 ) (-224 640 48 ) (-224 448 48 ) (-224 448 47 ) +4 197 (-288 448 47 ) (-288 640 47 ) (-224 640 47 ) (-224 448 47 ) +4 198 (-448 640 32 ) (-384 640 32 ) (-384 448 32 ) (-448 448 32 ) +4 198 (-288 640 32 ) (-288 640 47 ) (-288 448 47 ) (-288 448 32 ) +4 198 (-512 640 32 ) (-512 640 63 ) (-288 640 63 ) (-288 640 32 ) +4 199 (-288 640 32 ) (-288 448 32 ) (-288 448 0 ) (-288 640 0 ) +4 199 (-288 448 0 ) (-384 448 0 ) (-384 640 0 ) (-288 640 0 ) +4 199 (-384 640 32 ) (-288 640 32 ) (-288 640 0 ) (-384 640 0 ) +4 199 (-384 640 0 ) (-384 448 0 ) (-384 448 32 ) (-384 640 32 ) +4 200 (-512 640 31 ) (-512 640 32 ) (-448 640 32 ) (-448 640 31 ) +4 200 (-448 640 31 ) (-448 640 32 ) (-448 448 32 ) (-448 448 31 ) +4 200 (-512 448 31 ) (-512 640 31 ) (-448 640 31 ) (-448 448 31 ) +4 201 (-512 640 31 ) (-512 448 31 ) (-512 448 0 ) (-512 640 0 ) +4 201 (-704 448 0 ) (-704 448 63 ) (-704 640 63 ) (-704 640 0 ) +4 201 (-512 640 63 ) (-512 640 0 ) (-704 640 0 ) (-704 640 63 ) +4 201 (-512 448 0 ) (-704 448 0 ) (-704 640 0 ) (-512 640 0 ) +4 202 (-44 446 40 ) (-48 446 40 ) (-48 448 40 ) (-44 448 40 ) +4 202 (-24 446 40 ) (-32 446 40 ) (-32 448 40 ) (-24 448 40 ) +4 202 (-704 446 40 ) (-704 446 512 ) (-704 448 512 ) (-704 448 40 ) +4 202 (-64 448 40 ) (-64 448 63 ) (0 448 63 ) (0 448 40 ) +4 202 (-224 448 40 ) (-224 448 48 ) (-160 448 48 ) (-160 448 40 ) +4 202 (-288 448 40 ) (-288 448 47 ) (-224 448 47 ) (-224 448 40 ) +4 202 (0 448 512 ) (-704 448 512 ) (-704 446 512 ) (0 446 512 ) +4 203 (-20 448 32 ) (-20 446 32 ) (-20 446 36 ) (-20 448 36 ) +4 203 (-20 448 32 ) (-20 448 40 ) (0 448 40 ) (0 448 32 ) +3 204 (-20 448 36 ) (-24 448 40 ) (-20 448 40 ) +4 204 (-20 448 36 ) (-20 446 36 ) (-24 446 40 ) (-24 448 40 ) +4 205 (-24 446 32 ) (-28 446 32 ) (-28 448 32 ) (-24 448 32 ) +4 205 (-24 448 36 ) (-24 448 32 ) (-32 448 32 ) (-32 448 36 ) +4 205 (-24 446 36 ) (-24 448 36 ) (-32 448 36 ) (-32 446 36 ) +4 205 (-24 448 36 ) (-24 446 36 ) (-24 446 32 ) (-24 448 32 ) +4 206 (-40 446 32 ) (-44 446 32 ) (-44 448 32 ) (-40 448 32 ) +4 206 (-36 446 32 ) (-40 446 32 ) (-40 448 32 ) (-36 448 32 ) +4 206 (-44 448 32 ) (-44 446 32 ) (-44 446 40 ) (-44 448 40 ) +4 206 (-32 448 32 ) (-44 448 32 ) (-44 448 40 ) (-32 448 40 ) +4 206 (-32 448 36 ) (-32 448 40 ) (-32 446 40 ) (-32 446 36 ) +4 207 (-264 446 32 ) (-268 446 32 ) (-268 448 32 ) (-264 448 32 ) +4 207 (-240 446 32 ) (-252 446 32 ) (-252 448 32 ) (-240 448 32 ) +4 207 (-256 446 32 ) (-260 446 32 ) (-260 448 32 ) (-256 448 32 ) +4 207 (-198 446 32 ) (-202 446 32 ) (-202 448 32 ) (-198 448 32 ) +4 207 (-182 446 32 ) (-186 446 32 ) (-186 448 32 ) (-182 448 32 ) +4 207 (-178 446 32 ) (-182 446 32 ) (-182 448 32 ) (-178 448 32 ) +4 207 (-190 446 32 ) (-194 446 32 ) (-194 448 32 ) (-190 448 32 ) +4 207 (-174 446 32 ) (-178 446 32 ) (-178 448 32 ) (-174 448 32 ) +4 207 (-704 446 32 ) (-704 446 40 ) (-704 448 40 ) (-704 448 32 ) +4 207 (-48 448 32 ) (-64 448 32 ) (-64 448 40 ) (-48 448 40 ) +4 207 (-224 448 32 ) (-224 448 40 ) (-160 448 40 ) (-160 448 32 ) +4 207 (-288 448 32 ) (-288 448 40 ) (-224 448 40 ) (-224 448 32 ) +4 207 (-48 448 40 ) (-48 446 40 ) (-48 446 32 ) (-48 448 32 ) +4 208 (-20 448 24 ) (-20 446 24 ) (-20 446 32 ) (-20 448 32 ) +4 208 (-20 448 24 ) (-20 448 32 ) (0 448 32 ) (0 448 24 ) +4 209 (-24 446 24 ) (-28 446 24 ) (-28 448 24 ) (-24 448 24 ) +4 209 (-24 448 28 ) (-24 448 24 ) (-28 448 24 ) (-28 448 28 ) +4 209 (-24 448 28 ) (-24 446 28 ) (-24 446 24 ) (-24 448 24 ) +4 209 (-24 446 28 ) (-24 448 28 ) (-28 448 28 ) (-28 446 28 ) +4 210 (-28 446 24 ) (-32 446 24 ) (-32 448 24 ) (-28 448 24 ) +4 210 (-36 448 24 ) (-36 446 24 ) (-36 446 32 ) (-36 448 32 ) +4 210 (-28 448 28 ) (-28 448 32 ) (-28 446 32 ) (-28 446 28 ) +4 210 (-28 448 24 ) (-36 448 24 ) (-36 448 32 ) (-28 448 32 ) +4 211 (-40 446 24 ) (-44 446 24 ) (-44 448 24 ) (-40 448 24 ) +4 211 (-44 448 24 ) (-44 446 24 ) (-44 446 28 ) (-44 448 28 ) +4 211 (-40 448 28 ) (-40 446 28 ) (-40 446 24 ) (-40 448 24 ) +4 211 (-40 448 28 ) (-40 448 24 ) (-44 448 24 ) (-44 448 28 ) +4 211 (-40 446 28 ) (-40 448 28 ) (-44 448 28 ) (-44 446 28 ) +4 212 (-174 448 24 ) (-174 446 24 ) (-174 446 32 ) (-174 448 32 ) +4 212 (-48 448 32 ) (-48 446 32 ) (-48 446 24 ) (-48 448 24 ) +4 212 (-48 448 24 ) (-64 448 24 ) (-64 448 32 ) (-48 448 32 ) +4 212 (-174 448 24 ) (-174 448 32 ) (-160 448 32 ) (-160 448 24 ) +4 213 (-178 446 24 ) (-182 446 24 ) (-182 448 24 ) (-178 448 24 ) +4 213 (-182 448 24 ) (-182 446 24 ) (-182 446 28 ) (-182 448 28 ) +4 213 (-178 448 28 ) (-178 446 28 ) (-178 446 24 ) (-178 448 24 ) +4 213 (-178 448 28 ) (-178 448 24 ) (-182 448 24 ) (-182 448 28 ) +4 213 (-178 446 28 ) (-178 448 28 ) (-182 448 28 ) (-182 446 28 ) +4 214 (-186 448 24 ) (-190 448 24 ) (-190 448 32 ) (-186 448 32 ) +4 214 (-190 448 24 ) (-190 446 24 ) (-190 446 32 ) (-190 448 32 ) +4 214 (-186 448 32 ) (-186 446 32 ) (-186 446 24 ) (-186 448 24 ) +4 215 (-194 446 24 ) (-198 446 24 ) (-198 448 24 ) (-194 448 24 ) +4 215 (-198 448 24 ) (-198 446 24 ) (-198 446 32 ) (-198 448 32 ) +4 215 (-194 448 24 ) (-198 448 24 ) (-198 448 32 ) (-194 448 32 ) +4 215 (-194 448 32 ) (-194 446 32 ) (-194 446 24 ) (-194 448 24 ) +4 216 (-240 446 28 ) (-240 446 32 ) (-240 448 32 ) (-240 448 28 ) +4 216 (-202 448 24 ) (-224 448 24 ) (-224 448 32 ) (-202 448 32 ) +4 216 (-240 448 24 ) (-240 448 32 ) (-224 448 32 ) (-224 448 24 ) +4 216 (-202 448 32 ) (-202 446 32 ) (-202 446 24 ) (-202 448 24 ) +4 217 (-252 448 28 ) (-256 448 28 ) (-256 448 32 ) (-252 448 32 ) +4 217 (-256 446 28 ) (-256 446 32 ) (-256 448 32 ) (-256 448 28 ) +4 217 (-252 448 32 ) (-252 446 32 ) (-252 446 28 ) (-252 448 28 ) +4 218 (-246 446 24 ) (-246 448 24 ) (-244 448 28 ) (-244 446 28 ) +4 218 (-244 448 28 ) (-246 448 24 ) (-256 448 24 ) (-256 448 28 ) +4 218 (-256 448 24 ) (-256 446 24 ) (-256 446 28 ) (-256 448 28 ) +4 218 (-252 446 28 ) (-244 446 28 ) (-244 448 28 ) (-252 448 28 ) +3 219 (-240 448 28 ) (-240 448 24 ) (-242 448 24 ) +4 219 (-242 448 24 ) (-242 446 24 ) (-240 446 28 ) (-240 448 28 ) +4 220 (-260 446 24 ) (-264 446 24 ) (-264 448 24 ) (-260 448 24 ) +4 220 (-264 448 24 ) (-264 446 24 ) (-264 446 32 ) (-264 448 32 ) +4 220 (-260 448 24 ) (-264 448 24 ) (-264 448 32 ) (-260 448 32 ) +4 220 (-260 448 32 ) (-260 446 32 ) (-260 446 24 ) (-260 448 24 ) +4 221 (-484 446 24 ) (-492 446 24 ) (-492 448 24 ) (-484 448 24 ) +4 221 (-472 446 24 ) (-476 446 24 ) (-476 448 24 ) (-472 448 24 ) +4 221 (-420 446 24 ) (-428 446 24 ) (-428 448 24 ) (-420 448 24 ) +4 221 (-404 446 24 ) (-412 446 24 ) (-412 448 24 ) (-404 448 24 ) +4 221 (-704 446 24 ) (-704 446 32 ) (-704 448 32 ) (-704 448 24 ) +4 221 (-268 448 24 ) (-288 448 24 ) (-288 448 32 ) (-268 448 32 ) +4 221 (-448 448 24 ) (-448 448 32 ) (-384 448 32 ) (-384 448 24 ) +4 221 (-512 448 24 ) (-512 448 31 ) (-448 448 31 ) (-448 448 24 ) +4 221 (-268 448 32 ) (-268 446 32 ) (-268 446 24 ) (-268 448 24 ) +4 222 (-24 448 20 ) (-20 448 24 ) (0 448 24 ) (0 448 20 ) +4 222 (-24 448 20 ) (-24 446 20 ) (-20 446 24 ) (-20 448 24 ) +4 223 (-32 448 20 ) (-36 448 20 ) (-36 448 24 ) (-32 448 24 ) +4 223 (-32 448 24 ) (-32 446 24 ) (-32 446 20 ) (-32 448 20 ) +4 223 (-36 448 20 ) (-36 446 20 ) (-36 446 24 ) (-36 448 24 ) +4 224 (-174 448 20 ) (-174 446 20 ) (-174 446 24 ) (-174 448 24 ) +4 224 (-174 448 20 ) (-174 448 24 ) (-160 448 24 ) (-160 448 20 ) +4 224 (-48 448 20 ) (-64 448 20 ) (-64 448 24 ) (-48 448 24 ) +4 224 (-48 448 24 ) (-48 446 24 ) (-48 446 20 ) (-48 448 20 ) +4 225 (-190 448 20 ) (-190 446 20 ) (-190 446 24 ) (-190 448 24 ) +4 225 (-186 448 20 ) (-190 448 20 ) (-190 448 24 ) (-186 448 24 ) +4 225 (-186 448 24 ) (-186 446 24 ) (-186 446 20 ) (-186 448 20 ) +4 226 (-244 448 20 ) (-244 446 20 ) (-242 446 24 ) (-242 448 24 ) +4 226 (-202 448 24 ) (-202 446 24 ) (-202 446 20 ) (-202 448 20 ) +4 226 (-244 448 20 ) (-242 448 24 ) (-224 448 24 ) (-224 448 20 ) +4 226 (-202 448 20 ) (-224 448 20 ) (-224 448 24 ) (-202 448 24 ) +4 227 (-248 448 20 ) (-256 448 20 ) (-256 448 24 ) (-246 448 24 ) +4 227 (-256 448 20 ) (-256 446 20 ) (-256 446 24 ) (-256 448 24 ) +4 227 (-248 446 20 ) (-248 448 20 ) (-246 448 24 ) (-246 446 24 ) +4 228 (-400 448 20 ) (-404 448 24 ) (-384 448 24 ) (-384 448 20 ) +4 228 (-268 448 20 ) (-288 448 20 ) (-288 448 24 ) (-268 448 24 ) +4 228 (-268 448 24 ) (-268 446 24 ) (-268 446 20 ) (-268 448 20 ) +4 228 (-400 448 20 ) (-400 446 20 ) (-404 446 24 ) (-404 448 24 ) +4 229 (-412 448 20 ) (-416 448 20 ) (-420 448 24 ) (-412 448 24 ) +4 229 (-412 448 24 ) (-412 446 24 ) (-412 446 20 ) (-412 448 20 ) +4 229 (-416 448 20 ) (-416 446 20 ) (-420 446 24 ) (-420 448 24 ) +4 230 (-428 448 24 ) (-428 446 24 ) (-428 446 20 ) (-428 448 20 ) +4 230 (-472 448 20 ) (-472 448 24 ) (-448 448 24 ) (-448 448 20 ) +4 230 (-428 448 20 ) (-448 448 20 ) (-448 448 24 ) (-428 448 24 ) +4 230 (-472 448 20 ) (-472 446 20 ) (-472 446 24 ) (-472 448 24 ) +4 231 (-476 448 24 ) (-476 446 24 ) (-476 446 20 ) (-476 448 20 ) +4 231 (-476 448 20 ) (-480 448 20 ) (-484 448 24 ) (-476 448 24 ) +4 231 (-480 448 20 ) (-480 446 20 ) (-484 446 24 ) (-484 448 24 ) +4 232 (-492 448 24 ) (-492 446 24 ) (-492 446 20 ) (-492 448 20 ) +4 232 (-492 448 20 ) (-512 448 20 ) (-512 448 24 ) (-492 448 24 ) +4 232 (-704 446 20 ) (-704 446 24 ) (-704 448 24 ) (-704 448 20 ) +4 233 (-174 446 16 ) (-174 446 20 ) (-174 448 20 ) (-174 448 16 ) +4 233 (-174 448 12 ) (-174 446 12 ) (-174 446 16 ) (-174 448 16 ) +4 233 (-36 448 20 ) (-48 448 20 ) (-48 446 20 ) (-36 446 20 ) +4 233 (-24 448 20 ) (-32 448 20 ) (-32 446 20 ) (-24 446 20 ) +4 233 (-64 448 12 ) (-64 448 20 ) (0 448 20 ) (0 448 12 ) +4 233 (-174 448 12 ) (-174 448 20 ) (-160 448 20 ) (-160 448 12 ) +4 234 (-182 446 16 ) (-182 448 16 ) (-178 448 16 ) (-178 446 16 ) +4 234 (-178 448 16 ) (-182 448 16 ) (-182 448 20 ) (-178 448 20 ) +4 234 (-178 448 20 ) (-182 448 20 ) (-182 446 20 ) (-178 446 20 ) +4 234 (-182 446 16 ) (-182 446 20 ) (-182 448 20 ) (-182 448 16 ) +4 234 (-178 448 20 ) (-178 446 20 ) (-178 446 16 ) (-178 448 16 ) +4 235 (-190 448 12 ) (-190 446 12 ) (-190 446 20 ) (-190 448 20 ) +4 235 (-186 448 20 ) (-186 446 20 ) (-186 446 12 ) (-186 448 12 ) +4 235 (-186 448 12 ) (-190 448 12 ) (-190 448 20 ) (-186 448 20 ) +4 236 (-252 446 12 ) (-252 448 12 ) (-248 448 20 ) (-248 446 20 ) +4 236 (-252 448 12 ) (-256 448 12 ) (-256 448 20 ) (-248 448 20 ) +4 236 (-256 448 12 ) (-256 446 12 ) (-256 446 20 ) (-256 448 20 ) +4 237 (-248 448 12 ) (-244 448 20 ) (-224 448 20 ) (-224 448 12 ) +4 237 (-194 448 12 ) (-224 448 12 ) (-224 448 20 ) (-194 448 20 ) +4 237 (-194 448 20 ) (-202 448 20 ) (-202 446 20 ) (-194 446 20 ) +4 237 (-194 448 20 ) (-194 446 20 ) (-194 446 12 ) (-194 448 12 ) +4 237 (-248 448 12 ) (-248 446 12 ) (-244 446 20 ) (-244 448 20 ) +4 238 (-400 446 16 ) (-400 446 20 ) (-400 448 20 ) (-400 448 16 ) +4 238 (-400 448 12 ) (-400 448 20 ) (-384 448 20 ) (-384 448 12 ) +4 238 (-260 448 12 ) (-288 448 12 ) (-288 448 20 ) (-260 448 20 ) +4 238 (-260 448 20 ) (-268 448 20 ) (-268 446 20 ) (-260 446 20 ) +4 238 (-260 448 20 ) (-260 446 20 ) (-260 446 12 ) (-260 448 12 ) +3 239 (-400 448 16 ) (-400 448 12 ) (-404 448 12 ) +4 239 (-404 448 12 ) (-404 446 12 ) (-400 446 16 ) (-400 448 16 ) +4 240 (-416 446 12 ) (-416 446 20 ) (-416 448 20 ) (-416 448 12 ) +5 240 (-404 448 16 ) (-408 448 12 ) (-416 448 12 ) (-416 448 20 ) (-404 448 20 ) +4 240 (-404 448 20 ) (-412 448 20 ) (-412 446 20 ) (-404 446 20 ) +4 240 (-404 448 16 ) (-404 448 20 ) (-404 446 20 ) (-404 446 16 ) +4 240 (-408 446 12 ) (-408 448 12 ) (-404 448 16 ) (-404 446 16 ) +4 241 (-416 446 8 ) (-416 446 12 ) (-416 448 12 ) (-416 448 8 ) +4 241 (-412 446 8 ) (-412 448 8 ) (-408 448 12 ) (-408 446 12 ) +4 241 (-412 448 8 ) (-416 448 8 ) (-416 448 12 ) (-408 448 12 ) +4 242 (-400 446 8 ) (-408 446 8 ) (-408 448 8 ) (-400 448 8 ) +4 242 (-408 448 8 ) (-404 448 12 ) (-384 448 12 ) (-384 448 8 ) +4 242 (-288 448 8 ) (-288 448 12 ) (-224 448 12 ) (-224 448 8 ) +4 242 (-224 448 8 ) (-224 448 12 ) (-160 448 12 ) (-160 448 8 ) +4 242 (-64 448 8 ) (-64 448 12 ) (0 448 12 ) (0 448 8 ) +4 242 (-182 448 12 ) (-186 448 12 ) (-186 446 12 ) (-182 446 12 ) +4 242 (-174 448 12 ) (-182 448 12 ) (-182 446 12 ) (-174 446 12 ) +4 242 (-256 448 12 ) (-260 448 12 ) (-260 446 12 ) (-256 446 12 ) +4 242 (-190 448 12 ) (-194 448 12 ) (-194 446 12 ) (-190 446 12 ) +4 242 (-248 448 12 ) (-252 448 12 ) (-252 446 12 ) (-248 446 12 ) +4 242 (-408 448 8 ) (-408 446 8 ) (-404 446 12 ) (-404 448 12 ) +4 243 (-400 448 4 ) (-400 448 8 ) (-384 448 8 ) (-384 448 4 ) +4 243 (-288 448 4 ) (-288 448 8 ) (-224 448 8 ) (-224 448 4 ) +4 243 (-224 448 4 ) (-224 448 8 ) (-160 448 8 ) (-160 448 4 ) +4 243 (-64 448 4 ) (-64 448 8 ) (0 448 8 ) (0 448 4 ) +4 243 (-400 448 4 ) (-400 446 4 ) (-400 446 8 ) (-400 448 8 ) +4 244 (-412 448 8 ) (-412 446 8 ) (-412 446 4 ) (-412 448 4 ) +4 244 (-412 448 4 ) (-416 448 4 ) (-416 448 8 ) (-412 448 8 ) +3 245 (-416 448 8 ) (-416 448 4 ) (-420 448 4 ) +4 245 (-420 448 4 ) (-420 446 4 ) (-416 446 8 ) (-416 448 8 ) +4 246 (-424 448 16 ) (-420 448 16 ) (-420 446 16 ) (-424 446 16 ) +4 246 (-420 448 16 ) (-428 448 16 ) (-428 448 20 ) (-420 448 20 ) +4 246 (-420 448 20 ) (-428 448 20 ) (-428 446 20 ) (-420 446 20 ) +4 246 (-420 448 16 ) (-420 448 20 ) (-420 446 20 ) (-420 446 16 ) +4 247 (-424 448 8 ) (-420 448 8 ) (-420 446 8 ) (-424 446 8 ) +4 247 (-424 448 12 ) (-420 448 12 ) (-420 448 8 ) (-424 448 8 ) +4 247 (-420 448 8 ) (-420 448 12 ) (-420 446 12 ) (-420 446 8 ) +4 247 (-420 446 12 ) (-420 448 12 ) (-424 448 12 ) (-424 446 12 ) +4 248 (-424 448 12 ) (-424 448 16 ) (-424 446 16 ) (-424 446 12 ) +4 248 (-424 448 16 ) (-424 448 8 ) (-428 448 8 ) (-428 448 16 ) +4 248 (-428 446 8 ) (-428 448 8 ) (-424 448 8 ) (-424 446 8 ) +4 249 (-428 448 8 ) (-428 446 8 ) (-428 446 4 ) (-428 448 4 ) +4 249 (-472 448 4 ) (-472 448 20 ) (-448 448 20 ) (-448 448 4 ) +4 249 (-428 448 4 ) (-448 448 4 ) (-448 448 20 ) (-428 448 20 ) +4 249 (-472 448 4 ) (-472 446 4 ) (-472 446 20 ) (-472 448 20 ) +4 250 (-480 446 8 ) (-480 446 20 ) (-480 448 20 ) (-480 448 8 ) +4 250 (-476 448 20 ) (-476 446 20 ) (-476 446 4 ) (-476 448 4 ) +4 250 (-476 448 4 ) (-480 448 4 ) (-480 448 20 ) (-476 448 20 ) +3 251 (-480 448 8 ) (-480 448 4 ) (-484 448 4 ) +4 251 (-484 448 4 ) (-484 446 4 ) (-480 446 8 ) (-480 448 8 ) +4 252 (-488 448 16 ) (-484 448 16 ) (-484 446 16 ) (-488 446 16 ) +4 252 (-484 448 16 ) (-484 448 20 ) (-484 446 20 ) (-484 446 16 ) +4 252 (-484 448 16 ) (-492 448 16 ) (-492 448 20 ) (-484 448 20 ) +4 252 (-484 448 20 ) (-492 448 20 ) (-492 446 20 ) (-484 446 20 ) +4 253 (-488 448 16 ) (-488 448 12 ) (-492 448 12 ) (-492 448 16 ) +4 253 (-488 448 16 ) (-488 446 16 ) (-488 446 12 ) (-488 448 12 ) +4 254 (-488 446 12 ) (-484 446 12 ) (-484 448 12 ) (-488 448 12 ) +4 254 (-492 446 8 ) (-492 448 8 ) (-484 448 8 ) (-484 446 8 ) +4 254 (-484 448 8 ) (-484 448 12 ) (-484 446 12 ) (-484 446 8 ) +4 254 (-484 448 12 ) (-484 448 8 ) (-492 448 8 ) (-492 448 12 ) +4 255 (-492 448 8 ) (-492 446 8 ) (-492 446 4 ) (-492 448 4 ) +4 255 (-704 446 4 ) (-704 446 20 ) (-704 448 20 ) (-704 448 4 ) +4 255 (-492 448 4 ) (-512 448 4 ) (-512 448 20 ) (-492 448 20 ) +4 256 (-704 446 0 ) (-704 446 4 ) (-704 448 4 ) (-704 448 0 ) +4 256 (-64 448 4 ) (0 448 4 ) (0 448 0 ) (-64 448 0 ) +4 256 (-224 448 4 ) (-160 448 4 ) (-160 448 0 ) (-224 448 0 ) +4 256 (-288 448 4 ) (-224 448 4 ) (-224 448 0 ) (-288 448 0 ) +4 256 (-448 448 4 ) (-384 448 4 ) (-384 448 0 ) (-448 448 0 ) +4 256 (-512 448 4 ) (-448 448 4 ) (-448 448 0 ) (-512 448 0 ) +4 256 (-400 448 4 ) (-412 448 4 ) (-412 446 4 ) (-400 446 4 ) +4 256 (-420 448 4 ) (-428 448 4 ) (-428 446 4 ) (-420 446 4 ) +4 256 (-472 448 4 ) (-476 448 4 ) (-476 446 4 ) (-472 446 4 ) +4 256 (-484 448 4 ) (-492 448 4 ) (-492 446 4 ) (-484 446 4 ) +4 256 (0 446 0 ) (-704 446 0 ) (-704 448 0 ) (0 448 0 ) +4 257 (-192 0 192 ) (-320 0 192 ) (-320 128 192 ) (-192 128 192 ) +4 257 (0 0 192 ) (-32 0 192 ) (-32 128 192 ) (0 128 192 ) +4 257 (-704 446 512 ) (-704 446 192 ) (-704 0 192 ) (-704 0 512 ) +4 257 (0 446 512 ) (-704 446 512 ) (-704 0 512 ) (0 0 512 ) +4 258 (-384 128 0 ) (-320 128 0 ) (-320 128 64 ) (-384 128 64 ) +4 258 (-320 128 0 ) (-192 128 0 ) (-192 128 192 ) (-320 128 192 ) +4 258 (-32 128 0 ) (0 128 0 ) (0 128 192 ) (-32 128 192 ) +3 258 (-480 192 0 ) (-480 128 0 ) (-480 128 42.666672 ) +4 258 (-20 446 36 ) (-32 446 36 ) (-32 446 40 ) (-24 446 40 ) +4 258 (-24 446 36 ) (-20 446 36 ) (-20 446 32 ) (-24 446 32 ) +4 258 (-44 446 32 ) (-48 446 32 ) (-48 446 40 ) (-44 446 40 ) +4 258 (-20 446 24 ) (-24 446 24 ) (-24 446 32 ) (-20 446 32 ) +4 258 (-24 446 28 ) (-28 446 28 ) (-28 446 32 ) (-24 446 32 ) +4 258 (-36 446 24 ) (-40 446 24 ) (-40 446 32 ) (-36 446 32 ) +4 258 (-44 446 24 ) (-48 446 24 ) (-48 446 32 ) (-44 446 32 ) +4 258 (-40 446 28 ) (-44 446 28 ) (-44 446 32 ) (-40 446 32 ) +4 258 (-174 446 24 ) (-178 446 24 ) (-178 446 32 ) (-174 446 32 ) +4 258 (-190 446 24 ) (-194 446 24 ) (-194 446 32 ) (-190 446 32 ) +4 258 (-178 446 28 ) (-182 446 28 ) (-182 446 32 ) (-178 446 32 ) +4 258 (-182 446 24 ) (-186 446 24 ) (-186 446 32 ) (-182 446 32 ) +4 258 (-198 446 24 ) (-202 446 24 ) (-202 446 32 ) (-198 446 32 ) +4 258 (-256 446 24 ) (-260 446 24 ) (-260 446 32 ) (-256 446 32 ) +4 258 (-240 446 28 ) (-252 446 28 ) (-252 446 32 ) (-240 446 32 ) +4 258 (-244 446 28 ) (-240 446 28 ) (-242 446 24 ) (-246 446 24 ) +4 258 (-264 446 24 ) (-268 446 24 ) (-268 446 32 ) (-264 446 32 ) +4 258 (-24 446 20 ) (-32 446 20 ) (-32 446 24 ) (-20 446 24 ) +4 258 (-36 446 20 ) (-48 446 20 ) (-48 446 24 ) (-36 446 24 ) +4 258 (-174 446 20 ) (-186 446 20 ) (-186 446 24 ) (-174 446 24 ) +4 258 (-256 446 20 ) (-268 446 20 ) (-268 446 24 ) (-256 446 24 ) +4 258 (-190 446 20 ) (-202 446 20 ) (-202 446 24 ) (-190 446 24 ) +4 258 (-244 446 20 ) (-248 446 20 ) (-246 446 24 ) (-242 446 24 ) +4 258 (-400 446 20 ) (-412 446 20 ) (-412 446 24 ) (-404 446 24 ) +4 258 (-416 446 20 ) (-428 446 20 ) (-428 446 24 ) (-420 446 24 ) +4 258 (-472 446 20 ) (-476 446 20 ) (-476 446 24 ) (-472 446 24 ) +4 258 (-182 446 12 ) (-186 446 12 ) (-186 446 20 ) (-182 446 20 ) +4 258 (-174 446 16 ) (-174 446 12 ) (-182 446 12 ) (-182 446 16 ) +4 258 (-174 446 16 ) (-178 446 16 ) (-178 446 20 ) (-174 446 20 ) +4 258 (-256 446 12 ) (-260 446 12 ) (-260 446 20 ) (-256 446 20 ) +4 258 (-190 446 12 ) (-194 446 12 ) (-194 446 20 ) (-190 446 20 ) +4 258 (-248 446 12 ) (-252 446 12 ) (-248 446 20 ) (-244 446 20 ) +4 258 (-400 446 16 ) (-404 446 12 ) (-404 446 20 ) (-400 446 20 ) +3 258 (-404 446 16 ) (-404 446 12 ) (-408 446 12 ) +4 258 (-408 446 8 ) (-412 446 8 ) (-408 446 12 ) (-404 446 12 ) +4 258 (-400 446 4 ) (-412 446 4 ) (-412 446 8 ) (-400 446 8 ) +4 258 (-416 446 8 ) (-420 446 4 ) (-420 446 20 ) (-416 446 20 ) +4 258 (-420 446 8 ) (-420 446 4 ) (-428 446 4 ) (-428 446 8 ) +4 258 (-424 446 12 ) (-424 446 16 ) (-420 446 16 ) (-420 446 12 ) +4 258 (-472 446 4 ) (-476 446 4 ) (-476 446 20 ) (-472 446 20 ) +4 258 (-480 446 0 ) (0 446 0 ) (0 128 0 ) (-480 128 0 ) +4 259 (-704 192 0 ) (-704 446 0 ) (-480 446 0 ) (-480 192 0 ) +5 259 (-704 446 192 ) (-704 446 0 ) (-704 192 0 ) (-704 128 42.666672 ) (-704 128 192 ) +4 259 (-488 446 16 ) (-484 446 16 ) (-484 446 12 ) (-488 446 12 ) +4 259 (-484 446 8 ) (-484 446 4 ) (-492 446 4 ) (-492 446 8 ) +4 259 (-480 446 8 ) (-484 446 4 ) (-484 446 20 ) (-480 446 20 ) +4 259 (-480 446 20 ) (-492 446 20 ) (-492 446 24 ) (-484 446 24 ) +4 259 (-704 192 0 ) (-480 192 0 ) (-480 128 42.666664 ) (-704 128 42.666672 ) +4 260 (-32 16 16 ) (-192 16 16 ) (-192 112 16 ) (-32 112 16 ) +4 260 (-32 16 192 ) (-32 16 16 ) (-32 128 16 ) (-32 128 192 ) +4 260 (-192 128 192 ) (-192 128 16 ) (-192 16 16 ) (-192 16 192 ) +4 261 (-192 128 16 ) (-192 128 0 ) (-192 112 0 ) (-192 112 16 ) +4 261 (-192 112 0 ) (-192 128 0 ) (-32 128 0 ) (-32 112 0 ) +4 261 (-32 112 16 ) (-32 112 0 ) (-32 128 0 ) (-32 128 16 ) +4 261 (-32 112 0 ) (-32 112 16 ) (-192 112 16 ) (-192 112 0 ) +4 262 (-32 16 16 ) (-32 16 0 ) (-192 16 0 ) (-192 16 16 ) +4 262 (-192 16 0 ) (-192 0 0 ) (-192 0 192 ) (-192 16 192 ) +4 262 (-32 0 0 ) (-192 0 0 ) (-192 16 0 ) (-32 16 0 ) +4 262 (-32 16 192 ) (-32 0 192 ) (-32 0 0 ) (-32 16 0 ) +4 263 (-320 0 192 ) (-320 0 64 ) (-320 128 64 ) (-320 128 192 ) +4 263 (-384 0 64 ) (-384 128 64 ) (-320 128 64 ) (-320 0 64 ) +4 264 (-480 128 42.666664 ) (-480 128 0 ) (-480 0 0 ) (-480 0 128 ) +4 264 (-384 0 0 ) (-480 0 0 ) (-480 128 0 ) (-384 128 0 ) +4 264 (-384 0 64 ) (-384 0 0 ) (-384 128 0 ) (-384 128 64 ) +4 265 (-704 0 128 ) (-704 0 192 ) (-704 128 192 ) (-704 128 42.666664 ) +4 265 (-704 128 42.666672 ) (-480 128 42.666664 ) (-480 0 128 ) (-704 0 128 ) +4 266 (-704 -616 440 ) (-704 -584 440 ) (-632 -584 440 ) (-632 -616 440 ) +4 266 (-704 -280 440 ) (-704 -248 440 ) (-576 -248 440 ) (-576 -280 440 ) +4 266 (-704 -200 440 ) (-704 -168 440 ) (-576 -168 440 ) (-576 -200 440 ) +4 266 (-704 -960 512 ) (-704 -960 440 ) (0 -960 440 ) (0 -960 512 ) +4 266 (-704 0 512 ) (-704 0 440 ) (-704 -960 440 ) (-704 -960 512 ) +4 266 (0 0 512 ) (-704 0 512 ) (-704 -960 512 ) (0 -960 512 ) +4 267 (-704 -168 408 ) (-576 -168 408 ) (-576 -168 440 ) (-704 -168 440 ) +4 267 (-704 0 440 ) (-704 0 408 ) (-704 -168 408 ) (-704 -168 440 ) +4 268 (-576 -248 432 ) (-576 -280 432 ) (-576 -280 440 ) (-576 -248 440 ) +4 268 (-576 -168 440 ) (-576 -168 432 ) (-576 -200 432 ) (-576 -200 440 ) +4 268 (-576 -268 432 ) (-576 -260 432 ) (0 -260 432 ) (0 -268 432 ) +4 268 (-576 -188 432 ) (-576 -180 432 ) (0 -180 432 ) (0 -188 432 ) +4 268 (0 -960 432 ) (0 -960 440 ) (-576 -960 440 ) (-576 -960 432 ) +4 269 (-576 -168 432 ) (-576 -168 416 ) (-576 -176 416 ) (-576 -176 432 ) +4 269 (0 -176 420 ) (0 -176 428 ) (-576 -176 428 ) (-576 -176 420 ) +3 270 (-576 -188 416 ) (-576 -192 416 ) (-576 -192 420 ) +4 270 (0 -188 416 ) (-576 -188 416 ) (-576 -192 420 ) (0 -192 420 ) +3 271 (-576 -176 416 ) (-576 -180 416 ) (-576 -176 420 ) +4 271 (-576 -180 416 ) (0 -180 416 ) (0 -176 420 ) (-576 -176 420 ) +3 272 (-576 -180 432 ) (-576 -176 432 ) (-576 -176 428 ) +4 272 (-576 -176 428 ) (0 -176 428 ) (0 -180 432 ) (-576 -180 432 ) +3 273 (-576 -192 428 ) (-576 -192 432 ) (-576 -188 432 ) +4 273 (0 -192 428 ) (-576 -192 428 ) (-576 -188 432 ) (0 -188 432 ) +4 274 (-576 -248 416 ) (-576 -256 416 ) (-576 -256 432 ) (-576 -248 432 ) +4 274 (-576 -192 416 ) (-576 -200 416 ) (-576 -200 432 ) (-576 -192 432 ) +4 274 (0 -256 419.994049 ) (0 -256 428 ) (-576 -256 428 ) (-576 -256 419.994049 ) +4 274 (-576 -192 420 ) (-576 -192 428 ) (0 -192 428 ) (0 -192 420 ) +3 275 (-576 -260 432 ) (-576 -256 432 ) (-576 -256 428 ) +4 275 (-576 -256 428 ) (0 -256 428 ) (0 -260 432 ) (-576 -260 432 ) +3 276 (-576 -268 416 ) (-576 -272 416 ) (-576 -272 420 ) +4 276 (0 -268 416 ) (-576 -268 416 ) (-576 -272 420 ) (0 -272 420 ) +3 277 (-576 -256 416 ) (-576 -259.994049 416 ) (-576 -256 419.994049 ) +4 277 (-576 -259.994141 416 ) (0 -259.994141 416 ) (0 -256 419.994141 ) (-576 -256 419.994141 ) +3 278 (-576 -272 428 ) (-576 -272 432 ) (-576 -268 432 ) +4 278 (0 -272 428 ) (-576 -272 428 ) (-576 -268 432 ) (0 -268 432 ) +4 279 (-576 -272 416 ) (-576 -280 416 ) (-576 -280 432 ) (-576 -272 432 ) +4 279 (-576 -272 420 ) (-576 -272 428 ) (0 -272 428 ) (0 -272 420 ) +4 279 (0 -960 416 ) (0 -960 432 ) (-576 -960 432 ) (-576 -960 416 ) +4 280 (-576 -248 408 ) (-576 -280 408 ) (-576 -280 416 ) (-576 -248 416 ) +4 280 (-576 -168 416 ) (-576 -168 408 ) (-576 -200 408 ) (-576 -200 416 ) +4 280 (0 -268 416 ) (0 -259.994049 416 ) (-576 -259.994049 416 ) (-576 -268 416 ) +4 280 (0 -188 416 ) (0 -180 416 ) (-576 -180 416 ) (-576 -188 416 ) +4 280 (-576 -960 408 ) (0 -960 408 ) (0 -960 416 ) (-576 -960 416 ) +4 281 (-704 -248 408 ) (-576 -248 408 ) (-576 -248 440 ) (-704 -248 440 ) +4 281 (-704 -200 408 ) (-704 -248 408 ) (-704 -248 440 ) (-704 -200 440 ) +4 281 (-704 -200 440 ) (-576 -200 440 ) (-576 -200 408 ) (-704 -200 408 ) +4 282 (-704 -584 408 ) (-632 -584 408 ) (-632 -584 440 ) (-704 -584 440 ) +4 282 (-704 -280 408 ) (-704 -584 408 ) (-704 -584 440 ) (-704 -280 440 ) +4 282 (-704 -280 440 ) (-576 -280 440 ) (-576 -280 408 ) (-704 -280 408 ) +4 283 (-632 -584 440 ) (-632 -584 408 ) (-632 -616 408 ) (-632 -616 440 ) +4 284 (-704 -616 440 ) (-632 -616 440 ) (-632 -616 408 ) (-704 -616 408 ) +4 284 (-704 -616 408 ) (-704 -960 408 ) (-704 -960 440 ) (-704 -616 440 ) +4 284 (-704 -960 408 ) (-576 -960 408 ) (-576 -960 440 ) (-704 -960 440 ) +5 285 (-704 -704 256 ) (-704 -384 256 ) (-480 -384 256 ) (-480 -656 256 ) (-528 -704 256 ) +7 285 (0 -808 256 ) (0 -960 256 ) (-448 -960 256 ) (-448 -880 256 ) (-416 -816 256 ) (-368 -768 256 ) (-80 -768 256 ) +5 285 (-128 -768 256 ) (-368 -768 256 ) (-352 -752 256 ) (-256 -704 256 ) (-192 -704 256 ) +4 285 (-480 -384 256 ) (-704 -384 256 ) (-704 -192 256 ) (-480 -192 256 ) +4 285 (-704 0 408 ) (-704 0 256 ) (-704 -960 256 ) (-704 -960 408 ) +4 285 (-576 -200 408 ) (-576 -168 408 ) (-704 -168 408 ) (-704 -200 408 ) +4 285 (-576 -280 408 ) (-576 -248 408 ) (-704 -248 408 ) (-704 -280 408 ) +4 285 (-632 -616 408 ) (-632 -584 408 ) (-704 -584 408 ) (-704 -616 408 ) +4 285 (0 -960 408 ) (-704 -960 408 ) (-704 -960 256 ) (0 -960 256 ) +4 286 (-480 0 0 ) (-480 -64 0 ) (-480 -64 170.666656 ) (-480 0 128 ) +4 286 (-384 -64 0 ) (-320 -64 0 ) (-320 -64 64 ) (-384 -64 64 ) +4 286 (-320 -64 0 ) (-192 -64 0 ) (-192 -64 192 ) (-320 -64 192 ) +4 286 (-320 0 64 ) (-320 0 0 ) (-384 0 0 ) (-384 0 64 ) +4 286 (-192 0 0 ) (-320 0 0 ) (-320 0 192 ) (-192 0 192 ) +4 286 (-32 0 0 ) (-32 0 192 ) (0 0 192 ) (0 0 0 ) +4 286 (-480 -64 0 ) (-480 0 0 ) (0 0 0 ) (0 -64 0 ) +4 287 (-192 -192 192 ) (-320 -192 192 ) (-320 -64 192 ) (-192 -64 192 ) +4 288 (-192 -176 16 ) (-192 -80 16 ) (0 -80 16 ) (0 -176 16 ) +4 288 (-192 -192 192 ) (-192 -64 192 ) (-192 -64 16 ) (-192 -192 16 ) +4 288 (0 -192 16 ) (0 -64 16 ) (0 -64 192 ) (0 -192 192 ) +4 289 (-192 -64 16 ) (-192 -64 0 ) (-192 -80 0 ) (-192 -80 16 ) +4 289 (-192 -80 0 ) (-192 -64 0 ) (0 -64 0 ) (0 -80 0 ) +4 289 (0 -80 16 ) (0 -80 0 ) (0 -64 0 ) (0 -64 16 ) +4 289 (0 -80 16 ) (-192 -80 16 ) (-192 -80 0 ) (0 -80 0 ) +4 290 (0 -176 0 ) (-192 -176 0 ) (-192 -176 16 ) (0 -176 16 ) +4 290 (0 -176 16 ) (0 -192 16 ) (0 -192 0 ) (0 -176 0 ) +4 290 (0 -192 0 ) (-192 -192 0 ) (-192 -176 0 ) (0 -176 0 ) +4 290 (-192 -176 0 ) (-192 -192 0 ) (-192 -192 16 ) (-192 -176 16 ) +4 291 (-320 -192 192 ) (-320 -192 64 ) (-320 -64 64 ) (-320 -64 192 ) +4 291 (-384 -192 64 ) (-384 -64 64 ) (-320 -64 64 ) (-320 -192 64 ) +4 292 (-480 -64 0 ) (-480 -192 0 ) (-480 -192 256 ) (-480 -64 170.666656 ) +4 292 (-384 -192 64 ) (-384 -192 0 ) (-384 -64 0 ) (-384 -64 64 ) +4 292 (-384 -192 0 ) (-480 -192 0 ) (-480 -64 0 ) (-384 -64 0 ) +3 293 (-704 -192 256 ) (-704 0 256 ) (-704 0 128 ) +4 293 (-480 0 128 ) (-480 -192 256 ) (-704 -192 256 ) (-704 0 128 ) +4 294 (-128 -256 64 ) (-128 -256 192 ) (-320 -256 192 ) (-320 -256 64 ) +4 294 (-384 -256 0 ) (-128 -256 0 ) (-128 -256 64 ) (-384 -256 64 ) +4 294 (-480 -192 256 ) (-480 -192 0 ) (-480 -256 0 ) (-480 -256 256 ) +4 294 (-480 -192 0 ) (0 -192 0 ) (0 -256 0 ) (-480 -256 0 ) +4 294 (-320 -192 192 ) (-192 -192 192 ) (-192 -192 0 ) (-320 -192 0 ) +4 294 (-384 -192 64 ) (-320 -192 64 ) (-320 -192 0 ) (-384 -192 0 ) +4 295 (-128 -384 192 ) (-320 -384 192 ) (-320 -256 192 ) (-128 -256 192 ) +4 295 (-480 -384 192 ) (-480 -384 256 ) (-480 -256 256 ) (-480 -256 192 ) +4 296 (-128 -368 192 ) (-128 -256 192 ) (-128 -256 64 ) (-128 -368 64 ) +4 296 (-128 -256 64 ) (-128 -256 16 ) (-128 -368 16 ) (-128 -368 64 ) +4 296 (0 -368 16 ) (-128 -368 16 ) (-128 -272 16 ) (0 -272 16 ) +4 297 (-128 -256 16 ) (-128 -256 0 ) (-128 -272 0 ) (-128 -272 16 ) +4 297 (0 -256 0 ) (0 -272 0 ) (-128 -272 0 ) (-128 -256 0 ) +4 297 (0 -272 16 ) (-128 -272 16 ) (-128 -272 0 ) (0 -272 0 ) +4 298 (-128 -384 64 ) (-128 -384 192 ) (-128 -368 192 ) (-128 -368 64 ) +4 298 (-128 -384 0 ) (-128 -384 64 ) (-128 -368 64 ) (-128 -368 0 ) +4 298 (0 -368 16 ) (0 -368 0 ) (-128 -368 0 ) (-128 -368 16 ) +4 298 (0 -368 0 ) (0 -384 0 ) (-128 -384 0 ) (-128 -368 0 ) +4 299 (-384 -384 64 ) (-384 -256 64 ) (-320 -256 64 ) (-320 -384 64 ) +4 299 (-320 -256 192 ) (-320 -384 192 ) (-320 -384 64 ) (-320 -256 64 ) +4 300 (-384 -256 0 ) (-384 -256 64 ) (-384 -384 64 ) (-384 -384 0 ) +4 300 (-480 -256 0 ) (-480 -384 0 ) (-480 -384 192 ) (-480 -256 192 ) +4 300 (-384 -384 0 ) (-480 -384 0 ) (-480 -256 0 ) (-384 -256 0 ) +4 301 (-192 -704 256 ) (-256 -704 256 ) (-256 -704 192 ) (-192 -704 192 ) +4 301 (-320 -576 192 ) (-320 -448 192 ) (-128 -448 192 ) (-128 -576 192 ) +4 302 (-128 -448 128 ) (-128 -576 128 ) (-128 -576 192 ) (-128 -448 192 ) +4 303 (-128 -448 128 ) (-128 -448 192 ) (-320 -448 192 ) (-320 -448 128 ) +4 303 (-320 -384 128 ) (-320 -384 192 ) (-128 -384 192 ) (-128 -384 128 ) +4 304 (-180 -704 128 ) (-276 -704 128 ) (-260 -696 128 ) (-188 -696 128 ) +4 304 (-256 -704 128 ) (-192 -704 128 ) (-192 -704 192 ) (-256 -704 192 ) +4 304 (-320 -576 128 ) (-320 -576 192 ) (-128 -576 192 ) (-128 -576 128 ) +4 305 (-480 -384 256 ) (-480 -384 128 ) (-480 -656 128 ) (-480 -656 256 ) +4 305 (-320 -448 192 ) (-320 -576 192 ) (-320 -576 128 ) (-320 -448 128 ) +4 306 (-360 -760 128 ) (-368 -768 128 ) (-380 -768 128 ) (-372 -760 128 ) +4 306 (-332 -732 128 ) (-360 -760 128 ) (-372 -760 128 ) (-356 -744 128 ) +4 306 (-368 -768 256 ) (-368 -768 128 ) (-352 -752 128 ) (-352 -752 256 ) +4 307 (-60 -768 128 ) (-128 -768 128 ) (-136 -760 128 ) (-76 -760 128 ) +4 307 (-192 -704 128 ) (-180 -704 128 ) (-124 -760 128 ) (-136 -760 128 ) +4 307 (-128 -768 128 ) (-80 -768 128 ) (-80 -768 256 ) (-128 -768 256 ) +4 307 (-192 -704 256 ) (-192 -704 128 ) (-128 -768 128 ) (-128 -768 256 ) +4 308 (-276 -704 128 ) (-256 -704 128 ) (-352 -752 128 ) (-332 -732 128 ) +4 308 (-352 -752 256 ) (-352 -752 128 ) (-256 -704 128 ) (-256 -704 256 ) +4 309 (-448 -880 128 ) (-448 -860 128 ) (-424 -812 128 ) (-404 -792 128 ) +4 309 (-448 -880 256 ) (-448 -880 128 ) (-416 -816 128 ) (-416 -816 256 ) +4 310 (-80 -768 128 ) (-60 -768 128 ) (0 -798 128 ) (0 -808 128 ) +4 310 (-80 -768 256 ) (-80 -768 128 ) (0 -808 128 ) (0 -808 256 ) +4 311 (-416 -816 128 ) (-404 -792 128 ) (-380 -768 128 ) (-368 -768 128 ) +4 311 (-416 -816 256 ) (-416 -816 128 ) (-368 -768 128 ) (-368 -768 256 ) +4 312 (-448 -960 128 ) (-456 -960 128 ) (-456 -876 128 ) (-448 -860 128 ) +4 312 (-448 -880 256 ) (-448 -960 256 ) (-448 -960 128 ) (-448 -880 128 ) +4 312 (-448 -960 256 ) (-480 -960 256 ) (-480 -960 128 ) (-448 -960 128 ) +4 313 (-480 -384 128 ) (-480 -384 0 ) (-480 -448 0 ) (-480 -448 128 ) +4 313 (-384 -448 64 ) (-384 -448 0 ) (-320 -448 0 ) (-320 -448 64 ) +4 313 (-128 -448 128 ) (-320 -448 128 ) (-320 -448 0 ) (-128 -448 0 ) +4 313 (-480 -448 0 ) (-480 -384 0 ) (0 -384 0 ) (0 -448 0 ) +4 313 (-384 -384 64 ) (-128 -384 64 ) (-128 -384 0 ) (-384 -384 0 ) +4 313 (-320 -384 64 ) (-320 -384 128 ) (-128 -384 128 ) (-128 -384 64 ) +4 314 (0 -560 16 ) (-128 -560 16 ) (-128 -464 16 ) (0 -464 16 ) +4 314 (-128 -448 128 ) (-128 -448 16 ) (-128 -560 16 ) (-128 -560 128 ) +4 315 (-128 -448 16 ) (-128 -448 0 ) (-128 -464 0 ) (-128 -464 16 ) +4 315 (-128 -448 0 ) (0 -448 0 ) (0 -464 0 ) (-128 -464 0 ) +4 315 (0 -464 16 ) (-128 -464 16 ) (-128 -464 0 ) (0 -464 0 ) +4 316 (0 -560 16 ) (0 -560 0 ) (-128 -560 0 ) (-128 -560 16 ) +4 316 (-128 -560 0 ) (-128 -576 0 ) (-128 -576 128 ) (-128 -560 128 ) +4 316 (0 -560 0 ) (0 -576 0 ) (-128 -576 0 ) (-128 -560 0 ) +4 317 (-320 -576 128 ) (-320 -576 64 ) (-320 -448 64 ) (-320 -448 128 ) +4 317 (-384 -576 64 ) (-384 -448 64 ) (-320 -448 64 ) (-320 -576 64 ) +4 318 (-480 -448 0 ) (-480 -576 0 ) (-480 -576 128 ) (-480 -448 128 ) +4 318 (-384 -576 64 ) (-384 -576 0 ) (-384 -448 0 ) (-384 -448 64 ) +4 318 (-480 -576 0 ) (-480 -448 0 ) (-384 -448 0 ) (-384 -576 0 ) +4 319 (-260 -696 0 ) (-188 -696 0 ) (-188 -696 128 ) (-260 -696 128 ) +4 319 (-320 -576 64 ) (-320 -576 0 ) (-384 -576 0 ) (-384 -576 64 ) +4 319 (-128 -576 0 ) (-320 -576 0 ) (-320 -576 128 ) (-128 -576 128 ) +4 319 (-456 -696 0 ) (-456 -576 0 ) (0 -576 0 ) (0 -696 0 ) +4 320 (-456 -876 128 ) (-456 -876 0 ) (-424 -812 0 ) (-424 -812 128 ) +3 320 (-456 -876 0 ) (-456 -696 0 ) (-366 -696 0 ) +4 321 (-372 -760 128 ) (-372 -760 0 ) (-356 -744 0 ) (-356 -744 128 ) +4 321 (-398 -760 0 ) (-366 -696 0 ) (-308 -696 0 ) (-372 -760 0 ) +4 322 (-124 -760 0 ) (-76 -760 0 ) (-76 -760 128 ) (-124 -760 128 ) +4 322 (-188 -696 128 ) (-188 -696 0 ) (-124 -760 0 ) (-124 -760 128 ) +4 322 (-188 -696 0 ) (0 -696 0 ) (0 -760 0 ) (-124 -760 0 ) +3 323 (-308 -696 0 ) (-260 -696 0 ) (-356 -744 0 ) +4 323 (-355.998962 -744 128 ) (-355.998962 -744 0 ) (-260 -696 0 ) (-260 -696 128 ) +4 324 (-424 -812 128 ) (-424 -812 0 ) (-372 -760 0 ) (-372 -760 128 ) +3 324 (-424 -812 0 ) (-398 -760 0 ) (-372 -760 0 ) +3 325 (-76 -760 0 ) (0 -760 0 ) (0 -798 0 ) +4 325 (-76 -760 128 ) (-76 -760 0 ) (0 -798 0 ) (0 -798 128 ) +4 326 (-480 -576 0 ) (-480 -656 0 ) (-480 -656 128 ) (-480 -576 128 ) +4 326 (-456 -876 128 ) (-456 -960 128 ) (-456 -960 0 ) (-456 -876 0 ) +4 326 (-480 -960 0 ) (-456 -960 0 ) (-456 -960 128 ) (-480 -960 128 ) +4 326 (-456 -960 0 ) (-480 -960 0 ) (-480 -576 0 ) (-456 -576 0 ) +3 327 (-480 -656 0 ) (-480 -704 0 ) (-528 -704 0 ) +4 327 (-480 -656 256 ) (-480 -656 0 ) (-528 -704 0 ) (-528 -704 256 ) +4 328 (-528 -704 256 ) (-528 -704 0 ) (-704 -704 0 ) (-704 -704 256 ) +4 328 (-480 -960 0 ) (-704 -960 0 ) (-704 -704 0 ) (-480 -704 0 ) +4 328 (-704 -960 256 ) (-704 -704 256 ) (-704 -704 0 ) (-704 -960 0 ) +4 328 (-704 -960 256 ) (-704 -960 0 ) (-480 -960 0 ) (-480 -960 256 ) diff --git a/fakk/maps/example/autosprite.bsp b/fakk/maps/example/autosprite.bsp new file mode 100644 index 0000000..71177cb Binary files /dev/null and b/fakk/maps/example/autosprite.bsp differ diff --git a/fakk/maps/example/autosprite.map b/fakk/maps/example/autosprite.map new file mode 100644 index 0000000..2a77c4b --- /dev/null +++ b/fakk/maps/example/autosprite.map @@ -0,0 +1,281 @@ +{ +"classname" "worldspawn" +// brush 0 +{ +( -64 -320 136 ) ( -192 -320 136 ) ( -192 -448 136 ) common/skip -24 0 0.00 1 1 805306368 16512 0 +( -192 -448 240 ) ( -192 -320 240 ) ( -64 -320 240 ) common/skip -24 0 0.00 1 1 805306368 16512 0 +( -192 -448 144 ) ( -64 -448 144 ) ( -64 -448 136 ) common/skip -24 0 0.00 1 1 805306368 16512 0 +( -64 -448 144 ) ( -64 -320 144 ) ( -64 -320 136 ) common/skip 0 0 0.00 1 1 805306368 16512 0 +( -64 -320 144 ) ( -192 -320 144 ) ( -192 -320 136 ) common/skip -24 0 0.00 1 1 805306368 16512 0 +( -192 -320 144 ) ( -192 -448 144 ) ( -192 -448 136 ) testsprite2 0 0 0.00 1 1 805306368 16512 0 +} +// brush 1 +{ +( -64 0 136 ) ( -192 0 136 ) ( -192 -128 136 ) common/skip -24 0 0.00 1 1 805306368 16512 0 +( -192 -128 240 ) ( -192 0 240 ) ( -64 0 240 ) common/skip -24 0 0.00 1 1 805306368 16512 0 +( -192 -128 144 ) ( -64 -128 144 ) ( -64 -128 136 ) common/skip -24 0 0.00 1 1 805306368 16512 0 +( -64 -128 144 ) ( -64 0 144 ) ( -64 0 136 ) common/skip 0 0 0.00 1 1 805306368 16512 0 +( -64 0 144 ) ( -192 0 144 ) ( -192 0 136 ) common/skip -24 0 0.00 1 1 805306368 16512 0 +( -192 0 144 ) ( -192 -128 144 ) ( -192 -128 136 ) testsprite1 0 0 0.00 1 1 805306368 16512 0 +} +// brush 2 +{ +( 224 192 0 ) ( 224 224 0 ) ( -480 224 0 ) eden/bedtrim -224 -32 90.00 1 1 0 0 0 +( -480 224 64 ) ( 224 224 64 ) ( 224 192 64 ) eden/bedtrim -224 -32 90.00 1 1 0 0 0 +( -480 224 256 ) ( -480 192 256 ) ( -480 192 0 ) eden/bedtrim -224 0 0.00 1 1 0 0 0 +( -480 192 256 ) ( 224 192 256 ) ( 224 192 0 ) common/skip 0 0 0.00 1 1 805306368 16512 0 +( 224 224 256 ) ( -480 224 256 ) ( -480 224 0 ) eden/bedtrim 224 0 -180.00 1 -1 0 0 0 +( -416 224 0 ) ( -416 192 0 ) ( -416 208 64 ) eden/bedtrim 224 0 -180.00 1 -1 0 0 0 +} +// brush 3 +{ +( 224 192 0 ) ( 224 224 0 ) ( -480 224 0 ) eden/bedtrim -224 -32 90.00 1 1 0 0 0 +( -480 224 64 ) ( 224 224 64 ) ( 224 192 64 ) eden/bedtrim -224 -32 90.00 1 1 0 0 0 +( -480 192 256 ) ( 224 192 256 ) ( 224 192 0 ) eden/bedtrim 224 0 -180.00 1 -1 0 0 0 +( 224 192 256 ) ( 224 224 256 ) ( 224 224 0 ) eden/bedtrim -224 0 0.00 1 1 0 0 0 +( 224 224 256 ) ( -480 224 256 ) ( -480 224 0 ) eden/bedtrim 224 0 -180.00 1 -1 0 0 0 +( -480 192 0 ) ( -480 224 0 ) ( -480 208 64 ) eden/bedtrim 224 0 -180.00 1 -1 0 0 0 +} +// brush 4 +{ +( 224 192 64 ) ( 224 224 64 ) ( -480 224 64 ) eden/edenmetalwall -224 -224 90.00 1 1 0 0 0 +( -480 224 320 ) ( 224 224 320 ) ( 224 192 320 ) eden/edenmetalwall -224 -224 90.00 1 1 0 0 0 +( -480 224 96 ) ( -480 192 96 ) ( -480 192 64 ) eden/edenmetalwall -224 64 0.00 1 1 0 0 0 +( -480 192 96 ) ( 224 192 96 ) ( 224 192 64 ) common/skip 0 0 0.00 1 1 805306368 16512 0 +( 224 224 96 ) ( -480 224 96 ) ( -480 224 64 ) eden/edenmetalwall 224 63 -180.00 1 -1 0 0 0 +( -416 224 64 ) ( -416 192 64 ) ( -416 208 320 ) eden/edenmetalwall 224 63 -180.00 1 -1 0 0 0 +} +// brush 5 +{ +( 224 192 64 ) ( 224 224 64 ) ( -480 224 64 ) eden/edenmetalwall -224 -224 90.00 1 1 0 0 0 +( -480 224 640 ) ( 224 224 640 ) ( 224 192 640 ) eden/edenmetalwall -224 -224 90.00 1 1 0 0 0 +( -480 192 96 ) ( 224 192 96 ) ( 224 192 64 ) eden/edenmetalwall 224 63 -180.00 1 -1 0 0 0 +( 224 192 96 ) ( 224 224 96 ) ( 224 224 64 ) eden/edenmetalwall -224 64 0.00 1 1 0 0 0 +( 224 224 96 ) ( -480 224 96 ) ( -480 224 64 ) eden/edenmetalwall 224 63 -180.00 1 -1 0 0 0 +( -480 192 384 ) ( -480 224 384 ) ( -480 208 640 ) eden/edenmetalwall 224 63 -180.00 1 -1 0 0 0 +} +// brush 6 + { + patchDef2 + { + eden/edenmetalwall + ( 3 3 0 536870912 0 ) +( +( ( -480 96 63.999981 0 0 ) ( -480 96 352.000061 0 0.500000 ) ( -480 96 640 0 1 ) ) +( ( -384 96 63.999981 0.500000 0 ) ( -384 96 352.000061 0.500000 0.500000 ) ( -384 96 640 0.500000 1 ) ) +( ( -384 192 63.999981 1 0 ) ( -384 192 352.000061 1 0.500000 ) ( -384 192 640 1 1 ) ) +) + } + } +// brush 7 +{ +( -480 192 0 ) ( -512 192 0 ) ( -512 -512 0 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +( -512 -512 64 ) ( -512 192 64 ) ( -480 192 64 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +( -480 -512 256 ) ( -480 192 256 ) ( -480 192 0 ) common/skip 0 0 0.00 1 1 805306368 16512 0 +( -480 192 256 ) ( -512 192 256 ) ( -512 192 0 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +( -512 192 256 ) ( -512 -512 256 ) ( -512 -512 0 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +( -480 128 0 ) ( -512 128 0 ) ( -496 128 64 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +} +// brush 8 +{ +( -480 192 0 ) ( -512 192 0 ) ( -512 -512 0 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +( -512 -512 64 ) ( -512 192 64 ) ( -480 192 64 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +( -512 -512 256 ) ( -480 -512 256 ) ( -480 -512 0 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +( -480 -512 256 ) ( -480 192 256 ) ( -480 192 0 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +( -512 192 256 ) ( -512 -512 256 ) ( -512 -512 0 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +( -512 192 0 ) ( -480 192 0 ) ( -496 192 64 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +} +// brush 9 +{ +( -480 192 64 ) ( -512 192 64 ) ( -512 -512 64 ) eden/edenmetalwall 0 0 0.00 1 1 0 0 0 +( -512 -512 320 ) ( -512 192 320 ) ( -480 192 320 ) eden/edenmetalwall 0 0 0.00 1 1 0 0 0 +( -480 -512 96 ) ( -480 192 96 ) ( -480 192 64 ) common/skip 0 0 0.00 1 1 805306368 16512 0 +( -480 192 96 ) ( -512 192 96 ) ( -512 192 64 ) eden/edenmetalwall 0 64 0.00 1 1 0 0 0 +( -512 192 96 ) ( -512 -512 96 ) ( -512 -512 64 ) eden/edenmetalwall 0 64 0.00 1 1 0 0 0 +( -480 128 64 ) ( -512 128 64 ) ( -496 128 320 ) eden/edenmetalwall 0 64 0.00 1 1 0 0 0 +} +// brush 10 +{ +( -480 192 64 ) ( -512 192 64 ) ( -512 -512 64 ) eden/edenmetalwall 0 0 0.00 1 1 0 0 0 +( -512 -512 640 ) ( -512 192 640 ) ( -480 192 640 ) eden/edenmetalwall 0 0 0.00 1 1 0 0 0 +( -512 -512 96 ) ( -480 -512 96 ) ( -480 -512 64 ) eden/edenmetalwall 0 64 0.00 1 1 0 0 0 +( -480 -512 416 ) ( -480 192 416 ) ( -480 192 384 ) eden/edenmetalwall 0 64 0.00 1 1 0 0 0 +( -512 192 96 ) ( -512 -512 96 ) ( -512 -512 64 ) eden/edenmetalwall 0 64 0.00 1 1 0 0 0 +( -512 192 64 ) ( -480 192 64 ) ( -496 192 320 ) eden/edenmetalwall 0 64 0.00 1 1 0 0 0 +} +// brush 11 + { + patchDef2 + { + eden/bedtrim + ( 3 3 0 536870912 0 ) +( +( ( -480 96 0 0 0 ) ( -480 96 32 0 0.500000 ) ( -480 96 64 0 1 ) ) +( ( -384 96 0 0.500000 0 ) ( -384 96 32 0.500000 0.500000 ) ( -384 96 64 0.500000 1 ) ) +( ( -384 192 0 1 0 ) ( -384 192 32 1 0.500000 ) ( -384 192 64 1 1 ) ) +) + } + } +// brush 12 +{ +( 192 192 608 ) ( -480 192 608 ) ( -480 -512 608 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( -480 -512 640 ) ( -480 192 640 ) ( 192 192 640 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( -480 -512 640 ) ( 192 -512 640 ) ( 192 -512 608 ) eden/CL_edenroof3 0 -96 0.00 1 1 0 0 0 +( 192 192 640 ) ( -480 192 640 ) ( -480 192 608 ) eden/CL_edenroof3 0 -96 0.00 1 1 0 0 0 +( -480 192 640 ) ( -480 -512 640 ) ( -480 -512 608 ) eden/CL_edenroof3 0 -96 0.00 1 1 0 0 0 +( 216 -112 608 ) ( 216 -240 608 ) ( 216 -176 640 ) eden/CL_edenroof3 0 -96 0.00 1 1 0 0 0 +} +// brush 13 +{ +( 192 192 -32 ) ( -480 192 -32 ) ( -480 -512 -32 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( -480 -512 0 ) ( -480 192 0 ) ( 192 192 0 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( -480 -512 224 ) ( 192 -512 224 ) ( 192 -512 -32 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 192 -512 224 ) ( 192 192 224 ) ( 192 192 -32 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 192 192 224 ) ( -480 192 224 ) ( -480 192 -32 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( -480 192 224 ) ( -480 -512 224 ) ( -480 -512 -32 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +} +// brush 14 +{ +( -480 -512 64 ) ( -480 -544 64 ) ( 224 -544 64 ) eden/edenmetalwall -31 31 -90.00 1 1 0 0 0 +( 224 -544 640 ) ( -480 -544 640 ) ( -480 -512 640 ) eden/edenmetalwall -31 31 -90.00 1 1 0 0 0 +( 224 -544 96 ) ( 224 -512 96 ) ( 224 -512 64 ) eden/edenmetalwall -32 63 -180.00 1 -1 0 0 0 +( 224 -512 96 ) ( -480 -512 96 ) ( -480 -512 64 ) eden/edenmetalwall -32 62 0.00 1.000008 1 0 0 0 +( -480 -512 416 ) ( -480 -544 416 ) ( -480 -544 384 ) eden/edenmetalwall -33 63 -180.00 1 -1 0 0 0 +( -480 -544 96 ) ( 224 -544 96 ) ( 224 -544 64 ) eden/edenmetalwall -32 62 0.00 1.000008 1 0 0 0 +} +// brush 15 +{ +( -480 -512 0 ) ( -480 -544 0 ) ( 224 -544 0 ) eden/bedtrim -31 32 -90.00 1 1 0 0 0 +( 224 -544 64 ) ( -480 -544 64 ) ( -480 -512 64 ) eden/bedtrim -31 32 -90.00 1 1 0 0 0 +( 224 -544 256 ) ( 224 -512 256 ) ( 224 -512 0 ) eden/bedtrim -32 0 -180.00 1 -1 0 0 0 +( 224 -512 256 ) ( -480 -512 256 ) ( -480 -512 0 ) eden/bedtrim -32 0 0.00 1 1 0 0 0 +( -480 -512 256 ) ( -480 -544 256 ) ( -480 -544 0 ) eden/bedtrim -33 0 -180.00 1 -1 0 0 0 +( -480 -544 256 ) ( 224 -544 256 ) ( 224 -544 0 ) eden/bedtrim -32 0 0.00 1 1 0 0 0 +} +// brush 16 +{ +( 192 -512 0 ) ( 224 -512 0 ) ( 224 192 0 ) eden/bedtrim 160 0 -180.00 1 1 0 0 0 +( 224 192 64 ) ( 224 -512 64 ) ( 192 -512 64 ) eden/bedtrim 160 0 -180.00 1 1 0 0 0 +( 224 192 256 ) ( 192 192 256 ) ( 192 192 0 ) eden/bedtrim 160 0 -180.00 1 -1 0 0 0 +( 192 192 256 ) ( 192 -512 256 ) ( 192 -512 0 ) eden/bedtrim -64 0 -180.00 1 -1 0 0 0 +( 192 -512 256 ) ( 224 -512 256 ) ( 224 -512 0 ) eden/bedtrim 159 0 -180.00 1 -1 0 0 0 +( 224 -512 256 ) ( 224 192 256 ) ( 224 192 0 ) eden/bedtrim -64 0 -180.00 1 -1 0 0 0 +} +// brush 17 +{ +( 192 -512 64 ) ( 224 -512 64 ) ( 224 192 64 ) eden/edenmetalwall 160 63 -180.00 1 1 0 0 0 +( 224 192 640 ) ( 224 -512 640 ) ( 192 -512 640 ) eden/edenmetalwall 160 63 -180.00 1 1 0 0 0 +( 224 192 96 ) ( 192 192 96 ) ( 192 192 64 ) eden/edenmetalwall 160 64 -180.00 1 -1 0 0 0 +( 192 192 416 ) ( 192 -512 416 ) ( 192 -512 384 ) eden/edenmetalwall -64 62 -180.00 1 -1 0 0 0 +( 192 -512 96 ) ( 224 -512 96 ) ( 224 -512 64 ) eden/edenmetalwall 159 64 -180.00 1 -1 0 0 0 +( 224 -512 96 ) ( 224 192 96 ) ( 224 192 64 ) eden/edenmetalwall -64 62 -180.00 1 -1 0 0 0 +} +} +// entity 1 +{ +"targetname" "movinlight2" +"classname" "script_object" +// brush 0 +{ +( 16 -368 144 ) ( 0 -368 144 ) ( 0 -384 144 ) common/skip 32 16 0.00 1 1 805306368 16512 0 +( 0 -384 160 ) ( 0 -368 160 ) ( 16 -368 160 ) common/skip 32 16 0.00 1 1 805306368 16512 0 +( 0 -384 240 ) ( 16 -384 240 ) ( 16 -384 144 ) common/skip 32 -48 0.00 1 1 805306368 16512 0 +( 16 -384 240 ) ( 16 -368 240 ) ( 16 -368 144 ) common/skip -16 -48 0.00 1 1 805306368 16512 0 +( 16 -368 240 ) ( 0 -368 240 ) ( 0 -368 144 ) common/skip 32 -48 0.00 1 1 805306368 16512 0 +( 0 -368 240 ) ( 0 -384 240 ) ( 0 -384 144 ) common/skip -16 -48 0.00 1 1 805306368 16512 0 +} +} +// entity 2 +{ +"targetname" "movinlight1" +"classname" "script_object" +// brush 0 +{ +( -344 64 144 ) ( -360 64 144 ) ( -360 48 144 ) common/skip 0 0 0.00 1 1 805306368 16512 0 +( -360 48 160 ) ( -360 64 160 ) ( -344 64 160 ) common/skip 0 0 0.00 1 1 805306368 16512 0 +( -360 48 240 ) ( -344 48 240 ) ( -344 48 144 ) common/skip 0 -48 0.00 1 1 805306368 16512 0 +( -344 48 240 ) ( -344 64 240 ) ( -344 64 144 ) common/skip 0 -48 0.00 1 1 805306368 16512 0 +( -344 64 240 ) ( -360 64 240 ) ( -360 64 144 ) common/skip 0 -48 0.00 1 1 805306368 16512 0 +( -360 64 240 ) ( -360 48 240 ) ( -360 48 144 ) common/skip 0 -48 0.00 1 1 805306368 16512 0 +} +} +// entity 3 +{ +"classname" "light" +"spawnflags" "0" +"origin" "-352 56 168" +"light" "200" +"_color" "1.000000 0.724409 0.523622" +} +// entity 4 +{ +"classname" "info_player_start" +"angle" "0" +"origin" "-416 -176 24" +} +// entity 5 +{ +"origin" "8 56 168" +"spawnflags" "0" +"classname" "light" +"light" "200" +"_color" "0.629921 0.846457 1.000000" +} +// entity 6 +{ +"origin" "-344 -376 168" +"spawnflags" "0" +"classname" "light" +"light" "200" +} +// entity 7 +{ +"classname" "light" +"spawnflags" "0" +"origin" "8 -376 168" +"light" "200" +} +// entity 8 +{ +"light" "200" +"classname" "light" +"spawnflags" "0" +"origin" "-168 -160 168" +} +// entity 9 +{ +"_color" "1.000000 0.724409 0.523622" +"light" "200" +"origin" "-352 56 384" +"spawnflags" "0" +"classname" "light" +} +// entity 10 +{ +"_color" "0.629921 0.846457 1.000000" +"light" "200" +"classname" "light" +"spawnflags" "0" +"origin" "8 56 384" +} +// entity 11 +{ +"light" "200" +"classname" "light" +"spawnflags" "0" +"origin" "-344 -376 384" +} +// entity 12 +{ +"light" "200" +"origin" "8 -376 384" +"spawnflags" "0" +"classname" "light" +} +// entity 13 +{ +"origin" "-168 -160 384" +"spawnflags" "0" +"classname" "light" +"light" "200" +} diff --git a/fakk/maps/example/autosprite.prt b/fakk/maps/example/autosprite.prt new file mode 100644 index 0000000..ff1e3bb --- /dev/null +++ b/fakk/maps/example/autosprite.prt @@ -0,0 +1,24 @@ +PRT1 +4 +4 +16 +4 0 2 0 (0 0 0 ) (0 0 608 ) (0 192 608 ) (0 192 0 ) +4 0 1 0 (0 0 608 ) (0 0 0 ) (192 0 0 ) (192 0 608 ) +4 1 3 0 (0 -512 0 ) (0 -512 608 ) (0 0 608 ) (0 0 0 ) +4 2 3 0 (0 0 0 ) (0 0 608 ) (-480 0 608 ) (-480 0 0 ) +4 0 (0 0 608 ) (192 0 608 ) (192 192 608 ) (0 192 608 ) +4 0 (192 192 608 ) (192 192 0 ) (0 192 0 ) (0 192 608 ) +4 0 (192 0 608 ) (192 0 0 ) (192 192 0 ) (192 192 608 ) +4 0 (0 192 0 ) (192 192 0 ) (192 0 0 ) (0 0 0 ) +4 1 (0 -512 608 ) (192 -512 608 ) (192 0 608 ) (0 0 608 ) +4 1 (0 -512 608 ) (0 -512 0 ) (192 -512 0 ) (192 -512 608 ) +4 1 (192 -512 608 ) (192 -512 0 ) (192 0 0 ) (192 0 608 ) +4 1 (0 0 0 ) (192 0 0 ) (192 -512 0 ) (0 -512 0 ) +4 2 (0 192 608 ) (-480 192 608 ) (-480 0 608 ) (0 0 608 ) +4 2 (-480 192 0 ) (-480 192 608 ) (0 192 608 ) (0 192 0 ) +4 2 (-480 192 608 ) (-480 192 0 ) (-480 0 0 ) (-480 0 608 ) +4 2 (0 0 0 ) (-480 0 0 ) (-480 192 0 ) (0 192 0 ) +4 3 (0 0 608 ) (-480 0 608 ) (-480 -512 608 ) (0 -512 608 ) +4 3 (-480 0 608 ) (-480 0 0 ) (-480 -512 0 ) (-480 -512 608 ) +4 3 (-480 -512 608 ) (-480 -512 0 ) (0 -512 0 ) (0 -512 608 ) +4 3 (0 -512 0 ) (-480 -512 0 ) (-480 0 0 ) (0 0 0 ) diff --git a/fakk/maps/example/beam.bsp b/fakk/maps/example/beam.bsp new file mode 100644 index 0000000..c393cb5 Binary files /dev/null and b/fakk/maps/example/beam.bsp differ diff --git a/fakk/maps/example/beam.map b/fakk/maps/example/beam.map new file mode 100644 index 0000000..096c6da --- /dev/null +++ b/fakk/maps/example/beam.map @@ -0,0 +1,320 @@ +{ +"classname" "worldspawn" +// brush 0 +{ +( 224 192 0 ) ( 224 224 0 ) ( -480 224 0 ) eden/bedtrim -224 -32 90.00 1 1 0 0 0 +( -480 224 64 ) ( 224 224 64 ) ( 224 192 64 ) eden/bedtrim -224 -32 90.00 1 1 0 0 0 +( -480 224 256 ) ( -480 192 256 ) ( -480 192 0 ) eden/bedtrim -224 0 0.00 1 1 0 0 0 +( -480 192 256 ) ( 224 192 256 ) ( 224 192 0 ) common/skip 0 0 0.00 1 1 805306368 16512 0 +( 224 224 256 ) ( -480 224 256 ) ( -480 224 0 ) eden/bedtrim 224 0 -180.00 1 -1 0 0 0 +( -416 224 0 ) ( -416 192 0 ) ( -416 208 64 ) eden/bedtrim 224 0 -180.00 1 -1 0 0 0 +} +// brush 1 +{ +( 224 192 0 ) ( 224 224 0 ) ( -480 224 0 ) eden/bedtrim -224 -32 90.00 1 1 0 0 0 +( -480 224 64 ) ( 224 224 64 ) ( 224 192 64 ) eden/bedtrim -224 -32 90.00 1 1 0 0 0 +( -480 192 256 ) ( 224 192 256 ) ( 224 192 0 ) eden/bedtrim 224 0 -180.00 1 -1 0 0 0 +( 224 192 256 ) ( 224 224 256 ) ( 224 224 0 ) eden/bedtrim -224 0 0.00 1 1 0 0 0 +( 224 224 256 ) ( -480 224 256 ) ( -480 224 0 ) eden/bedtrim 224 0 -180.00 1 -1 0 0 0 +( -480 192 0 ) ( -480 224 0 ) ( -480 208 64 ) eden/bedtrim 224 0 -180.00 1 -1 0 0 0 +} +// brush 2 +{ +( 224 192 64 ) ( 224 224 64 ) ( -480 224 64 ) eden/edenmetalwall -224 -224 90.00 1 1 0 0 0 +( -480 224 320 ) ( 224 224 320 ) ( 224 192 320 ) eden/edenmetalwall -224 -224 90.00 1 1 0 0 0 +( -480 224 96 ) ( -480 192 96 ) ( -480 192 64 ) eden/edenmetalwall -224 64 0.00 1 1 0 0 0 +( -480 192 96 ) ( 224 192 96 ) ( 224 192 64 ) common/skip 0 0 0.00 1 1 805306368 16512 0 +( 224 224 96 ) ( -480 224 96 ) ( -480 224 64 ) eden/edenmetalwall 224 63 -180.00 1 -1 0 0 0 +( -416 224 64 ) ( -416 192 64 ) ( -416 208 320 ) eden/edenmetalwall 224 63 -180.00 1 -1 0 0 0 +} +// brush 3 +{ +( 224 192 64 ) ( 224 224 64 ) ( -480 224 64 ) eden/edenmetalwall -224 -224 90.00 1 1 0 0 0 +( -480 224 320 ) ( 224 224 320 ) ( 224 192 320 ) eden/edenmetalwall -224 -224 90.00 1 1 0 0 0 +( -480 192 96 ) ( 224 192 96 ) ( 224 192 64 ) eden/edenmetalwall 224 63 -180.00 1 -1 0 0 0 +( 224 192 96 ) ( 224 224 96 ) ( 224 224 64 ) eden/edenmetalwall -224 64 0.00 1 1 0 0 0 +( 224 224 96 ) ( -480 224 96 ) ( -480 224 64 ) eden/edenmetalwall 224 63 -180.00 1 -1 0 0 0 +( -480 192 64 ) ( -480 224 64 ) ( -480 208 320 ) eden/edenmetalwall 224 63 -180.00 1 -1 0 0 0 +} +// brush 4 + { + patchDef2 + { + eden/edenmetalwall + ( 3 3 0 536870912 0 ) +( +( ( -480 96 63.999992 0 0 ) ( -480 96 192 0 0.500000 ) ( -480 96 320 0 1 ) ) +( ( -384 96 63.999992 0.500000 0 ) ( -384 96 192 0.500000 0.500000 ) ( -384 96 320 0.500000 1 ) ) +( ( -384 192 63.999992 1 0 ) ( -384 192 192 1 0.500000 ) ( -384 192 320 1 1 ) ) +) + } + } +// brush 5 +{ +( -480 192 0 ) ( -512 192 0 ) ( -512 -512 0 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +( -512 -512 64 ) ( -512 192 64 ) ( -480 192 64 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +( -480 -512 256 ) ( -480 192 256 ) ( -480 192 0 ) common/skip 0 0 0.00 1 1 805306368 16512 0 +( -480 192 256 ) ( -512 192 256 ) ( -512 192 0 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +( -512 192 256 ) ( -512 -512 256 ) ( -512 -512 0 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +( -480 128 0 ) ( -512 128 0 ) ( -496 128 64 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +} +// brush 6 +{ +( -480 192 0 ) ( -512 192 0 ) ( -512 -512 0 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +( -512 -512 64 ) ( -512 192 64 ) ( -480 192 64 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +( -512 -512 256 ) ( -480 -512 256 ) ( -480 -512 0 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +( -480 -512 256 ) ( -480 192 256 ) ( -480 192 0 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +( -512 192 256 ) ( -512 -512 256 ) ( -512 -512 0 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +( -512 192 0 ) ( -480 192 0 ) ( -496 192 64 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +} +// brush 7 +{ +( -480 192 64 ) ( -512 192 64 ) ( -512 -512 64 ) eden/edenmetalwall 0 0 0.00 1 1 0 0 0 +( -512 -512 320 ) ( -512 192 320 ) ( -480 192 320 ) eden/edenmetalwall 0 0 0.00 1 1 0 0 0 +( -480 -512 96 ) ( -480 192 96 ) ( -480 192 64 ) common/skip 0 0 0.00 1 1 805306368 16512 0 +( -480 192 96 ) ( -512 192 96 ) ( -512 192 64 ) eden/edenmetalwall 0 64 0.00 1 1 0 0 0 +( -512 192 96 ) ( -512 -512 96 ) ( -512 -512 64 ) eden/edenmetalwall 0 64 0.00 1 1 0 0 0 +( -480 128 64 ) ( -512 128 64 ) ( -496 128 320 ) eden/edenmetalwall 0 64 0.00 1 1 0 0 0 +} +// brush 8 +{ +( -480 192 64 ) ( -512 192 64 ) ( -512 -512 64 ) eden/edenmetalwall 0 0 0.00 1 1 0 0 0 +( -512 -512 320 ) ( -512 192 320 ) ( -480 192 320 ) eden/edenmetalwall 0 0 0.00 1 1 0 0 0 +( -512 -512 96 ) ( -480 -512 96 ) ( -480 -512 64 ) eden/edenmetalwall 0 64 0.00 1 1 0 0 0 +( -480 -512 96 ) ( -480 192 96 ) ( -480 192 64 ) eden/edenmetalwall 0 64 0.00 1 1 0 0 0 +( -512 192 96 ) ( -512 -512 96 ) ( -512 -512 64 ) eden/edenmetalwall 0 64 0.00 1 1 0 0 0 +( -512 192 64 ) ( -480 192 64 ) ( -496 192 320 ) eden/edenmetalwall 0 64 0.00 1 1 0 0 0 +} +// brush 9 + { + patchDef2 + { + eden/bedtrim + ( 3 3 0 536870912 0 ) +( +( ( -480 96 0 0 0 ) ( -480 96 32 0 0.500000 ) ( -480 96 64 0 1 ) ) +( ( -384 96 0 0.500000 0 ) ( -384 96 32 0.500000 0.500000 ) ( -384 96 64 0.500000 1 ) ) +( ( -384 192 0 1 0 ) ( -384 192 32 1 0.500000 ) ( -384 192 64 1 1 ) ) +) + } + } +// brush 10 +{ +( 96 96 352 ) ( -32 96 352 ) ( -32 -416 352 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( -32 -416 416 ) ( -32 96 416 ) ( 96 96 416 ) we_cemetary_test/levelord_sky 0 0 0.00 1 1 0 0 0 +( -32 -416 416 ) ( 96 -416 416 ) ( 96 -416 352 ) we_cemetary_test/levelord_sky 0 0 0.00 1 1 0 0 0 +( 96 -416 416 ) ( 96 96 416 ) ( 96 96 352 ) we_cemetary_test/levelord_sky 0 0 0.00 1 1 0 0 0 +( 96 96 416 ) ( -32 96 416 ) ( -32 96 352 ) we_cemetary_test/levelord_sky 0 0 0.00 1 1 0 0 0 +( -32 96 416 ) ( -32 -416 416 ) ( -32 -416 352 ) we_cemetary_test/levelord_sky 0 0 0.00 1 1 0 0 0 +} +// brush 11 +{ +( -64 -416 304 ) ( -64 -448 304 ) ( 128 -448 304 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( 128 -448 352 ) ( -64 -448 352 ) ( -64 -416 352 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( 96 -416 352 ) ( -32 -416 352 ) ( -32 -416 320 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( 128 -448 352 ) ( 96 -416 352 ) ( 96 -416 320 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( -64 -448 320 ) ( -64 -448 352 ) ( 128 -448 352 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( -64 -448 320 ) ( -32 -416 320 ) ( -32 -416 352 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +} +// brush 12 +{ +( -32 128 304 ) ( -64 128 304 ) ( -64 -64 304 ) eden/FL_edenhouse 0 32 90.00 1 1 0 0 0 +( -64 -64 352 ) ( -64 128 352 ) ( -32 128 352 ) eden/FL_edenhouse 0 32 90.00 1 1 0 0 0 +( -32 -32 352 ) ( -32 96 352 ) ( -32 96 320 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( -64 -448 352 ) ( -32 -416 352 ) ( -32 -416 320 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( -64 128 320 ) ( -64 128 352 ) ( -64 -64 352 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( -64 128 320 ) ( -32 96 320 ) ( -32 96 352 ) eden/FL_edenhouse -64 0 -180.00 1 -1 0 0 0 +} +// brush 13 +{ +( 128 -64 304 ) ( 128 128 304 ) ( 96 128 304 ) eden/FL_edenhouse 0 -96 90.00 1 1 0 0 0 +( 96 128 352 ) ( 128 128 352 ) ( 128 -64 352 ) eden/FL_edenhouse 0 -96 90.00 1 1 0 0 0 +( 96 96 320 ) ( 96 96 352 ) ( 96 -32 352 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( 96 -416 320 ) ( 96 -416 352 ) ( 128 -448 352 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( 128 -64 352 ) ( 128 128 352 ) ( 128 128 320 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( 96 96 352 ) ( 96 96 320 ) ( 128 128 320 ) eden/FL_edenhouse -64 0 -180.00 1 -1 0 0 0 +} +// brush 14 +{ +( 128 128 304 ) ( -64 128 304 ) ( -64 96 304 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( -64 96 352 ) ( -64 128 352 ) ( 128 128 352 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( -32 96 320 ) ( -32 96 352 ) ( 96 96 352 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( 96 96 320 ) ( 96 96 352 ) ( 128 128 352 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( 128 128 352 ) ( -64 128 352 ) ( -64 128 320 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( -32 96 352 ) ( -32 96 320 ) ( -64 128 320 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +} +// brush 15 +{ +( 128 192 320 ) ( -64 192 320 ) ( -64 128 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( -64 128 352 ) ( -64 192 352 ) ( 128 192 352 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( -64 128 352 ) ( 128 128 352 ) ( 128 128 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( 128 128 352 ) ( 128 192 352 ) ( 128 192 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( 128 192 352 ) ( -64 192 352 ) ( -64 192 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( -64 192 352 ) ( -64 128 352 ) ( -64 128 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +} +// brush 16 +{ +( 192 192 320 ) ( 128 192 320 ) ( 128 -448 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( 128 -448 352 ) ( 128 192 352 ) ( 192 192 352 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( 128 -448 352 ) ( 192 -448 352 ) ( 192 -448 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( 192 -448 352 ) ( 192 192 352 ) ( 192 192 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( 192 192 352 ) ( 128 192 352 ) ( 128 192 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( 128 192 352 ) ( 128 -448 352 ) ( 128 -448 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +} +// brush 17 +{ +( 192 192 320 ) ( -480 192 320 ) ( -480 -512 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( -480 -512 352 ) ( -480 192 352 ) ( 192 192 352 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( -480 -512 352 ) ( 192 -512 352 ) ( 192 -512 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( 192 -512 352 ) ( 192 192 352 ) ( 192 192 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( 224 -448 352 ) ( -448 -448 352 ) ( -448 -448 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( -64 -256 320 ) ( -64 -128 320 ) ( -64 -192 352 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +} +// brush 18 +{ +( 192 192 320 ) ( -480 192 320 ) ( -480 -512 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( -480 -512 352 ) ( -480 192 352 ) ( 192 192 352 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( -480 -512 352 ) ( 192 -512 352 ) ( 192 -512 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( 192 192 352 ) ( -480 192 352 ) ( -480 192 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( -480 192 352 ) ( -480 -512 352 ) ( -480 -512 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( -64 -128 320 ) ( -64 -256 320 ) ( -64 -192 352 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +} +// brush 19 +{ +( 192 192 -32 ) ( -480 192 -32 ) ( -480 -512 -32 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( -480 -512 0 ) ( -480 192 0 ) ( 192 192 0 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( -480 -512 224 ) ( 192 -512 224 ) ( 192 -512 -32 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 192 -512 224 ) ( 192 192 224 ) ( 192 192 -32 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 192 192 224 ) ( -480 192 224 ) ( -480 192 -32 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( -480 192 224 ) ( -480 -512 224 ) ( -480 -512 -32 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +} +// brush 20 +{ +( -480 -512 64 ) ( -480 -544 64 ) ( 224 -544 64 ) eden/edenmetalwall -31 31 -90.00 1 1 0 0 0 +( 224 -544 320 ) ( -480 -544 320 ) ( -480 -512 320 ) eden/edenmetalwall -31 31 -90.00 1 1 0 0 0 +( 224 -544 96 ) ( 224 -512 96 ) ( 224 -512 64 ) eden/edenmetalwall -32 63 -180.00 1 -1 0 0 0 +( 224 -512 96 ) ( -480 -512 96 ) ( -480 -512 64 ) eden/edenmetalwall -32 62 0.00 1.000008 1 0 0 0 +( -480 -512 96 ) ( -480 -544 96 ) ( -480 -544 64 ) eden/edenmetalwall -33 63 -180.00 1 -1 0 0 0 +( -480 -544 96 ) ( 224 -544 96 ) ( 224 -544 64 ) eden/edenmetalwall -32 62 0.00 1.000008 1 0 0 0 +} +// brush 21 +{ +( -480 -512 0 ) ( -480 -544 0 ) ( 224 -544 0 ) eden/bedtrim -31 32 -90.00 1 1 0 0 0 +( 224 -544 64 ) ( -480 -544 64 ) ( -480 -512 64 ) eden/bedtrim -31 32 -90.00 1 1 0 0 0 +( 224 -544 256 ) ( 224 -512 256 ) ( 224 -512 0 ) eden/bedtrim -32 0 -180.00 1 -1 0 0 0 +( 224 -512 256 ) ( -480 -512 256 ) ( -480 -512 0 ) eden/bedtrim -32 0 0.00 1 1 0 0 0 +( -480 -512 256 ) ( -480 -544 256 ) ( -480 -544 0 ) eden/bedtrim -33 0 -180.00 1 -1 0 0 0 +( -480 -544 256 ) ( 224 -544 256 ) ( 224 -544 0 ) eden/bedtrim -32 0 0.00 1 1 0 0 0 +} +// brush 22 +{ +( 192 -512 0 ) ( 224 -512 0 ) ( 224 192 0 ) eden/bedtrim 160 0 -180.00 1 1 0 0 0 +( 224 192 64 ) ( 224 -512 64 ) ( 192 -512 64 ) eden/bedtrim 160 0 -180.00 1 1 0 0 0 +( 224 192 256 ) ( 192 192 256 ) ( 192 192 0 ) eden/bedtrim 160 0 -180.00 1 -1 0 0 0 +( 192 192 256 ) ( 192 -512 256 ) ( 192 -512 0 ) eden/bedtrim -64 0 -180.00 1 -1 0 0 0 +( 192 -512 256 ) ( 224 -512 256 ) ( 224 -512 0 ) eden/bedtrim 159 0 -180.00 1 -1 0 0 0 +( 224 -512 256 ) ( 224 192 256 ) ( 224 192 0 ) eden/bedtrim -64 0 -180.00 1 -1 0 0 0 +} +// brush 23 +{ +( 192 -512 64 ) ( 224 -512 64 ) ( 224 192 64 ) eden/edenmetalwall 160 63 -180.00 1 1 0 0 0 +( 224 192 320 ) ( 224 -512 320 ) ( 192 -512 320 ) eden/edenmetalwall 160 63 -180.00 1 1 0 0 0 +( 224 192 96 ) ( 192 192 96 ) ( 192 192 64 ) eden/edenmetalwall 160 64 -180.00 1 -1 0 0 0 +( 192 192 96 ) ( 192 -512 96 ) ( 192 -512 64 ) eden/edenmetalwall -64 62 -180.00 1 -1 0 0 0 +( 192 -512 96 ) ( 224 -512 96 ) ( 224 -512 64 ) eden/edenmetalwall 159 64 -180.00 1 -1 0 0 0 +( 224 -512 96 ) ( 224 192 96 ) ( 224 192 64 ) eden/edenmetalwall -64 62 -180.00 1 -1 0 0 0 +} +} +// entity 1 +{ +"origin" "-116 -44 76" +"targetname" "t6" +"classname" "info_notnull" +} +// entity 2 +{ +"origin" "-196 -60 180" +"targetname" "t5" +"classname" "info_notnull" +} +// entity 3 +{ +"shader" "beam_darkblue" +"numsegments" "5" +"maxoffset" "0" +"minoffset" "0" +"origin" "-416 -56 184" +"spawnflags" "1" +"target" "t5" +"classname" "func_beam" +"targetname" "blah" +"rendereffects" "+lightstyledynamiclight" +} +// entity 4 +{ +"classname" "script_object" +"targetname" "t2" +// brush 0 +{ +( 16 -360 144 ) ( 0 -360 144 ) ( 0 -376 144 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( 0 -376 160 ) ( 0 -360 160 ) ( 16 -360 160 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( 0 -376 240 ) ( 16 -376 240 ) ( 16 -376 144 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( 16 -376 240 ) ( 16 -360 240 ) ( 16 -360 144 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( 16 -360 240 ) ( 0 -360 240 ) ( 0 -360 144 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( 0 -360 240 ) ( 0 -376 240 ) ( 0 -376 144 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +} +} +// entity 5 +{ +"_color" "1.000000 0.724409 0.523622" +"light" "200" +"origin" "-352 48 168" +"spawnflags" "0" +"classname" "light" +} +// entity 6 +{ +"origin" "-432 -464 24" +"angle" "45" +"classname" "info_player_start" +} +// entity 7 +{ +"_color" "0.629921 0.846457 1.000000" +"light" "200" +"classname" "light" +"spawnflags" "0" +"origin" "8 56 168" +} +// entity 8 +{ +"light" "200" +"classname" "light" +"spawnflags" "0" +"origin" "-344 -376 168" +} +// entity 9 +{ +"light" "200" +"origin" "8 -380 168" +"spawnflags" "0" +"classname" "light" +} +// entity 10 +{ +"origin" "-168 -160 168" +"spawnflags" "0" +"classname" "light" +"light" "200" +} +// entity 11 +{ +"classname" "func_beam" +"target" "t6" +"spawnflags" "1" +"origin" "-112 -40 248" +"minoffset" "0" +"maxoffset" "0" +"numsegments" "5" +"shader" "beam_darkblue" +} diff --git a/fakk/maps/example/beam.prt b/fakk/maps/example/beam.prt new file mode 100644 index 0000000..63b4d74 --- /dev/null +++ b/fakk/maps/example/beam.prt @@ -0,0 +1,96 @@ +PRT1 +16 +28 +64 +4 0 4 0 (128 0 304 ) (192 0 304 ) (192 0 320 ) (128 0 320 ) +4 0 3 0 (128 192 304 ) (192 192 304 ) (192 0 304 ) (128 0 304 ) +4 0 1 0 (128 192 320 ) (128 192 304 ) (128 128 304 ) (128 128 320 ) +4 1 8 0 (0 192 320 ) (0 192 304 ) (0 128 304 ) (0 128 320 ) +4 1 3 0 (0 192 304 ) (128 192 304 ) (128 128 304 ) (0 128 304 ) +4 2 9 0 (0 0 304 ) (0 0 352 ) (0 96 352 ) (0 96 304 ) +4 2 5 0 (0 0 352 ) (0 0 304 ) (96 0 304 ) (96 0 352 ) +4 2 3 0 (96 0 304 ) (0 0 304 ) (0 96 304 ) (96 96 304 ) +4 3 11 0 (0 0 0 ) (0 0 304 ) (0 192 304 ) (0 192 0 ) +4 3 7 0 (0 0 304 ) (0 0 0 ) (192 0 0 ) (192 0 304 ) +4 4 7 0 (128 0 304 ) (192 0 304 ) (192 -448 304 ) (128 -448 304 ) +4 4 6 0 (128 -448 304 ) (192 -448 304 ) (192 -448 320 ) (128 -448 320 ) +4 5 12 0 (0 0 352 ) (0 0 304 ) (0 -416 304 ) (0 -416 352 ) +4 5 7 0 (0 0 304 ) (96 0 304 ) (96 -416 304 ) (0 -416 304 ) +4 6 13 0 (0 -512 304 ) (0 -512 320 ) (0 -448 320 ) (0 -448 304 ) +4 6 7 0 (192 -448 304 ) (192 -512 304 ) (0 -512 304 ) (0 -448 304 ) +4 7 15 0 (0 -512 0 ) (0 -512 304 ) (0 0 304 ) (0 0 0 ) +4 8 11 0 (-64 128 304 ) (-64 192 304 ) (0 192 304 ) (0 128 304 ) +4 8 10 0 (-64 192 320 ) (-64 192 304 ) (-64 128 304 ) (-64 128 320 ) +4 9 12 0 (0 0 304 ) (0 0 352 ) (-32 0 352 ) (-32 0 304 ) +4 9 11 0 (0 0 304 ) (-32 0 304 ) (-32 96 304 ) (0 96 304 ) +4 10 14 0 (-480 0 320 ) (-480 0 304 ) (-64 0 304 ) (-64 0 320 ) +4 10 11 0 (-64 0 304 ) (-480 0 304 ) (-480 192 304 ) (-64 192 304 ) +4 11 15 0 (0 0 0 ) (0 0 304 ) (-480 0 304 ) (-480 0 0 ) +4 12 15 0 (-32 0 304 ) (0 0 304 ) (0 -416 304 ) (-32 -416 304 ) +4 13 15 0 (0 -512 304 ) (-64 -512 304 ) (-64 -448 304 ) (0 -448 304 ) +4 13 14 0 (-64 -448 304 ) (-64 -512 304 ) (-64 -512 320 ) (-64 -448 320 ) +4 14 15 0 (-64 -512 304 ) (-480 -512 304 ) (-480 0 304 ) (-64 0 304 ) +4 0 (128 96 304 ) (128 0 304 ) (128 0 320 ) (128 96 320 ) +4 0 (128 128 304 ) (128 96 304 ) (128 96 320 ) (128 128 320 ) +4 0 (192 0 320 ) (192 0 304 ) (192 192 304 ) (192 192 320 ) +4 0 (128 192 320 ) (192 192 320 ) (192 192 304 ) (128 192 304 ) +4 0 (192 0 320 ) (192 192 320 ) (128 192 320 ) (128 0 320 ) +4 1 (0 128 304 ) (128 128 304 ) (128 128 320 ) (0 128 320 ) +4 1 (128 192 320 ) (128 192 304 ) (0 192 304 ) (0 192 320 ) +4 1 (128 192 320 ) (0 192 320 ) (0 128 320 ) (128 128 320 ) +4 2 (96 96 352 ) (0 96 352 ) (0 0 352 ) (96 0 352 ) +4 2 (0 96 352 ) (96 96 352 ) (96 96 304 ) (0 96 304 ) +4 2 (96 0 352 ) (96 0 304 ) (96 96 304 ) (96 96 352 ) +4 3 (192 192 304 ) (192 192 0 ) (0 192 0 ) (0 192 304 ) +4 3 (192 0 304 ) (192 0 0 ) (192 192 0 ) (192 192 304 ) +4 3 (0 128 304 ) (0 96 304 ) (128 96 304 ) (128 128 304 ) +4 3 (96 96 304 ) (96 0 304 ) (128 0 304 ) (128 96 304 ) +4 3 (0 192 0 ) (192 192 0 ) (192 0 0 ) (0 0 0 ) +4 4 (128 0 304 ) (128 -448 304 ) (128 -448 320 ) (128 0 320 ) +4 4 (192 -448 320 ) (192 -448 304 ) (192 0 304 ) (192 0 320 ) +4 4 (192 0 320 ) (128 0 320 ) (128 -448 320 ) (192 -448 320 ) +4 5 (96 -416 352 ) (96 0 352 ) (0 0 352 ) (0 -416 352 ) +4 5 (96 0 352 ) (96 -416 352 ) (96 -416 304 ) (96 0 304 ) +4 5 (0 -416 304 ) (96 -416 304 ) (96 -416 352 ) (0 -416 352 ) +4 6 (192 -448 320 ) (192 -512 320 ) (192 -512 304 ) (192 -448 304 ) +4 6 (0 -512 320 ) (0 -512 304 ) (192 -512 304 ) (192 -512 320 ) +4 6 (96 -448 320 ) (128 -448 320 ) (128 -448 304 ) (96 -448 304 ) +4 6 (96 -448 320 ) (96 -448 304 ) (0 -448 304 ) (0 -448 320 ) +4 6 (0 -512 320 ) (192 -512 320 ) (192 -448 320 ) (0 -448 320 ) +4 7 (0 -512 304 ) (0 -512 0 ) (192 -512 0 ) (192 -512 304 ) +4 7 (192 -512 304 ) (192 -512 0 ) (192 0 0 ) (192 0 304 ) +4 7 (96 -448 304 ) (128 -448 304 ) (128 0 304 ) (96 0 304 ) +4 7 (0 -416 304 ) (0 -448 304 ) (96 -448 304 ) (96 -416 304 ) +4 7 (0 0 0 ) (192 0 0 ) (192 -512 0 ) (0 -512 0 ) +4 8 (-64 128 320 ) (-64 128 304 ) (0 128 304 ) (0 128 320 ) +4 8 (-64 192 304 ) (-64 192 320 ) (0 192 320 ) (0 192 304 ) +4 8 (0 192 320 ) (-64 192 320 ) (-64 128 320 ) (0 128 320 ) +4 9 (0 96 352 ) (-32 96 352 ) (-32 0 352 ) (0 0 352 ) +4 9 (0 96 304 ) (-32 96 304 ) (-32 96 352 ) (0 96 352 ) +4 9 (-32 96 352 ) (-32 96 304 ) (-32 0 304 ) (-32 0 352 ) +4 10 (-480 192 320 ) (-480 192 304 ) (-480 0 304 ) (-480 0 320 ) +4 10 (-64 192 320 ) (-64 192 304 ) (-480 192 304 ) (-480 192 320 ) +4 10 (-64 128 320 ) (-64 96 320 ) (-64 96 304 ) (-64 128 304 ) +4 10 (-64 96 320 ) (-64 0 320 ) (-64 0 304 ) (-64 96 304 ) +4 10 (-64 0 320 ) (-64 192 320 ) (-480 192 320 ) (-480 0 320 ) +4 11 (-480 192 0 ) (-480 192 304 ) (0 192 304 ) (0 192 0 ) +4 11 (-480 192 304 ) (-480 192 0 ) (-480 0 0 ) (-480 0 304 ) +4 11 (0 96 304 ) (0 128 304 ) (-64 128 304 ) (-64 96 304 ) +4 11 (-32 96 304 ) (-64 96 304 ) (-64 0 304 ) (-32 0 304 ) +4 11 (0 0 0 ) (-480 0 0 ) (-480 192 0 ) (0 192 0 ) +4 12 (0 -416 352 ) (-32 -416 352 ) (-32 -416 304 ) (0 -416 304 ) +4 12 (-32 -416 352 ) (0 -416 352 ) (0 0 352 ) (-32 0 352 ) +4 12 (-32 0 304 ) (-32 -416 304 ) (-32 -416 352 ) (-32 0 352 ) +4 13 (-64 -512 304 ) (0 -512 304 ) (0 -512 320 ) (-64 -512 320 ) +4 13 (0 -448 320 ) (0 -448 304 ) (-64 -448 304 ) (-64 -448 320 ) +4 13 (0 -448 320 ) (-64 -448 320 ) (-64 -512 320 ) (0 -512 320 ) +4 14 (-480 -512 320 ) (-480 -512 304 ) (-64 -512 304 ) (-64 -512 320 ) +4 14 (-480 0 320 ) (-480 0 304 ) (-480 -512 304 ) (-480 -512 320 ) +4 14 (-64 -416 320 ) (-64 -448 320 ) (-64 -448 304 ) (-64 -416 304 ) +4 14 (-64 -416 320 ) (-64 -416 304 ) (-64 0 304 ) (-64 0 320 ) +4 14 (-480 0 320 ) (-480 -512 320 ) (-64 -512 320 ) (-64 0 320 ) +4 15 (-480 0 304 ) (-480 0 0 ) (-480 -512 0 ) (-480 -512 304 ) +4 15 (-480 -512 304 ) (-480 -512 0 ) (0 -512 0 ) (0 -512 304 ) +4 15 (0 -448 304 ) (0 -416 304 ) (-64 -416 304 ) (-64 -448 304 ) +4 15 (-32 -416 304 ) (-32 0 304 ) (-64 0 304 ) (-64 -416 304 ) +4 15 (0 -512 0 ) (-480 -512 0 ) (-480 0 0 ) (0 0 0 ) diff --git a/fakk/maps/example/beam.scr b/fakk/maps/example/beam.scr new file mode 100644 index 0000000..29a9b55 --- /dev/null +++ b/fakk/maps/example/beam.scr @@ -0,0 +1,3 @@ +waitforplayer +$blah lightstyle 20 +end diff --git a/fakk/maps/example/beam1.bsp b/fakk/maps/example/beam1.bsp new file mode 100644 index 0000000..6a4cb28 Binary files /dev/null and b/fakk/maps/example/beam1.bsp differ diff --git a/fakk/maps/example/beam1.map b/fakk/maps/example/beam1.map new file mode 100644 index 0000000..fb8dad5 --- /dev/null +++ b/fakk/maps/example/beam1.map @@ -0,0 +1,279 @@ +{ +"classname" "worldspawn" +// brush 0 +{ +( 224 192 0 ) ( 224 224 0 ) ( -480 224 0 ) eden/bedtrim -224 -32 90.00 1 1 0 0 0 +( -480 224 64 ) ( 224 224 64 ) ( 224 192 64 ) eden/bedtrim -224 -32 90.00 1 1 0 0 0 +( -480 224 256 ) ( -480 192 256 ) ( -480 192 0 ) eden/bedtrim -224 0 0.00 1 1 0 0 0 +( -480 192 256 ) ( 224 192 256 ) ( 224 192 0 ) common/skip 0 0 0.00 1 1 805306368 16512 0 +( 224 224 256 ) ( -480 224 256 ) ( -480 224 0 ) eden/bedtrim 224 0 -180.00 1 -1 0 0 0 +( -416 224 0 ) ( -416 192 0 ) ( -416 208 64 ) eden/bedtrim 224 0 -180.00 1 -1 0 0 0 +} +// brush 1 +{ +( 224 192 0 ) ( 224 224 0 ) ( -480 224 0 ) eden/bedtrim -224 -32 90.00 1 1 0 0 0 +( -480 224 64 ) ( 224 224 64 ) ( 224 192 64 ) eden/bedtrim -224 -32 90.00 1 1 0 0 0 +( -480 192 256 ) ( 224 192 256 ) ( 224 192 0 ) eden/bedtrim 224 0 -180.00 1 -1 0 0 0 +( 224 192 256 ) ( 224 224 256 ) ( 224 224 0 ) eden/bedtrim -224 0 0.00 1 1 0 0 0 +( 224 224 256 ) ( -480 224 256 ) ( -480 224 0 ) eden/bedtrim 224 0 -180.00 1 -1 0 0 0 +( -480 192 0 ) ( -480 224 0 ) ( -480 208 64 ) eden/bedtrim 224 0 -180.00 1 -1 0 0 0 +} +// brush 2 +{ +( 224 192 64 ) ( 224 224 64 ) ( -480 224 64 ) eden/edenmetalwall -224 -224 90.00 1 1 0 0 0 +( -480 224 320 ) ( 224 224 320 ) ( 224 192 320 ) eden/edenmetalwall -224 -224 90.00 1 1 0 0 0 +( -480 224 96 ) ( -480 192 96 ) ( -480 192 64 ) eden/edenmetalwall -224 64 0.00 1 1 0 0 0 +( -480 192 96 ) ( 224 192 96 ) ( 224 192 64 ) common/skip 0 0 0.00 1 1 805306368 16512 0 +( 224 224 96 ) ( -480 224 96 ) ( -480 224 64 ) eden/edenmetalwall 224 63 -180.00 1 -1 0 0 0 +( -416 224 64 ) ( -416 192 64 ) ( -416 208 320 ) eden/edenmetalwall 224 63 -180.00 1 -1 0 0 0 +} +// brush 3 +{ +( 224 192 64 ) ( 224 224 64 ) ( -480 224 64 ) eden/edenmetalwall -224 -224 90.00 1 1 0 0 0 +( -480 224 320 ) ( 224 224 320 ) ( 224 192 320 ) eden/edenmetalwall -224 -224 90.00 1 1 0 0 0 +( -480 192 96 ) ( 224 192 96 ) ( 224 192 64 ) eden/edenmetalwall 224 63 -180.00 1 -1 0 0 0 +( 224 192 96 ) ( 224 224 96 ) ( 224 224 64 ) eden/edenmetalwall -224 64 0.00 1 1 0 0 0 +( 224 224 96 ) ( -480 224 96 ) ( -480 224 64 ) eden/edenmetalwall 224 63 -180.00 1 -1 0 0 0 +( -480 192 64 ) ( -480 224 64 ) ( -480 208 320 ) eden/edenmetalwall 224 63 -180.00 1 -1 0 0 0 +} +// brush 4 + { + patchDef2 + { + eden/edenmetalwall + ( 3 3 0 536870912 0 ) +( +( ( -480 96 63.999992 0 0 ) ( -480 96 192 0 0.500000 ) ( -480 96 320 0 1 ) ) +( ( -384 96 63.999992 0.500000 0 ) ( -384 96 192 0.500000 0.500000 ) ( -384 96 320 0.500000 1 ) ) +( ( -384 192 63.999992 1 0 ) ( -384 192 192 1 0.500000 ) ( -384 192 320 1 1 ) ) +) + } + } +// brush 5 +{ +( -480 192 0 ) ( -512 192 0 ) ( -512 -512 0 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +( -512 -512 64 ) ( -512 192 64 ) ( -480 192 64 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +( -480 -512 256 ) ( -480 192 256 ) ( -480 192 0 ) common/skip 0 0 0.00 1 1 805306368 16512 0 +( -480 192 256 ) ( -512 192 256 ) ( -512 192 0 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +( -512 192 256 ) ( -512 -512 256 ) ( -512 -512 0 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +( -480 128 0 ) ( -512 128 0 ) ( -496 128 64 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +} +// brush 6 +{ +( -480 192 0 ) ( -512 192 0 ) ( -512 -512 0 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +( -512 -512 64 ) ( -512 192 64 ) ( -480 192 64 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +( -512 -512 256 ) ( -480 -512 256 ) ( -480 -512 0 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +( -480 -512 256 ) ( -480 192 256 ) ( -480 192 0 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +( -512 192 256 ) ( -512 -512 256 ) ( -512 -512 0 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +( -512 192 0 ) ( -480 192 0 ) ( -496 192 64 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +} +// brush 7 +{ +( -480 192 64 ) ( -512 192 64 ) ( -512 -512 64 ) eden/edenmetalwall 0 0 0.00 1 1 0 0 0 +( -512 -512 320 ) ( -512 192 320 ) ( -480 192 320 ) eden/edenmetalwall 0 0 0.00 1 1 0 0 0 +( -480 -512 96 ) ( -480 192 96 ) ( -480 192 64 ) common/skip 0 0 0.00 1 1 805306368 16512 0 +( -480 192 96 ) ( -512 192 96 ) ( -512 192 64 ) eden/edenmetalwall 0 64 0.00 1 1 0 0 0 +( -512 192 96 ) ( -512 -512 96 ) ( -512 -512 64 ) eden/edenmetalwall 0 64 0.00 1 1 0 0 0 +( -480 128 64 ) ( -512 128 64 ) ( -496 128 320 ) eden/edenmetalwall 0 64 0.00 1 1 0 0 0 +} +// brush 8 +{ +( -480 192 64 ) ( -512 192 64 ) ( -512 -512 64 ) eden/edenmetalwall 0 0 0.00 1 1 0 0 0 +( -512 -512 320 ) ( -512 192 320 ) ( -480 192 320 ) eden/edenmetalwall 0 0 0.00 1 1 0 0 0 +( -512 -512 96 ) ( -480 -512 96 ) ( -480 -512 64 ) eden/edenmetalwall 0 64 0.00 1 1 0 0 0 +( -480 -512 96 ) ( -480 192 96 ) ( -480 192 64 ) eden/edenmetalwall 0 64 0.00 1 1 0 0 0 +( -512 192 96 ) ( -512 -512 96 ) ( -512 -512 64 ) eden/edenmetalwall 0 64 0.00 1 1 0 0 0 +( -512 192 64 ) ( -480 192 64 ) ( -496 192 320 ) eden/edenmetalwall 0 64 0.00 1 1 0 0 0 +} +// brush 9 + { + patchDef2 + { + eden/bedtrim + ( 3 3 0 536870912 0 ) +( +( ( -480 96 0 0 0 ) ( -480 96 32 0 0.500000 ) ( -480 96 64 0 1 ) ) +( ( -384 96 0 0.500000 0 ) ( -384 96 32 0.500000 0.500000 ) ( -384 96 64 0.500000 1 ) ) +( ( -384 192 0 1 0 ) ( -384 192 32 1 0.500000 ) ( -384 192 64 1 1 ) ) +) + } + } +// brush 10 +{ +( 96 96 352 ) ( -32 96 352 ) ( -32 -416 352 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( -32 -416 416 ) ( -32 96 416 ) ( 96 96 416 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( -32 -416 416 ) ( 96 -416 416 ) ( 96 -416 352 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( 96 -416 416 ) ( 96 96 416 ) ( 96 96 352 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( 96 96 416 ) ( -32 96 416 ) ( -32 96 352 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( -32 96 416 ) ( -32 -416 416 ) ( -32 -416 352 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +} +// brush 11 +{ +( -64 -416 304 ) ( -64 -448 304 ) ( 128 -448 304 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( 128 -448 352 ) ( -64 -448 352 ) ( -64 -416 352 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( 96 -416 352 ) ( -32 -416 352 ) ( -32 -416 320 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( 128 -448 352 ) ( 96 -416 352 ) ( 96 -416 320 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( -64 -448 320 ) ( -64 -448 352 ) ( 128 -448 352 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( -64 -448 320 ) ( -32 -416 320 ) ( -32 -416 352 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +} +// brush 12 +{ +( -32 128 304 ) ( -64 128 304 ) ( -64 -64 304 ) eden/FL_edenhouse 0 32 90.00 1 1 0 0 0 +( -64 -64 352 ) ( -64 128 352 ) ( -32 128 352 ) eden/FL_edenhouse 0 32 90.00 1 1 0 0 0 +( -32 -32 352 ) ( -32 96 352 ) ( -32 96 320 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( -64 -448 352 ) ( -32 -416 352 ) ( -32 -416 320 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( -64 128 320 ) ( -64 128 352 ) ( -64 -64 352 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( -64 128 320 ) ( -32 96 320 ) ( -32 96 352 ) eden/FL_edenhouse -64 0 -180.00 1 -1 0 0 0 +} +// brush 13 +{ +( 128 -64 304 ) ( 128 128 304 ) ( 96 128 304 ) eden/FL_edenhouse 0 -96 90.00 1 1 0 0 0 +( 96 128 352 ) ( 128 128 352 ) ( 128 -64 352 ) eden/FL_edenhouse 0 -96 90.00 1 1 0 0 0 +( 96 96 320 ) ( 96 96 352 ) ( 96 -32 352 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( 96 -416 320 ) ( 96 -416 352 ) ( 128 -448 352 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( 128 -64 352 ) ( 128 128 352 ) ( 128 128 320 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( 96 96 352 ) ( 96 96 320 ) ( 128 128 320 ) eden/FL_edenhouse -64 0 -180.00 1 -1 0 0 0 +} +// brush 14 +{ +( 128 128 304 ) ( -64 128 304 ) ( -64 96 304 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( -64 96 352 ) ( -64 128 352 ) ( 128 128 352 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( -32 96 320 ) ( -32 96 352 ) ( 96 96 352 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( 96 96 320 ) ( 96 96 352 ) ( 128 128 352 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( 128 128 352 ) ( -64 128 352 ) ( -64 128 320 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( -32 96 352 ) ( -32 96 320 ) ( -64 128 320 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +} +// brush 15 +{ +( 128 192 320 ) ( -64 192 320 ) ( -64 128 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( -64 128 352 ) ( -64 192 352 ) ( 128 192 352 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( -64 128 352 ) ( 128 128 352 ) ( 128 128 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( 128 128 352 ) ( 128 192 352 ) ( 128 192 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( 128 192 352 ) ( -64 192 352 ) ( -64 192 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( -64 192 352 ) ( -64 128 352 ) ( -64 128 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +} +// brush 16 +{ +( 192 192 320 ) ( 128 192 320 ) ( 128 -448 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( 128 -448 352 ) ( 128 192 352 ) ( 192 192 352 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( 128 -448 352 ) ( 192 -448 352 ) ( 192 -448 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( 192 -448 352 ) ( 192 192 352 ) ( 192 192 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( 192 192 352 ) ( 128 192 352 ) ( 128 192 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( 128 192 352 ) ( 128 -448 352 ) ( 128 -448 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +} +// brush 17 +{ +( 192 192 320 ) ( -480 192 320 ) ( -480 -512 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( -480 -512 352 ) ( -480 192 352 ) ( 192 192 352 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( -480 -512 352 ) ( 192 -512 352 ) ( 192 -512 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( 192 -512 352 ) ( 192 192 352 ) ( 192 192 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( 224 -448 352 ) ( -448 -448 352 ) ( -448 -448 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( -64 -256 320 ) ( -64 -128 320 ) ( -64 -192 352 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +} +// brush 18 +{ +( 192 192 320 ) ( -480 192 320 ) ( -480 -512 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( -480 -512 352 ) ( -480 192 352 ) ( 192 192 352 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( -480 -512 352 ) ( 192 -512 352 ) ( 192 -512 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( 192 192 352 ) ( -480 192 352 ) ( -480 192 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( -480 192 352 ) ( -480 -512 352 ) ( -480 -512 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( -64 -128 320 ) ( -64 -256 320 ) ( -64 -192 352 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +} +// brush 19 +{ +( 192 192 -32 ) ( -480 192 -32 ) ( -480 -512 -32 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( -480 -512 0 ) ( -480 192 0 ) ( 192 192 0 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( -480 -512 224 ) ( 192 -512 224 ) ( 192 -512 -32 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 192 -512 224 ) ( 192 192 224 ) ( 192 192 -32 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 192 192 224 ) ( -480 192 224 ) ( -480 192 -32 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( -480 192 224 ) ( -480 -512 224 ) ( -480 -512 -32 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +} +// brush 20 +{ +( -480 -512 64 ) ( -480 -544 64 ) ( 224 -544 64 ) eden/edenmetalwall -31 31 -90.00 1 1 0 0 0 +( 224 -544 320 ) ( -480 -544 320 ) ( -480 -512 320 ) eden/edenmetalwall -31 31 -90.00 1 1 0 0 0 +( 224 -544 96 ) ( 224 -512 96 ) ( 224 -512 64 ) eden/edenmetalwall -32 63 -180.00 1 -1 0 0 0 +( 224 -512 96 ) ( -480 -512 96 ) ( -480 -512 64 ) eden/edenmetalwall -32 62 0.00 1.000008 1 0 0 0 +( -480 -512 96 ) ( -480 -544 96 ) ( -480 -544 64 ) eden/edenmetalwall -33 63 -180.00 1 -1 0 0 0 +( -480 -544 96 ) ( 224 -544 96 ) ( 224 -544 64 ) eden/edenmetalwall -32 62 0.00 1.000008 1 0 0 0 +} +// brush 21 +{ +( -480 -512 0 ) ( -480 -544 0 ) ( 224 -544 0 ) eden/bedtrim -31 32 -90.00 1 1 0 0 0 +( 224 -544 64 ) ( -480 -544 64 ) ( -480 -512 64 ) eden/bedtrim -31 32 -90.00 1 1 0 0 0 +( 224 -544 256 ) ( 224 -512 256 ) ( 224 -512 0 ) eden/bedtrim -32 0 -180.00 1 -1 0 0 0 +( 224 -512 256 ) ( -480 -512 256 ) ( -480 -512 0 ) eden/bedtrim -32 0 0.00 1 1 0 0 0 +( -480 -512 256 ) ( -480 -544 256 ) ( -480 -544 0 ) eden/bedtrim -33 0 -180.00 1 -1 0 0 0 +( -480 -544 256 ) ( 224 -544 256 ) ( 224 -544 0 ) eden/bedtrim -32 0 0.00 1 1 0 0 0 +} +// brush 22 +{ +( 192 -512 0 ) ( 224 -512 0 ) ( 224 192 0 ) eden/bedtrim 160 0 -180.00 1 1 0 0 0 +( 224 192 64 ) ( 224 -512 64 ) ( 192 -512 64 ) eden/bedtrim 160 0 -180.00 1 1 0 0 0 +( 224 192 256 ) ( 192 192 256 ) ( 192 192 0 ) eden/bedtrim 160 0 -180.00 1 -1 0 0 0 +( 192 192 256 ) ( 192 -512 256 ) ( 192 -512 0 ) eden/bedtrim -64 0 -180.00 1 -1 0 0 0 +( 192 -512 256 ) ( 224 -512 256 ) ( 224 -512 0 ) eden/bedtrim 159 0 -180.00 1 -1 0 0 0 +( 224 -512 256 ) ( 224 192 256 ) ( 224 192 0 ) eden/bedtrim -64 0 -180.00 1 -1 0 0 0 +} +// brush 23 +{ +( 192 -512 64 ) ( 224 -512 64 ) ( 224 192 64 ) eden/edenmetalwall 160 63 -180.00 1 1 0 0 0 +( 224 192 320 ) ( 224 -512 320 ) ( 192 -512 320 ) eden/edenmetalwall 160 63 -180.00 1 1 0 0 0 +( 224 192 96 ) ( 192 192 96 ) ( 192 192 64 ) eden/edenmetalwall 160 64 -180.00 1 -1 0 0 0 +( 192 192 96 ) ( 192 -512 96 ) ( 192 -512 64 ) eden/edenmetalwall -64 62 -180.00 1 -1 0 0 0 +( 192 -512 96 ) ( 224 -512 96 ) ( 224 -512 64 ) eden/edenmetalwall 159 64 -180.00 1 -1 0 0 0 +( 224 -512 96 ) ( 224 192 96 ) ( 224 192 64 ) eden/edenmetalwall -64 62 -180.00 1 -1 0 0 0 +} +} +// entity 1 +{ +"spawnflags" "1" +"angles" "0 0 0" +"classname" "func_beam" +"origin" "-128 -128 136" +"damage" "10" +"shootradius" "10" +} +// entity 2 +{ +"classname" "light" +"spawnflags" "0" +"origin" "-352 48 168" +"light" "200" +"_color" "1.000000 0.724409 0.523622" +} +// entity 3 +{ +"classname" "info_player_start" +"angle" "45" +"origin" "-432 -464 24" +} +// entity 4 +{ +"origin" "8 56 168" +"spawnflags" "0" +"classname" "light" +"light" "200" +"_color" "0.629921 0.846457 1.000000" +} +// entity 5 +{ +"origin" "-344 -376 168" +"spawnflags" "0" +"classname" "light" +"light" "200" +} +// entity 6 +{ +"classname" "light" +"spawnflags" "0" +"origin" "8 -380 168" +"light" "200" +} +// entity 7 +{ +"light" "200" +"classname" "light" +"spawnflags" "0" +"origin" "-168 -160 168" +} diff --git a/fakk/maps/example/beam1.prt b/fakk/maps/example/beam1.prt new file mode 100644 index 0000000..63b4d74 --- /dev/null +++ b/fakk/maps/example/beam1.prt @@ -0,0 +1,96 @@ +PRT1 +16 +28 +64 +4 0 4 0 (128 0 304 ) (192 0 304 ) (192 0 320 ) (128 0 320 ) +4 0 3 0 (128 192 304 ) (192 192 304 ) (192 0 304 ) (128 0 304 ) +4 0 1 0 (128 192 320 ) (128 192 304 ) (128 128 304 ) (128 128 320 ) +4 1 8 0 (0 192 320 ) (0 192 304 ) (0 128 304 ) (0 128 320 ) +4 1 3 0 (0 192 304 ) (128 192 304 ) (128 128 304 ) (0 128 304 ) +4 2 9 0 (0 0 304 ) (0 0 352 ) (0 96 352 ) (0 96 304 ) +4 2 5 0 (0 0 352 ) (0 0 304 ) (96 0 304 ) (96 0 352 ) +4 2 3 0 (96 0 304 ) (0 0 304 ) (0 96 304 ) (96 96 304 ) +4 3 11 0 (0 0 0 ) (0 0 304 ) (0 192 304 ) (0 192 0 ) +4 3 7 0 (0 0 304 ) (0 0 0 ) (192 0 0 ) (192 0 304 ) +4 4 7 0 (128 0 304 ) (192 0 304 ) (192 -448 304 ) (128 -448 304 ) +4 4 6 0 (128 -448 304 ) (192 -448 304 ) (192 -448 320 ) (128 -448 320 ) +4 5 12 0 (0 0 352 ) (0 0 304 ) (0 -416 304 ) (0 -416 352 ) +4 5 7 0 (0 0 304 ) (96 0 304 ) (96 -416 304 ) (0 -416 304 ) +4 6 13 0 (0 -512 304 ) (0 -512 320 ) (0 -448 320 ) (0 -448 304 ) +4 6 7 0 (192 -448 304 ) (192 -512 304 ) (0 -512 304 ) (0 -448 304 ) +4 7 15 0 (0 -512 0 ) (0 -512 304 ) (0 0 304 ) (0 0 0 ) +4 8 11 0 (-64 128 304 ) (-64 192 304 ) (0 192 304 ) (0 128 304 ) +4 8 10 0 (-64 192 320 ) (-64 192 304 ) (-64 128 304 ) (-64 128 320 ) +4 9 12 0 (0 0 304 ) (0 0 352 ) (-32 0 352 ) (-32 0 304 ) +4 9 11 0 (0 0 304 ) (-32 0 304 ) (-32 96 304 ) (0 96 304 ) +4 10 14 0 (-480 0 320 ) (-480 0 304 ) (-64 0 304 ) (-64 0 320 ) +4 10 11 0 (-64 0 304 ) (-480 0 304 ) (-480 192 304 ) (-64 192 304 ) +4 11 15 0 (0 0 0 ) (0 0 304 ) (-480 0 304 ) (-480 0 0 ) +4 12 15 0 (-32 0 304 ) (0 0 304 ) (0 -416 304 ) (-32 -416 304 ) +4 13 15 0 (0 -512 304 ) (-64 -512 304 ) (-64 -448 304 ) (0 -448 304 ) +4 13 14 0 (-64 -448 304 ) (-64 -512 304 ) (-64 -512 320 ) (-64 -448 320 ) +4 14 15 0 (-64 -512 304 ) (-480 -512 304 ) (-480 0 304 ) (-64 0 304 ) +4 0 (128 96 304 ) (128 0 304 ) (128 0 320 ) (128 96 320 ) +4 0 (128 128 304 ) (128 96 304 ) (128 96 320 ) (128 128 320 ) +4 0 (192 0 320 ) (192 0 304 ) (192 192 304 ) (192 192 320 ) +4 0 (128 192 320 ) (192 192 320 ) (192 192 304 ) (128 192 304 ) +4 0 (192 0 320 ) (192 192 320 ) (128 192 320 ) (128 0 320 ) +4 1 (0 128 304 ) (128 128 304 ) (128 128 320 ) (0 128 320 ) +4 1 (128 192 320 ) (128 192 304 ) (0 192 304 ) (0 192 320 ) +4 1 (128 192 320 ) (0 192 320 ) (0 128 320 ) (128 128 320 ) +4 2 (96 96 352 ) (0 96 352 ) (0 0 352 ) (96 0 352 ) +4 2 (0 96 352 ) (96 96 352 ) (96 96 304 ) (0 96 304 ) +4 2 (96 0 352 ) (96 0 304 ) (96 96 304 ) (96 96 352 ) +4 3 (192 192 304 ) (192 192 0 ) (0 192 0 ) (0 192 304 ) +4 3 (192 0 304 ) (192 0 0 ) (192 192 0 ) (192 192 304 ) +4 3 (0 128 304 ) (0 96 304 ) (128 96 304 ) (128 128 304 ) +4 3 (96 96 304 ) (96 0 304 ) (128 0 304 ) (128 96 304 ) +4 3 (0 192 0 ) (192 192 0 ) (192 0 0 ) (0 0 0 ) +4 4 (128 0 304 ) (128 -448 304 ) (128 -448 320 ) (128 0 320 ) +4 4 (192 -448 320 ) (192 -448 304 ) (192 0 304 ) (192 0 320 ) +4 4 (192 0 320 ) (128 0 320 ) (128 -448 320 ) (192 -448 320 ) +4 5 (96 -416 352 ) (96 0 352 ) (0 0 352 ) (0 -416 352 ) +4 5 (96 0 352 ) (96 -416 352 ) (96 -416 304 ) (96 0 304 ) +4 5 (0 -416 304 ) (96 -416 304 ) (96 -416 352 ) (0 -416 352 ) +4 6 (192 -448 320 ) (192 -512 320 ) (192 -512 304 ) (192 -448 304 ) +4 6 (0 -512 320 ) (0 -512 304 ) (192 -512 304 ) (192 -512 320 ) +4 6 (96 -448 320 ) (128 -448 320 ) (128 -448 304 ) (96 -448 304 ) +4 6 (96 -448 320 ) (96 -448 304 ) (0 -448 304 ) (0 -448 320 ) +4 6 (0 -512 320 ) (192 -512 320 ) (192 -448 320 ) (0 -448 320 ) +4 7 (0 -512 304 ) (0 -512 0 ) (192 -512 0 ) (192 -512 304 ) +4 7 (192 -512 304 ) (192 -512 0 ) (192 0 0 ) (192 0 304 ) +4 7 (96 -448 304 ) (128 -448 304 ) (128 0 304 ) (96 0 304 ) +4 7 (0 -416 304 ) (0 -448 304 ) (96 -448 304 ) (96 -416 304 ) +4 7 (0 0 0 ) (192 0 0 ) (192 -512 0 ) (0 -512 0 ) +4 8 (-64 128 320 ) (-64 128 304 ) (0 128 304 ) (0 128 320 ) +4 8 (-64 192 304 ) (-64 192 320 ) (0 192 320 ) (0 192 304 ) +4 8 (0 192 320 ) (-64 192 320 ) (-64 128 320 ) (0 128 320 ) +4 9 (0 96 352 ) (-32 96 352 ) (-32 0 352 ) (0 0 352 ) +4 9 (0 96 304 ) (-32 96 304 ) (-32 96 352 ) (0 96 352 ) +4 9 (-32 96 352 ) (-32 96 304 ) (-32 0 304 ) (-32 0 352 ) +4 10 (-480 192 320 ) (-480 192 304 ) (-480 0 304 ) (-480 0 320 ) +4 10 (-64 192 320 ) (-64 192 304 ) (-480 192 304 ) (-480 192 320 ) +4 10 (-64 128 320 ) (-64 96 320 ) (-64 96 304 ) (-64 128 304 ) +4 10 (-64 96 320 ) (-64 0 320 ) (-64 0 304 ) (-64 96 304 ) +4 10 (-64 0 320 ) (-64 192 320 ) (-480 192 320 ) (-480 0 320 ) +4 11 (-480 192 0 ) (-480 192 304 ) (0 192 304 ) (0 192 0 ) +4 11 (-480 192 304 ) (-480 192 0 ) (-480 0 0 ) (-480 0 304 ) +4 11 (0 96 304 ) (0 128 304 ) (-64 128 304 ) (-64 96 304 ) +4 11 (-32 96 304 ) (-64 96 304 ) (-64 0 304 ) (-32 0 304 ) +4 11 (0 0 0 ) (-480 0 0 ) (-480 192 0 ) (0 192 0 ) +4 12 (0 -416 352 ) (-32 -416 352 ) (-32 -416 304 ) (0 -416 304 ) +4 12 (-32 -416 352 ) (0 -416 352 ) (0 0 352 ) (-32 0 352 ) +4 12 (-32 0 304 ) (-32 -416 304 ) (-32 -416 352 ) (-32 0 352 ) +4 13 (-64 -512 304 ) (0 -512 304 ) (0 -512 320 ) (-64 -512 320 ) +4 13 (0 -448 320 ) (0 -448 304 ) (-64 -448 304 ) (-64 -448 320 ) +4 13 (0 -448 320 ) (-64 -448 320 ) (-64 -512 320 ) (0 -512 320 ) +4 14 (-480 -512 320 ) (-480 -512 304 ) (-64 -512 304 ) (-64 -512 320 ) +4 14 (-480 0 320 ) (-480 0 304 ) (-480 -512 304 ) (-480 -512 320 ) +4 14 (-64 -416 320 ) (-64 -448 320 ) (-64 -448 304 ) (-64 -416 304 ) +4 14 (-64 -416 320 ) (-64 -416 304 ) (-64 0 304 ) (-64 0 320 ) +4 14 (-480 0 320 ) (-480 -512 320 ) (-64 -512 320 ) (-64 0 320 ) +4 15 (-480 0 304 ) (-480 0 0 ) (-480 -512 0 ) (-480 -512 304 ) +4 15 (-480 -512 304 ) (-480 -512 0 ) (0 -512 0 ) (0 -512 304 ) +4 15 (0 -448 304 ) (0 -416 304 ) (-64 -416 304 ) (-64 -448 304 ) +4 15 (-32 -416 304 ) (-32 0 304 ) (-64 0 304 ) (-64 -416 304 ) +4 15 (0 -512 0 ) (-480 -512 0 ) (-480 0 0 ) (0 0 0 ) diff --git a/fakk/maps/example/box3.bsp b/fakk/maps/example/box3.bsp new file mode 100644 index 0000000..e0937eb Binary files /dev/null and b/fakk/maps/example/box3.bsp differ diff --git a/fakk/maps/example/box3.map b/fakk/maps/example/box3.map new file mode 100644 index 0000000..646545b --- /dev/null +++ b/fakk/maps/example/box3.map @@ -0,0 +1,298 @@ +{ +"classname" "worldspawn" +// brush 0 +{ +( 384 320 0 ) ( 384 352 0 ) ( -320 352 0 ) eden/bedtrim -96 0 90.00 1 1 0 0 0 +( -320 352 64 ) ( 384 352 64 ) ( 384 320 64 ) eden/bedtrim -96 0 90.00 1 1 0 0 0 +( -320 352 256 ) ( -320 320 256 ) ( -320 320 0 ) eden/bedtrim -96 0 0.00 1 1 0 0 0 +( -320 320 256 ) ( 384 320 256 ) ( 384 320 0 ) common/skip -32 0 0.00 1 1 805306368 16512 0 +( 384 352 256 ) ( -320 352 256 ) ( -320 352 0 ) eden/bedtrim 128 0 -180.00 1 -1 0 0 0 +( -256 352 0 ) ( -256 320 0 ) ( -256 336 64 ) eden/bedtrim 96 0 -180.00 1 -1 0 0 0 +} +// brush 1 +{ +( 384 320 0 ) ( 384 352 0 ) ( -320 352 0 ) eden/bedtrim -96 0 90.00 1 1 0 0 0 +( -320 352 64 ) ( 384 352 64 ) ( 384 320 64 ) eden/bedtrim -96 0 90.00 1 1 0 0 0 +( -320 320 256 ) ( 384 320 256 ) ( 384 320 0 ) eden/bedtrim 128 0 -180.00 1 -1 0 0 0 +( 384 320 256 ) ( 384 352 256 ) ( 384 352 0 ) eden/bedtrim -96 0 0.00 1 1 0 0 0 +( 384 352 256 ) ( -320 352 256 ) ( -320 352 0 ) eden/bedtrim 128 0 -180.00 1 -1 0 0 0 +( -320 320 0 ) ( -320 352 0 ) ( -320 336 64 ) eden/bedtrim 96 0 -180.00 1 -1 0 0 0 +} +// brush 2 +{ +( 384 320 64 ) ( 384 352 64 ) ( -320 352 64 ) eden/edenmetalwall -96 -128 90.00 1 1 0 0 0 +( -320 352 320 ) ( 384 352 320 ) ( 384 320 320 ) eden/edenmetalwall -96 -128 90.00 1 1 0 0 0 +( -320 352 96 ) ( -320 320 96 ) ( -320 320 64 ) eden/edenmetalwall -96 64 0.00 1 1 0 0 0 +( -320 320 96 ) ( 384 320 96 ) ( 384 320 64 ) common/skip -32 0 0.00 1 1 805306368 16512 0 +( 384 352 96 ) ( -320 352 96 ) ( -320 352 64 ) eden/edenmetalwall 128 63 -180.00 1 -1 0 0 0 +( -256 352 64 ) ( -256 320 64 ) ( -256 336 320 ) eden/edenmetalwall 96 63 -180.00 1 -1 0 0 0 +} +// brush 3 +{ +( 384 320 64 ) ( 384 352 64 ) ( -320 352 64 ) eden/edenmetalwall -96 -128 90.00 1 1 0 0 0 +( -320 352 320 ) ( 384 352 320 ) ( 384 320 320 ) eden/edenmetalwall -96 -128 90.00 1 1 0 0 0 +( -320 320 96 ) ( 384 320 96 ) ( 384 320 64 ) eden/edenmetalwall 128 63 -180.00 1 -1 0 0 0 +( 384 320 96 ) ( 384 352 96 ) ( 384 352 64 ) eden/edenmetalwall -96 64 0.00 1 1 0 0 0 +( 384 352 96 ) ( -320 352 96 ) ( -320 352 64 ) eden/edenmetalwall 128 63 -180.00 1 -1 0 0 0 +( -320 320 64 ) ( -320 352 64 ) ( -320 336 320 ) eden/edenmetalwall 96 63 -180.00 1 -1 0 0 0 +} +// brush 4 + { + patchDef2 + { + eden/edenmetalwall + ( 3 3 0 536870912 0 ) +( +( ( -320 224 63.999992 0 0 ) ( -320 224 192 0 0.500000 ) ( -320 224 320 0 1 ) ) +( ( -224 224 63.999992 0.500000 0 ) ( -224 224 192 0.500000 0.500000 ) ( -224 224 320 0.500000 1 ) ) +( ( -224 320 63.999992 1 0 ) ( -224 320 192 1 0.500000 ) ( -224 320 320 1 1 ) ) +) + } + } +// brush 5 +{ +( -320 320 0 ) ( -352 320 0 ) ( -352 -384 0 ) eden/bedtrim -160 0 0.00 1 1 0 0 0 +( -352 -384 64 ) ( -352 320 64 ) ( -320 320 64 ) eden/bedtrim -160 0 0.00 1 1 0 0 0 +( -320 -384 256 ) ( -320 320 256 ) ( -320 320 0 ) common/skip 0 0 0.00 1 1 805306368 16512 0 +( -320 320 256 ) ( -352 320 256 ) ( -352 320 0 ) eden/bedtrim -160 0 0.00 1 1 0 0 0 +( -352 320 256 ) ( -352 -384 256 ) ( -352 -384 0 ) eden/bedtrim -128 0 0.00 1 1 0 0 0 +( -320 256 0 ) ( -352 256 0 ) ( -336 256 64 ) eden/bedtrim -160 0 0.00 1 1 0 0 0 +} +// brush 6 +{ +( -320 320 0 ) ( -352 320 0 ) ( -352 -384 0 ) eden/bedtrim -160 0 0.00 1 1 0 0 0 +( -352 -384 64 ) ( -352 320 64 ) ( -320 320 64 ) eden/bedtrim -160 0 0.00 1 1 0 0 0 +( -352 -384 256 ) ( -320 -384 256 ) ( -320 -384 0 ) eden/bedtrim -160 0 0.00 1 1 0 0 0 +( -320 -384 256 ) ( -320 320 256 ) ( -320 320 0 ) eden/bedtrim -128 0 0.00 1 1 0 0 0 +( -352 320 256 ) ( -352 -384 256 ) ( -352 -384 0 ) eden/bedtrim -128 0 0.00 1 1 0 0 0 +( -352 320 0 ) ( -320 320 0 ) ( -336 320 64 ) eden/bedtrim -160 0 0.00 1 1 0 0 0 +} +// brush 7 +{ +( -320 320 64 ) ( -352 320 64 ) ( -352 -384 64 ) eden/edenmetalwall -160 128 0.00 1 1 0 0 0 +( -352 -384 320 ) ( -352 320 320 ) ( -320 320 320 ) eden/edenmetalwall -160 128 0.00 1 1 0 0 0 +( -320 -384 96 ) ( -320 320 96 ) ( -320 320 64 ) common/skip 0 0 0.00 1 1 805306368 16512 0 +( -320 320 96 ) ( -352 320 96 ) ( -352 320 64 ) eden/edenmetalwall -160 64 0.00 1 1 0 0 0 +( -352 320 96 ) ( -352 -384 96 ) ( -352 -384 64 ) eden/edenmetalwall -128 64 0.00 1 1 0 0 0 +( -320 256 64 ) ( -352 256 64 ) ( -336 256 320 ) eden/edenmetalwall -160 64 0.00 1 1 0 0 0 +} +// brush 8 +{ +( -320 320 64 ) ( -352 320 64 ) ( -352 -384 64 ) eden/edenmetalwall -160 128 0.00 1 1 0 0 0 +( -352 -384 320 ) ( -352 320 320 ) ( -320 320 320 ) eden/edenmetalwall -160 128 0.00 1 1 0 0 0 +( -352 -384 96 ) ( -320 -384 96 ) ( -320 -384 64 ) eden/edenmetalwall -160 64 0.00 1 1 0 0 0 +( -320 -384 96 ) ( -320 320 96 ) ( -320 320 64 ) eden/edenmetalwall -128 64 0.00 1 1 0 0 0 +( -352 320 96 ) ( -352 -384 96 ) ( -352 -384 64 ) eden/edenmetalwall -128 64 0.00 1 1 0 0 0 +( -352 320 64 ) ( -320 320 64 ) ( -336 320 320 ) eden/edenmetalwall -160 64 0.00 1 1 0 0 0 +} +// brush 9 + { + patchDef2 + { + eden/bedtrim + ( 3 3 0 536870912 0 ) +( +( ( -320 224 0 0 0 ) ( -320 224 32 0 0.500000 ) ( -320 224 64 0 1 ) ) +( ( -224 224 0 0.500000 0 ) ( -224 224 32 0.500000 0.500000 ) ( -224 224 64 0.500000 1 ) ) +( ( -224 320 0 1 0 ) ( -224 320 32 1 0.500000 ) ( -224 320 64 1 1 ) ) +) + } + } +// brush 10 +{ +( 256 224 352 ) ( 128 224 352 ) ( 128 -288 352 ) we_cemetary_test/levelord_sky -160 128 0.00 1 1 0 1044 0 +( 128 -288 416 ) ( 128 224 416 ) ( 256 224 416 ) we_cemetary_test/levelord_sky -160 128 0.00 1 1 0 1044 0 +( 128 -288 416 ) ( 256 -288 416 ) ( 256 -288 352 ) we_cemetary_test/levelord_sky -160 0 0.00 1 1 0 1044 0 +( 256 -288 416 ) ( 256 224 416 ) ( 256 224 352 ) we_cemetary_test/levelord_sky -128 0 0.00 1 1 0 1044 0 +( 256 224 416 ) ( 128 224 416 ) ( 128 224 352 ) we_cemetary_test/levelord_sky -160 0 0.00 1 1 0 1044 0 +( 128 224 416 ) ( 128 -288 416 ) ( 128 -288 352 ) we_cemetary_test/levelord_sky -128 0 0.00 1 1 0 1044 0 +} +// brush 11 +{ +( 96 -288 304 ) ( 96 -320 304 ) ( 288 -320 304 ) eden/FL_edenhouse -32 0 0.00 1 1 0 0 0 +( 288 -320 352 ) ( 96 -320 352 ) ( 96 -288 352 ) eden/FL_edenhouse -32 0 0.00 1 1 0 0 0 +( 256 -288 352 ) ( 128 -288 352 ) ( 128 -288 320 ) eden/FL_edenhouse -32 0 0.00 1 1 0 0 0 +( 288 -320 352 ) ( 256 -288 352 ) ( 256 -288 320 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( 96 -320 320 ) ( 96 -320 352 ) ( 288 -320 352 ) eden/FL_edenhouse -32 0 0.00 1 1 0 0 0 +( 96 -320 320 ) ( 128 -288 320 ) ( 128 -288 352 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +} +// brush 12 +{ +( 128 256 304 ) ( 96 256 304 ) ( 96 64 304 ) eden/FL_edenhouse 0 0 90.00 1 1 0 0 0 +( 96 64 352 ) ( 96 256 352 ) ( 128 256 352 ) eden/FL_edenhouse 0 0 90.00 1 1 0 0 0 +( 128 96 352 ) ( 128 224 352 ) ( 128 224 320 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( 96 -320 352 ) ( 128 -288 352 ) ( 128 -288 320 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( 96 256 320 ) ( 96 256 352 ) ( 96 64 352 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( 96 256 320 ) ( 128 224 320 ) ( 128 224 352 ) eden/FL_edenhouse 64 0 -180.00 1 -1 0 0 0 +} +// brush 13 +{ +( 288 64 304 ) ( 288 256 304 ) ( 256 256 304 ) eden/FL_edenhouse 0 0 90.00 1 1 0 0 0 +( 256 256 352 ) ( 288 256 352 ) ( 288 64 352 ) eden/FL_edenhouse 0 0 90.00 1 1 0 0 0 +( 256 224 320 ) ( 256 224 352 ) ( 256 96 352 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( 256 -288 320 ) ( 256 -288 352 ) ( 288 -320 352 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( 288 64 352 ) ( 288 256 352 ) ( 288 256 320 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( 256 224 352 ) ( 256 224 320 ) ( 288 256 320 ) eden/FL_edenhouse 64 0 -180.00 1 -1 0 0 0 +} +// brush 14 +{ +( 288 256 304 ) ( 96 256 304 ) ( 96 224 304 ) eden/FL_edenhouse -32 0 0.00 1 1 0 0 0 +( 96 224 352 ) ( 96 256 352 ) ( 288 256 352 ) eden/FL_edenhouse -32 0 0.00 1 1 0 0 0 +( 128 224 320 ) ( 128 224 352 ) ( 256 224 352 ) eden/FL_edenhouse -32 0 0.00 1 1 0 0 0 +( 256 224 320 ) ( 256 224 352 ) ( 288 256 352 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( 288 256 352 ) ( 96 256 352 ) ( 96 256 320 ) eden/FL_edenhouse -32 0 0.00 1 1 0 0 0 +( 128 224 352 ) ( 128 224 320 ) ( 96 256 320 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +} +// brush 15 +{ +( 288 320 320 ) ( 96 320 320 ) ( 96 256 320 ) eden/CL_edenroof3 -32 0 0.00 1 1 0 0 0 +( 96 256 352 ) ( 96 320 352 ) ( 288 320 352 ) eden/CL_edenroof3 -32 0 0.00 1 1 0 0 0 +( 96 256 352 ) ( 288 256 352 ) ( 288 256 320 ) eden/CL_edenroof3 -32 0 0.00 1 1 0 0 0 +( 288 256 352 ) ( 288 320 352 ) ( 288 320 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( 288 320 352 ) ( 96 320 352 ) ( 96 320 320 ) eden/CL_edenroof3 -32 0 0.00 1 1 0 0 0 +( 96 320 352 ) ( 96 256 352 ) ( 96 256 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +} +// brush 16 +{ +( 352 320 320 ) ( 288 320 320 ) ( 288 -320 320 ) eden/CL_edenroof3 -32 0 0.00 1 1 0 0 0 +( 288 -320 352 ) ( 288 320 352 ) ( 352 320 352 ) eden/CL_edenroof3 -32 0 0.00 1 1 0 0 0 +( 288 -320 352 ) ( 352 -320 352 ) ( 352 -320 320 ) eden/CL_edenroof3 -32 0 0.00 1 1 0 0 0 +( 352 -320 352 ) ( 352 320 352 ) ( 352 320 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( 352 320 352 ) ( 288 320 352 ) ( 288 320 320 ) eden/CL_edenroof3 -32 0 0.00 1 1 0 0 0 +( 288 320 352 ) ( 288 -320 352 ) ( 288 -320 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +} +// brush 17 +{ +( 352 320 320 ) ( -320 320 320 ) ( -320 -384 320 ) eden/CL_edenroof3 -32 0 0.00 1 1 0 0 0 +( -320 -384 352 ) ( -320 320 352 ) ( 352 320 352 ) eden/CL_edenroof3 -32 0 0.00 1 1 0 0 0 +( -320 -384 352 ) ( 352 -384 352 ) ( 352 -384 320 ) eden/CL_edenroof3 -32 0 0.00 1 1 0 0 0 +( 352 -384 352 ) ( 352 320 352 ) ( 352 320 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( 384 -320 352 ) ( -288 -320 352 ) ( -288 -320 320 ) eden/CL_edenroof3 -32 0 0.00 1 1 0 0 0 +( 96 -128 320 ) ( 96 0 320 ) ( 96 -64 352 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +} +// brush 18 +{ +( 352 320 320 ) ( -320 320 320 ) ( -320 -384 320 ) eden/CL_edenroof3 -32 0 0.00 1 1 0 0 0 +( -320 -384 352 ) ( -320 320 352 ) ( 352 320 352 ) eden/CL_edenroof3 -32 0 0.00 1 1 0 0 0 +( -320 -384 352 ) ( 352 -384 352 ) ( 352 -384 320 ) eden/CL_edenroof3 -32 0 0.00 1 1 0 0 0 +( 352 320 352 ) ( -320 320 352 ) ( -320 320 320 ) eden/CL_edenroof3 -32 0 0.00 1 1 0 0 0 +( -320 320 352 ) ( -320 -384 352 ) ( -320 -384 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( 96 0 320 ) ( 96 -128 320 ) ( 96 -64 352 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +} +// brush 19 +{ +( 352 320 -32 ) ( -320 320 -32 ) ( -320 -384 -32 ) eden/FL_edenhouse3 -32 0 0.00 1 1 0 0 0 +( -320 -384 0 ) ( -320 320 0 ) ( 352 320 0 ) eden/FL_edenhouse3 -32 0 0.00 1 1 0 0 0 +( -320 -384 224 ) ( 352 -384 224 ) ( 352 -384 -32 ) eden/FL_edenhouse3 -32 0 0.00 1 1 0 0 0 +( 352 -384 224 ) ( 352 320 224 ) ( 352 320 -32 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 352 320 224 ) ( -320 320 224 ) ( -320 320 -32 ) eden/FL_edenhouse3 -32 0 0.00 1 1 0 0 0 +( -320 320 224 ) ( -320 -384 224 ) ( -320 -384 -32 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +} +// brush 20 +{ +( -320 -384 64 ) ( -320 -416 64 ) ( 384 -416 64 ) eden/edenmetalwall 97 190 -90.00 1 1 0 0 0 +( 384 -416 320 ) ( -320 -416 320 ) ( -320 -384 320 ) eden/edenmetalwall 97 190 -90.00 1 1 0 0 0 +( 384 -416 96 ) ( 384 -384 96 ) ( 384 -384 64 ) eden/edenmetalwall 96 63 -180.00 1 -1 0 0 0 +( 384 -384 96 ) ( -320 -384 96 ) ( -320 -384 64 ) eden/edenmetalwall -191 62 0.00 1.000008 1 0 0 0 +( -320 -384 96 ) ( -320 -416 96 ) ( -320 -416 64 ) eden/edenmetalwall 95 63 -180.00 1 -1 0 0 0 +( -320 -416 96 ) ( 384 -416 96 ) ( 384 -416 64 ) eden/edenmetalwall -191 62 0.00 1.000008 1 0 0 0 +} +// brush 21 +{ +( -320 -384 0 ) ( -320 -416 0 ) ( 384 -416 0 ) eden/bedtrim 97 63 -90.00 1 1 0 0 0 +( 384 -416 64 ) ( -320 -416 64 ) ( -320 -384 64 ) eden/bedtrim 97 63 -90.00 1 1 0 0 0 +( 384 -416 256 ) ( 384 -384 256 ) ( 384 -384 0 ) eden/bedtrim 96 0 -180.00 1 -1 0 0 0 +( 384 -384 256 ) ( -320 -384 256 ) ( -320 -384 0 ) eden/bedtrim -192 0 0.00 1 1 0 0 0 +( -320 -384 256 ) ( -320 -416 256 ) ( -320 -416 0 ) eden/bedtrim 95 0 -180.00 1 -1 0 0 0 +( -320 -416 256 ) ( 384 -416 256 ) ( 384 -416 0 ) eden/bedtrim -192 0 0.00 1 1 0 0 0 +} +// brush 22 +{ +( 352 -384 0 ) ( 384 -384 0 ) ( 384 320 0 ) eden/bedtrim 64 0 -180.00 1 1 0 0 0 +( 384 320 64 ) ( 384 -384 64 ) ( 352 -384 64 ) eden/bedtrim 64 0 -180.00 1 1 0 0 0 +( 384 320 256 ) ( 352 320 256 ) ( 352 320 0 ) eden/bedtrim 64 0 -180.00 1 -1 0 0 0 +( 352 320 256 ) ( 352 -384 256 ) ( 352 -384 0 ) eden/bedtrim 64 0 -180.00 1 -1 0 0 0 +( 352 -384 256 ) ( 384 -384 256 ) ( 384 -384 0 ) eden/bedtrim 63 0 -180.00 1 -1 0 0 0 +( 384 -384 256 ) ( 384 320 256 ) ( 384 320 0 ) eden/bedtrim 64 0 -180.00 1 -1 0 0 0 +} +// brush 23 +{ +( 352 -384 64 ) ( 384 -384 64 ) ( 384 320 64 ) eden/edenmetalwall 64 -65 -180.00 1 1 0 0 0 +( 384 320 320 ) ( 384 -384 320 ) ( 352 -384 320 ) eden/edenmetalwall 64 -65 -180.00 1 1 0 0 0 +( 384 320 96 ) ( 352 320 96 ) ( 352 320 64 ) eden/edenmetalwall 64 64 -180.00 1 -1 0 0 0 +( 352 320 96 ) ( 352 -384 96 ) ( 352 -384 64 ) eden/edenmetalwall 64 62 -180.00 1 -1 0 0 0 +( 352 -384 96 ) ( 384 -384 96 ) ( 384 -384 64 ) eden/edenmetalwall 63 64 -180.00 1 -1 0 0 0 +( 384 -384 96 ) ( 384 320 96 ) ( 384 320 64 ) eden/edenmetalwall 64 62 -180.00 1 -1 0 0 0 +} +} +// entity 1 +{ +"classname" "script_object" +"targetname" "movinlight2" +// brush 0 +{ +( 176 -240 144 ) ( 160 -240 144 ) ( 160 -256 144 ) common/skip 0 16 0.00 1 1 805306368 16512 0 +( 160 -256 160 ) ( 160 -240 160 ) ( 176 -240 160 ) common/skip 0 16 0.00 1 1 805306368 16512 0 +( 160 -256 240 ) ( 176 -256 240 ) ( 176 -256 144 ) common/skip 0 -48 0.00 1 1 805306368 16512 0 +( 176 -256 240 ) ( 176 -240 240 ) ( 176 -240 144 ) common/skip -16 -48 0.00 1 1 805306368 16512 0 +( 176 -240 240 ) ( 160 -240 240 ) ( 160 -240 144 ) common/skip 0 -48 0.00 1 1 805306368 16512 0 +( 160 -240 240 ) ( 160 -256 240 ) ( 160 -256 144 ) common/skip -16 -48 0.00 1 1 805306368 16512 0 +} +} +// entity 2 +{ +"classname" "script_object" +"targetname" "movinlight1" +// brush 0 +{ +( -184 192 144 ) ( -200 192 144 ) ( -200 176 144 ) common/skip -32 0 0.00 1 1 805306368 16512 0 +( -200 176 160 ) ( -200 192 160 ) ( -184 192 160 ) common/skip -32 0 0.00 1 1 805306368 16512 0 +( -200 176 240 ) ( -184 176 240 ) ( -184 176 144 ) common/skip -32 -48 0.00 1 1 805306368 16512 0 +( -184 176 240 ) ( -184 192 240 ) ( -184 192 144 ) common/skip 0 -48 0.00 1 1 805306368 16512 0 +( -184 192 240 ) ( -200 192 240 ) ( -200 192 144 ) common/skip -32 -48 0.00 1 1 805306368 16512 0 +( -200 192 240 ) ( -200 176 240 ) ( -200 176 144 ) common/skip 0 -48 0.00 1 1 805306368 16512 0 +} +} +// entity 3 +{ +"_color" "1.000000 0.724409 0.523622" +"light" "200" +"origin" "-192 184 168" +"spawnflags" "0" +"classname" "light" +} +// entity 4 +{ +"origin" "-272 -336 24" +"angle" "45" +"classname" "info_player_start" +} +// entity 5 +{ +"_color" "0.629921 0.846457 1.000000" +"light" "200" +"classname" "light" +"spawnflags" "0" +"origin" "168 184 168" +} +// entity 6 +{ +"light" "200" +"classname" "light" +"spawnflags" "0" +"origin" "-184 -248 168" +} +// entity 7 +{ +"light" "200" +"origin" "168 -248 168" +"spawnflags" "0" +"classname" "light" +} +// entity 8 +{ +"origin" "-8 -32 168" +"spawnflags" "0" +"classname" "light" +"light" "200" +} diff --git a/fakk/maps/example/climb.bsp b/fakk/maps/example/climb.bsp new file mode 100644 index 0000000..a9609d4 Binary files /dev/null and b/fakk/maps/example/climb.bsp differ diff --git a/fakk/maps/example/climb.map b/fakk/maps/example/climb.map new file mode 100644 index 0000000..5bda77c --- /dev/null +++ b/fakk/maps/example/climb.map @@ -0,0 +1,145 @@ +{ +"classname" "worldspawn" +// brush 0 +{ +( 264 -272 8 ) ( 264 264 8 ) ( 264 264 0 ) eden/WL_edenhouse 0 0 0.00 1 1 0 0 0 +( 264 264 8 ) ( -264 264 8 ) ( -264 264 0 ) eden/WL_edenhouse 0 0 0.00 1 1 0 0 0 +( -264 256 8 ) ( 264 256 8 ) ( -264 256 0 ) eden/WL_edenhouse 0 0 0.00 1 1 0 0 0 +( -128 256 384 ) ( -128 272 384 ) ( 120 272 384 ) eden/WL_edenhouse 0 0 0.00 1 1 0 0 0 +( -128 264 256 ) ( -224 264 256 ) ( -224 256 256 ) eden/WL_edenhouse 0 0 0.00 1 1 0 0 0 +( 256 264 384 ) ( 256 256 384 ) ( 256 264 0 ) eden/WL_edenhouse 0 0 0.00 1 1 0 0 0 +} +// brush 1 +{ +( 264 -272 8 ) ( 264 264 8 ) ( 264 264 0 ) eden/WL_edenhouse 0 0 0.00 1 1 0 0 0 +( 264 264 8 ) ( -264 264 8 ) ( -264 264 0 ) eden/WL_edenhouse 0 0 0.00 1 1 0 0 0 +( -264 256 8 ) ( 264 256 8 ) ( -264 256 0 ) eden/WL_edenhouse 0 0 0.00 1 1 0 0 0 +( 120 272 0 ) ( -128 272 0 ) ( -128 256 0 ) eden/WL_edenhouse 0 0 0.00 1 1 0 0 0 +( 128 272 8 ) ( 128 256 8 ) ( 128 272 0 ) eden/WL_edenhouse 0 0 0.00 1 1 0 0 0 +( -224 264 256 ) ( -128 264 256 ) ( -224 256 256 ) eden/WL_edenhouse 0 0 0.00 1 1 0 0 0 +} +// brush 2 +{ +( 264 264 8 ) ( -264 264 8 ) ( -264 264 0 ) eden/WL_edenhouse 0 0 0.00 1 1 0 0 0 +( -264 264 8 ) ( -264 -272 8 ) ( -264 -272 0 ) eden/WL_edenhouse 0 0 0.00 1 1 0 0 0 +( -264 256 8 ) ( 264 256 8 ) ( -264 256 0 ) eden/WL_edenhouse 0 0 0.00 1 1 0 0 0 +( -128 256 384 ) ( -128 272 384 ) ( 120 272 384 ) eden/WL_edenhouse 0 0 0.00 1 1 0 0 0 +( -128 264 256 ) ( -224 264 256 ) ( -224 256 256 ) eden/WL_edenhouse 0 0 0.00 1 1 0 0 0 +( -256 256 384 ) ( -256 264 384 ) ( -256 256 0 ) eden/WL_edenhouse 0 0 0.00 1 1 0 0 0 +} +// brush 3 +{ +( 264 264 8 ) ( -264 264 8 ) ( -264 264 0 ) eden/WL_edenhouse 0 0 0.00 1 1 0 0 0 +( -264 264 8 ) ( -264 -272 8 ) ( -264 -272 0 ) eden/WL_edenhouse 0 0 0.00 1 1 0 0 0 +( -264 256 8 ) ( 264 256 8 ) ( -264 256 0 ) eden/WL_edenhouse 0 0 0.00 1 1 0 0 0 +( 120 272 0 ) ( -128 272 0 ) ( -128 256 0 ) eden/WL_edenhouse 0 0 0.00 1 1 0 0 0 +( -128 256 8 ) ( -128 272 8 ) ( -128 256 0 ) eden/WL_edenhouse 0 0 0.00 1 1 0 0 0 +( -224 264 256 ) ( -128 264 256 ) ( -224 256 256 ) eden/WL_edenhouse 0 0 0.00 1 1 0 0 0 +} +// brush 4 +{ +( 120 272 0 ) ( -128 272 0 ) ( -128 256 0 ) swamps/CL_new_canopy5b 0 0 0.00 1 1 0 0 0 +surfaceparm ladder +( -128 256 8 ) ( 120 256 8 ) ( 120 256 0 ) swamps/CL_new_canopy5b 0 0 0.00 1 1 0 0 0 +surfaceparm ladder +( 128 256 8 ) ( 128 272 8 ) ( 128 272 0 ) swamps/CL_new_canopy5b 0 0 0.00 1 1 0 0 0 +surfaceparm ladder +( 120 264 8 ) ( -128 264 8 ) ( -128 264 0 ) swamps/CL_new_canopy5b 0 0 0.00 1 1 0 0 0 +surfaceparm ladder +( -128 272 8 ) ( -128 256 8 ) ( -128 256 0 ) swamps/CL_new_canopy5b 0 0 0.00 1 1 0 0 0 +surfaceparm ladder +( -224 264 256 ) ( -128 264 256 ) ( -224 256 256 ) swamps/CL_new_canopy5b 0 0 0.00 1 1 0 0 0 +surfaceparm ladder +} +// brush 5 +{ +( -128 264 256 ) ( -224 264 256 ) ( -224 256 256 ) swamps/CL_new_canopy5b 0 0 0.00 1 1 0 0 0 +surfaceparm ladder +( -224 256 384 ) ( -224 264 384 ) ( -128 264 384 ) swamps/CL_new_canopy5b 0 0 0.00 1 1 0 0 0 +surfaceparm ladder +( -224 256 384 ) ( -128 256 384 ) ( -128 256 0 ) swamps/CL_new_canopy5b 0 0 0.00 1 1 0 0 0 +surfaceparm ladder +( 256 256 384 ) ( 256 264 384 ) ( 256 264 0 ) swamps/CL_new_canopy5b 0 0 0.00 1 1 0 0 0 +surfaceparm ladder +( -128 264 384 ) ( -224 264 384 ) ( -224 264 0 ) swamps/CL_new_canopy5b 0 0 0.00 1 1 0 0 0 +surfaceparm ladder +( -256 264 384 ) ( -256 256 384 ) ( -256 256 0 ) swamps/CL_new_canopy5b 0 0 0.00 1 1 0 0 0 +surfaceparm ladder +} +// brush 6 +{ +( -264 -272 448 ) ( -264 264 448 ) ( 264 264 448 ) eden/WL_edenhouse 0 0 0.00 1 1 0 0 0 +( 264 -272 8 ) ( 264 264 8 ) ( 264 264 0 ) eden/WL_edenhouse 0 0 0.00 1 1 0 0 0 +( 264 264 8 ) ( -264 264 8 ) ( -264 264 0 ) eden/WL_edenhouse 0 0 0.00 1 1 0 0 0 +( -264 264 8 ) ( -264 -272 8 ) ( -264 -272 0 ) eden/WL_edenhouse 0 0 0.00 1 1 0 0 0 +( -264 256 8 ) ( 264 256 8 ) ( -264 256 0 ) eden/WL_edenhouse 0 0 0.00 1 1 0 0 0 +( -128 272 384 ) ( -128 256 384 ) ( 120 272 384 ) eden/WL_edenhouse 0 0 0.00 1 1 0 0 0 +} +// brush 7 +{ +( 264 264 -8 ) ( -264 264 -8 ) ( -264 -272 -8 ) eden/WL_edenhouse 0 0 0.00 1 1 0 0 0 +( 264 -272 8 ) ( 264 264 8 ) ( 264 264 0 ) eden/WL_edenhouse 0 0 0.00 1 1 0 0 0 +( 264 264 8 ) ( -264 264 8 ) ( -264 264 0 ) eden/WL_edenhouse 0 0 0.00 1 1 0 0 0 +( -264 264 8 ) ( -264 -272 8 ) ( -264 -272 0 ) eden/WL_edenhouse 0 0 0.00 1 1 0 0 0 +( -264 256 8 ) ( 264 256 8 ) ( -264 256 0 ) eden/WL_edenhouse 0 0 0.00 1 1 0 0 0 +( -128 272 0 ) ( 120 272 0 ) ( -128 256 0 ) eden/WL_edenhouse 0 0 0.00 1 1 0 0 0 +} +// brush 8 +{ +( 264 264 -8 ) ( -264 264 -8 ) ( -264 -272 -8 ) eden/WL_edenhouse 0 0 0.00 1 1 0 0 0 +( -264 -272 448 ) ( -264 264 448 ) ( 264 264 448 ) eden/WL_edenhouse 0 0 0.00 1 1 0 0 0 +( -264 -264 8 ) ( 264 -264 8 ) ( 264 -264 0 ) eden/WL_edenhouse 0 0 0.00 1 1 0 0 0 +( 264 264 8 ) ( -264 264 8 ) ( -264 264 0 ) eden/WL_edenhouse 0 0 0.00 1 1 0 0 0 +( -264 264 8 ) ( -264 -272 8 ) ( -264 -272 0 ) eden/WL_edenhouse 0 0 0.00 1 1 0 0 0 +( -256 -272 192 ) ( -256 264 192 ) ( -256 -272 184 ) eden/WL_edenhouse 0 0 0.00 1 1 0 0 0 +} +// brush 9 +{ +( 264 264 -8 ) ( -264 264 -8 ) ( -264 -272 -8 ) eden/WL_edenhouse 0 0 0.00 1 1 0 0 0 +( -264 -272 448 ) ( -264 264 448 ) ( 264 264 448 ) eden/WL_edenhouse 0 0 0.00 1 1 0 0 0 +( -264 -264 8 ) ( 264 -264 8 ) ( 264 -264 0 ) eden/WL_edenhouse 0 0 0.00 1 1 0 0 0 +( 264 -272 8 ) ( 264 264 8 ) ( 264 264 0 ) eden/WL_edenhouse 0 0 0.00 1 1 0 0 0 +( 264 264 8 ) ( -264 264 8 ) ( -264 264 0 ) eden/WL_edenhouse 0 0 0.00 1 1 0 0 0 +( 256 264 192 ) ( 256 -272 192 ) ( 256 264 184 ) eden/WL_edenhouse 0 0 0.00 1 1 0 0 0 +} +// brush 10 +{ +( 264 264 -8 ) ( -264 264 -8 ) ( -264 -272 -8 ) eden/WL_edenhouse 0 0 0.00 1 1 0 0 0 +( -264 -272 448 ) ( -264 264 448 ) ( 264 264 448 ) eden/WL_edenhouse 0 0 0.00 1 1 0 0 0 +( -264 -264 8 ) ( 264 -264 8 ) ( 264 -264 0 ) eden/WL_edenhouse 0 0 0.00 1 1 0 0 0 +( 264 -272 8 ) ( 264 264 8 ) ( 264 264 0 ) eden/WL_edenhouse 0 0 0.00 1 1 0 0 0 +( -264 264 8 ) ( -264 -272 8 ) ( -264 -272 0 ) eden/WL_edenhouse 0 0 0.00 1 1 0 0 0 +( 264 -256 8 ) ( -264 -256 8 ) ( 264 -256 0 ) eden/WL_edenhouse 0 0 0.00 1 1 0 0 0 +} +// brush 11 +{ +( -264 -272 456 ) ( -264 264 456 ) ( 264 264 456 ) eden/FL_edenhouse2 0 0 0.00 1 1 0 0 0 +( -264 -264 16 ) ( 264 -264 16 ) ( 264 -264 8 ) eden/FL_edenhouse2 0 8 0.00 1 1 0 0 0 +( 264 -272 16 ) ( 264 264 16 ) ( 264 264 8 ) eden/FL_edenhouse2 0 8 0.00 1 1 0 0 0 +( 264 264 16 ) ( -264 264 16 ) ( -264 264 8 ) eden/FL_edenhouse2 0 8 0.00 1 1 0 0 0 +( -264 264 16 ) ( -264 -272 16 ) ( -264 -272 8 ) eden/FL_edenhouse2 0 8 0.00 1 1 0 0 0 +( -264 264 448 ) ( -264 -272 448 ) ( 264 264 448 ) eden/FL_edenhouse2 0 0 0.00 1 1 0 0 0 +} +// brush 12 +{ +( 264 264 -8 ) ( -264 264 -8 ) ( -264 -272 -8 ) eden/fl_street1 0 0 0.00 1 1 0 0 0 +( -264 -264 8 ) ( 264 -264 8 ) ( 264 -264 0 ) eden/fl_street1 0 0 0.00 1 1 0 0 0 +( 264 -272 8 ) ( 264 264 8 ) ( 264 264 0 ) eden/fl_street1 0 0 0.00 1 1 0 0 0 +( 264 264 8 ) ( -264 264 8 ) ( -264 264 0 ) eden/fl_street1 0 0 0.00 1 1 0 0 0 +( -264 264 8 ) ( -264 -272 8 ) ( -264 -272 0 ) eden/fl_street1 0 0 0.00 1 1 0 0 0 +( -264 264 0 ) ( 264 264 0 ) ( -264 -272 0 ) eden/fl_street1 0 0 0.00 1 1 0 0 0 +} +} +// entity 1 +{ +"classname" "func_rope" +// brush 0 +{ +( 48 64 24 ) ( -24 64 24 ) ( -24 -16 24 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( -24 -16 448 ) ( -24 64 448 ) ( 48 64 448 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( -24 -16 416 ) ( 48 -16 416 ) ( 48 -16 352 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( 40 -24 416 ) ( 40 56 416 ) ( 40 56 352 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( 48 56 416 ) ( -24 56 416 ) ( -24 56 352 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( -24 64 416 ) ( -24 -16 416 ) ( -24 -16 352 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +} +} +// entity 2 +{ +"origin" "0 0 128" +"light" "1000" +"classname" "light" +} +// entity 3 +{ +"origin" "0 -192 16" +"angle" "90" +"classname" "info_player_start" +} diff --git a/fakk/maps/example/climb.prt b/fakk/maps/example/climb.prt new file mode 100644 index 0000000..a62fb9c --- /dev/null +++ b/fakk/maps/example/climb.prt @@ -0,0 +1,24 @@ +PRT1 +4 +4 +16 +4 0 2 0 (0 0 0 ) (0 0 448 ) (0 256 448 ) (0 256 0 ) +4 0 1 0 (0 0 448 ) (0 0 0 ) (256 0 0 ) (256 0 448 ) +4 1 3 0 (0 0 448 ) (0 0 0 ) (0 -256 0 ) (0 -256 448 ) +4 2 3 0 (-256 0 0 ) (0 0 0 ) (0 0 448 ) (-256 0 448 ) +4 0 (256 0 448 ) (256 0 0 ) (256 256 0 ) (256 256 448 ) +4 0 (256 256 448 ) (256 256 0 ) (0 256 0 ) (0 256 448 ) +4 0 (256 0 0 ) (0 0 0 ) (0 256 0 ) (256 256 0 ) +4 0 (0 0 448 ) (256 0 448 ) (256 256 448 ) (0 256 448 ) +4 1 (0 -256 448 ) (0 -256 0 ) (256 -256 0 ) (256 -256 448 ) +4 1 (256 -256 448 ) (256 -256 0 ) (256 0 0 ) (256 0 448 ) +4 1 (0 -256 0 ) (0 0 0 ) (256 0 0 ) (256 -256 0 ) +4 1 (256 0 448 ) (0 0 448 ) (0 -256 448 ) (256 -256 448 ) +4 2 (-256 256 448 ) (-256 256 0 ) (-256 0 0 ) (-256 0 448 ) +4 2 (-256 256 0 ) (-256 256 448 ) (0 256 448 ) (0 256 0 ) +4 2 (0 0 0 ) (-256 0 0 ) (-256 256 0 ) (0 256 0 ) +4 2 (0 256 448 ) (-256 256 448 ) (-256 0 448 ) (0 0 448 ) +4 3 (-256 -256 448 ) (-256 -256 0 ) (0 -256 0 ) (0 -256 448 ) +4 3 (-256 0 448 ) (-256 0 0 ) (-256 -256 0 ) (-256 -256 448 ) +4 3 (-256 -256 0 ) (-256 0 0 ) (0 0 0 ) (0 -256 0 ) +4 3 (0 0 448 ) (-256 0 448 ) (-256 -256 448 ) (0 -256 448 ) diff --git a/fakk/maps/example/cover.bsp b/fakk/maps/example/cover.bsp new file mode 100644 index 0000000..a0a325a Binary files /dev/null and b/fakk/maps/example/cover.bsp differ diff --git a/fakk/maps/example/cover.map b/fakk/maps/example/cover.map new file mode 100644 index 0000000..48b5b06 --- /dev/null +++ b/fakk/maps/example/cover.map @@ -0,0 +1,1408 @@ +{ +"classname" "worldspawn" +// brush 0 +{ +( 152 560 64 ) ( 152 576 64 ) ( 136 576 64 ) eden/genmetal 0 8 0.00 1 1 0 0 0 +( 136 576 240 ) ( 152 576 240 ) ( 152 560 240 ) eden/genmetal 0 8 0.00 1 1 0 0 0 +( 136 576 256 ) ( 136 560 256 ) ( 136 560 0 ) eden/genmetal -32 0 0.00 1 1 0 0 0 +( 136 568 256 ) ( 152 568 256 ) ( 152 568 0 ) eden/genmetal 24 0 0.00 1 1 0 0 0 +( 152 568 256 ) ( 152 584 256 ) ( 152 584 0 ) eden/genmetal -32 0 0.00 1 1 0 0 0 +( 152 576 256 ) ( 136 576 256 ) ( 136 576 0 ) eden/genmetal 56 0 -180.00 1 -1 0 0 0 +} +// brush 1 +{ +( 184 560 64 ) ( 184 576 64 ) ( 168 576 64 ) eden/genmetal 0 -8 0.00 1 1 0 0 0 +( 168 576 240 ) ( 184 576 240 ) ( 184 560 240 ) eden/genmetal 0 -8 0.00 1 1 0 0 0 +( 168 584 256 ) ( 168 568 256 ) ( 168 568 0 ) eden/genmetal -32 0 0.00 1 1 0 0 0 +( 168 568 256 ) ( 184 568 256 ) ( 184 568 0 ) eden/genmetal 40 0 0.00 1 1 0 0 0 +( 184 560 256 ) ( 184 576 256 ) ( 184 576 0 ) eden/genmetal -32 0 0.00 1 1 0 0 0 +( 184 576 256 ) ( 168 576 256 ) ( 168 576 0 ) eden/genmetal 72 0 -180.00 1 -1 0 0 0 +} +// brush 2 +{ +( 176 576 272 ) ( 144 576 272 ) ( 144 576 16 ) eden/genmetal 32 16 0.00 1 1 0 0 0 +( 168 568 272 ) ( 168 584 272 ) ( 168 584 16 ) eden/genmetal -32 16 0.00 1 1 0 0 0 +( 136 568 256 ) ( 168 568 256 ) ( 168 568 0 ) eden/genmetal 32 16 0.00 1 1 0 0 0 +( 152 584 272 ) ( 152 568 272 ) ( 152 568 16 ) eden/genmetal -32 16 0.00 1 1 0 0 0 +( 144 576 80 ) ( 176 576 80 ) ( 176 560 80 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( 176 560 64 ) ( 176 576 64 ) ( 144 576 64 ) eden/genmetal 0 -64 90.00 1 1 0 0 0 +} +// brush 3 +{ +( 176 576 432 ) ( 144 576 432 ) ( 144 576 176 ) eden/genmetal 32 48 0.00 1 1 0 0 0 +( 168 568 432 ) ( 168 584 432 ) ( 168 584 176 ) eden/genmetal -32 48 0.00 1 1 0 0 0 +( 136 568 416 ) ( 168 568 416 ) ( 168 568 160 ) eden/genmetal 32 48 0.00 1 1 0 0 0 +( 152 584 432 ) ( 152 568 432 ) ( 152 568 176 ) eden/genmetal -32 48 0.00 1 1 0 0 0 +( 144 576 240 ) ( 176 576 240 ) ( 176 560 240 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( 176 560 224 ) ( 176 576 224 ) ( 144 576 224 ) eden/genmetal 0 -64 90.00 1 1 0 0 0 +} +// brush 4 +{ +( 168 576 240 ) ( 152 576 240 ) ( 152 576 64 ) otto/ottolight 35 -16 90.00 -2.250000 -0.500000 0 0 0 +( 168 568 240 ) ( 168 576 240 ) ( 168 576 64 ) otto/ottolight 35 16 90.00 -2.250000 -0.500000 0 0 0 +( 152 572 240 ) ( 168 572 240 ) ( 168 572 64 ) otto/ottolight 35 -16 90.00 -2.250000 -0.500000 0 0 0 +( 152 576 240 ) ( 152 568 240 ) ( 152 568 64 ) otto/ottolight 35 16 90.00 -2.250000 -0.500000 0 0 0 +( 152 576 224 ) ( 168 576 224 ) ( 168 568 224 ) otto/ottolight 35 -16 90.00 -2.250000 -0.500000 0 0 0 +( 168 568 80 ) ( 168 576 80 ) ( 152 576 80 ) otto/ottolight 6 16 0.00 2.250000 0.500000 0 0 0 +} +// brush 5 +{ +( 152 -768 64 ) ( 152 -768 240 ) ( 168 -768 240 ) otto/ottolight 35 -16 90.00 -2.250000 -0.500000 0 0 0 +( 168 -768 64 ) ( 168 -768 240 ) ( 168 -760 240 ) otto/ottolight 34 16 90.00 -2.250000 -0.500000 0 0 0 +( 168 -764 64 ) ( 168 -764 240 ) ( 152 -764 240 ) otto/ottolight 35 -16 90.00 -2.250000 -0.500000 0 0 0 +( 152 -760 64 ) ( 152 -760 240 ) ( 152 -768 240 ) otto/ottolight 34 16 90.00 -2.250000 -0.500000 0 0 0 +( 168 -760 224 ) ( 168 -768 224 ) ( 152 -768 224 ) otto/ottolight 34 -16 90.00 -2.250000 -0.500000 0 0 0 +( 152 -768 80 ) ( 168 -768 80 ) ( 168 -760 80 ) otto/ottolight 5 16 0.00 2.250000 0.500000 0 0 0 +} +// brush 6 +{ +( 144 -768 176 ) ( 144 -768 432 ) ( 176 -768 432 ) eden/genmetal 32 48 0.00 1 1 0 0 0 +( 168 -776 176 ) ( 168 -776 432 ) ( 168 -760 432 ) eden/genmetal -96 48 0.00 1 1 0 0 0 +( 168 -760 160 ) ( 168 -760 416 ) ( 136 -760 416 ) eden/genmetal 32 48 0.00 1 1 0 0 0 +( 152 -760 176 ) ( 152 -760 432 ) ( 152 -776 432 ) eden/genmetal -96 48 0.00 1 1 0 0 0 +( 176 -752 240 ) ( 176 -768 240 ) ( 144 -768 240 ) eden/genmetal -64 0 0.00 1 1 0 0 0 +( 144 -768 224 ) ( 176 -768 224 ) ( 176 -752 224 ) eden/genmetal 64 -63 90.00 1 1 0 0 0 +} +// brush 7 +{ +( 144 -768 16 ) ( 144 -768 272 ) ( 176 -768 272 ) eden/genmetal 32 16 0.00 1 1 0 0 0 +( 168 -776 16 ) ( 168 -776 272 ) ( 168 -760 272 ) eden/genmetal -96 16 0.00 1 1 0 0 0 +( 168 -760 0 ) ( 168 -760 256 ) ( 136 -760 256 ) eden/genmetal 32 16 0.00 1 1 0 0 0 +( 152 -760 16 ) ( 152 -760 272 ) ( 152 -776 272 ) eden/genmetal -96 16 0.00 1 1 0 0 0 +( 176 -752 80 ) ( 176 -768 80 ) ( 144 -768 80 ) eden/genmetal -64 0 0.00 1 1 0 0 0 +( 144 -768 64 ) ( 176 -768 64 ) ( 176 -752 64 ) eden/genmetal 64 -63 90.00 1 1 0 0 0 +} +// brush 8 +{ +( 168 -768 64 ) ( 184 -768 64 ) ( 184 -752 64 ) eden/genmetal -64 -8 0.00 1 1 0 0 0 +( 184 -752 240 ) ( 184 -768 240 ) ( 168 -768 240 ) eden/genmetal -64 -8 0.00 1 1 0 0 0 +( 168 -760 0 ) ( 168 -760 256 ) ( 168 -776 256 ) eden/genmetal -96 0 0.00 1 1 0 0 0 +( 184 -760 0 ) ( 184 -760 256 ) ( 168 -760 256 ) eden/genmetal 40 0 0.00 1 1 0 0 0 +( 184 -768 0 ) ( 184 -768 256 ) ( 184 -752 256 ) eden/genmetal -96 0 0.00 1 1 0 0 0 +( 168 -768 0 ) ( 168 -768 256 ) ( 184 -768 256 ) eden/genmetal 71 0 -180.00 1 -1 0 0 0 +} +// brush 9 +{ +( 136 -768 64 ) ( 152 -768 64 ) ( 152 -752 64 ) eden/genmetal -64 8 0.00 1 1 0 0 0 +( 152 -752 240 ) ( 152 -768 240 ) ( 136 -768 240 ) eden/genmetal -64 8 0.00 1 1 0 0 0 +( 136 -752 0 ) ( 136 -752 256 ) ( 136 -768 256 ) eden/genmetal -96 0 0.00 1 1 0 0 0 +( 152 -760 0 ) ( 152 -760 256 ) ( 136 -760 256 ) eden/genmetal 24 0 0.00 1 1 0 0 0 +( 152 -776 0 ) ( 152 -776 256 ) ( 152 -760 256 ) eden/genmetal -96 0 0.00 1 1 0 0 0 +( 136 -768 0 ) ( 136 -768 256 ) ( 152 -768 256 ) eden/genmetal 55 0 -180.00 1 -1 0 0 0 +} +// brush 10 +{ +( 832 -120 64 ) ( 832 -104 64 ) ( 816 -104 64 ) eden/genmetal -64 8 0.00 1 1 0 0 0 +( 816 -104 240 ) ( 832 -104 240 ) ( 832 -120 240 ) eden/genmetal -64 8 0.00 1 1 0 0 0 +( 816 -120 0 ) ( 816 -120 256 ) ( 832 -120 256 ) eden/genmetal -64 0 0.00 1 1 0 0 0 +( 824 -104 0 ) ( 824 -104 256 ) ( 824 -120 256 ) eden/genmetal -8 0 0.00 1 1 0 0 0 +( 840 -104 0 ) ( 840 -104 256 ) ( 824 -104 256 ) eden/genmetal -64 0 0.00 1 1 0 0 0 +( 832 -120 0 ) ( 832 -120 256 ) ( 832 -104 256 ) eden/genmetal -8 0 0.00 1 1 0 0 0 +} +// brush 11 +{ +( 832 -88 64 ) ( 832 -72 64 ) ( 816 -72 64 ) eden/genmetal -64 -8 0.00 1 1 0 0 0 +( 816 -72 240 ) ( 832 -72 240 ) ( 832 -88 240 ) eden/genmetal -64 -8 0.00 1 1 0 0 0 +( 824 -88 0 ) ( 824 -88 256 ) ( 840 -88 256 ) eden/genmetal -64 0 0.00 1 1 0 0 0 +( 824 -72 0 ) ( 824 -72 256 ) ( 824 -88 256 ) eden/genmetal 8 0 0.00 1 1 0 0 0 +( 832 -72 0 ) ( 832 -72 256 ) ( 816 -72 256 ) eden/genmetal -64 0 0.00 1 1 0 0 0 +( 832 -88 0 ) ( 832 -88 256 ) ( 832 -72 256 ) eden/genmetal 8 0 0.00 1 1 0 0 0 +} +// brush 12 +{ +( 832 -112 16 ) ( 832 -112 272 ) ( 832 -80 272 ) eden/genmetal 0 16 0.00 1 1 0 0 0 +( 840 -88 16 ) ( 840 -88 272 ) ( 824 -88 272 ) eden/genmetal -64 16 0.00 1 1 0 0 0 +( 824 -88 0 ) ( 824 -88 256 ) ( 824 -120 256 ) eden/genmetal 0 16 0.00 1 1 0 0 0 +( 824 -104 16 ) ( 824 -104 272 ) ( 840 -104 272 ) eden/genmetal -64 16 0.00 1 1 0 0 0 +( 816 -80 80 ) ( 832 -80 80 ) ( 832 -112 80 ) eden/genmetal -64 0 0.00 1 1 0 0 0 +( 832 -112 64 ) ( 832 -80 64 ) ( 816 -80 64 ) eden/genmetal -64 0 0.00 1 1 0 0 0 +} +// brush 13 +{ +( 832 -112 176 ) ( 832 -112 432 ) ( 832 -80 432 ) eden/genmetal 0 48 0.00 1 1 0 0 0 +( 840 -88 176 ) ( 840 -88 432 ) ( 824 -88 432 ) eden/genmetal -64 48 0.00 1 1 0 0 0 +( 824 -88 160 ) ( 824 -88 416 ) ( 824 -120 416 ) eden/genmetal 0 48 0.00 1 1 0 0 0 +( 824 -104 176 ) ( 824 -104 432 ) ( 840 -104 432 ) eden/genmetal -64 48 0.00 1 1 0 0 0 +( 816 -80 240 ) ( 832 -80 240 ) ( 832 -112 240 ) eden/genmetal -64 0 0.00 1 1 0 0 0 +( 832 -112 224 ) ( 832 -80 224 ) ( 816 -80 224 ) eden/genmetal -64 0 0.00 1 1 0 0 0 +} +// brush 14 +{ +( 832 -104 64 ) ( 832 -104 240 ) ( 832 -88 240 ) otto/ottolight 35 16 90.00 -2.250000 -0.500000 0 0 0 +( 832 -88 64 ) ( 832 -88 240 ) ( 824 -88 240 ) otto/ottolight 34 16 90.00 -2.250000 -0.500000 0 0 0 +( 828 -88 64 ) ( 828 -88 240 ) ( 828 -104 240 ) otto/ottolight 35 16 90.00 -2.250000 -0.500000 0 0 0 +( 824 -104 64 ) ( 824 -104 240 ) ( 832 -104 240 ) otto/ottolight 34 16 90.00 -2.250000 -0.500000 0 0 0 +( 824 -88 224 ) ( 832 -88 224 ) ( 832 -104 224 ) otto/ottolight 34 16 90.00 -2.250000 -0.500000 0 0 0 +( 832 -104 80 ) ( 832 -88 80 ) ( 824 -88 80 ) otto/ottolight 34 16 90.00 -2.250000 -0.500000 0 0 0 +} +// brush 15 +{ +( -512 -88 240 ) ( -512 -104 240 ) ( -512 -104 64 ) otto/ottolight 35 16 90.00 -2.250000 -0.500000 0 0 0 +( -504 -88 240 ) ( -512 -88 240 ) ( -512 -88 64 ) otto/ottolight 35 16 90.00 -2.250000 -0.500000 0 0 0 +( -508 -104 240 ) ( -508 -88 240 ) ( -508 -88 64 ) otto/ottolight 35 16 90.00 -2.250000 -0.500000 0 0 0 +( -512 -104 240 ) ( -504 -104 240 ) ( -504 -104 64 ) otto/ottolight 35 16 90.00 -2.250000 -0.500000 0 0 0 +( -512 -104 224 ) ( -512 -88 224 ) ( -504 -88 224 ) otto/ottolight 35 16 90.00 -2.250000 -0.500000 0 0 0 +( -504 -88 80 ) ( -512 -88 80 ) ( -512 -104 80 ) otto/ottolight 35 16 90.00 -2.250000 -0.500000 0 0 0 +} +// brush 16 +{ +( -512 -80 432 ) ( -512 -112 432 ) ( -512 -112 176 ) eden/genmetal 0 48 0.00 1 1 0 0 0 +( -504 -88 432 ) ( -520 -88 432 ) ( -520 -88 176 ) eden/genmetal 0 48 0.00 1 1 0 0 0 +( -504 -120 416 ) ( -504 -88 416 ) ( -504 -88 160 ) eden/genmetal 0 48 0.00 1 1 0 0 0 +( -520 -104 432 ) ( -504 -104 432 ) ( -504 -104 176 ) eden/genmetal 0 48 0.00 1 1 0 0 0 +( -512 -112 240 ) ( -512 -80 240 ) ( -496 -80 240 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( -496 -80 224 ) ( -512 -80 224 ) ( -512 -112 224 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +} +// brush 17 +{ +( -512 -80 272 ) ( -512 -112 272 ) ( -512 -112 16 ) eden/genmetal 0 16 0.00 1 1 0 0 0 +( -504 -88 272 ) ( -520 -88 272 ) ( -520 -88 16 ) eden/genmetal 0 16 0.00 1 1 0 0 0 +( -504 -120 256 ) ( -504 -88 256 ) ( -504 -88 0 ) eden/genmetal 0 16 0.00 1 1 0 0 0 +( -520 -104 272 ) ( -504 -104 272 ) ( -504 -104 16 ) eden/genmetal 0 16 0.00 1 1 0 0 0 +( -512 -112 80 ) ( -512 -80 80 ) ( -496 -80 80 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( -496 -80 64 ) ( -512 -80 64 ) ( -512 -112 64 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +} +// brush 18 +{ +( -496 -72 64 ) ( -512 -72 64 ) ( -512 -88 64 ) eden/genmetal 0 -8 0.00 1 1 0 0 0 +( -512 -88 240 ) ( -512 -72 240 ) ( -496 -72 240 ) eden/genmetal 0 -8 0.00 1 1 0 0 0 +( -520 -88 256 ) ( -504 -88 256 ) ( -504 -88 0 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( -504 -88 256 ) ( -504 -72 256 ) ( -504 -72 0 ) eden/genmetal 8 0 0.00 1 1 0 0 0 +( -496 -72 256 ) ( -512 -72 256 ) ( -512 -72 0 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( -512 -72 256 ) ( -512 -88 256 ) ( -512 -88 0 ) eden/genmetal 8 0 0.00 1 1 0 0 0 +} +// brush 19 +{ +( -496 -104 64 ) ( -512 -104 64 ) ( -512 -120 64 ) eden/genmetal 0 8 0.00 1 1 0 0 0 +( -512 -120 240 ) ( -512 -104 240 ) ( -496 -104 240 ) eden/genmetal 0 8 0.00 1 1 0 0 0 +( -512 -120 256 ) ( -496 -120 256 ) ( -496 -120 0 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( -504 -120 256 ) ( -504 -104 256 ) ( -504 -104 0 ) eden/genmetal -8 0 0.00 1 1 0 0 0 +( -504 -104 256 ) ( -520 -104 256 ) ( -520 -104 0 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( -512 -104 256 ) ( -512 -120 256 ) ( -512 -120 0 ) eden/genmetal -8 0 0.00 1 1 0 0 0 +} +// brush 20 +{ +( 128 704 -96 ) ( 128 672 -96 ) ( 128 672 -128 ) eden/edenmetalwall 0 0 0.00 1 1 0 0 0 +( 352 704 -96 ) ( 128 704 -96 ) ( 128 704 -128 ) eden/edenmetalwall 64 0 0.00 1 1 0 0 0 +( 384 672 -96 ) ( 384 704 -96 ) ( 384 704 -128 ) eden/edenmetalwall 0 0 0.00 1 1 0 0 0 +( 128 672 -96 ) ( 352 672 -96 ) ( 352 672 -128 ) eden/edenmetalwall 64 0 0.00 1 1 0 0 0 +( 128 672 -96 ) ( 128 704 -96 ) ( 352 704 -96 ) eden/edenmetalwall 64 0 0.00 1 1 0 0 0 +( 352 704 -128 ) ( 128 704 -128 ) ( 128 672 -128 ) eden/edenmetalwall 64 0 0.00 1 1 0 0 0 +} +// brush 21 + { + patchDef2 + { + eden/edenmetalwall + ( 9 3 0 536870912 0 subdivisions 90.458153 ) +( +( ( -344 -568 288 0 0 ) ( -344 -568 496 0 0.812500 ) ( 72 -184 496 0 3.437500 ) ) +( ( -312 -600 288 0.125000 0 ) ( -312 -600 496 0.125000 0.812500 ) ( 104 -216 496 0.125000 3.437500 ) ) +( ( -280 -568 288 0.250000 0 ) ( -280 -568 464 0.250000 0.812500 ) ( 104 -216 464 0.250000 3.437500 ) ) +( ( -248 -536 288 0.375000 0 ) ( -248 -536 432 0.375000 0.812500 ) ( 104 -216 432 0.375000 3.437500 ) ) +( ( -280 -504 288 0.500000 0 ) ( -280 -504 432 0.500000 0.812500 ) ( 72 -184 432 0.500000 3.437500 ) ) +( ( -312 -472 288 0.625000 0 ) ( -312 -472 432 0.625000 0.812500 ) ( 40 -152 432 0.625000 3.437500 ) ) +( ( -344 -504 288 0.750000 0 ) ( -344 -504 464 0.750000 0.812500 ) ( 40 -152 464 0.750000 3.437500 ) ) +( ( -376 -536 288 0.875000 0 ) ( -376 -536 496 0.875000 0.812500 ) ( 40 -152 496 0.875000 3.437500 ) ) +( ( -344 -568 288 1 0 ) ( -344 -568 496 1 0.812500 ) ( 72 -184 496 1 3.437500 ) ) +) + } + } +// brush 22 + { + patchDef2 + { + eden/edenmetalwall + ( 9 3 0 536870912 0 subdivisions 90.458153 ) +( +( ( 88 -8 496 0 3.437500 ) ( -328 376 496 0 0.812500 ) ( -328 376 288 0 0 ) ) +( ( 120 24 496 0.125000 3.437500 ) ( -296 408 496 0.125000 0.812500 ) ( -296 408 288 0.125000 0 ) ) +( ( 120 24 464 0.250000 3.437500 ) ( -264 376 464 0.250000 0.812500 ) ( -264 376 288 0.250000 0 ) ) +( ( 120 24 432 0.375000 3.437500 ) ( -232 344 432 0.375000 0.812500 ) ( -232 344 288 0.375000 0 ) ) +( ( 88 -8 432 0.500000 3.437500 ) ( -264 312 432 0.500000 0.812500 ) ( -264 312 288 0.500000 0 ) ) +( ( 56 -40 432 0.625000 3.437500 ) ( -296 280 432 0.625000 0.812500 ) ( -296 280 288 0.625000 0 ) ) +( ( 56 -40 464 0.750000 3.437500 ) ( -328 312 464 0.750000 0.812500 ) ( -328 312 288 0.750000 0 ) ) +( ( 56 -40 496 0.875000 3.437500 ) ( -360 344 496 0.875000 0.812500 ) ( -360 344 288 0.875000 0 ) ) +( ( 88 -8 496 1 3.437500 ) ( -328 376 496 1 0.812500 ) ( -328 376 288 1 0 ) ) +) + } + } +// brush 23 + { + patchDef2 + { + eden/edenmetalwall + ( 9 3 0 536870912 0 subdivisions 90.458153 ) +( +( ( 648 376 288 0 0 ) ( 648 376 496 0 0.812500 ) ( 232 -8 496 0 3.437500 ) ) +( ( 616 408 288 0.125000 0 ) ( 616 408 496 0.125000 0.812500 ) ( 200 24 496 0.125000 3.437500 ) ) +( ( 584 376 288 0.250000 0 ) ( 584 376 464 0.250000 0.812500 ) ( 200 24 464 0.250000 3.437500 ) ) +( ( 552 344 288 0.375000 0 ) ( 552 344 432 0.375000 0.812500 ) ( 200 24 432 0.375000 3.437500 ) ) +( ( 584 312 288 0.500000 0 ) ( 584 312 432 0.500000 0.812500 ) ( 232 -8 432 0.500000 3.437500 ) ) +( ( 616 280 288 0.625000 0 ) ( 616 280 432 0.625000 0.812500 ) ( 264 -40 432 0.625000 3.437500 ) ) +( ( 648 312 288 0.750000 0 ) ( 648 312 464 0.750000 0.812500 ) ( 264 -40 464 0.750000 3.437500 ) ) +( ( 680 344 288 0.875000 0 ) ( 680 344 496 0.875000 0.812500 ) ( 264 -40 496 0.875000 3.437500 ) ) +( ( 648 376 288 1 0 ) ( 648 376 496 1 0.812500 ) ( 232 -8 496 1 3.437500 ) ) +) + } + } +// brush 24 + { + patchDef2 + { + eden/edenmetalwall + ( 9 3 0 536870912 0 subdivisions 90.458153 ) +( +( ( 248 -184 496 0 3.437500 ) ( 664 -568 496 0 0.812500 ) ( 664 -568 288 0 0 ) ) +( ( 216 -216 496 0.125000 3.437500 ) ( 632 -600 496 0.125000 0.812500 ) ( 632 -600 288 0.125000 0 ) ) +( ( 216 -216 464 0.250000 3.437500 ) ( 600 -568 464 0.250000 0.812500 ) ( 600 -568 288 0.250000 0 ) ) +( ( 216 -216 432 0.375000 3.437500 ) ( 568 -536 432 0.375000 0.812500 ) ( 568 -536 288 0.375000 0 ) ) +( ( 248 -184 432 0.500000 3.437500 ) ( 600 -504 432 0.500000 0.812500 ) ( 600 -504 288 0.500000 0 ) ) +( ( 280 -152 432 0.625000 3.437500 ) ( 632 -472 432 0.625000 0.812500 ) ( 632 -472 288 0.625000 0 ) ) +( ( 280 -152 464 0.750000 3.437500 ) ( 664 -504 464 0.750000 0.812500 ) ( 664 -504 288 0.750000 0 ) ) +( ( 280 -152 496 0.875000 3.437500 ) ( 696 -536 496 0.875000 0.812500 ) ( 696 -536 288 0.875000 0 ) ) +( ( 248 -184 496 1 3.437500 ) ( 664 -568 496 1 0.812500 ) ( 664 -568 288 1 0 ) ) +) + } + } +// brush 25 +{ +( 280 -144 408 ) ( 280 -144 504 ) ( 280 -48 504 ) eden/edenmetalwall 8 24 0.00 1 1 0 0 0 +( 280 -48 496 ) ( 232 -64 496 ) ( 232 -64 408 ) eden/edenmetalwall -216 24 0.00 1 1 0 0 0 +( 232 -64 496 ) ( 232 -128 496 ) ( 232 -128 408 ) eden/edenmetalwall 8 24 0.00 1 1 0 0 0 +( 280 -144 408 ) ( 232 -128 408 ) ( 232 -128 496 ) eden/edenmetalwall -216 24 0.00 1 1 0 0 0 +( 224 -48 496 ) ( 288 -48 496 ) ( 288 -144 496 ) eden/edenmetalwall -200 8 0.00 1 1 0 0 0 +( 288 -144 408 ) ( 288 -48 408 ) ( 224 -48 408 ) eden/edenmetalwall 64 193 -180.00 1 1 0 0 0 +} +// brush 26 +{ +( 208 24 504 ) ( 112 24 504 ) ( 112 24 408 ) eden/edenmetalwall -72 24 0.00 1 1 0 0 0 +( 192 -24 408 ) ( 192 -24 496 ) ( 208 24 496 ) eden/edenmetalwall -120 24 0.00 1 1 0 0 0 +( 128 -24 408 ) ( 128 -24 496 ) ( 192 -24 496 ) eden/edenmetalwall -72 24 0.00 1 1 0 0 0 +( 128 -24 496 ) ( 128 -24 408 ) ( 112 24 408 ) eden/edenmetalwall -120 24 0.00 1 1 0 0 0 +( 112 32 496 ) ( 208 32 496 ) ( 208 -32 496 ) eden/edenmetalwall -88 104 0.00 1 1 0 0 0 +( 208 -32 408 ) ( 208 32 408 ) ( 112 32 408 ) eden/edenmetalwall -192 -47 90.00 1 1 0 0 0 +} +// brush 27 +{ +( 40 -48 408 ) ( 112 24 408 ) ( 112 24 496 ) eden/edenmetalwall -160 0 0.00 1 1 0 0 0 +( 40 -48 496 ) ( 88 -64 496 ) ( 88 -64 408 ) eden/edenmetalwall -16 0 0.00 1 1 0 0 0 +( 88 -64 496 ) ( 128 -24 496 ) ( 128 -24 408 ) eden/edenmetalwall -160 0 0.00 1 1 0 0 0 +( 112 24 408 ) ( 128 -24 408 ) ( 128 -24 496 ) eden/edenmetalwall -160 0 0.00 1 1 0 0 0 +( 40 -48 496 ) ( 80 0 496 ) ( 128 -16 496 ) eden/edenmetalwall -16 160 0.00 1 1 0 0 0 +( 88 -64 408 ) ( 128 -16 408 ) ( 80 0 408 ) eden/edenmetalwall -16 160 0.00 1 1 0 0 0 +} +// brush 28 +{ +( 208 24 496 ) ( 208 24 408 ) ( 280 -48 408 ) eden/edenmetalwall -160 0 0.00 1 1 0 0 0 +( 232 -64 408 ) ( 232 -64 496 ) ( 280 -48 496 ) eden/edenmetalwall -160 0 0.00 1 1 0 0 0 +( 192 -24 408 ) ( 192 -24 496 ) ( 232 -64 496 ) eden/edenmetalwall -160 0 0.00 1 1 0 0 0 +( 192 -24 496 ) ( 192 -24 408 ) ( 208 24 408 ) eden/edenmetalwall -160 0 0.00 1 1 0 0 0 +( 192 -16 496 ) ( 240 0 496 ) ( 280 -48 496 ) eden/edenmetalwall -160 160 0.00 1 1 0 0 0 +( 240 0 408 ) ( 192 -16 408 ) ( 232 -64 408 ) eden/edenmetalwall -160 160 0.00 1 1 0 0 0 +} +// brush 29 +{ +( 232 -128 408 ) ( 192 -176 408 ) ( 240 -192 408 ) eden/edenmetalwall -160 0 0.00 1 1 0 0 0 +( 280 -144 496 ) ( 240 -192 496 ) ( 192 -176 496 ) eden/edenmetalwall -160 0 0.00 1 1 0 0 0 +( 208 -216 408 ) ( 192 -168 408 ) ( 192 -168 496 ) eden/edenmetalwall 0 0 0.00 1 1 0 0 0 +( 232 -128 496 ) ( 192 -168 496 ) ( 192 -168 408 ) eden/edenmetalwall 0 0 0.00 1 1 0 0 0 +( 280 -144 496 ) ( 232 -128 496 ) ( 232 -128 408 ) eden/edenmetalwall -160 0 0.00 1 1 0 0 0 +( 280 -144 408 ) ( 208 -216 408 ) ( 208 -216 496 ) eden/edenmetalwall 0 0 0.00 1 1 0 0 0 +} +// brush 30 +{ +( 112 -224 408 ) ( 208 -224 408 ) ( 208 -160 408 ) eden/edenmetalwall 0 -47 90.00 1 1 0 0 0 +( 208 -160 496 ) ( 208 -224 496 ) ( 112 -224 496 ) eden/edenmetalwall -88 -88 0.00 1 1 0 0 0 +( 112 -216 408 ) ( 128 -168 408 ) ( 128 -168 496 ) eden/edenmetalwall 72 24 0.00 1 1 0 0 0 +( 192 -168 496 ) ( 128 -168 496 ) ( 128 -168 408 ) eden/edenmetalwall -72 24 0.00 1 1 0 0 0 +( 208 -216 496 ) ( 192 -168 496 ) ( 192 -168 408 ) eden/edenmetalwall 72 24 0.00 1 1 0 0 0 +( 112 -216 408 ) ( 112 -216 504 ) ( 208 -216 504 ) eden/edenmetalwall -72 24 0.00 1 1 0 0 0 +} +// brush 31 +{ +( 112 -216 496 ) ( 112 -216 408 ) ( 40 -144 408 ) eden/edenmetalwall 0 0 0.00 1 1 0 0 0 +( 88 -128 408 ) ( 88 -128 496 ) ( 40 -144 496 ) eden/edenmetalwall 0 0 0.00 1 1 0 0 0 +( 128 -168 408 ) ( 128 -168 496 ) ( 88 -128 496 ) eden/edenmetalwall 0 0 0.00 1 1 0 0 0 +( 128 -168 496 ) ( 128 -168 408 ) ( 112 -216 408 ) eden/edenmetalwall 0 0 0.00 1 1 0 0 0 +( 128 -176 496 ) ( 80 -192 496 ) ( 40 -143.999954 496 ) eden/edenmetalwall 0 0 0.00 1 1 0 0 0 +( 80 -192 408 ) ( 128 -176 408 ) ( 88 -127.999954 408 ) eden/edenmetalwall 0 0 0.00 1 1 0 0 0 +} +// brush 32 +{ +( 96 -48 408 ) ( 32 -48 408 ) ( 32 -144 408 ) eden/edenmetalwall 0 0 0.00 1 1 0 0 0 +( 32 -144 496 ) ( 32 -48 496 ) ( 96 -48 496 ) eden/edenmetalwall 0 0 0.00 1 1 0 0 0 +( 88 -128 496 ) ( 88 -128 408 ) ( 40 -144 408 ) eden/edenmetalwall 0 24 0.00 1 1 0 0 0 +( 88 -128 408 ) ( 88 -128 496 ) ( 88 -64 496 ) eden/edenmetalwall 0 24 0.00 1 1 0 0 0 +( 88 -64 408 ) ( 88 -64 496 ) ( 40 -48 496 ) eden/edenmetalwall 0 24 0.00 1 1 0 0 0 +( 40 -48 504 ) ( 40 -144 504 ) ( 40 -144 408 ) eden/edenmetalwall 0 24 0.00 1 1 0 0 0 +} +// brush 33 + { + patchDef2 + { + eden/edenmetalwall + ( 3 3 0 536870912 0 ) +( +( ( 32 -96 400 0 0 ) ( 16 -240 400 0 0.093750 ) ( 160 -224 400 0 0.187500 ) ) +( ( 64 -96 400 0.156250 0 ) ( 72 -184 400 0.156250 0.093750 ) ( 160 -200 400 0.156250 0.187500 ) ) +( ( 96 -96 400 0.312500 0 ) ( 96 -160 400 0.312500 0.093750 ) ( 160 -160 400 0.312500 0.187500 ) ) +) + } + } +// brush 34 + { + patchDef2 + { + eden/edenmetalwall + ( 3 3 0 536870912 0 ) +( +( ( 160 -224 400 0 0.187500 ) ( 304 -240 400 0 0.093750 ) ( 288 -96 400 0 0 ) ) +( ( 160 -200 400 0.156250 0.187500 ) ( 248 -184 400 0.156250 0.093750 ) ( 256 -96 400 0.156250 0 ) ) +( ( 160 -160 400 0.312500 0.187500 ) ( 224 -160 400 0.312500 0.093750 ) ( 224 -96 400 0.312500 0 ) ) +) + } + } +// brush 35 + { + patchDef2 + { + eden/edenmetalwall + ( 3 3 0 536870912 0 ) +( +( ( 288 -96 400 0 0 ) ( 304 48 400 0 0.093750 ) ( 160 32 400 0 0.187500 ) ) +( ( 256 -96 400 0.156250 0 ) ( 248 -8 400 0.156250 0.093750 ) ( 160 8 400 0.156250 0.187500 ) ) +( ( 224 -96 400 0.312500 0 ) ( 224 -32 400 0.312500 0.093750 ) ( 160 -32 400 0.312500 0.187500 ) ) +) + } + } +// brush 36 + { + patchDef2 + { + eden/edenmetalwall + ( 3 3 0 536870912 0 ) +( +( ( 160 32 400 0 0.187500 ) ( 16 48 400 0 0.093750 ) ( 32 -96 400 0 0 ) ) +( ( 160 8 400 0.156250 0.187500 ) ( 72 -8 400 0.156250 0.093750 ) ( 64 -96 400 0.156250 0 ) ) +( ( 160 -32 400 0.312500 0.187500 ) ( 96 -32 400 0.312500 0.093750 ) ( 96 -96 400 0.312500 0 ) ) +) + } + } +// brush 37 + { + patchDef2 + { + eden/edenmetalwall + ( 9 3 0 536870912 0 ) +( +( ( 95.999992 -96.000008 496 0 0.375000 ) ( 95.999992 -96.000008 448 0 0.187500 ) ( 95.999992 -96.000008 400 0 0 ) ) +( ( 96 -160 496 0.125000 0.375000 ) ( 96 -160 448 0.125000 0.187500 ) ( 96 -160 400 0.125000 0 ) ) +( ( 160 -159.999969 496 0.250000 0.375000 ) ( 160 -159.999969 448 0.250000 0.187500 ) ( 160 -159.999969 400 0.250000 0 ) ) +( ( 224 -160 496 0.375000 0.375000 ) ( 224 -160 448 0.375000 0.187500 ) ( 224 -160 400 0.375000 0 ) ) +( ( 223.999969 -96.000008 496 0.500000 0.375000 ) ( 223.999969 -96.000008 448 0.500000 0.187500 ) ( 223.999969 -96.000008 400 0.500000 0 ) ) +( ( 224 -31.999996 496 0.625000 0.375000 ) ( 224 -31.999996 448 0.625000 0.187500 ) ( 224 -31.999996 400 0.625000 0 ) ) +( ( 160 -32 496 0.750000 0.375000 ) ( 160 -32 448 0.750000 0.187500 ) ( 160 -32 400 0.750000 0 ) ) +( ( 96 -31.999996 496 0.875000 0.375000 ) ( 96 -31.999996 448 0.875000 0.187500 ) ( 96 -31.999996 400 0.875000 0 ) ) +( ( 95.999992 -96.000008 496 1 0.375000 ) ( 95.999992 -96.000008 448 1 0.187500 ) ( 95.999992 -96.000008 400 1 0 ) ) +) + } + } +// brush 38 + { + patchDef2 + { + eden/edenmetalwall + ( 9 3 0 536870912 0 subdivisions 90.501022 ) +( +( ( 160 576 288 0 0 ) ( 160 576 496 0 0.812500 ) ( 160 32 496 0 3.437500 ) ) +( ( 128 576 288 0.125000 0 ) ( 128 576 496 0.125000 0.812500 ) ( 128 32 496 0.125000 3.437500 ) ) +( ( 128 544 288 0.250000 0 ) ( 128 544 464 0.250000 0.812500 ) ( 128 32 464 0.250000 3.437500 ) ) +( ( 128 512 288 0.375000 0 ) ( 128 512 432 0.375000 0.812500 ) ( 128 32 432 0.375000 3.437500 ) ) +( ( 160 512 288 0.500000 0 ) ( 160 512 432 0.500000 0.812500 ) ( 160 32 432 0.500000 3.437500 ) ) +( ( 192 512 288 0.625000 0 ) ( 192 512 432 0.625000 0.812500 ) ( 192 32 432 0.625000 3.437500 ) ) +( ( 192 544 288 0.750000 0 ) ( 192 544 464 0.750000 0.812500 ) ( 192 32 464 0.750000 3.437500 ) ) +( ( 192 576 288 0.875000 0 ) ( 192 576 496 0.875000 0.812500 ) ( 192 32 496 0.875000 3.437500 ) ) +( ( 160 576 288 1 0 ) ( 160 576 496 1 0.812500 ) ( 160 32 496 1 3.437500 ) ) +) + } + } +// brush 39 + { + patchDef2 + { + eden/edenmetalwall + ( 9 3 0 536870912 0 subdivisions 91.251312 ) +( +( ( 160 -224 496 0 3.437500 ) ( 160 -768 496 0 0.812500 ) ( 160 -768 288 0 0 ) ) +( ( 128 -224 496 0.125000 3.437500 ) ( 128 -768 496 0.125000 0.812500 ) ( 128 -768 288 0.125000 0 ) ) +( ( 128 -224 464 0.250000 3.437500 ) ( 128 -736 464 0.250000 0.812500 ) ( 128 -736 288 0.250000 0 ) ) +( ( 128 -224 432 0.375000 3.437500 ) ( 128 -704 432 0.375000 0.812500 ) ( 128 -704 288 0.375000 0 ) ) +( ( 160 -224 432 0.500000 3.437500 ) ( 160 -704 432 0.500000 0.812500 ) ( 160 -704 288 0.500000 0 ) ) +( ( 192 -224 432 0.625000 3.437500 ) ( 192 -704 432 0.625000 0.812500 ) ( 192 -704 288 0.625000 0 ) ) +( ( 192 -224 464 0.750000 3.437500 ) ( 192 -736 464 0.750000 0.812500 ) ( 192 -736 288 0.750000 0 ) ) +( ( 192 -224 496 0.875000 3.437500 ) ( 192 -768 496 0.875000 0.812500 ) ( 192 -768 288 0.875000 0 ) ) +( ( 160 -224 496 1 3.437500 ) ( 160 -768 496 1 0.812500 ) ( 160 -768 288 1 0 ) ) +) + } + } +// brush 40 + { + patchDef2 + { + eden/edenmetalwall + ( 9 3 0 536870912 0 subdivisions 90.458153 ) +( +( ( 288 -96 496 0 3.437500 ) ( 832 -96 496 0 0.812500 ) ( 832 -96 288 0 0 ) ) +( ( 288 -128 496 0.125000 3.437500 ) ( 832 -128 496 0.125000 0.812500 ) ( 832 -128 288 0.125000 0 ) ) +( ( 288 -128 464 0.250000 3.437500 ) ( 800 -128 464 0.250000 0.812500 ) ( 800 -128 288 0.250000 0 ) ) +( ( 288 -128 432 0.375000 3.437500 ) ( 768 -128 432 0.375000 0.812500 ) ( 768 -128 288 0.375000 0 ) ) +( ( 288 -96 432 0.500000 3.437500 ) ( 768 -96 432 0.500000 0.812500 ) ( 768 -96 288 0.500000 0 ) ) +( ( 288 -64 432 0.625000 3.437500 ) ( 768 -64 432 0.625000 0.812500 ) ( 768 -64 288 0.625000 0 ) ) +( ( 288 -64 464 0.750000 3.437500 ) ( 800 -64 464 0.750000 0.812500 ) ( 800 -64 288 0.750000 0 ) ) +( ( 288 -64 496 0.875000 3.437500 ) ( 832 -64 496 0.875000 0.812500 ) ( 832 -64 288 0.875000 0 ) ) +( ( 288 -96 496 1 3.437500 ) ( 832 -96 496 1 0.812500 ) ( 832 -96 288 1 0 ) ) +) + } + } +// brush 41 + { + patchDef2 + { + eden/edenmetalwall + ( 9 3 0 536870912 0 subdivisions 91.251312 ) +( +( ( -512 -96 288 0 0 ) ( -512 -96 496 0 0.812500 ) ( 32 -96 496 0 3.437500 ) ) +( ( -512 -128 288 0.125000 0 ) ( -512 -128 496 0.125000 0.812500 ) ( 32 -128 496 0.125000 3.437500 ) ) +( ( -480 -128 288 0.250000 0 ) ( -480 -128 464 0.250000 0.812500 ) ( 32 -128 464 0.250000 3.437500 ) ) +( ( -448 -128 288 0.375000 0 ) ( -448 -128 432 0.375000 0.812500 ) ( 32 -128 432 0.375000 3.437500 ) ) +( ( -448 -96 288 0.500000 0 ) ( -448 -96 432 0.500000 0.812500 ) ( 32 -96 432 0.500000 3.437500 ) ) +( ( -448 -64 288 0.625000 0 ) ( -448 -64 432 0.625000 0.812500 ) ( 32 -64 432 0.625000 3.437500 ) ) +( ( -480 -64 288 0.750000 0 ) ( -480 -64 464 0.750000 0.812500 ) ( 32 -64 464 0.750000 3.437500 ) ) +( ( -512 -64 288 0.875000 0 ) ( -512 -64 496 0.875000 0.812500 ) ( 32 -64 496 0.875000 3.437500 ) ) +( ( -512 -96 288 1 0 ) ( -512 -96 496 1 0.812500 ) ( 32 -96 496 1 3.437500 ) ) +) + } + } +// brush 42 +{ +( 8 -576 -128 ) ( -8 -576 -128 ) ( -8 -584 -128 ) eden/genmetal 24 0 0.00 1 1 0 0 0 +( -8 -584 8 ) ( -8 -576 8 ) ( 8 -576 8 ) eden/genmetal 24 0 0.00 1 1 0 0 0 +( -8 -584 8 ) ( 8 -584 8 ) ( 8 -584 -128 ) eden/genmetal 24 0 0.00 1 1 0 0 0 +( 8 -584 8 ) ( 8 -576 8 ) ( 8 -576 -128 ) eden/genmetal 24 0 0.00 1 1 0 0 0 +( 8 -576 8 ) ( -8 -576 8 ) ( -8 -576 -128 ) eden/genmetal 24 0 0.00 1 1 0 0 0 +( -8 -576 8 ) ( -8 -584 8 ) ( -8 -584 -128 ) eden/genmetal 24 0 0.00 1 1 0 0 0 +} +// brush 43 +{ +( 0 -352 8 ) ( 0 -776 8 ) ( 0 -776 -128 ) eden/genmetal 32 0 0.00 1 1 0 0 0 +( 8 -344 8 ) ( -120 -344 8 ) ( -120 -344 -128 ) eden/genmetal 32 0 0.00 1 1 0 0 0 +( 8 -768 8 ) ( 8 -344 8 ) ( 8 -344 -128 ) eden/genmetal 32 0 0.00 1 1 0 0 0 +( 8 -344 -128 ) ( -120 -344 -128 ) ( -120 -768 -128 ) eden/genmetal 32 0 0.00 1 1 0 0 0 +( -120 -576 8 ) ( -120 -344 -112 ) ( 8 -460 -52 ) eden/genmetal 32 0 0.00 1 1 0 0 0 +( 8 -576 -128 ) ( 0 -576 -128 ) ( 4 -576 8 ) eden/genmetal 32 0 0.00 1 1 0 0 0 +} +// brush 44 +{ +( 0 328 0 ) ( -8 328 0 ) ( -8 224 0 ) eden/genmetal 24 0 0.00 1 1 0 0 0 +( -8 224 8 ) ( -8 328 8 ) ( 0 328 8 ) eden/genmetal 24 0 0.00 1 1 0 0 0 +( -16 -576 8 ) ( -8 -576 8 ) ( -8 -576 -128 ) eden/genmetal 24 0 0.00 1 1 0 0 0 +( 0 224 8 ) ( 0 328 8 ) ( 0 328 -128 ) eden/genmetal 24 0 0.00 1 1 0 0 0 +( 0 328 8 ) ( -8 328 8 ) ( -8 328 -128 ) eden/genmetal 24 0 0.00 1 1 0 0 0 +( -8 120 8 ) ( -8 16 8 ) ( -8 16 -128 ) eden/genmetal 24 0 0.00 1 1 0 0 0 +} +// brush 45 +{ +( 8 0 -120 ) ( 0 0 -120 ) ( 0 320 8 ) eden/genmetal 24 0 0.00 1 1 0 0 0 +( 0 0 -128 ) ( 8 0 -128 ) ( 8 512 -128 ) eden/genmetal 24 0 0.00 1 1 0 0 0 +( 8 320 8 ) ( 0 320 8 ) ( 0 512 8 ) eden/genmetal 24 0 0.00 1 1 0 0 0 +( 0 -8 -112 ) ( 0 -8 -128 ) ( 0 512 -128 ) eden/genmetal 32 0 0.00 1 1 0 0 0 +( 8 0 -128 ) ( 0 0 -128 ) ( 0 0 -120 ) eden/genmetal 24 0 0.00 1 1 0 0 0 +( 8 -8 -128 ) ( 8 -8 -112 ) ( 8 312 8 ) eden/genmetal 32 0 0.00 1 1 0 0 0 +( 0 328 -128 ) ( 8 328 -128 ) ( 4 328 8 ) eden/genmetal 32 0 0.00 1 1 0 0 0 +} +// brush 46 +{ +( -544 192 496 ) ( -544 -352 496 ) ( -544 -352 240 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( -512 192 496 ) ( -544 192 496 ) ( -544 192 240 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( -512 -384 496 ) ( -512 160 496 ) ( -512 160 240 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( -544 -384 496 ) ( -512 -384 496 ) ( -512 -384 240 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( -544 -352 496 ) ( -544 192 496 ) ( -512 192 496 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( -512 192 288 ) ( -544 192 288 ) ( -544 -352 288 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +} +// brush 47 +{ +( 832 192 544 ) ( 832 -352 544 ) ( 832 -352 288 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( 864 192 496 ) ( 832 192 496 ) ( 832 192 240 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( 864 -384 496 ) ( 864 160 496 ) ( 864 160 240 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( 832 -384 496 ) ( 864 -384 496 ) ( 864 -384 240 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( 832 -352 496 ) ( 832 192 496 ) ( 864 192 496 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( 864 192 288 ) ( 832 192 288 ) ( 832 -352 288 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +} +// brush 48 +{ +( 448 -800 288 ) ( 448 -768 288 ) ( -96 -768 288 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( -96 -768 496 ) ( 448 -768 496 ) ( 448 -800 496 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( -128 -768 544 ) ( -128 -800 544 ) ( -128 -800 288 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( -128 -800 496 ) ( 416 -800 496 ) ( 416 -800 240 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( 448 -800 544 ) ( 448 -768 544 ) ( 448 -768 288 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( 448 -768 496 ) ( -96 -768 496 ) ( -96 -768 240 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +} +// brush 49 +{ +( 448 576 288 ) ( 448 608 288 ) ( -96 608 288 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( -96 608 496 ) ( 448 608 496 ) ( 448 576 496 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( -128 608 544 ) ( -128 576 544 ) ( -128 576 288 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( -128 576 496 ) ( 416 576 496 ) ( 416 576 240 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( 448 576 544 ) ( 448 608 544 ) ( 448 608 288 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( 448 608 496 ) ( -96 608 496 ) ( -96 608 240 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +} +// brush 50 +{ +( 448 -768 544 ) ( 448 -800 544 ) ( 448 -800 288 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( 832 -384 240 ) ( 832 -384 496 ) ( 448 -768 496 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( 864 -384 240 ) ( 864 -384 496 ) ( 832 -384 496 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( 864 -384 496 ) ( 864 -384 240 ) ( 448 -800 240 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( 832 -384 496 ) ( 832 -416 496 ) ( 448 -800 496 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( 832 -416 288 ) ( 832 -384 288 ) ( 448 -768 288 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +} +// brush 51 +{ +( -128 -800 288 ) ( -128 -800 544 ) ( -128 -768 544 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( -128 -768 496 ) ( -512 -384 496 ) ( -512 -384 240 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( -512 -384 496 ) ( -544 -384 496 ) ( -544 -384 240 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( -128 -800 240 ) ( -544 -384 240 ) ( -544 -384 496 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( -128 -800 496 ) ( -512 -416 496 ) ( -512 -384 496 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( -128 -768 288 ) ( -512 -384 288 ) ( -512 -416 288 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +} +// brush 52 +{ +( -512 224 288 ) ( -512 192 288 ) ( -128 576 288 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( -512 192 496 ) ( -512 224 496 ) ( -128 608 496 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( -544 192 496 ) ( -544 192 240 ) ( -128 608 240 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( -544 192 240 ) ( -544 192 496 ) ( -512 192 496 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( -512 192 240 ) ( -512 192 496 ) ( -128 576 496 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( -128 576 544 ) ( -128 608 544 ) ( -128 608 288 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +} +// brush 53 +{ +( 448 576 288 ) ( 832 192 288 ) ( 832 224 288 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( 448 608 496 ) ( 832 224 496 ) ( 832 192 496 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( 448 608 240 ) ( 864 192 240 ) ( 864 192 496 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( 832 192 496 ) ( 864 192 496 ) ( 864 192 240 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( 448 576 496 ) ( 832 192 496 ) ( 832 192 240 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( 448 608 288 ) ( 448 608 544 ) ( 448 576 544 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +} +// brush 54 +{ +( -512 192 496 ) ( -496 208 496 ) ( -504 200 512 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( 832 -384 480 ) ( 800 -416 480 ) ( 816 -400 736 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( 832 576 736 ) ( -544 576 736 ) ( -544 576 480 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( 832 -768 736 ) ( 832 640 736 ) ( 832 640 480 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( -544 -768 736 ) ( 832 -768 736 ) ( 832 -768 480 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( -544 -768 512 ) ( -544 640 512 ) ( 832 640 512 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( 832 640 496 ) ( -544 640 496 ) ( -544 -768 496 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( 448 576 480 ) ( 480 544 480 ) ( 464 560 736 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( -512 352 480 ) ( -512 432 480 ) ( -512 392 512 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( -128 -768 496 ) ( -144 -752 496 ) ( -136 -760 512 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +} +// brush 55 +{ +( 624 -384.000244 256 ) ( 600 192.000046 256 ) ( 576 -384.000244 256 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( -448 -352 400 ) ( -448 -352 384 ) ( -512 -384 384 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( -448 -352 384 ) ( -448 -352 400 ) ( -448 160 400 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( -448 160 384 ) ( -448 160 400 ) ( -512 192 400 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( -512 192 384 ) ( -512 -384 384 ) ( -512 -384 352 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( 544 -384.000244 288 ) ( 576 192.000046 288 ) ( 608 -384.000244 288 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +} +// brush 56 +{ +( 624 -767.999939 256 ) ( 600 -351.999878 256 ) ( 576 -767.999939 256 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( -128 -768 400 ) ( -128 -768 384 ) ( -512 -384.000427 384 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( -448 -352 384 ) ( -448 -352 400 ) ( -512 -384 400 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( -448 -352 400 ) ( -448 -352 384 ) ( -96 -704 384 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( -96 -704 224 ) ( -96 -704 208 ) ( -128 -768 208 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( 544 -767.999939 288 ) ( 576 -351.999878 288 ) ( 608 -767.999939 288 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +} +// brush 57 +{ +( -128 -768 352 ) ( -128 -768 384 ) ( 448 -768 384 ) eden/genmetal 32 0 0.00 1 1 0 0 0 +( 416 -704 96 ) ( 416 -704 80 ) ( 448 -768 80 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( -96 -704 400 ) ( -96 -704 384 ) ( 416 -704 384 ) eden/genmetal 32 0 0.00 1 1 0 0 0 +( -96 -704 208 ) ( -96 -704 224 ) ( -128 -768 224 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( -128 -768 256 ) ( 448 -768 256 ) ( 448 -704 256 ) eden/genmetal 0 -64 90.00 1 1 0 0 0 +( 544 -768 288 ) ( 576 -704 288 ) ( 608 -768 288 ) eden/genmetal 0 -64 90.00 1 1 0 0 0 +} +// brush 58 +{ +( 768 -320 256 ) ( 384 -704 256 ) ( 448 -768 256 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( 416 -704 80 ) ( 416 -704 96 ) ( 448 -768 96 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( 416 -704 96 ) ( 416 -704 80 ) ( 768 -352 80 ) eden/genmetal -32 0 0.00 1 1 0 0 0 +( 768 -352 224 ) ( 768 -352 208 ) ( 832 -384 208 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( 832 -384 384 ) ( 448 -768 384 ) ( 448 -768 400 ) eden/genmetal -32 0 0.00 1 1 0 0 0 +( 544 -768.000061 288 ) ( 576 -352 288 ) ( 608 -768.000061 288 ) eden/genmetal -32 0 0.00 1 1 0 0 0 +} +// brush 59 +{ +( 832 -384 352 ) ( 832 -384 384 ) ( 832 192 384 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( 768 160 96 ) ( 768 160 80 ) ( 832 192 80 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( 768 -352 272 ) ( 768 -352 256 ) ( 768 160 256 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( 768 -352 208 ) ( 768 -352 224 ) ( 832 -384 224 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( 832 -384 256 ) ( 832 192 256 ) ( 768 192 256 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( 544 -384 288 ) ( 576 192.000504 288 ) ( 608 -384 288 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +} +// brush 60 +{ +( 448 576 400 ) ( 448 576 384 ) ( 832 192 384 ) eden/genmetal -64 0 0.00 1 1 0 0 0 +( 768 160 80 ) ( 768 160 96 ) ( 832 192 96 ) eden/genmetal -32 0 0.00 1 1 0 0 0 +( 768 160 272 ) ( 768 160 256 ) ( 416 512 256 ) eden/genmetal -64 0 0.00 1 1 0 0 0 +( 416 512 96 ) ( 416 512 80 ) ( 448 576 80 ) eden/genmetal -32 0 0.00 1 1 0 0 0 +( 448 576 256 ) ( 384 512 256 ) ( 768 128 256 ) eden/genmetal 0 32 0.00 1 1 0 0 0 +( 544 159.999893 288 ) ( 576 576 288 ) ( 608 159.999893 288 ) eden/genmetal 0 32 0.00 1 1 0 0 0 +} +// brush 61 +{ +( 448 576 208 ) ( -128 576 208 ) ( -128 576 176 ) eden/genmetal 32 0 0.00 1 1 0 0 0 +( 416 512 80 ) ( 416 512 96 ) ( 448 576 96 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( 416 512 400 ) ( 416 512 384 ) ( -96 512 384 ) eden/genmetal 32 0 0.00 1 1 0 0 0 +( -96 512 224 ) ( -96 512 208 ) ( -128 576 208 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( 448 512 256 ) ( 448 576 256 ) ( -128 576 256 ) eden/genmetal 0 -64 90.00 1 1 0 0 0 +( 544 512 288 ) ( 576 576 288 ) ( 608 512 288 ) eden/genmetal 0 -64 90.00 1 1 0 0 0 +} +// brush 62 +{ +( 624 159.999817 256 ) ( 600 576 256 ) ( 576 159.999817 256 ) eden/genmetal 0 32 0.00 1 1 0 0 0 +( -96 512 208 ) ( -96 512 224 ) ( -128 576 224 ) eden/genmetal -32 0 0.00 1 1 0 0 0 +( -448 160 384 ) ( -448 160 400 ) ( -96 512 400 ) eden/genmetal -64 0 0.00 1 1 0 0 0 +( -448 160 400 ) ( -448 160 384 ) ( -512 192 384 ) eden/genmetal -32 0 0.00 1 1 0 0 0 +( -512 192 384 ) ( -128 576 384 ) ( -128 576 400 ) eden/genmetal -64 0 0.00 1 1 0 0 0 +( 544 159.999817 288 ) ( 576 576 288 ) ( 608 159.999817 288 ) eden/genmetal -64 0 0.00 1 1 0 0 0 +} +// brush 63 +{ +( 320 192 0 ) ( 320 64 0 ) ( 320 64 -128 ) eden/edentable 64 0 0.00 -1 1 0 0 0 +( 448 192 0 ) ( 320 192 0 ) ( 320 192 -128 ) eden/edentable 64 0 0.00 -1 1 0 0 0 +( 448 64 0 ) ( 448 192 0 ) ( 448 192 -128 ) eden/edentable 64 0 0.00 -1 1 0 0 0 +( 320 64 0 ) ( 448 64 0 ) ( 448 64 -128 ) eden/edentable 64 0 0.00 -1 1 0 0 0 +( 320 64 0 ) ( 320 192 0 ) ( 448 192 0 ) eden/edentable 64 64 0.00 -1 1 0 0 0 +( 448 192 -128 ) ( 320 192 -128 ) ( 320 64 -128 ) eden/edentable 64 64 0.00 -1 1 0 0 0 +} +// brush 64 +{ +( 136 -8 -128 ) ( 136 -8 -112 ) ( 136 312 8 ) eden/genmetal 32 0 0.00 1 1 0 0 0 +( 136 0 -128 ) ( 128 0 -128 ) ( 128 0 -120 ) eden/genmetal 24 0 0.00 1 1 0 0 0 +( 128 -8 -112 ) ( 128 -8 -128 ) ( 128 512 -128 ) eden/genmetal 32 0 0.00 1 1 0 0 0 +( 256 512 8 ) ( 128 512 8 ) ( 128 512 -128 ) eden/genmetal 24 0 0.00 1 1 0 0 0 +( 136 320 8 ) ( 128 320 8 ) ( 128 512 8 ) eden/genmetal 24 0 0.00 1 1 0 0 0 +( 128 0 -128 ) ( 136 0 -128 ) ( 136 512 -128 ) eden/genmetal 24 0 0.00 1 1 0 0 0 +( 136 0 -120 ) ( 128 0 -120 ) ( 128 320 8 ) eden/genmetal 24 0 0.00 1 1 0 0 0 +} +// brush 65 +{ +( 128 -352 8 ) ( 128 -776 8 ) ( 128 -776 -128 ) eden/genmetal 32 0 0.00 1 1 0 0 0 +( 136 -344 8 ) ( 8 -344 8 ) ( 8 -344 -128 ) eden/genmetal 32 0 0.00 1 1 0 0 0 +( 136 -768 8 ) ( 136 -344 8 ) ( 136 -344 -128 ) eden/genmetal 32 0 0.00 1 1 0 0 0 +( 8 -768 8 ) ( 136 -768 8 ) ( 136 -768 -128 ) eden/genmetal 32 0 0.00 1 1 0 0 0 +( 8 -768 8 ) ( 8 -344 8 ) ( 136 -344 8 ) eden/genmetal 32 0 0.00 1 1 0 0 0 +( 136 -344 -128 ) ( 8 -344 -128 ) ( 8 -768 -128 ) eden/genmetal 32 0 0.00 1 1 0 0 0 +( 8 -576 8 ) ( 8 -344 -112 ) ( 136 -460 -52 ) eden/genmetal 32 0 0.00 1 1 0 0 0 +} +// brush 66 +{ +( 0 -352 -96 ) ( 0 -384 -96 ) ( 0 -384 -224 ) eden/FL_edenhouse3 -64 -96 0.00 1 1 0 0 0 +( 128 -352 -96 ) ( 0 -352 -96 ) ( 0 -352 -224 ) eden/FL_edenhouse2 0 -96 0.00 1 1 0 0 0 +( 128 -384 -96 ) ( 128 -352 -96 ) ( 128 -352 -224 ) eden/FL_edenhouse2 0 0 0.00 1 1 0 0 0 +( 0 -384 -96 ) ( 128 -384 -96 ) ( 128 -384 -224 ) eden/FL_edenhouse3 0 -96 0.00 1 1 0 0 0 +( 0 -384 -112 ) ( 0 -352 -112 ) ( 128 -352 -112 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 0 -304 -128 ) ( 0 -384 -128 ) ( 128 -344 -128 ) eden/FL_edenhouse3 0 64 0.00 1 1 0 0 0 +} +// brush 67 +{ +( 0 -416 -96 ) ( 0 -384 -96 ) ( 128 -384 -96 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 0 -416 -48 ) ( 128 -416 -48 ) ( 128 -416 -176 ) eden/FL_edenhouse3 0 -48 0.00 1 1 0 0 0 +( 128 -416 -48 ) ( 128 -384 -48 ) ( 128 -384 -176 ) eden/FL_edenhouse2 0 0 0.00 1 1 0 0 0 +( 128 -384 -48 ) ( 0 -384 -48 ) ( 0 -384 -176 ) eden/FL_edenhouse2 0 -48 0.00 1 1 0 0 0 +( 0 -384 -48 ) ( 0 -416 -48 ) ( 0 -416 -176 ) eden/FL_edenhouse3 -32 -48 0.00 1 1 0 0 0 +( 112 -416 -128 ) ( 80 -384 -128 ) ( 48 -416 -128 ) eden/FL_edenhouse3 -32 -48 0.00 1 1 0 0 0 +} +// brush 68 +{ +( 112 -448 -128 ) ( 80 -416 -128 ) ( 48 -448 -128 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 0 -448 -80 ) ( 0 -416 -80 ) ( 128 -416 -80 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 0 -448 -48 ) ( 128 -448 -48 ) ( 128 -448 -176 ) eden/FL_edenhouse3 0 -48 0.00 1 1 0 0 0 +( 128 -448 -48 ) ( 128 -416 -48 ) ( 128 -416 -176 ) eden/FL_edenhouse2 0 0 0.00 1 1 0 0 0 +( 128 -416 -48 ) ( 0 -416 -48 ) ( 0 -416 -176 ) eden/FL_edenhouse2 0 -48 0.00 1 1 0 0 0 +( 0 -416 -48 ) ( 0 -448 -48 ) ( 0 -448 -176 ) eden/FL_edenhouse3 0 -48 0.00 1 1 0 0 0 +} +// brush 69 +{ +( 0 -480 -64 ) ( 0 -448 -64 ) ( 128 -448 -64 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 0 -480 -48 ) ( 128 -480 -48 ) ( 128 -480 -176 ) eden/FL_edenhouse3 0 -48 0.00 1 1 0 0 0 +( 128 -480 -48 ) ( 128 -448 -48 ) ( 128 -448 -176 ) eden/FL_edenhouse2 0 0 0.00 1 1 0 0 0 +( 128 -448 -48 ) ( 0 -448 -48 ) ( 0 -448 -176 ) eden/FL_edenhouse2 0 -48 0.00 1 1 0 0 0 +( 0 -448 -48 ) ( 0 -480 -48 ) ( 0 -480 -176 ) eden/FL_edenhouse3 -96 -48 0.00 1 1 0 0 0 +( 112 -480 -128 ) ( 80 -448 -128 ) ( 48 -480 -128 ) eden/FL_edenhouse3 -96 -48 0.00 1 1 0 0 0 +} +// brush 70 +{ +( 0 -480 0 ) ( 0 -512 0 ) ( 0 -512 -128 ) eden/FL_edenhouse3 -64 0 0.00 1 1 0 0 0 +( 128 -480 0 ) ( 0 -480 0 ) ( 0 -480 -128 ) eden/FL_edenhouse2 0 0 0.00 1 1 0 0 0 +( 128 -512 0 ) ( 128 -480 0 ) ( 128 -480 -128 ) eden/FL_edenhouse2 -64 0 0.00 1 1 0 0 0 +( 0 -512 0 ) ( 128 -512 0 ) ( 128 -512 -128 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 0 -512 -48 ) ( 0 -480 -48 ) ( 128 -480 -48 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 128 -480 -128 ) ( 0 -480 -128 ) ( 0 -512 -128 ) eden/FL_edenhouse3 0 64 0.00 1 1 0 0 0 +} +// brush 71 +{ +( 128 -512 -128 ) ( 0 -512 -128 ) ( 0 -544 -128 ) eden/FL_edenhouse3 0 32 0.00 1 1 0 0 0 +( 0 -544 -32 ) ( 0 -512 -32 ) ( 128 -512 -32 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 0 -544 0 ) ( 128 -544 0 ) ( 128 -544 -128 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 128 -544 0 ) ( 128 -512 0 ) ( 128 -512 -128 ) eden/FL_edenhouse2 -32 0 0.00 1 1 0 0 0 +( 128 -512 0 ) ( 0 -512 0 ) ( 0 -512 -128 ) eden/FL_edenhouse2 0 0 0.00 1 1 0 0 0 +( 0 -512 0 ) ( 0 -544 0 ) ( 0 -544 -128 ) eden/FL_edenhouse3 -32 0 0.00 1 1 0 0 0 +} +// brush 72 +{ +( 0 -544 0 ) ( 0 -576 0 ) ( 0 -576 -128 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 128 -544 0 ) ( 0 -544 0 ) ( 0 -544 -128 ) eden/FL_edenhouse2 0 0 0.00 1 1 0 0 0 +( 128 -576 0 ) ( 128 -544 0 ) ( 128 -544 -128 ) eden/FL_edenhouse2 0 0 0.00 1 1 0 0 0 +( 0 -576 0 ) ( 128 -576 0 ) ( 128 -576 -128 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 0 -576 -16 ) ( 0 -544 -16 ) ( 128 -544 -16 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 128 -544 -128 ) ( 0 -544 -128 ) ( 0 -576 -128 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +} +// brush 73 +{ +( 128 -512 -128 ) ( 0 -512 -128 ) ( 0 -704 -128 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 0 -704 0 ) ( 0 -512 0 ) ( 128 -512 0 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 0 -704 0 ) ( 128 -704 0 ) ( 128 -704 -128 ) eden/FL_edenhouse2 0 0 0.00 1 1 0 0 0 +( 128 -704 0 ) ( 128 -512 0 ) ( 128 -512 -128 ) eden/FL_edenhouse2 0 0 0.00 1 1 0 0 0 +( 144 -576 0 ) ( 16 -576 0 ) ( 16 -576 -128 ) eden/FL_edenhouse2 0 0 0.00 1 1 0 0 0 +( 0 -512 0 ) ( 0 -704 0 ) ( 0 -704 -128 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +} +// brush 74 +{ +( 144 0 -128 ) ( 96 320 -128 ) ( 48 0 -128 ) eden/FL_edenhouse2 0 0 0.00 1 1 0 0 0 +( 128 0 -128 ) ( 0 0 -128 ) ( 0 320 0 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 128 0 -256 ) ( 128 0 -128 ) ( 128 320 0 ) eden/FL_edenhouse2 0 0 0.00 1 1 0 0 0 +( 128 320 0 ) ( 0 320 0 ) ( 0 320 -128 ) eden/FL_edenhouse2 0 0 0.00 1 1 0 0 0 +( 0 0 -128 ) ( 0 0 -256 ) ( 0 320 -128 ) eden/FL_edenhouse2 0 0 0.00 1 1 0 0 0 +} +// brush 75 +{ +( 0 512 0 ) ( 0 320 0 ) ( 0 320 -128 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 128 512 0 ) ( 0 512 0 ) ( 0 512 -128 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 128 320 0 ) ( 128 512 0 ) ( 128 512 -128 ) eden/FL_edenhouse2 0 0 0.00 1 1 0 0 0 +( 0 320 0 ) ( 128 320 0 ) ( 128 320 -128 ) eden/FL_edenhouse2 0 0 0.00 1 1 0 0 0 +( 0 320 0 ) ( 0 512 0 ) ( 128 512 0 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 128 512 -128 ) ( 0 512 -128 ) ( 0 320 -128 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +} +// brush 76 +{ +( 832 -384 -160 ) ( 800 -416 -160 ) ( 816 -400 96 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 832 576 96 ) ( -544 576 96 ) ( -544 576 -160 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 832 -768 96 ) ( 832 640 96 ) ( 832 640 -160 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( -544 -768 96 ) ( 832 -768 96 ) ( 832 -768 -160 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( -544 -768 -128 ) ( -544 640 -128 ) ( 832 640 -128 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 832 640 -160 ) ( -544 640 -160 ) ( -544 -768 -160 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 448 576 -160 ) ( 480 544 -160 ) ( 464 560 96 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 0 336 -160 ) ( 0 416 -160 ) ( 0 376 -128 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +} +// brush 77 +{ +( -512 192 -32 ) ( -480 224 -32 ) ( -496 208 224 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( -512 640 224 ) ( -512 -768 224 ) ( -512 -768 -32 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 832 576 224 ) ( -544 576 224 ) ( -544 576 -32 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( -544 -768 224 ) ( 832 -768 224 ) ( 832 -768 -32 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( -544 -768 0 ) ( -544 640 0 ) ( 832 640 0 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 832 640 -128 ) ( -544 640 -128 ) ( -544 -768 -128 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( -128 -768 -32 ) ( -160 -736 -32 ) ( -144 -752 224 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 0 416 -32 ) ( 0 336 -32 ) ( 0 376 0 ) eden/FL_edenhouse2 0 0 0.00 1 1 0 0 0 +} +// brush 78 +{ +( -512 192 0 ) ( -128 576 0 ) ( -128 576 16 ) eden/genmetal -64 0 0.00 1 1 0 0 0 +( -448 160 16 ) ( -448 160 0 ) ( -512 192 0 ) eden/genmetal -32 0 0.00 1 1 0 0 0 +( -448 160 0 ) ( -448 160 16 ) ( -96 512 16 ) eden/genmetal -64 0 0.00 1 1 0 0 0 +( -96 512 0 ) ( -96 512 16 ) ( -128 576 16 ) eden/genmetal -32 0 0.00 1 1 0 0 0 +( -448 128 0 ) ( -64 512 0 ) ( -128 576 0 ) eden/genmetal 0 32 0.00 1 1 0 0 0 +( -432 159.999817 8 ) ( -420 576 8 ) ( -408 159.999817 8 ) eden/genmetal 0 32 0.00 1 1 0 0 0 +} +// brush 79 +{ +( 448 512 -128 ) ( 448 576 -128 ) ( -128 576 -128 ) eden/genmetal 0 -64 90.00 1 1 0 0 0 +( -128 576 8 ) ( 448 576 8 ) ( 448 512 8 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( -96 512 16 ) ( -96 512 0 ) ( -128 576 0 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( 416 512 16 ) ( 416 512 0 ) ( -96 512 0 ) eden/genmetal 32 0 0.00 1 1 0 0 0 +( 416 512 -128 ) ( 416 512 -112 ) ( 448 576 -112 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( 448 576 0 ) ( -128 576 0 ) ( -128 576 -32 ) eden/genmetal 32 0 0.00 1 1 0 0 0 +} +// brush 80 +{ +( -432 159.999832 8 ) ( -420 576.000183 8 ) ( -408 159.999832 8 ) eden/genmetal 0 32 0.00 1 1 0 0 0 +( 448 576 -128 ) ( 384 512 -128 ) ( 768 128 -128 ) eden/genmetal 0 32 0.00 1 1 0 0 0 +( 416 512 -112 ) ( 416 512 -128 ) ( 448 576 -128 ) eden/genmetal -32 0 0.00 1 1 0 0 0 +( 768 160 -112 ) ( 768 160 -128 ) ( 416 512 -128 ) eden/genmetal -64 0 0.00 1 1 0 0 0 +( 768 160 -128 ) ( 768 160 -112 ) ( 832 192 -112 ) eden/genmetal -32 0 0.00 1 1 0 0 0 +( 448 576 16 ) ( 448 576 0 ) ( 832 192 0 ) eden/genmetal -64 0 0.00 1 1 0 0 0 +} +// brush 81 +{ +( 832 -384 -128 ) ( 832 192 -128 ) ( 768 192 -128 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( 768 192 8 ) ( 832 192 8 ) ( 832 -384 8 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( 768 -352 0 ) ( 768 -352 16 ) ( 832 -384 16 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( 768 -352 -112 ) ( 768 -352 -128 ) ( 768 160 -128 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( 768 160 -112 ) ( 768 160 -128 ) ( 832 192 -128 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( 832 -384 -32 ) ( 832 -384 0 ) ( 832 192 0 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +} +// brush 82 +{ +( -432 -768.000244 8 ) ( -420 -351.999817 8 ) ( -408 -768.000244 8 ) eden/genmetal -32 0 0.00 1 1 0 0 0 +( 832 -384 0 ) ( 448 -768 0 ) ( 448 -768 16 ) eden/genmetal -32 0 0.00 1 1 0 0 0 +( 768 -352 16 ) ( 768 -352 0 ) ( 832 -384 0 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( 416 -704 -112 ) ( 416 -704 -128 ) ( 768 -352 -128 ) eden/genmetal -32 0 0.00 1 1 0 0 0 +( 416 -704 -128 ) ( 416 -704 -112 ) ( 448 -768 -112 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( 768 -320 -128 ) ( 384 -704 -128 ) ( 448 -768 -128 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +} +// brush 83 +{ +( -128 -768 -128 ) ( 448 -768 -128 ) ( 448 -704 -128 ) eden/genmetal 0 -64 90.00 1 1 0 0 0 +( 448 -704 8 ) ( 448 -768 8 ) ( -128 -768 8 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( -96 -704 0 ) ( -96 -704 16 ) ( -128 -768 16 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( -96 -704 16 ) ( -96 -704 0 ) ( 416 -704 0 ) eden/genmetal 32 0 0.00 1 1 0 0 0 +( 416 -704 -112 ) ( 416 -704 -128 ) ( 448 -768 -128 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( -128 -768 -32 ) ( -128 -768 0 ) ( 448 -768 0 ) eden/genmetal 32 0 0.00 1 1 0 0 0 +} +// brush 84 +{ +( -128 -768 0 ) ( -64 -704 0 ) ( -448 -320.000427 0 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( -96 -704 16 ) ( -96 -704 0 ) ( -128 -768 0 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( -448 -352 16 ) ( -448 -352 0 ) ( -96 -704 0 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( -448 -352 0 ) ( -448 -352 16 ) ( -512 -384 16 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( -128 -768 16 ) ( -128 -768 0 ) ( -512 -384.000427 0 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( -432 -767.999939 8 ) ( -420 -351.999878 8 ) ( -408 -767.999939 8 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +} +// brush 85 +{ +( -512 192 0 ) ( -512 -384 0 ) ( -512 -384 -32 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( -448 160 0 ) ( -448 160 16 ) ( -512 192 16 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( -448 -352 0 ) ( -448 -352 16 ) ( -448 160 16 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( -448 -352 16 ) ( -448 -352 0 ) ( -512 -384 0 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( -512 -384 8 ) ( -512 192 8 ) ( -448 192 8 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( -448 192 0 ) ( -512 192 0 ) ( -512 -384 0 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +} +// brush 86 +{ +( 448 576 0 ) ( 832 192 0 ) ( 832 224 0 ) eden/WL_edentown2 0 0 0.00 1 1 0 0 0 +( 448 608 256 ) ( 832 224 256 ) ( 832 192 256 ) eden/WL_edentown2 0 0 0.00 1 1 0 0 0 +( 448 608 0 ) ( 864 192 0 ) ( 864 192 256 ) eden/WL_edentown2 0 0 0.00 1 1 0 0 0 +( 832 192 256 ) ( 864 192 256 ) ( 864 192 0 ) eden/WL_edentown2 0 0 0.00 1 1 0 0 0 +( 448 576 256 ) ( 832 192 256 ) ( 832 192 0 ) eden/WL_edentown2 0 0 0.00 1 1 0 0 0 +( 448 608 0 ) ( 448 608 256 ) ( 448 576 256 ) eden/WL_edentown2 0 0 0.00 1 1 0 0 0 +} +// brush 87 +{ +( -512 224 0 ) ( -512 192 0 ) ( -128 576 0 ) eden/WL_edentown2 -64 0 0.00 1 1 0 0 0 +( -512 192 256 ) ( -512 224 256 ) ( -128 608 256 ) eden/WL_edentown2 -64 0 0.00 1 1 0 0 0 +( -544 192 256 ) ( -544 192 0 ) ( -128 608 0 ) eden/WL_edentown2 0 0 0.00 1 1 0 0 0 +( -544 192 0 ) ( -544 192 256 ) ( -512 192 256 ) eden/WL_edentown2 -64 0 0.00 1 1 0 0 0 +( -512 192 0 ) ( -512 192 256 ) ( -128 576 256 ) eden/WL_edentown2 0 0 0.00 1 1 0 0 0 +( -128 576 256 ) ( -128 608 256 ) ( -128 608 0 ) eden/WL_edentown2 0 0 0.00 1 1 0 0 0 +} +// brush 88 +{ +( -128 -800 0 ) ( -128 -800 256 ) ( -128 -768 256 ) eden/WL_edentown2 0 0 0.00 1 1 0 0 0 +( -128 -768 256 ) ( -512 -384 256 ) ( -512 -384 0 ) eden/WL_edentown2 0 0 0.00 1 1 0 0 0 +( -512 -384 256 ) ( -544 -384 256 ) ( -544 -384 0 ) eden/WL_edentown2 -64 0 0.00 1 1 0 0 0 +( -128 -800 0 ) ( -544 -384 0 ) ( -544 -384 256 ) eden/WL_edentown2 0 0 0.00 1 1 0 0 0 +( -128 -800 256 ) ( -512 -416 256 ) ( -512 -384 256 ) eden/WL_edentown2 -64 0 0.00 1 1 0 0 0 +( -128 -768 0 ) ( -512 -384 0 ) ( -512 -416 0 ) eden/WL_edentown2 -64 0 0.00 1 1 0 0 0 +} +// brush 89 +{ +( 448 -768 256 ) ( 448 -800 256 ) ( 448 -800 0 ) eden/WL_edentown2 0 0 0.00 1 1 0 0 0 +( 832 -384 0 ) ( 832 -384 256 ) ( 448 -768 256 ) eden/WL_edentown2 0 0 0.00 1 1 0 0 0 +( 864 -384 0 ) ( 864 -384 256 ) ( 832 -384 256 ) eden/WL_edentown2 0 0 0.00 1 1 0 0 0 +( 864 -384 256 ) ( 864 -384 0 ) ( 448 -800 0 ) eden/WL_edentown2 0 0 0.00 1 1 0 0 0 +( 832 -384 256 ) ( 832 -416 256 ) ( 448 -800 256 ) eden/WL_edentown2 0 0 0.00 1 1 0 0 0 +( 832 -416 0 ) ( 832 -384 0 ) ( 448 -768 0 ) eden/WL_edentown2 0 0 0.00 1 1 0 0 0 +} +// brush 90 +{ +( 448 576 0 ) ( 448 608 0 ) ( -96 608 0 ) eden/WL_edentown2 0 0 0.00 1 1 0 0 0 +( -96 608 256 ) ( 448 608 256 ) ( 448 576 256 ) eden/WL_edentown2 0 0 0.00 1 1 0 0 0 +( -128 608 256 ) ( -128 576 256 ) ( -128 576 0 ) eden/WL_edentown2 -64 0 0.00 1 1 0 0 0 +( -128 576 256 ) ( 416 576 256 ) ( 416 576 0 ) eden/WL_edentown2 64 0 0.00 1 1 0 0 0 +( 448 576 256 ) ( 448 608 256 ) ( 448 608 0 ) eden/WL_edentown2 -64 0 0.00 1 1 0 0 0 +( 448 608 256 ) ( -96 608 256 ) ( -96 608 0 ) eden/WL_edentown2 64 0 -180.00 1 -1 0 0 0 +} +// brush 91 +{ +( 448 -800 0 ) ( 448 -768 0 ) ( -96 -768 0 ) eden/WL_edentown2 32 0 0.00 1 1 0 0 0 +( -96 -768 256 ) ( 448 -768 256 ) ( 448 -800 256 ) eden/WL_edentown2 32 0 0.00 1 1 0 0 0 +( -128 -768 256 ) ( -128 -800 256 ) ( -128 -800 0 ) eden/WL_edentown2 -32 0 0.00 1 1 0 0 0 +( -128 -800 256 ) ( 416 -800 256 ) ( 416 -800 0 ) eden/WL_edentown2 64 0 0.00 1 1 0 0 0 +( 448 -800 256 ) ( 448 -768 256 ) ( 448 -768 0 ) eden/WL_edentown2 -32 0 0.00 1 1 0 0 0 +( 448 -768 256 ) ( -96 -768 256 ) ( -96 -768 0 ) eden/WL_edentown2 63 0 -180.00 1 -1 0 0 0 +} +// brush 92 +{ +( 832 192 256 ) ( 832 -352 256 ) ( 832 -352 0 ) eden/WL_edentown2 0 0 0.00 1 1 0 0 0 +( 864 192 256 ) ( 832 192 256 ) ( 832 192 0 ) eden/WL_edentown2 -96 0 0.00 1 1 0 0 0 +( 864 -384 256 ) ( 864 160 256 ) ( 864 160 0 ) eden/WL_edentown2 0 0 0.00 1 1 0 0 0 +( 832 -384 256 ) ( 864 -384 256 ) ( 864 -384 0 ) eden/WL_edentown2 -96 0 0.00 1 1 0 0 0 +( 832 -352 256 ) ( 832 192 256 ) ( 864 192 256 ) eden/WL_edentown2 -96 0 0.00 1 1 0 0 0 +( 864 192 0 ) ( 832 192 0 ) ( 832 -352 0 ) eden/WL_edentown2 -96 0 0.00 1 1 0 0 0 +} +// brush 93 +{ +( -544 192 256 ) ( -544 -352 256 ) ( -544 -352 0 ) eden/WL_edentown2 0 0 0.00 1 1 0 0 0 +( -512 192 256 ) ( -544 192 256 ) ( -544 192 0 ) eden/WL_edentown2 0 0 0.00 1 1 0 0 0 +( -512 -384 256 ) ( -512 160 256 ) ( -512 160 0 ) eden/WL_edentown2 0 0 0.00 1 1 0 0 0 +( -544 -384 256 ) ( -512 -384 256 ) ( -512 -384 0 ) eden/WL_edentown2 0 0 0.00 1 1 0 0 0 +( -544 -352 256 ) ( -544 192 256 ) ( -512 192 256 ) eden/WL_edentown2 0 0 0.00 1 1 0 0 0 +( -512 192 0 ) ( -544 192 0 ) ( -544 -352 0 ) eden/WL_edentown2 0 0 0.00 1 1 0 0 0 +} +} +// entity 1 +{ +"classname" "Characters_EdenMale_EAtest" +"scale" "1.0" +"model" "edenmale_EAexample.tik" +"origin" "-168.00 -160.00 0.00" +} +// entity 2 +{ +"classname" "light" +"_color" "0.710744 0.987603 1.000000" +"origin" "-500 -96 200" +} +// entity 3 +{ +"origin" "184 424 -128" +"classname" "info_pathnode" +"spawnflags" "4" +} +// entity 4 +{ +"origin" "624 -464 -128" +"angle" "135" +"classname" "info_player_start" +} +// entity 5 +{ +"type" "patchCapped" +"classname" "func_group" +// brush 0 + { + patchDef2 + { + eden/edenmetalwall + ( 9 3 0 536870912 0 ) +( +( ( 32 -96 400 0 0 ) ( 32 -96 448 0 0.406250 ) ( 32 -96 496 0 0.812500 ) ) +( ( 16 -240 400 0.500000 0 ) ( 16 -240 448 0.500000 0.406250 ) ( 16 -240 496 0.500000 0.812500 ) ) +( ( 160 -224 400 1 0 ) ( 160 -224 448 1 0.406250 ) ( 160 -224 496 1 0.812500 ) ) +( ( 304 -240 400 1.500000 0 ) ( 304 -240 448 1.500000 0.406250 ) ( 304 -240 496 1.500000 0.812500 ) ) +( ( 288 -96 400 2 0 ) ( 288 -96 448 2 0.406250 ) ( 288 -96 496 2 0.812500 ) ) +( ( 304 48 400 2.500000 0 ) ( 304 48 448 2.500000 0.406250 ) ( 304 48 496 2.500000 0.812500 ) ) +( ( 160 32 400 3 0 ) ( 160 32 448 3 0.406250 ) ( 160 32 496 3 0.812500 ) ) +( ( 16 48 400 3.500000 0 ) ( 16 48 448 3.500000 0.406250 ) ( 16 48 496 3.500000 0.812500 ) ) +( ( 32 -96 400 4 0 ) ( 32 -96 448 4 0.406250 ) ( 32 -96 496 4 0.812500 ) ) +) + } + } +} +// entity 6 +{ +"classname" "info_pathnode" +"origin" "360 424 -128" +"spawnflags" "4" +} +// entity 7 +{ +"classname" "info_pathnode" +"origin" "184 232 -128" +"spawnflags" "4" +} +// entity 8 +{ +"spawnflags" "6" +"origin" "360 232 -128" +"classname" "info_pathnode" +} +// entity 9 +{ +"classname" "info_pathnode" +"origin" "184 72 -128" +"spawnflags" "4" +} +// entity 10 +{ +"origin" "184 -120 -128" +"classname" "info_pathnode" +} +// entity 11 +{ +"classname" "info_pathnode" +"origin" "360 -120 -128" +"spawnflags" "4" +} +// entity 12 +{ +"origin" "184 -280 -128" +"classname" "info_pathnode" +} +// entity 13 +{ +"classname" "info_pathnode" +"origin" "360 -280 -128" +} +// entity 14 +{ +"classname" "info_pathnode" +"origin" "184 -472 -128" +} +// entity 15 +{ +"origin" "360 -472 -128" +"classname" "info_pathnode" +} +// entity 16 +{ +"classname" "info_pathnode" +"origin" "184 -632 -128" +} +// entity 17 +{ +"origin" "360 -632 -128" +"classname" "info_pathnode" +} +// entity 18 +{ +"origin" "536 -120 -128" +"classname" "info_pathnode" +"spawnflags" "4" +} +// entity 19 +{ +"classname" "info_pathnode" +"origin" "536 -312 -128" +} +// entity 20 +{ +"classname" "info_pathnode" +"origin" "536 -472 -128" +} +// entity 21 +{ +"classname" "info_pathnode" +"origin" "696 88 -128" +"spawnflags" "4" +} +// entity 22 +{ +"classname" "info_pathnode" +"origin" "696 -72 -128" +"spawnflags" "4" +} +// entity 23 +{ +"origin" "696 -264 -128" +"classname" "info_pathnode" +} +// entity 24 +{ +"spawnflags" "4" +"classname" "info_pathnode" +"origin" "536 232 -128" +} +// entity 25 +{ +"spawnflags" "4" +"classname" "info_pathnode" +"origin" "536 40 -128" +} +// entity 26 +{ +"classname" "info_pathnode" +"origin" "72 -280 -128" +} +// entity 27 +{ +"origin" "72 -56 -128" +"classname" "info_pathnode" +} +// entity 28 +{ +"origin" "72 -344 -112" +"classname" "info_pathnode" +} +// entity 29 +{ +"classname" "info_pathnode" +"origin" "72 -408 -80" +} +// entity 30 +{ +"origin" "72 -472 -48" +"classname" "info_pathnode" +} +// entity 31 +{ +"classname" "info_pathnode" +"origin" "72 -536 -16" +} +// entity 32 +{ +"origin" "72 -568 0" +"classname" "info_pathnode" +} +// entity 33 +{ +"classname" "info_pathnode" +"origin" "72 -696 0" +} +// entity 34 +{ +"origin" "-56 -664 0" +"classname" "info_pathnode" +} +// entity 35 +{ +"classname" "info_pathnode" +"origin" "72 -24 -128" +} +// entity 36 +{ +"origin" "72 72 -80" +"classname" "info_pathnode" +} +// entity 37 +{ +"classname" "info_pathnode" +"origin" "72 312 0" +} +// entity 38 +{ +"origin" "72 440 0" +"classname" "info_pathnode" +} +// entity 39 +{ +"classname" "info_pathnode" +"origin" "-88 440 0" +} +// entity 40 +{ +"classname" "info_pathnode" +"origin" "-88 -376 0" +} +// entity 41 +{ +"classname" "info_pathnode" +"origin" "-88 -536 0" +} +// entity 42 +{ +"classname" "info_pathnode" +"origin" "-88 328 0" +} +// entity 43 +{ +"classname" "info_pathnode" +"origin" "-88 168 0" +} +// entity 44 +{ +"origin" "-88 -24 0" +"classname" "info_pathnode" +} +// entity 45 +{ +"origin" "-88 -184 0" +"classname" "info_pathnode" +} +// entity 46 +{ +"origin" "-248 -376 0" +"classname" "info_pathnode" +} +// entity 47 +{ +"origin" "-216 -504 0" +"classname" "info_pathnode" +} +// entity 48 +{ +"origin" "-248 264 0" +"classname" "info_pathnode" +} +// entity 49 +{ +"origin" "-248 168 0" +"classname" "info_pathnode" +} +// entity 50 +{ +"classname" "info_pathnode" +"origin" "-248 -24 0" +} +// entity 51 +{ +"classname" "info_pathnode" +"origin" "-248 -184 0" +} +// entity 52 +{ +"classname" "info_pathnode" +"origin" "-408 -312 0" +} +// entity 53 +{ +"classname" "info_pathnode" +"origin" "-408 104 0" +} +// entity 54 +{ +"origin" "-408 -24 0" +"classname" "info_pathnode" +} +// entity 55 +{ +"origin" "-408 -184 0" +"classname" "info_pathnode" +} +// entity 56 +{ +"spawnflags" "6" +"origin" "360 8 -128" +"classname" "info_pathnode" +} +// entity 57 +{ +"classname" "info_pathnode" +"origin" "72 168 -48" +} +// entity 58 +{ +"origin" "72 256 -16" +"classname" "info_pathnode" +} +// entity 59 +{ +"origin" "-500 -96 112" +"_color" "0.710744 0.987603 1.000000" +"classname" "light" +} +// entity 60 +{ +"origin" "820 -96 200" +"_color" "0.710744 0.987603 1.000000" +"classname" "light" +} +// entity 61 +{ +"classname" "light" +"_color" "0.710744 0.987603 1.000000" +"origin" "820 -96 112" +} +// entity 62 +{ +"origin" "160 564 200" +"_color" "0.710744 0.987603 1.000000" +"classname" "light" +} +// entity 63 +{ +"classname" "light" +"_color" "0.710744 0.987603 1.000000" +"origin" "160 564 112" +} +// entity 64 +{ +"classname" "light" +"_color" "0.710744 0.987603 1.000000" +"origin" "160 -756 200" +} +// entity 65 +{ +"origin" "160 -756 112" +"_color" "0.710744 0.987603 1.000000" +"classname" "light" +} +// entity 66 +{ +"origin" "-308 112 424" +"_color" "1.000000 1.000000 1.000000" +"classname" "light" +} +// entity 67 +{ +"classname" "light" +"_color" "1.000000 1.000000 1.000000" +"origin" "-4 352 424" +} +// entity 68 +{ +"origin" "348 352 424" +"_color" "1.000000 1.000000 1.000000" +"classname" "light" +} +// entity 69 +{ +"classname" "light" +"_color" "1.000000 1.000000 1.000000" +"origin" "620 80 424" +} +// entity 70 +{ +"origin" "636 -288 424" +"_color" "1.000000 1.000000 1.000000" +"classname" "light" +} +// entity 71 +{ +"classname" "light" +"_color" "1.000000 1.000000 1.000000" +"origin" "348 -576 424" +} +// entity 72 +{ +"origin" "-20 -560 424" +"_color" "1.000000 1.000000 1.000000" +"classname" "light" +} +// entity 73 +{ +"classname" "light" +"_color" "1.000000 1.000000 1.000000" +"origin" "-276 -256 424" +} +// entity 74 +{ +"origin" "164 -96 424" +"_color" "1.000000 1.000000 1.000000" +"classname" "light" +} +// entity 75 +{ +"origin" "616 184 -128" +"classname" "info_pathnode" +"spawnflags" "4" +} +// entity 76 +{ +"classname" "info_pathnode" +"origin" "632 -376 -128" +} +// entity 77 +{ +"classname" "info_pathnode" +"origin" "456 344 -128" +"spawnflags" "4" +} +// entity 78 +{ +"origin" "488 -552 -128" +"classname" "info_pathnode" +} diff --git a/fakk/maps/example/cover.prt b/fakk/maps/example/cover.prt new file mode 100644 index 0000000..1133044 --- /dev/null +++ b/fakk/maps/example/cover.prt @@ -0,0 +1,538 @@ +PRT1 +74 +187 +347 +4 0 59 0 (0 24 496 ) (0 576 496 ) (0 576 408 ) (0 24 408 ) +5 0 3 0 (0 576 408 ) (448 576 408 ) (832 192 408 ) (832 24 408 ) (0 24 408 ) +4 0 2 0 (208 24 408 ) (832 24 408 ) (832 24 496 ) (208 24 496 ) +4 0 1 0 (0 24 408 ) (112 24 408 ) (112 24 496 ) (0 24 496 ) +4 1 59 0 (0 0 408 ) (0 0 496 ) (0 24 496 ) (0 24 408 ) +4 1 27 0 (40 0 408 ) (88 0 408 ) (88 0 496 ) (40 0 496 ) +4 1 30 0 (0 0 496 ) (0 0 408 ) (40 0 408 ) (40 0 496 ) +4 1 3 0 (88 0 408 ) (0 0 408 ) (0 24 408 ) (112 24 408 ) +4 2 23 0 (232 0 408 ) (280 0 408 ) (280 0 496 ) (232 0 496 ) +4 2 21 0 (280 0 408 ) (832 0 408 ) (832 0 496 ) (280 0 496 ) +4 2 3 0 (832 24 408 ) (832 0 408 ) (232 0 408 ) (208 24 408 ) +4 3 59 0 (0 0 288 ) (0 0 408 ) (0 576 408 ) (0 576 288 ) +4 3 31 0 (0 0 408 ) (0 0 288 ) (832 0 288 ) (832 0 408 ) +5 3 4 0 (768 0 288 ) (0 0 288 ) (0 512 288 ) (416 512 288 ) (768 160 288 ) +4 4 60 0 (0 0 256 ) (0 0 288 ) (0 512 288 ) (0 512 256 ) +4 4 32 0 (0 0 288 ) (0 0 256 ) (768 0 256 ) (768 0 288 ) +5 4 10 0 (768 0 256 ) (0 0 256 ) (0 512 256 ) (416 512 256 ) (768 160 256 ) +4 5 61 0 (0 568 256 ) (0 576 256 ) (0 576 240 ) (0 568 240 ) +4 5 10 0 (456 568 256 ) (0 568 256 ) (0 568 240 ) (456 568 240 ) +4 5 8 0 (136 568 240 ) (0 568 240 ) (0 576 240 ) (136 576 240 ) +4 5 6 0 (456 568 240 ) (184 568 240 ) (184 576 240 ) (448 576 240 ) +4 6 10 0 (456 568 240 ) (184 568 240 ) (184 568 64 ) (456 568 64 ) +4 6 9 0 (456 568 64 ) (184 568 64 ) (184 576 64 ) (448 576 64 ) +4 7 10 0 (152 568 224 ) (152 568 80 ) (168 568 80 ) (168 568 224 ) +4 8 61 0 (0 576 240 ) (0 576 64 ) (0 568 64 ) (0 568 240 ) +4 8 10 0 (136 568 240 ) (0 568 240 ) (0 568 64 ) (136 568 64 ) +4 8 9 0 (136 568 64 ) (0 568 64 ) (0 576 64 ) (136 576 64 ) +4 9 61 0 (0 576 64 ) (0 576 8 ) (0 568 8 ) (0 568 64 ) +4 9 10 0 (0 568 8 ) (456 568 8 ) (456 568 64 ) (0 568 64 ) +4 10 61 0 (0 0 8 ) (0 0 256 ) (0 568 256 ) (0 568 8 ) +4 10 38 0 (0 0 240 ) (0 0 8 ) (824 0 8 ) (824 0 240 ) +4 10 37 0 (824 0 8 ) (832 0 8 ) (832 0 64 ) (824 0 64 ) +4 10 34 0 (832 0 64 ) (832 0 240 ) (824 0 240 ) (824 0 64 ) +4 10 33 0 (0 0 256 ) (0 0 240 ) (832 0 240 ) (832 0 256 ) +4 10 19 0 (8 328 8 ) (128 328 8 ) (128 320 8 ) (8 320 8 ) +4 10 18 0 (0 328 8 ) (0 512 8 ) (128 512 8 ) (128 328 8 ) +4 10 17 0 (128 0 8 ) (0 0 8 ) (0 320 8 ) (128 320 8 ) +4 10 16 0 (136 0 8 ) (128 0 8 ) (128 320 8 ) (136 320 8 ) +4 10 15 0 (320 0 8 ) (136 0 8 ) (136 512 8 ) (320 512 8 ) +5 10 11 0 (320 64 8 ) (320 512 8 ) (416 512 8 ) (768 160 8 ) (768 64 8 ) +4 10 14 0 (768 0 8 ) (320 0 8 ) (320 64 8 ) (768 64 8 ) +4 11 15 0 (320 512 8 ) (320 512 0 ) (320 64 0 ) (320 64 8 ) +5 11 13 0 (768 64 0 ) (448 64 0 ) (448 192 0 ) (736 192 0 ) (768 160 0 ) +4 11 12 0 (320 192 0 ) (320 512 0 ) (416 512 0 ) (736 192 0 ) +4 11 14 0 (320 64 8 ) (320 64 0 ) (768 64 0 ) (768 64 8 ) +4 12 15 0 (320 512 0 ) (320 512 -128 ) (320 192 -128 ) (320 192 0 ) +4 12 13 0 (736 192 -128 ) (736 192 0 ) (448 192 0 ) (448 192 -128 ) +4 13 14 0 (448 64 -128 ) (768 64 -128 ) (768 64 0 ) (448 64 0 ) +4 14 43 0 (320 0 -128 ) (768 0 -128 ) (768 0 8 ) (320 0 8 ) +4 14 15 0 (320 64 -128 ) (320 0 -128 ) (320 0 8 ) (320 64 8 ) +4 15 43 0 (136 0 -128 ) (320 0 -128 ) (320 0 8 ) (136 0 8 ) +3 15 16 0 (136 0 -120 ) (136 0 8 ) (136 320 8 ) +4 16 43 0 (136 0 -120 ) (136 0 8 ) (128 0 8 ) (128 0 -120 ) +3 16 17 0 (128 0 -120 ) (128 0 8 ) (128 320 8 ) +4 17 55 0 (0 0 8 ) (0 0 -120 ) (8 0 -120 ) (8 0 8 ) +4 17 43 0 (8 0 -120 ) (128 0 -120 ) (128 0 8 ) (8 0 8 ) +4 17 20 0 (128 300 0 ) (128 0 -120 ) (8 0 -120 ) (8 300 0 ) +4 17 19 0 (8 320 8 ) (128 320 8 ) (128 300 0 ) (8 300 0 ) +4 18 62 0 (0 328 8 ) (0 512 8 ) (0 512 0 ) (0 328 0 ) +4 18 19 0 (8 328 0 ) (128 328 0 ) (128 328 8 ) (8 328 8 ) +4 19 20 0 (128 300 0 ) (8 300 0 ) (8 320 0 ) (128 320 0 ) +4 20 43 0 (8 0 -128 ) (128 0 -128 ) (128 0 -120 ) (8 0 -120 ) +5 21 31 0 (280 0 408 ) (832 0 408 ) (832 -384 408 ) (448 -768 408 ) (280 -768 408 ) +4 21 23 0 (280 0 408 ) (280 -48 408 ) (280 -48 496 ) (280 0 496 ) +4 21 22 0 (280 -144 408 ) (280 -216 408 ) (280 -216 496 ) (280 -144 496 ) +4 21 29 0 (280 -216 408 ) (280 -768 408 ) (280 -768 496 ) (280 -216 496 ) +4 22 31 0 (280 -144 408 ) (280 -216 408 ) (232 -216 408 ) (232 -192 408 ) +4 22 25 0 (232 -192 408 ) (232 -216 408 ) (232 -216 496 ) (232 -192 496 ) +4 22 29 0 (232 -216 408 ) (280 -216 408 ) (280 -216 496 ) (232 -216 496 ) +3 23 31 0 (232 0 408 ) (280 0 408 ) (280 -48 408 ) +8 24 31 0 (232 -64 408 ) (232 -128 408 ) (192 -168 408 ) (128 -168 408 ) (88 -128 408 ) (88 -64 408 ) (128 -24 408 ) (192 -24 408 ) +3 25 31 0 (232 -192 408 ) (232 -216 408 ) (208 -216 408 ) +4 25 29 0 (208 -216 408 ) (232 -216 408 ) (232 -216 496 ) (208 -216 496 ) +3 26 31 0 (112 -216 408 ) (88 -216 408 ) (88 -192 408 ) +4 26 28 0 (88 -192 408 ) (88 -216 408 ) (88 -216 496 ) (88 -192 496 ) +4 26 29 0 (88 -216 408 ) (112 -216 408 ) (112 -216 496 ) (88 -216 496 ) +3 27 31 0 (40 0 408 ) (88 0 408 ) (40 -48 408 ) +4 27 30 0 (40 0 408 ) (40 -48 408 ) (40 -48 496 ) (40 0 496 ) +4 28 31 0 (88 -192 408 ) (88 -216 408 ) (40 -216 408 ) (40 -144 408 ) +4 28 29 0 (40 -216 496 ) (40 -216 408 ) (88 -216 408 ) (88 -216 496 ) +4 28 30 0 (40 -144 408 ) (40 -216 408 ) (40 -216 496 ) (40 -144 496 ) +4 29 31 0 (280 -216 408 ) (280 -768 408 ) (40 -768 408 ) (40 -216 408 ) +4 29 30 0 (40 -216 408 ) (40 -768 408 ) (40 -768 496 ) (40 -216 496 ) +4 30 64 0 (0 -768 496 ) (0 0 496 ) (0 0 408 ) (0 -768 408 ) +4 30 31 0 (0 -768 408 ) (0 0 408 ) (40 0 408 ) (40 -768 408 ) +4 31 64 0 (0 -768 408 ) (0 0 408 ) (0 0 288 ) (0 -768 288 ) +5 31 32 0 (0 -704 288 ) (0 0 288 ) (768 0 288 ) (768 -352 288 ) (416 -704 288 ) +4 32 65 0 (0 -704 288 ) (0 0 288 ) (0 0 256 ) (0 -704 256 ) +5 32 33 0 (0 -704 256 ) (0 0 256 ) (768 0 256 ) (768 -352 256 ) (416 -704 256 ) +4 33 66 0 (0 -768 256 ) (0 0 256 ) (0 0 240 ) (0 -768 240 ) +4 33 39 0 (184 -760 240 ) (456 -760 240 ) (448 -768 240 ) (184 -768 240 ) +4 33 41 0 (0 -768 240 ) (0 -760 240 ) (136 -760 240 ) (136 -768 240 ) +5 33 38 0 (0 -760 240 ) (0 0 240 ) (824 0 240 ) (824 -392 240 ) (456 -760 240 ) +4 33 36 0 (832 -120 240 ) (832 -384 240 ) (824 -392 240 ) (824 -120 240 ) +4 33 34 0 (824 0 240 ) (832 0 240 ) (832 -72 240 ) (824 -72 240 ) +4 34 38 0 (824 -72 240 ) (824 0 240 ) (824 0 64 ) (824 -72 64 ) +4 34 37 0 (824 -72 64 ) (824 0 64 ) (832 0 64 ) (832 -72 64 ) +4 35 38 0 (824 -88 224 ) (824 -88 80 ) (824 -104 80 ) (824 -104 224 ) +4 36 38 0 (824 -392 240 ) (824 -120 240 ) (824 -120 64 ) (824 -392 64 ) +4 36 37 0 (824 -392 64 ) (824 -120 64 ) (832 -120 64 ) (832 -384 64 ) +4 37 38 0 (824 0 8 ) (824 -392 8 ) (824 -392 64 ) (824 0 64 ) +4 38 66 0 (0 -760 240 ) (0 0 240 ) (0 0 8 ) (0 -760 8 ) +4 38 58 0 (0 -704 8 ) (0 -584 8 ) (8 -584 8 ) (8 -704 8 ) +4 38 56 0 (0 -576 8 ) (0 -344 8 ) (8 -344 8 ) (8 -576 8 ) +4 38 55 0 (0 -344 8 ) (0 0 8 ) (8 0 8 ) (8 -344 8 ) +4 38 53 0 (128 -704 8 ) (8 -704 8 ) (8 -576 8 ) (128 -576 8 ) +4 38 51 0 (8 -576 8 ) (8 -544 8 ) (128 -544 8 ) (128 -576 8 ) +4 38 49 0 (8 -544 8 ) (8 -512 8 ) (128 -512 8 ) (128 -544 8 ) +4 38 47 0 (8 -512 8 ) (8 -480 8 ) (128 -480 8 ) (128 -512 8 ) +4 38 46 0 (8 -480 8 ) (8 -344 8 ) (128 -344 8 ) (128 -480 8 ) +4 38 45 0 (128 -576 8 ) (128 -344 8 ) (136 -344 8 ) (136 -576 8 ) +5 38 44 0 (768 -344 8 ) (768 -352 8 ) (416 -704 8 ) (136 -704 8 ) (136 -344 8 ) +4 38 43 0 (8 0 8 ) (768 0 8 ) (768 -344 8 ) (8 -344 8 ) +4 38 42 0 (0 -760 8 ) (456 -760 8 ) (456 -760 64 ) (0 -760 64 ) +4 38 40 0 (152 -760 224 ) (152 -760 80 ) (168 -760 80 ) (168 -760 224 ) +4 38 39 0 (456 -760 64 ) (456 -760 240 ) (184 -760 240 ) (184 -760 64 ) +4 38 41 0 (136 -760 240 ) (0 -760 240 ) (0 -760 64 ) (136 -760 64 ) +4 39 42 0 (448 -768 64 ) (184 -768 64 ) (184 -760 64 ) (456 -760 64 ) +4 41 66 0 (0 -768 240 ) (0 -760 240 ) (0 -760 64 ) (0 -768 64 ) +4 41 42 0 (136 -768 64 ) (0 -768 64 ) (0 -760 64 ) (136 -760 64 ) +4 42 66 0 (0 -760 64 ) (0 -760 8 ) (0 -768 8 ) (0 -768 64 ) +4 43 55 0 (8 0 -128 ) (8 -344 -128 ) (8 -344 8 ) (8 0 8 ) +4 43 54 0 (8 -344 -112 ) (8 -344 -128 ) (128 -344 -128 ) (128 -344 -112 ) +4 43 52 0 (8 -344 -96 ) (8 -344 -112 ) (128 -344 -112 ) (128 -344 -96 ) +4 43 50 0 (8 -344 -80 ) (8 -344 -96 ) (128 -344 -96 ) (128 -344 -80 ) +4 43 48 0 (8 -344 -64 ) (8 -344 -80 ) (128 -344 -80 ) (128 -344 -64 ) +4 43 46 0 (8 -344 8 ) (8 -344 -64 ) (128 -344 -64 ) (128 -344 8 ) +4 43 45 0 (136 -344 -112 ) (136 -344 8 ) (128 -344 8 ) (128 -344 -112 ) +4 43 44 0 (136 -344 -128 ) (768 -344 -128 ) (768 -344 8 ) (136 -344 8 ) +3 44 45 0 (136 -344 8 ) (136 -344 -112 ) (136 -576 8 ) +3 45 52 0 (128 -344 -96 ) (128 -344 -112 ) (128 -374.933319 -96 ) +3 45 51 0 (128 -544 -8.551724 ) (128 -576 8 ) (128 -544 8 ) +4 45 50 0 (128 -344 -80 ) (128 -344 -96 ) (128 -374.933319 -96 ) (128 -405.866669 -80 ) +4 45 49 0 (128 -512 -25.103449 ) (128 -544 -8.551724 ) (128 -544 8 ) (128 -512 8 ) +4 45 48 0 (128 -344 -64 ) (128 -344 -80 ) (128 -405.866669 -80 ) (128 -436.799988 -64 ) +4 45 47 0 (128 -480 -41.655170 ) (128 -512 -25.103449 ) (128 -512 8 ) (128 -480 8 ) +5 45 46 0 (128 -344 8 ) (128 -344 -64 ) (128 -436.799988 -64 ) (128 -480 -41.655170 ) (128 -480 8 ) +5 46 57 0 (8 -344 0 ) (8 -344 -64 ) (8 -436.799988 -64 ) (8 -480 -41.655167 ) (8 -480 0 ) +4 46 56 0 (8 -480 8 ) (8 -344 8 ) (8 -344 0 ) (8 -480 0 ) +4 46 48 0 (8 -448 -64 ) (8 -344 -64 ) (128 -344 -64 ) (128 -448 -64 ) +4 46 47 0 (8 -480 8 ) (8 -480 -48 ) (128 -480 -48 ) (128 -480 8 ) +4 47 57 0 (8 -480 0 ) (8 -480 -41.655163 ) (8 -512 -25.103441 ) (8 -512 0 ) +4 47 56 0 (8 -512 8 ) (8 -480 8 ) (8 -480 0 ) (8 -512 0 ) +4 47 49 0 (8 -512 8 ) (8 -512 -32 ) (128 -512 -32 ) (128 -512 8 ) +4 48 57 0 (8 -344 -64 ) (8 -344 -80 ) (8 -405.866638 -80 ) (8 -436.799988 -64 ) +4 48 50 0 (8 -416 -80 ) (8 -344 -80 ) (128 -344 -80 ) (128 -416 -80 ) +4 49 57 0 (8 -512 0 ) (8 -512 -25.103439 ) (8 -544 -8.551716 ) (8 -544 0 ) +4 49 56 0 (8 -544 8 ) (8 -512 8 ) (8 -512 0 ) (8 -544 0 ) +4 49 51 0 (8 -544 8 ) (8 -544 -16 ) (128 -544 -16 ) (128 -544 8 ) +4 50 57 0 (8 -344 -80 ) (8 -344 -96 ) (8 -374.933319 -96 ) (8 -405.866638 -80 ) +4 50 52 0 (8 -384 -96 ) (8 -344 -96 ) (128 -344 -96 ) (128 -384 -96 ) +3 51 57 0 (8 -544 0 ) (8 -544 -8.551715 ) (8 -560.533325 0 ) +4 51 56 0 (8 -576 8 ) (8 -544 8 ) (8 -544 0 ) (8 -560.533325 0 ) +4 51 53 0 (8 -576 8 ) (8 -576 0 ) (128 -576 0 ) (128 -576 8 ) +3 52 57 0 (8 -344 -96 ) (8 -344 -112 ) (8 -374.933319 -96 ) +4 52 54 0 (8 -352 -112 ) (8 -344 -112 ) (128 -344 -112 ) (128 -352 -112 ) +4 53 58 0 (8 -704 0 ) (8 -704 8 ) (8 -584 8 ) (8 -584 0 ) +4 55 57 0 (8 -344 -112 ) (8 -344 0 ) (0 -344 0 ) (0 -344 -112 ) +4 55 56 0 (8 -344 0 ) (8 -344 8 ) (0 -344 8 ) (0 -344 0 ) +4 56 57 0 (0 -560.533325 0 ) (0 -344 0 ) (8 -344 0 ) (8 -560.533325 0 ) +4 58 72 0 (0 -704 8 ) (0 -584 8 ) (0 -584 0 ) (0 -704 0 ) +4 59 64 0 (-512 0 288 ) (0 0 288 ) (0 0 496 ) (-512 0 496 ) +5 59 60 0 (0 0 288 ) (-448 0 288 ) (-448 160 288 ) (-96 512 288 ) (0 512 288 ) +4 60 65 0 (-448 0 256 ) (0 0 256 ) (0 0 288 ) (-448 0 288 ) +5 60 61 0 (0 0 256 ) (-448 0 256 ) (-448 160 256 ) (-96 512 256 ) (0 512 256 ) +4 61 71 0 (-512 0 8 ) (-504 0 8 ) (-504 0 64 ) (-512 0 64 ) +4 61 68 0 (-504 0 64 ) (-504 0 240 ) (-512 0 240 ) (-512 0 64 ) +4 61 67 0 (-504 0 240 ) (-504 0 256 ) (-512 0 256 ) (-512 0 240 ) +4 61 66 0 (-504 0 8 ) (0 0 8 ) (0 0 256 ) (-504 0 256 ) +5 61 63 0 (-8 0 8 ) (-448 0 8 ) (-448 160 8 ) (-96 512 8 ) (-8 512 8 ) +4 61 62 0 (-8 328 8 ) (-8 512 8 ) (0 512 8 ) (0 328 8 ) +4 62 63 0 (-8 512 8 ) (-8 512 0 ) (-8 328 0 ) (-8 328 8 ) +4 63 73 0 (-8 0 8 ) (-448 0 8 ) (-448 0 0 ) (-8 0 0 ) +5 64 65 0 (-448 0 288 ) (0 0 288 ) (0 -704 288 ) (-96 -704 288 ) (-448 -352 288 ) +5 65 66 0 (-448 0 256 ) (0 0 256 ) (0 -704 256 ) (-96 -704 256 ) (-448 -352 256 ) +5 66 73 0 (-448 0 8 ) (-8 0 8 ) (-8 -704 8 ) (-96 -704 8 ) (-448 -352 8 ) +4 66 72 0 (0 -584 8 ) (0 -704 8 ) (-8 -704 8 ) (-8 -584 8 ) +4 66 71 0 (-504 0 8 ) (-504 -392 8 ) (-504 -392 64 ) (-504 0 64 ) +4 66 70 0 (-504 -392 64 ) (-504 -392 240 ) (-504 -120 240 ) (-504 -120 64 ) +4 66 69 0 (-504 -104 80 ) (-504 -104 224 ) (-504 -88 224 ) (-504 -88 80 ) +4 66 68 0 (-504 -72 240 ) (-504 0 240 ) (-504 0 64 ) (-504 -72 64 ) +4 66 67 0 (-504 -392 240 ) (-504 -392 256 ) (-504 0 256 ) (-504 0 240 ) +4 67 70 0 (-512 -384 240 ) (-512 -120 240 ) (-504 -120 240 ) (-504 -392 240 ) +4 67 68 0 (-512 -72 240 ) (-512 0 240 ) (-504 0 240 ) (-504 -72 240 ) +4 68 71 0 (-512 -72 64 ) (-512 0 64 ) (-504 0 64 ) (-504 -72 64 ) +4 70 71 0 (-512 -384 64 ) (-512 -120 64 ) (-504 -120 64 ) (-504 -392 64 ) +4 72 73 0 (-8 -584 0 ) (-8 -704 0 ) (-8 -704 8 ) (-8 -584 8 ) +4 0 (112 24 408 ) (208 24 408 ) (208 24 496 ) (112 24 496 ) +4 0 (448 576 408 ) (0 576 408 ) (0 576 496 ) (448 576 496 ) +5 0 (832 24 496 ) (832 192 496 ) (448 576 496 ) (0 576 496 ) (0 24 496 ) +4 0 (832 24 408 ) (832 192 408 ) (832 192 496 ) (832 24 496 ) +4 0 (832 192 496 ) (832 192 408 ) (448 576 408 ) (448 576 496 ) +4 1 (88 0 408 ) (112 24 408 ) (112 24 496 ) (88 0 496 ) +4 1 (112 24 496 ) (0 24 496 ) (0 0 496 ) (88 0 496 ) +4 2 (832 24 408 ) (832 24 496 ) (832 0 496 ) (832 0 408 ) +4 2 (832 24 496 ) (208 24 496 ) (232 0 496 ) (832 0 496 ) +4 2 (208 24 496 ) (208 24 408 ) (232 0 408 ) (232 0 496 ) +4 3 (416 512 288 ) (512 512 288 ) (768 256 288 ) (768 160 288 ) +4 3 (832 0 288 ) (768 0 288 ) (768 256 288 ) (832 192 288 ) +4 3 (0 512 288 ) (0 576 288 ) (448 576 288 ) (512 512 288 ) +4 3 (832 192 408 ) (832 0 408 ) (832 0 288 ) (832 192 288 ) +4 3 (0 576 408 ) (448 576 408 ) (448 576 288 ) (0 576 288 ) +4 3 (208 24 408 ) (112 24 408 ) (88 0 408 ) (232 0 408 ) +4 3 (448 576 288 ) (448 576 408 ) (832 192 408 ) (832 192 288 ) +4 4 (768 160 288 ) (768 0 288 ) (768 0 256 ) (768 160 256 ) +4 4 (0 512 288 ) (416 512 288 ) (416 512 256 ) (0 512 256 ) +4 4 (768 160 288 ) (768 160 256 ) (416 512 256 ) (416 512 288 ) +4 5 (152 568 240 ) (136 568 240 ) (136 576 240 ) (152 576 240 ) +4 5 (168 568 240 ) (152 568 240 ) (152 572 240 ) (168 572 240 ) +4 5 (152 572 240 ) (152 576 240 ) (168 576 240 ) (168 572 240 ) +4 5 (184 568 240 ) (168 568 240 ) (168 576 240 ) (184 576 240 ) +4 5 (456 568 256 ) (448 576 256 ) (0 576 256 ) (0 568 256 ) +4 5 (448 576 240 ) (0 576 240 ) (0 576 256 ) (448 576 256 ) +4 5 (456 568 256 ) (456 568 240 ) (448 576 240 ) (448 576 256 ) +4 6 (184 576 64 ) (184 568 64 ) (184 568 240 ) (184 576 240 ) +4 6 (448 576 64 ) (184 576 64 ) (184 576 240 ) (448 576 240 ) +4 6 (456 568 64 ) (448 576 64 ) (448 576 240 ) (456 568 240 ) +4 7 (152 568 80 ) (152 568 224 ) (152 572 224 ) (152 572 80 ) +4 7 (168 572 224 ) (168 572 80 ) (152 572 80 ) (152 572 224 ) +4 7 (168 572 80 ) (168 572 224 ) (168 568 224 ) (168 568 80 ) +4 7 (152 568 80 ) (152 572 80 ) (168 572 80 ) (168 568 80 ) +4 7 (168 568 224 ) (168 572 224 ) (152 572 224 ) (152 568 224 ) +4 8 (136 576 64 ) (0 576 64 ) (0 576 240 ) (136 576 240 ) +4 8 (136 576 240 ) (136 568 240 ) (136 568 64 ) (136 576 64 ) +4 9 (0 568 8 ) (0 576 8 ) (448 576 8 ) (456 568 8 ) +4 9 (0 576 64 ) (448 576 64 ) (448 576 8 ) (0 576 8 ) +4 9 (184 576 64 ) (168 576 64 ) (168 568 64 ) (184 568 64 ) +4 9 (168 576 64 ) (152 576 64 ) (152 568 64 ) (168 568 64 ) +4 9 (152 576 64 ) (136 576 64 ) (136 568 64 ) (152 568 64 ) +4 9 (448 576 8 ) (448 576 64 ) (456 568 64 ) (456 568 8 ) +4 10 (0 320 8 ) (0 328 8 ) (8 328 8 ) (8 320 8 ) +4 10 (128 320 8 ) (128 512 8 ) (136 512 8 ) (136 320 8 ) +4 10 (416 512 8 ) (512 512 8 ) (768 256 8 ) (768 160 8 ) +4 10 (0 512 8 ) (0 568 8 ) (456 568 8 ) (512 512 8 ) +4 10 (832 0 8 ) (768 0 8 ) (768 256 8 ) (832 192 8 ) +4 10 (832 192 256 ) (832 0 256 ) (832 0 8 ) (832 192 8 ) +4 10 (152 568 64 ) (136 568 64 ) (136 568 240 ) (152 568 240 ) +4 10 (168 568 224 ) (152 568 224 ) (152 568 240 ) (168 568 240 ) +4 10 (168 568 80 ) (168 568 64 ) (152 568 64 ) (152 568 80 ) +4 10 (184 568 64 ) (168 568 64 ) (168 568 240 ) (184 568 240 ) +4 10 (512 512 256 ) (456 568 256 ) (0 568 256 ) (0 512 256 ) +4 10 (832 192 256 ) (768 256 256 ) (768 0 256 ) (832 0 256 ) +4 10 (768 160 256 ) (768 256 256 ) (512 512 256 ) (416 512 256 ) +4 10 (832 192 256 ) (832 192 8 ) (456 568 8 ) (456 568 256 ) +4 11 (448 64 0 ) (320 64 0 ) (320 192 0 ) (448 192 0 ) +4 11 (768 64 0 ) (768 160 0 ) (768 160 8 ) (768 64 8 ) +4 11 (416 512 0 ) (320 512 0 ) (320 512 8 ) (416 512 8 ) +4 11 (768 160 8 ) (768 160 0 ) (416 512 0 ) (416 512 8 ) +4 12 (448 192 0 ) (320 192 0 ) (320 192 -128 ) (448 192 -128 ) +4 12 (416 512 -128 ) (416 512 0 ) (736 192 0 ) (736 192 -128 ) +4 12 (320 512 0 ) (416 512 0 ) (416 512 -128 ) (320 512 -128 ) +4 12 (320 192 -128 ) (320 512 -128 ) (416 512 -128 ) (736 192 -128 ) +5 13 (768 160 -128 ) (768 64 -128 ) (448 64 -128 ) (448 192 -128 ) (736 192 -128 ) +4 13 (768 160 0 ) (768 64 0 ) (768 64 -128 ) (768 160 -128 ) +4 13 (736 192 0 ) (768 160 0 ) (768 160 -128 ) (736 192 -128 ) +4 13 (448 192 0 ) (448 192 -128 ) (448 64 -128 ) (448 64 0 ) +4 14 (448 64 0 ) (448 64 -128 ) (320 64 -128 ) (320 64 0 ) +4 14 (768 64 -128 ) (768 0 -128 ) (320 0 -128 ) (320 64 -128 ) +4 14 (768 64 -128 ) (768 64 8 ) (768 0 8 ) (768 0 -128 ) +5 15 (136 512 8 ) (136 512 -128 ) (136 0 -128 ) (136 0 -120 ) (136 320 8 ) +4 15 (320 192 0 ) (320 64 0 ) (320 64 -128 ) (320 192 -128 ) +4 15 (136 512 8 ) (320 512 8 ) (320 512 -128 ) (136 512 -128 ) +4 15 (320 0 -128 ) (136 0 -128 ) (136 512 -128 ) (320 512 -128 ) +4 16 (128 0 -120 ) (128 319.998993 8 ) (136 320 8 ) (136 0 -120 ) +4 17 (0 0 0 ) (0 0 8 ) (0 320 8 ) (0 300 0 ) +3 17 (0 0 -120 ) (0 0 0 ) (0 300 0 ) +4 17 (8 0 -120 ) (0 0 -120 ) (0 300 0 ) (8 300 0 ) +4 17 (0 320 8 ) (8 320 8 ) (8 300 0 ) (0 300 0 ) +4 18 (8 512 0 ) (128 512 0 ) (128 328 0 ) (8 328 0 ) +4 18 (0 328 0 ) (0 512 0 ) (8 512 0 ) (8 328 0 ) +4 18 (0 328 0 ) (8 328 0 ) (8 328 8 ) (0 328 8 ) +4 18 (0 512 0 ) (0 512 8 ) (128 512 8 ) (128 512 0 ) +4 18 (128 328 8 ) (128 328 0 ) (128 512 0 ) (128 512 8 ) +4 19 (8 320 0 ) (8 328 0 ) (128 328 0 ) (128 320 0 ) +4 19 (128 328 8 ) (128 320 8 ) (128 300 0 ) (128 328 0 ) +4 19 (8 328 8 ) (8 328 0 ) (8 300 0 ) (8 320 8 ) +4 20 (8 0 -120 ) (8 300 0 ) (8 320 0 ) (8 0 -128 ) +4 20 (128 320 0 ) (128 300 0 ) (128 0 -120 ) (128 0 -128 ) +4 20 (8 0 -128 ) (8 319.998627 0 ) (128 319.998627 0 ) (128 0 -128 ) +4 21 (280 -48 408 ) (280 -144 408 ) (280 -144 496 ) (280 -48 496 ) +4 21 (832 0 496 ) (832 -384 496 ) (832 -384 408 ) (832 0 408 ) +5 21 (280 -768 496 ) (448 -768 496 ) (832 -384 496 ) (832 0 496 ) (280 0 496 ) +4 21 (280 -768 408 ) (448 -768 408 ) (448 -768 496 ) (280 -768 496 ) +4 21 (448 -768 496 ) (448 -768 408 ) (832 -384 408 ) (832 -384 496 ) +4 22 (280 -144 496 ) (280 -144 408 ) (232 -192 408 ) (232 -192 496 ) +4 22 (232 -192 496 ) (232 -216 496 ) (280 -216 496 ) (280 -144 496 ) +3 23 (280 -48 496 ) (280 0 496 ) (232 0 496 ) +4 23 (232 0 496 ) (232 0 408 ) (280 -48 408 ) (280 -48 496 ) +4 24 (88 -64 408 ) (88 -128 408 ) (88 -128 496 ) (88 -64 496 ) +4 24 (128 -168 408 ) (192 -168 408 ) (192 -168 496 ) (128 -168 496 ) +4 24 (192 -168 496 ) (192 -168 408 ) (232 -128 408 ) (232 -128 496 ) +4 24 (88 -128 496 ) (88 -128 408 ) (128 -168 408 ) (128 -168 496 ) +4 24 (232 -64 496 ) (232 -128 496 ) (232 -128 408 ) (232 -64 408 ) +8 24 (192 -24 496 ) (128 -24 496 ) (88 -64 496 ) (88 -128 496 ) (128 -168 496 ) (192 -168 496 ) (232 -128 496 ) (232 -64 496 ) +4 24 (128 -24 496 ) (192 -24 496 ) (192 -24 408 ) (128 -24 408 ) +4 24 (128 -24 496 ) (128 -24 408 ) (88 -64 408 ) (88 -64 496 ) +4 24 (232 -64 496 ) (232 -64 408 ) (192 -24 408 ) (192 -24 496 ) +4 25 (232 -192 496 ) (232 -192 408 ) (208 -216 408 ) (208 -216 496 ) +3 25 (208 -216 496 ) (232 -216 496 ) (232 -192 496 ) +3 26 (88 -192 496 ) (88 -216 496 ) (112 -216 496 ) +4 26 (112 -216 496 ) (112 -216 408 ) (88 -192 408 ) (88 -192 496 ) +4 27 (40 -48 496 ) (40 -48 408 ) (88 0 408 ) (88 0 496 ) +3 27 (40 -48 496 ) (88 0 496 ) (40 0 496 ) +4 28 (40 -144 496 ) (40 -216 496 ) (88 -216 496 ) (88 -192 496 ) +4 28 (88 -192 496 ) (88 -192 408 ) (40 -144 408 ) (40 -144 496 ) +4 29 (112 -216 496 ) (208 -216 496 ) (208 -216 408 ) (112 -216 408 ) +4 29 (40 -768 408 ) (280 -768 408 ) (280 -768 496 ) (40 -768 496 ) +4 29 (40 -216 496 ) (40 -768 496 ) (280 -768 496 ) (280 -216 496 ) +4 30 (40 -48 496 ) (40 -144 496 ) (40 -144 408 ) (40 -48 408 ) +4 30 (40 -768 496 ) (40 0 496 ) (0 0 496 ) (0 -768 496 ) +4 30 (0 -768 408 ) (40 -768 408 ) (40 -768 496 ) (0 -768 496 ) +4 31 (768 -352 288 ) (768 -448 288 ) (512 -704 288 ) (416 -704 288 ) +4 31 (0 -768 288 ) (0 -704 288 ) (512 -704 288 ) (448 -768 288 ) +4 31 (768 0 288 ) (832 0 288 ) (832 -384 288 ) (768 -448 288 ) +4 31 (832 0 408 ) (832 -384 408 ) (832 -384 288 ) (832 0 288 ) +4 31 (232 -192 408 ) (280 -144 408 ) (280 -48 408 ) (232 0 408 ) +4 31 (88 -24 408 ) (232 -24 408 ) (232 0 408 ) (88 0 408 ) +3 31 (88 -128 408 ) (88 -168 408 ) (128 -168 408 ) +3 31 (128 -24 408 ) (88 -24 408 ) (88 -64 408 ) +3 31 (192 -168 408 ) (232 -168 408 ) (232 -128 408 ) +3 31 (192 -24 408 ) (232 -64 408 ) (232 -24 408 ) +6 31 (88 -168 408 ) (88 -192 408 ) (112 -216 408 ) (208 -216 408 ) (232 -192 408 ) (232 -168 408 ) +4 31 (40 -48 408 ) (40 -144 408 ) (88 -192 408 ) (88 0 408 ) +4 31 (0 -768 288 ) (448 -768 288 ) (448 -768 408 ) (0 -768 408 ) +4 31 (448 -768 408 ) (448 -768 288 ) (832 -384 288 ) (832 -384 408 ) +4 32 (0 -704 256 ) (416 -704 256 ) (416 -704 288 ) (0 -704 288 ) +4 32 (768 0 288 ) (768 -352 288 ) (768 -352 256 ) (768 0 256 ) +4 32 (416 -704 288 ) (416 -704 256 ) (768 -352 256 ) (768 -352 288 ) +4 33 (152 -760 240 ) (168 -760 240 ) (168 -764 240 ) (152 -764 240 ) +4 33 (168 -760 240 ) (184 -760 240 ) (184 -764 240 ) (168 -764 240 ) +4 33 (184 -764 240 ) (184 -768 240 ) (152 -768 240 ) (152 -764 240 ) +4 33 (136 -760 240 ) (152 -760 240 ) (152 -768 240 ) (136 -768 240 ) +4 33 (832 -104 240 ) (832 -120 240 ) (824 -120 240 ) (824 -104 240 ) +4 33 (828 -104 240 ) (824 -104 240 ) (824 -88 240 ) (828 -88 240 ) +4 33 (832 -88 240 ) (832 -104 240 ) (828 -104 240 ) (828 -88 240 ) +4 33 (832 -72 240 ) (832 -88 240 ) (824 -88 240 ) (824 -72 240 ) +4 33 (832 0 256 ) (832 -384 256 ) (832 -384 240 ) (832 0 240 ) +4 33 (768 -448 256 ) (832 -384 256 ) (832 0 256 ) (768 0 256 ) +4 33 (448 -768 256 ) (512 -704 256 ) (0 -704 256 ) (0 -768 256 ) +4 33 (416 -704 256 ) (512 -704 256 ) (768 -448 256 ) (768 -352 256 ) +4 33 (0 -768 240 ) (448 -768 240 ) (448 -768 256 ) (0 -768 256 ) +4 33 (448 -768 256 ) (448 -768 240 ) (832 -384 240 ) (832 -384 256 ) +4 34 (832 0 240 ) (832 -72 240 ) (832 -72 64 ) (832 0 64 ) +4 34 (824 -72 240 ) (824 -72 64 ) (832 -72 64 ) (832 -72 240 ) +4 35 (824 -104 224 ) (824 -104 80 ) (828 -104 80 ) (828 -104 224 ) +4 35 (828 -104 224 ) (828 -104 80 ) (828 -88 80 ) (828 -88 224 ) +4 35 (828 -88 224 ) (828 -88 80 ) (824 -88 80 ) (824 -88 224 ) +4 35 (828 -104 80 ) (824 -104 80 ) (824 -88 80 ) (828 -88 80 ) +4 35 (824 -104 224 ) (828 -104 224 ) (828 -88 224 ) (824 -88 224 ) +4 36 (832 -120 240 ) (832 -120 64 ) (824 -120 64 ) (824 -120 240 ) +4 36 (832 -120 240 ) (832 -384 240 ) (832 -384 64 ) (832 -120 64 ) +4 36 (824 -392 240 ) (824 -392 64 ) (832 -384 64 ) (832 -384 240 ) +4 37 (824 0 8 ) (832 0 8 ) (832 -384 8 ) (824 -392 8 ) +4 37 (832 0 64 ) (832 -384 64 ) (832 -384 8 ) (832 0 8 ) +4 37 (832 -120 64 ) (832 -104 64 ) (824 -104 64 ) (824 -120 64 ) +4 37 (832 -104 64 ) (832 -88 64 ) (824 -88 64 ) (824 -104 64 ) +4 37 (832 -88 64 ) (832 -72 64 ) (824 -72 64 ) (824 -88 64 ) +4 37 (832 -384 8 ) (832 -384 64 ) (824 -392 64 ) (824 -392 8 ) +4 38 (0 -584 8 ) (0 -576 8 ) (8 -576 8 ) (8 -584 8 ) +4 38 (136 -704 8 ) (128 -704 8 ) (128 -576 8 ) (136 -576 8 ) +4 38 (768 -352 8 ) (768 -448 8 ) (512 -704 8 ) (416 -704 8 ) +4 38 (768 0 8 ) (824 0 8 ) (824 -392 8 ) (768 -448 8 ) +4 38 (0 -760 8 ) (0 -704 8 ) (512 -704 8 ) (456 -760 8 ) +4 38 (152 -760 80 ) (152 -760 64 ) (168 -760 64 ) (168 -760 80 ) +4 38 (168 -760 240 ) (152 -760 240 ) (152 -760 224 ) (168 -760 224 ) +4 38 (184 -760 240 ) (168 -760 240 ) (168 -760 64 ) (184 -760 64 ) +4 38 (152 -760 240 ) (136 -760 240 ) (136 -760 64 ) (152 -760 64 ) +4 38 (824 -120 64 ) (824 -104 64 ) (824 -104 240 ) (824 -120 240 ) +4 38 (824 -104 224 ) (824 -88 224 ) (824 -88 240 ) (824 -104 240 ) +4 38 (824 -104 80 ) (824 -104 64 ) (824 -88 64 ) (824 -88 80 ) +4 38 (824 -88 64 ) (824 -72 64 ) (824 -72 240 ) (824 -88 240 ) +4 38 (456 -760 240 ) (456 -760 8 ) (824 -392 8 ) (824 -392 240 ) +4 39 (184 -760 240 ) (184 -760 64 ) (184 -764 64 ) (184 -764 240 ) +4 39 (184 -764 64 ) (184 -768 64 ) (184 -768 240 ) (184 -764 240 ) +4 39 (448 -768 240 ) (184 -768 240 ) (184 -768 64 ) (448 -768 64 ) +4 39 (448 -768 240 ) (448 -768 64 ) (456 -760 64 ) (456 -760 240 ) +4 40 (152 -760 224 ) (152 -764 224 ) (168 -764 224 ) (168 -760 224 ) +4 40 (152 -764 224 ) (152 -764 80 ) (168 -764 80 ) (168 -764 224 ) +4 40 (152 -760 224 ) (152 -760 80 ) (152 -764 80 ) (152 -764 224 ) +4 40 (168 -764 224 ) (168 -764 80 ) (168 -760 80 ) (168 -760 224 ) +4 40 (168 -760 80 ) (168 -764 80 ) (152 -764 80 ) (152 -760 80 ) +4 41 (136 -768 240 ) (136 -768 64 ) (136 -760 64 ) (136 -760 240 ) +4 41 (136 -768 240 ) (0 -768 240 ) (0 -768 64 ) (136 -768 64 ) +4 42 (0 -768 8 ) (0 -760 8 ) (456 -760 8 ) (448 -768 8 ) +4 42 (0 -768 8 ) (448 -768 8 ) (448 -768 64 ) (0 -768 64 ) +4 42 (152 -760 64 ) (136 -760 64 ) (136 -768 64 ) (152 -768 64 ) +4 42 (184 -764 64 ) (152 -764 64 ) (152 -768 64 ) (184 -768 64 ) +4 42 (168 -764 64 ) (184 -764 64 ) (184 -760 64 ) (168 -760 64 ) +4 42 (168 -764 64 ) (168 -760 64 ) (152 -760 64 ) (152 -764 64 ) +4 42 (456 -760 8 ) (456 -760 64 ) (448 -768 64 ) (448 -768 8 ) +4 43 (128 -344 -128 ) (136 -344 -128 ) (136 -344 -112 ) (128 -344 -112 ) +4 43 (768 0 8 ) (768 -344 8 ) (768 -344 -128 ) (768 0 -128 ) +4 43 (128 0 -120 ) (136 0 -120 ) (136 0 -128 ) (128 0 -128 ) +4 43 (8 0 -128 ) (768 0 -128 ) (768 -344 -128 ) (8 -344 -128 ) +5 44 (136 -344 -112 ) (136 -344 -128 ) (136 -704 -128 ) (136 -704 8 ) (136 -576 8 ) +5 44 (768 -344 -128 ) (768 -352 -128 ) (416 -704 -128 ) (136 -704 -128 ) (136 -344 -128 ) +4 44 (136 -704 -128 ) (416 -704 -128 ) (416 -704 8 ) (136 -704 8 ) +4 44 (768 -344 8 ) (768 -352 8 ) (768 -352 -128 ) (768 -344 -128 ) +4 44 (416 -704 8 ) (416 -704 -128 ) (768 -352 -128 ) (768 -352 8 ) +4 45 (128 -576 8 ) (128 -344 -112 ) (136 -344 -112 ) (136 -576 8 ) +3 46 (8 -436.799988 -64 ) (8 -480 -64 ) (8 -480 -41.655167 ) +4 46 (8 -480 -64 ) (8 -448 -64 ) (128 -448 -64 ) (128 -480 -64 ) +4 46 (8 -480 -48 ) (8 -480 -64 ) (128 -480 -64 ) (128 -480 -48 ) +3 46 (128 -480 -64 ) (128 -436.799988 -64 ) (128 -480 -41.655167 ) +4 47 (8 -480 -41.655163 ) (8 -480 -48 ) (8 -512 -48 ) (8 -512 -25.103441 ) +4 47 (8 -512 -32 ) (8 -512 -48 ) (128 -512 -48 ) (128 -512 -32 ) +4 47 (128 -512 -48 ) (128 -480 -48 ) (128 -480 -41.655167 ) (128 -512 -25.103443 ) +4 47 (128 -512 -48 ) (8 -512 -48 ) (8 -480 -48 ) (128 -480 -48 ) +4 48 (8 -405.866638 -80 ) (8 -448 -80 ) (8 -448 -64 ) (8 -436.799988 -64 ) +4 48 (8 -448 -80 ) (8 -416 -80 ) (128 -416 -80 ) (128 -448 -80 ) +4 48 (128 -448 -64 ) (128 -448 -80 ) (128 -405.866638 -80 ) (128 -436.799988 -64 ) +4 48 (8 -448 -80 ) (128 -448 -80 ) (128 -448 -64 ) (8 -448 -64 ) +4 49 (8 -512 -25.103439 ) (8 -512 -32 ) (8 -544 -32 ) (8 -544 -8.551716 ) +4 49 (8 -544 -16 ) (8 -544 -32 ) (128 -544 -32 ) (128 -544 -16 ) +4 49 (128 -544 -32 ) (128 -512 -32 ) (128 -512 -25.103443 ) (128 -544 -8.551723 ) +4 49 (128 -544 -32 ) (8 -544 -32 ) (8 -512 -32 ) (128 -512 -32 ) +4 50 (8 -374.933319 -96 ) (8 -416 -96 ) (8 -416 -80 ) (8 -405.866638 -80 ) +4 50 (8 -416 -96 ) (8 -384 -96 ) (128 -384 -96 ) (128 -416 -96 ) +4 50 (128 -416 -80 ) (128 -416 -96 ) (128 -374.933319 -96 ) (128 -405.866638 -80 ) +4 50 (8 -416 -96 ) (128 -416 -96 ) (128 -416 -80 ) (8 -416 -80 ) +5 51 (8 -544 -8.551715 ) (8 -544 -16 ) (8 -576 -16 ) (8 -576 0 ) (8 -560.533325 0 ) +3 51 (8 -576 8 ) (8 -560.533325 0 ) (8 -576 0 ) +4 51 (8 -576 0 ) (8 -576 -16 ) (128 -576 -16 ) (128 -576 0 ) +4 51 (128 -544 -16 ) (128 -544 -8.551723 ) (128 -576 8 ) (128 -576 -16 ) +4 51 (128 -576 -16 ) (8 -576 -16 ) (8 -544 -16 ) (128 -544 -16 ) +4 52 (8 -344 -112 ) (8 -384 -112 ) (8 -384 -96 ) (8 -374.933319 -96 ) +4 52 (8 -384 -112 ) (8 -352 -112 ) (128 -352 -112 ) (128 -384 -112 ) +4 52 (128 -374.933319 -96 ) (128 -384 -96 ) (128 -384 -112 ) (128 -344 -112 ) +4 52 (8 -384 -112 ) (128 -384 -112 ) (128 -384 -96 ) (8 -384 -96 ) +4 53 (8 -584 8 ) (8 -576 8 ) (8 -576 0 ) (8 -584 0 ) +4 53 (128 -704 0 ) (128 -704 8 ) (8 -704 8 ) (8 -704 0 ) +4 53 (128 -576 0 ) (128 -576 8 ) (128 -704 8 ) (128 -704 0 ) +4 53 (8 -704 0 ) (8 -576 0 ) (128 -576 0 ) (128 -704 0 ) +4 54 (8 -344 -128 ) (8 -352 -128 ) (8 -352 -112 ) (8 -344 -112 ) +4 54 (128 -352 -112 ) (128 -352 -128 ) (128 -344 -128 ) (128 -344 -112 ) +4 54 (8 -352 -128 ) (8 -344 -128 ) (128 -344 -128 ) (128 -352 -128 ) +4 54 (128 -352 -128 ) (128 -352 -112 ) (8 -352 -112 ) (8 -352 -128 ) +4 55 (0 -344 8 ) (0 0 8 ) (0 0 0 ) (0 -344 0 ) +4 55 (0 0 0 ) (0 0 -128 ) (0 -344 -128 ) (0 -344 0 ) +4 55 (0 -344 -128 ) (8 -344 -128 ) (8 -344 -112 ) (0 -344 -112 ) +4 55 (0 -344 -128 ) (0 0 -128 ) (8 0 -128 ) (8 -344 -128 ) +4 55 (8 0 -120 ) (8 0 -128 ) (0 0 -128 ) (0 0 -120 ) +4 56 (0 -576 8 ) (0 -344 8 ) (0 -344 0 ) (0 -560.533325 0 ) +4 56 (0 -560.532898 0 ) (8 -560.532898 0 ) (8 -576 8 ) (0 -576 8 ) +3 57 (0 -344 0 ) (0 -344 -112 ) (0 -560.533325 0 ) +4 57 (8 -560.532898 0 ) (0 -560.532898 0 ) (0 -344 -112 ) (8 -344 -112 ) +4 58 (8 -704 0 ) (8 -704 8 ) (0 -704 8 ) (0 -704 0 ) +4 58 (0 -584 0 ) (0 -584 8 ) (8 -584 8 ) (8 -584 0 ) +4 58 (0 -584 0 ) (8 -584 0 ) (8 -704 0 ) (0 -704 0 ) +4 59 (-448 160 288 ) (-448 256 288 ) (-192 512 288 ) (-96 512 288 ) +4 59 (-448 0 288 ) (-512 0 288 ) (-512 192 288 ) (-448 256 288 ) +4 59 (-192 512 288 ) (-128 576 288 ) (0 576 288 ) (0 512 288 ) +4 59 (-128 576 496 ) (0 576 496 ) (0 576 288 ) (-128 576 288 ) +5 59 (0 576 496 ) (-128 576 496 ) (-512 192 496 ) (-512 0 496 ) (0 0 496 ) +4 59 (-512 192 288 ) (-512 0 288 ) (-512 0 496 ) (-512 192 496 ) +4 59 (-128 576 496 ) (-128 576 288 ) (-512 192 288 ) (-512 192 496 ) +4 60 (-448 160 256 ) (-448 0 256 ) (-448 0 288 ) (-448 160 288 ) +4 60 (-96 512 288 ) (0 512 288 ) (0 512 256 ) (-96 512 256 ) +4 60 (-96 512 288 ) (-96 512 256 ) (-448 160 256 ) (-448 160 288 ) +4 61 (-448 160 8 ) (-448 256 8 ) (-192 512 8 ) (-96 512 8 ) +4 61 (0 0 8 ) (-8 0 8 ) (-8 328 8 ) (0 328 8 ) +4 61 (-192 512 8 ) (-128 576 8 ) (0 576 8 ) (0 512 8 ) +4 61 (-448 0 8 ) (-512 0 8 ) (-512 192 8 ) (-448 256 8 ) +4 61 (-512 192 8 ) (-512 0 8 ) (-512 0 256 ) (-512 192 256 ) +4 61 (-192 512 256 ) (0 512 256 ) (0 576 256 ) (-128 576 256 ) +4 61 (-448 256 256 ) (-512 192 256 ) (-512 0 256 ) (-448 0 256 ) +4 61 (-96 512 256 ) (-192 512 256 ) (-448 256 256 ) (-448 160 256 ) +4 61 (-128 576 256 ) (0 576 256 ) (0 576 8 ) (-128 576 8 ) +4 61 (-128 576 256 ) (-128 576 8 ) (-512 192 8 ) (-512 192 256 ) +4 62 (-8 512 8 ) (0 512 8 ) (0 512 0 ) (-8 512 0 ) +4 62 (-8 328 0 ) (-8 512 0 ) (0 512 0 ) (0 328 0 ) +4 62 (-8 328 8 ) (-8 328 0 ) (0 328 0 ) (0 328 8 ) +4 63 (-96 512 8 ) (-8 512 8 ) (-8 512 0 ) (-96 512 0 ) +4 63 (-448 0 0 ) (-448 0 8 ) (-448 160 8 ) (-448 160 0 ) +5 63 (-8 0 0 ) (-448 0 0 ) (-448 160 0 ) (-96 512 0 ) (-8 512 0 ) +4 63 (-8 328 8 ) (-8 0 8 ) (-8 0 0 ) (-8 328 0 ) +4 63 (-96 512 8 ) (-96 512 0 ) (-448 160 0 ) (-448 160 8 ) +4 64 (-96 -704 288 ) (-192 -704 288 ) (-448 -448 288 ) (-448 -352 288 ) +4 64 (-512 0 288 ) (-448 0 288 ) (-448 -448 288 ) (-512 -384 288 ) +4 64 (0 -704 288 ) (0 -768 288 ) (-128 -768 288 ) (-192 -704 288 ) +4 64 (-128 -768 288 ) (0 -768 288 ) (0 -768 496 ) (-128 -768 496 ) +5 64 (-512 -384 496 ) (-128 -768 496 ) (0 -768 496 ) (0 0 496 ) (-512 0 496 ) +4 64 (-512 0 288 ) (-512 -384 288 ) (-512 -384 496 ) (-512 0 496 ) +4 64 (-512 -384 496 ) (-512 -384 288 ) (-128 -768 288 ) (-128 -768 496 ) +4 65 (-448 0 256 ) (-448 -352 256 ) (-448 -352 288 ) (-448 0 288 ) +4 65 (-96 -704 256 ) (0 -704 256 ) (0 -704 288 ) (-96 -704 288 ) +4 65 (-448 -352 288 ) (-448 -352 256 ) (-96 -704 256 ) (-96 -704 288 ) +4 66 (-96 -704 8 ) (-192 -704 8 ) (-448 -448 8 ) (-448 -352 8 ) +4 66 (-8 0 8 ) (0 0 8 ) (0 -584 8 ) (-8 -584 8 ) +4 66 (0 -704 8 ) (0 -768 8 ) (-128 -768 8 ) (-192 -704 8 ) +4 66 (-504 0 8 ) (-448 0 8 ) (-448 -448 8 ) (-504 -392 8 ) +4 66 (-504 -88 64 ) (-504 -104 64 ) (-504 -104 80 ) (-504 -88 80 ) +4 66 (-504 -72 224 ) (-504 -72 64 ) (-504 -88 64 ) (-504 -88 224 ) +4 66 (-504 -104 240 ) (-504 -72 240 ) (-504 -72 224 ) (-504 -104 224 ) +4 66 (-504 -120 240 ) (-504 -104 240 ) (-504 -104 64 ) (-504 -120 64 ) +4 66 (-128 -768 8 ) (0 -768 8 ) (0 -768 256 ) (-128 -768 256 ) +4 66 (-128 -768 256 ) (0 -768 256 ) (0 -704 256 ) (-192 -704 256 ) +4 66 (-504 -392 256 ) (-448 -448 256 ) (-448 0 256 ) (-504 0 256 ) +4 66 (-448 -352 256 ) (-448 -448 256 ) (-192 -704 256 ) (-96 -704 256 ) +4 66 (-504 -392 256 ) (-504 -392 8 ) (-128 -768 8 ) (-128 -768 256 ) +4 67 (-508 -72 240 ) (-504 -72 240 ) (-504 -104 240 ) (-508 -104 240 ) +4 67 (-504 -104 240 ) (-504 -120 240 ) (-508 -120 240 ) (-508 -104 240 ) +4 67 (-512 -120 240 ) (-512 -72 240 ) (-508 -72 240 ) (-508 -120 240 ) +4 67 (-512 -384 256 ) (-504 -392 256 ) (-504 0 256 ) (-512 0 256 ) +4 67 (-512 -384 256 ) (-512 0 256 ) (-512 0 240 ) (-512 -384 240 ) +4 67 (-512 -384 256 ) (-512 -384 240 ) (-504 -392 240 ) (-504 -392 256 ) +4 68 (-508 -72 64 ) (-504 -72 64 ) (-504 -72 224 ) (-508 -72 224 ) +4 68 (-504 -72 224 ) (-504 -72 240 ) (-508 -72 240 ) (-508 -72 224 ) +4 68 (-512 -72 64 ) (-508 -72 64 ) (-508 -72 240 ) (-512 -72 240 ) +4 68 (-512 -72 240 ) (-512 0 240 ) (-512 0 64 ) (-512 -72 64 ) +4 69 (-504 -88 80 ) (-508 -88 80 ) (-508 -88 224 ) (-504 -88 224 ) +4 69 (-508 -104 224 ) (-508 -104 80 ) (-504 -104 80 ) (-504 -104 224 ) +4 69 (-508 -104 80 ) (-508 -104 224 ) (-508 -88 224 ) (-508 -88 80 ) +4 69 (-504 -88 224 ) (-508 -88 224 ) (-508 -104 224 ) (-504 -104 224 ) +4 69 (-504 -104 80 ) (-508 -104 80 ) (-508 -88 80 ) (-504 -88 80 ) +4 70 (-512 -384 240 ) (-512 -120 240 ) (-512 -120 64 ) (-512 -384 64 ) +4 70 (-512 -120 240 ) (-508 -120 240 ) (-508 -120 64 ) (-512 -120 64 ) +4 70 (-508 -120 240 ) (-504 -120 240 ) (-504 -120 64 ) (-508 -120 64 ) +4 70 (-512 -384 64 ) (-504 -392 64 ) (-504 -392 240 ) (-512 -384 240 ) +4 71 (-512 0 8 ) (-504 0 8 ) (-504 -392 8 ) (-512 -384 8 ) +4 71 (-512 0 8 ) (-512 -384 8 ) (-512 -384 64 ) (-512 0 64 ) +4 71 (-508 -120 64 ) (-508 -72 64 ) (-512 -72 64 ) (-512 -120 64 ) +4 71 (-508 -104 64 ) (-508 -120 64 ) (-504 -120 64 ) (-504 -104 64 ) +4 71 (-508 -88 64 ) (-504 -88 64 ) (-504 -72 64 ) (-508 -72 64 ) +4 71 (-508 -88 64 ) (-508 -104 64 ) (-504 -104 64 ) (-504 -88 64 ) +4 71 (-504 -392 8 ) (-504 -392 64 ) (-512 -384 64 ) (-512 -384 8 ) +4 72 (-8 -704 0 ) (0 -704 0 ) (0 -704 8 ) (-8 -704 8 ) +4 72 (0 -704 0 ) (-8 -704 0 ) (-8 -584 0 ) (0 -584 0 ) +4 72 (0 -584 8 ) (0 -584 0 ) (-8 -584 0 ) (-8 -584 8 ) +4 73 (-96 -704 0 ) (-8 -704 0 ) (-8 -704 8 ) (-96 -704 8 ) +4 73 (-448 -352 8 ) (-448 0 8 ) (-448 0 0 ) (-448 -352 0 ) +5 73 (-8 -704 0 ) (-96 -704 0 ) (-448 -352 0 ) (-448 0 0 ) (-8 0 0 ) +4 73 (-8 0 8 ) (-8 -584 8 ) (-8 -584 0 ) (-8 0 0 ) +4 73 (-448 -352 8 ) (-448 -352 0 ) (-96 -704 0 ) (-96 -704 8 ) diff --git a/fakk/maps/example/cover.pth b/fakk/maps/example/cover.pth new file mode 100644 index 0000000..717df7b Binary files /dev/null and b/fakk/maps/example/cover.pth differ diff --git a/fakk/maps/example/door.bsp b/fakk/maps/example/door.bsp new file mode 100644 index 0000000..64a6873 Binary files /dev/null and b/fakk/maps/example/door.bsp differ diff --git a/fakk/maps/example/door.map b/fakk/maps/example/door.map new file mode 100644 index 0000000..3cd1361 --- /dev/null +++ b/fakk/maps/example/door.map @@ -0,0 +1,327 @@ +{ +"classname" "worldspawn" +// brush 0 +{ +( -256 448 64 ) ( 640 448 64 ) ( 640 512 64 ) eden/lt_edenlt22b 16 0 0.00 -1 0.125000 0 0 0 +( 640 512 192 ) ( 640 448 192 ) ( -256 448 192 ) eden/lt_edenlt22b 16 0 0.00 -1 0.125000 0 0 0 +( -192 512 0 ) ( -176 512 0 ) ( -184 512 256 ) eden/lt_edenlt22b 16 64 0.00 -1 1 0 0 0 +( -208 496 0 ) ( -208 512 0 ) ( -208 504 256 ) eden/lt_edenlt22b 0 64 0.00 -0.500000 1 0 0 0 +( -176 512 0 ) ( -176 496 0 ) ( -176 504 256 ) eden/lt_edenlt22b 0 64 0.00 -0.500000 1 0 0 0 +( -176 496 0 ) ( -192 496 0 ) ( -184 496 256 ) eden/lt_edenlt22b 16 64 0.00 -1 1 0 0 0 +} +// brush 1 +{ +( -192 448 64 ) ( 704 448 64 ) ( 704 512 64 ) eden/lt_edenlt22b 16 0 0.00 -1 0.125000 0 0 0 +( 704 512 192 ) ( 704 448 192 ) ( -192 448 192 ) eden/lt_edenlt22b 16 0 0.00 -1 0.125000 0 0 0 +( -128 512 0 ) ( -112 512 0 ) ( -120 512 256 ) eden/lt_edenlt22b 16 64 0.00 -1 1 0 0 0 +( -144 496 0 ) ( -144 512 0 ) ( -144 504 256 ) eden/lt_edenlt22b 0 64 0.00 -0.500000 1 0 0 0 +( -112 512 0 ) ( -112 496 0 ) ( -112 504 256 ) eden/lt_edenlt22b 0 64 0.00 -0.500000 1 0 0 0 +( -112 496 0 ) ( -128 496 0 ) ( -120 496 256 ) eden/lt_edenlt22b 16 64 0.00 -1 1 0 0 0 +} +// brush 2 +{ +( -64 448 64 ) ( 832 448 64 ) ( 832 512 64 ) eden/lt_edenlt24 16 0 0.00 -1 0.125000 0 0 0 +( 832 512 192 ) ( 832 448 192 ) ( -64 448 192 ) eden/lt_edenlt24 16 0 0.00 -1 0.125000 0 0 0 +( 0 512 0 ) ( 16 512 0 ) ( 8 512 256 ) eden/lt_edenlt24 16 64 0.00 -1 1 0 0 0 +( -16 496 0 ) ( -16 512 0 ) ( -16 504 256 ) eden/lt_edenlt24 0 64 0.00 -0.500000 1 0 0 0 +( 16 512 0 ) ( 16 496 0 ) ( 16 504 256 ) eden/lt_edenlt24 0 64 0.00 -0.500000 1 0 0 0 +( 16 496 0 ) ( 0 496 0 ) ( 8 496 256 ) eden/lt_edenlt24 16 64 0.00 -1 1 0 0 0 +} +// brush 3 +{ +( -128 448 64 ) ( 768 448 64 ) ( 768 512 64 ) eden/lt_edenlt18v 16 0 0.00 -1 0.125000 0 0 0 +( 768 512 192 ) ( 768 448 192 ) ( -128 448 192 ) eden/lt_edenlt18v 16 0 0.00 -1 0.125000 0 0 0 +( -64 512 0 ) ( -48 512 0 ) ( -56 512 256 ) eden/lt_edenlt18v 16 64 0.00 -1 1 0 0 0 +( -80 496 0 ) ( -80 512 0 ) ( -80 504 256 ) eden/lt_edenlt18v 0 64 0.00 -0.500000 1 0 0 0 +( -48 512 0 ) ( -48 496 0 ) ( -48 504 256 ) eden/lt_edenlt18v 0 64 0.00 -0.500000 1 0 0 0 +( -48 496 0 ) ( -64 496 0 ) ( -56 496 256 ) eden/lt_edenlt18v 16 64 0.00 -1 1 0 0 0 +} +// brush 4 +{ +( 0 448 64 ) ( 896 448 64 ) ( 896 512 64 ) eden/lt_edenlt22w 16 0 0.00 -1 0.125000 0 0 0 +( 896 512 192 ) ( 896 448 192 ) ( 0 448 192 ) eden/lt_edenlt22w 16 0 0.00 -1 0.125000 0 0 0 +( 64 512 0 ) ( 80 512 0 ) ( 72 512 256 ) eden/lt_edenlt22w 16 64 0.00 -1 1 0 0 0 +( 48 496 0 ) ( 48 512 0 ) ( 48 504 256 ) eden/lt_edenlt22w 0 64 0.00 -0.500000 1 0 0 0 +( 80 512 0 ) ( 80 496 0 ) ( 80 504 256 ) eden/lt_edenlt22w 0 64 0.00 -0.500000 1 0 0 0 +( 80 496 0 ) ( 64 496 0 ) ( 72 496 256 ) eden/lt_edenlt22w 16 64 0.00 -1 1 0 0 0 +} +// brush 5 +{ +( 0 -304 64 ) ( 896 -304 64 ) ( 896 -240 64 ) eden/lt_edenlt23w 16 0 0.00 -1 0.125000 0 0 0 +( 896 -240 192 ) ( 896 -304 192 ) ( 0 -304 192 ) eden/lt_edenlt23w 16 0 0.00 -1 0.125000 0 0 0 +( 64 -240 0 ) ( 80 -240 0 ) ( 72 -240 256 ) eden/lt_edenlt23w 16 64 0.00 -1 1 0 0 0 +( 48 -256 0 ) ( 48 -240 0 ) ( 48 -248 256 ) eden/lt_edenlt23w 0 64 0.00 -0.500000 1 0 0 0 +( 80 -240 0 ) ( 80 -256 0 ) ( 80 -248 256 ) eden/lt_edenlt23w 0 64 0.00 -0.500000 1 0 0 0 +( 80 -256 0 ) ( 64 -256 0 ) ( 72 -256 256 ) eden/lt_edenlt23w 16 64 0.00 -1 1 0 0 0 +} +// brush 6 +{ +( -128 -304 64 ) ( 768 -304 64 ) ( 768 -240 64 ) eden/lt_edenlt21w 16 0 0.00 -1 0.125000 0 0 0 +( 768 -240 192 ) ( 768 -304 192 ) ( -128 -304 192 ) eden/lt_edenlt21w 16 0 0.00 -1 0.125000 0 0 0 +( -64 -240 0 ) ( -48 -240 0 ) ( -56 -240 256 ) eden/lt_edenlt21w 16 64 0.00 -1 1 0 0 0 +( -80 -256 0 ) ( -80 -240 0 ) ( -80 -248 256 ) eden/lt_edenlt21w 0 64 0.00 -0.500000 1 0 0 0 +( -48 -240 0 ) ( -48 -256 0 ) ( -48 -248 256 ) eden/lt_edenlt21w 0 64 0.00 -0.500000 1 0 0 0 +( -48 -256 0 ) ( -64 -256 0 ) ( -56 -256 256 ) eden/lt_edenlt21w 16 64 0.00 -1 1 0 0 0 +} +// brush 7 +{ +( -64 -304 64 ) ( 832 -304 64 ) ( 832 -240 64 ) eden/lt_edenlt20 16 0 0.00 -1 0.125000 0 0 0 +( 832 -240 192 ) ( 832 -304 192 ) ( -64 -304 192 ) eden/lt_edenlt20 16 0 0.00 -1 0.125000 0 0 0 +( 0 -240 0 ) ( 16 -240 0 ) ( 8 -240 256 ) eden/lt_edenlt20 16 64 0.00 -1 1 0 0 0 +( -16 -256 0 ) ( -16 -240 0 ) ( -16 -248 256 ) eden/lt_edenlt20 0 64 0.00 -0.500000 1 0 0 0 +( 16 -240 0 ) ( 16 -256 0 ) ( 16 -248 256 ) eden/lt_edenlt20 0 64 0.00 -0.500000 1 0 0 0 +( 16 -256 0 ) ( 0 -256 0 ) ( 8 -256 256 ) eden/lt_edenlt20 16 64 0.00 -1 1 0 0 0 +} +// brush 8 +{ +( -192 -304 64 ) ( 704 -304 64 ) ( 704 -240 64 ) eden/lt_edenlt17b 16 0 0.00 -1 0.125000 0 0 0 +( 704 -240 192 ) ( 704 -304 192 ) ( -192 -304 192 ) eden/lt_edenlt17b 16 0 0.00 -1 0.125000 0 0 0 +( -128 -240 0 ) ( -112 -240 0 ) ( -120 -240 256 ) eden/lt_edenlt17b 16 64 0.00 -1 1 0 0 0 +( -144 -256 0 ) ( -144 -240 0 ) ( -144 -248 256 ) eden/lt_edenlt17b 0 64 0.00 -0.500000 1 0 0 0 +( -112 -240 0 ) ( -112 -256 0 ) ( -112 -248 256 ) eden/lt_edenlt17b 0 64 0.00 -0.500000 1 0 0 0 +( -112 -256 0 ) ( -128 -256 0 ) ( -120 -256 256 ) eden/lt_edenlt17b 16 64 0.00 -1 1 0 0 0 +} +// brush 9 +{ +( -256 -304 64 ) ( 640 -304 64 ) ( 640 -240 64 ) eden/lt_edenlt17w 16 0 0.00 -1 0.125000 0 0 0 +( 640 -240 192 ) ( 640 -304 192 ) ( -256 -304 192 ) eden/lt_edenlt17w 16 0 0.00 -1 0.125000 0 0 0 +( -192 -240 0 ) ( -176 -240 0 ) ( -184 -240 256 ) eden/lt_edenlt17w 16 64 0.00 -1 1 0 0 0 +( -208 -256 0 ) ( -208 -240 0 ) ( -208 -248 256 ) eden/lt_edenlt17w 0 64 0.00 -0.500000 1 0 0 0 +( -176 -240 0 ) ( -176 -256 0 ) ( -176 -248 256 ) eden/lt_edenlt17w 0 64 0.00 -0.500000 1 0 0 0 +( -176 -256 0 ) ( -192 -256 0 ) ( -184 -256 256 ) eden/lt_edenlt17w 16 64 0.00 -1 1 0 0 0 +} +// brush 10 +{ +( 192 0 0 ) ( 176 0 0 ) ( 176 -64 0 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 176 -64 128 ) ( 176 0 128 ) ( 192 0 128 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 176 -64 32 ) ( 192 -64 32 ) ( 192 -64 0 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 192 -64 32 ) ( 192 0 32 ) ( 192 0 0 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 192 0 32 ) ( 176 0 32 ) ( 176 0 0 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 176 0 96 ) ( 176 -64 96 ) ( 176 -64 64 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +} +// brush 11 +{ +( 640 512 256 ) ( -256 512 256 ) ( -256 -256 256 ) eden/genmetal_2 0 0 0.00 1 1 0 0 0 +( -256 -256 320 ) ( -256 512 320 ) ( 640 512 320 ) eden/genmetal_2 0 0 0.00 1 1 0 0 0 +( -256 -256 320 ) ( 640 -256 320 ) ( 640 -256 256 ) eden/genmetal_2 0 0 0.00 1 1 0 0 0 +( 640 -256 320 ) ( 640 512 320 ) ( 640 512 256 ) eden/genmetal_2 0 0 0.00 1 1 0 0 0 +( 640 512 320 ) ( -256 512 320 ) ( -256 512 256 ) eden/genmetal_2 0 0 0.00 1 1 0 0 0 +( -256 512 320 ) ( -256 -256 320 ) ( -256 -256 256 ) eden/genmetal_2 0 0 0.00 1 1 0 0 0 +} +// brush 12 +{ +( 2432 -1664 0 ) ( 2432 -512 0 ) ( 3712 -512 0 ) eden/fl_grass 0 0 0.00 1 1 0 0 0 +( -256 256 -64 ) ( -256 320 -64 ) ( -256 288 0 ) eden/fl_grass 0 0 0.00 1 1 0 0 0 +( 64 512 -64 ) ( 256 512 -64 ) ( 160 512 0 ) eden/fl_grass 0 0 0.00 1 1 0 0 0 +( 192 -384 -64 ) ( 192 -448 -64 ) ( 192 -416 0 ) eden/fl_grass 0 0 0.00 1 1 0 0 0 +( -208 -256 -64 ) ( -256 -256 -64 ) ( -232 -256 0 ) eden/fl_grass 0 0 0.00 1 1 0 0 0 +( 192 -256 -64 ) ( 32 512 -64 ) ( -128 -256 -64 ) eden/fl_grass 0 0 0.00 1 1 0 0 0 +} +// brush 13 +{ +( 304 3008 0 ) ( 304 1728 0 ) ( -848 1728 0 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 224 -640 -96 ) ( 224 -576 -80 ) ( 224 -640 -64 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 624 512 -32 ) ( 640 512 -32 ) ( 632 512 0 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 288 -256 -32 ) ( 208 -256 -32 ) ( 248 -256 0 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 640 512 -32 ) ( 640 480 -32 ) ( 640 496 0 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 192 -256 -64 ) ( 32 512 -64 ) ( -128 -256 -64 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +} +// brush 14 +{ +( -256 -320 0 ) ( 640 -320 0 ) ( 640 -256 0 ) eden/WL_neweden_4 0 0 0.00 1 1 0 0 0 +( 640 -256 256 ) ( 640 -320 256 ) ( -256 -320 256 ) eden/WL_neweden_4 0 0 0.00 1 1 0 0 0 +( 640 -256 64 ) ( -256 -256 64 ) ( -256 -256 0 ) eden/WL_neweden_4 0 0 0.00 1 1 0 0 0 +( -256 -256 64 ) ( -256 -320 64 ) ( -256 -320 0 ) eden/WL_neweden_4 0 0 0.00 1 1 0 0 0 +( -256 -320 64 ) ( 640 -320 64 ) ( 640 -320 0 ) eden/WL_neweden_4 0 0 0.00 1 1 0 0 0 +( 640 -320 64 ) ( 640 -256 64 ) ( 640 -256 0 ) eden/WL_neweden_4 0 0 0.00 1 1 0 0 0 +} +// brush 15 +{ +( -320 640 0 ) ( -320 -256 0 ) ( -256 -256 0 ) eden/WL_neweden_4 0 0 0.00 1 1 0 0 0 +( -256 -256 256 ) ( -320 -256 256 ) ( -320 640 256 ) eden/WL_neweden_4 0 0 0.00 1 1 0 0 0 +( -256 -256 64 ) ( -256 640 64 ) ( -256 640 0 ) eden/WL_neweden_4 0 0 0.00 1 1 0 0 0 +( -320 640 64 ) ( -320 -256 64 ) ( -320 -256 0 ) eden/WL_neweden_4 0 0 0.00 1 1 0 0 0 +( -320 -256 64 ) ( -256 -256 64 ) ( -256 -256 0 ) eden/WL_neweden_4 0 0 0.00 1 1 0 0 0 +( -384 512 0 ) ( -64 512 0 ) ( -224 512 256 ) eden/WL_neweden_4 0 0 0.00 1 1 0 0 0 +} +// brush 16 +{ +( 704 -384 0 ) ( 704 512 0 ) ( 640 512 0 ) eden/WL_neweden_4 0 0 0.00 1 1 0 0 0 +( 640 512 256 ) ( 704 512 256 ) ( 704 -384 256 ) eden/WL_neweden_4 0 0 0.00 1 1 0 0 0 +( 640 512 64 ) ( 640 -384 64 ) ( 640 -384 0 ) eden/WL_neweden_4 0 0 0.00 1 1 0 0 0 +( 704 -384 64 ) ( 704 512 64 ) ( 704 512 0 ) eden/WL_neweden_4 0 0 0.00 1 1 0 0 0 +( 704 512 64 ) ( 640 512 64 ) ( 640 512 0 ) eden/WL_neweden_4 0 0 0.00 1 1 0 0 0 +( 768 -256 0 ) ( 448 -256 0 ) ( 608 -256 256 ) eden/WL_neweden_4 0 0 0.00 1 1 0 0 0 +} +// brush 17 +{ +( 640 576 0 ) ( -256 576 0 ) ( -256 512 0 ) eden/WL_neweden_4 0 0 0.00 1 1 0 0 0 +( -256 512 256 ) ( -256 576 256 ) ( 640 576 256 ) eden/WL_neweden_4 0 0 0.00 1 1 0 0 0 +( -256 512 64 ) ( 640 512 64 ) ( 640 512 0 ) eden/WL_neweden_4 0 0 0.00 1 1 0 0 0 +( 640 512 64 ) ( 640 576 64 ) ( 640 576 0 ) eden/WL_neweden_4 0 0 0.00 1 1 0 0 0 +( 640 576 64 ) ( -256 576 64 ) ( -256 576 0 ) eden/WL_neweden_4 0 0 0.00 1 1 0 0 0 +( -256 576 64 ) ( -256 512 64 ) ( -256 512 0 ) eden/WL_neweden_4 0 0 0.00 1 1 0 0 0 +} +// brush 18 +{ +( 672 240 256 ) ( 672 448 256 ) ( 960 448 256 ) eden/WL_neweden_1 0 0 0.00 1 1 0 0 0 +( 192 336 0 ) ( 192 384 0 ) ( 192 360 256 ) eden/WL_neweden_1 0 0 0.00 1 1 0 0 0 +( 224 448 0 ) ( 224 400 0 ) ( 224 424 256 ) eden/WL_edenhouse 0 0 0.00 1 1 0 0 0 +( 192 -480 0 ) ( 192 -544 0 ) ( 208 -512 0 ) eden/WL_neweden_1 0 0 0.00 1 1 0 0 0 +( 160 64 0 ) ( 256 64 0 ) ( 208 64 256 ) eden/genmetal_3 0 0 0.00 1 1 0 0 0 +( 320 -256 0 ) ( 64 -256 0 ) ( 192 -256 256 ) eden/genmetal_3 0 0 0.00 1 1 0 0 0 +} +// brush 19 +{ +( 672 176 256 ) ( 672 384 256 ) ( 960 384 256 ) eden/WL_neweden_1 0 0 0.00 1 1 0 0 0 +( 192 272 0 ) ( 192 320 0 ) ( 192 296 256 ) eden/WL_neweden_1 0 0 0.00 1 1 0 0 0 +( 224 640 0 ) ( 224 592 0 ) ( 224 616 256 ) eden/WL_edenhouse 0 0 0.00 1 1 0 0 0 +( 192 -576 0 ) ( 192 -640 0 ) ( 208 -608 0 ) eden/WL_neweden_1 0 0 0.00 1 1 0 0 0 +( 256 192 0 ) ( 160 192 0 ) ( 208 192 256 ) eden/genmetal_3 0 0 0.00 1 1 0 0 0 +( 128 512 0 ) ( 384 512 0 ) ( 256 512 256 ) eden/genmetal_3 0 0 0.00 1 1 0 0 0 +} +// brush 20 +{ +( 304 3552 0 ) ( 304 2272 0 ) ( -848 2272 0 ) eden/genmetal_3 0 0 0.00 1 1 0 0 0 +( 368 -64 -32 ) ( 328 -32 -32 ) ( 288 -64 -32 ) eden/genmetal_3 0 0 0.00 1 1 0 0 0 +( 192 -64 -32 ) ( 192 0 -16 ) ( 192 -64 0 ) eden/genmetal_3 0 0 0.00 1 1 0 0 0 +( 224 192 -32 ) ( 224 160 -32 ) ( 224 176 0 ) eden/genmetal_3 0 0 0.00 1 1 0 0 0 +( 192 64 -32 ) ( 192 64 16 ) ( 224 64 -8 ) eden/genmetal_3 0 0 0.00 1 1 0 0 0 +( 192 192 0 ) ( 192 192 -32 ) ( 224 192 -16 ) eden/genmetal_3 0 0 0.00 1 1 0 0 0 +} +// brush 21 +{ +( 672 240 256 ) ( 672 448 256 ) ( 960 448 256 ) eden/WL_neweden_1 0 0 0.00 1 1 0 0 0 +( 192 336 0 ) ( 192 384 0 ) ( 192 360 256 ) eden/WL_neweden_1 0 0 0.00 1 1 0 0 0 +( 224 448 0 ) ( 224 400 0 ) ( 224 424 256 ) eden/WL_edenhouse 0 0 0.00 1 1 0 0 0 +( 176 192 0 ) ( 240 192 0 ) ( 208 192 256 ) eden/WL_neweden_1 0 0 0.00 1 1 0 0 0 +( 256 64 0 ) ( 192 64 0 ) ( 224 64 256 ) eden/WL_neweden_1 0 0 0.00 1 1 0 0 0 +( 192 176 128 ) ( 192 96 128 ) ( 224 136 128 ) eden/genmetal_3 0 0 0.00 1 1 0 0 0 +} +// brush 22 +{ +( 192 240 0 ) ( 192 288 0 ) ( 192 264 256 ) eden/WL_edendoor 64 0 0.00 1 1 0 0 0 +( 192 192 0 ) ( 272 192 0 ) ( 232 192 256 ) eden/genmetal_3 0 0 0.00 1 1 0 0 0 +( 204 192 0 ) ( 204 168 0 ) ( 204 180 256 ) eden/genmetal_3 0 0 0.00 1 1 0 0 0 +( 192 192 0 ) ( 192 160 128 ) ( 200 176 64 ) eden/genmetal_3 0 0 0.00 1 1 0 0 0 +( 192 160 128 ) ( 192 224 128 ) ( 200 192 128 ) eden/genmetal_3 0 0 0.00 1 1 0 0 0 +} +// brush 23 +{ +( 224 352 0 ) ( 224 304 0 ) ( 224 328 256 ) eden/WL_edendoor 64 0 0.00 1 1 0 0 0 +( 192 192 0 ) ( 272 192 0 ) ( 232 192 256 ) eden/genmetal_3 0 0 0.00 1 1 0 0 0 +( 212 176 0 ) ( 212 192 0 ) ( 212 184 256 ) eden/genmetal_3 0 0 0.00 1 1 0 0 0 +( 216 192 0 ) ( 216 160 128 ) ( 224 176 64 ) eden/genmetal_3 0 0 0.00 1 1 0 0 0 +( 216 160 128 ) ( 216 224 128 ) ( 224 192 128 ) eden/genmetal_3 0 0 0.00 1 1 0 0 0 +} +// brush 24 +{ +( 224 -72 256 ) ( 224 -48 0 ) ( 224 -96 0 ) eden/WL_edendoor 64 0 0.00 1 1 0 0 0 +( 232 64 256 ) ( 272 64 0 ) ( 192 64 0 ) eden/genmetal_3 0 0 0.00 1 1 0 0 0 +( 212 72 256 ) ( 212 64 0 ) ( 212 80 0 ) eden/genmetal_3 0 0 0.00 1 1 0 0 0 +( 220 80 64 ) ( 212 96 128 ) ( 212 64 0 ) eden/genmetal_3 0 0 0.00 1 1 0 0 0 +( 224 64 128 ) ( 216 32 128 ) ( 216 96 128 ) eden/genmetal_3 0 0 0.00 1 1 0 0 0 +} +// brush 25 +{ +( 192 -8 256 ) ( 192 -32 0 ) ( 192 16 0 ) eden/WL_edendoor 64 0 0.00 1 1 0 0 0 +( 232 64 256 ) ( 272 64 0 ) ( 192 64 0 ) eden/genmetal_3 0 0 0.00 1 1 0 0 0 +( 204 76 256 ) ( 204 88 0 ) ( 204 64 0 ) eden/genmetal_3 0 0 0.00 1 1 0 0 0 +( 204 80 64 ) ( 196 96 128 ) ( 196 64 0 ) eden/genmetal_3 0 0 0.00 1 1 0 0 0 +( 200 64 128 ) ( 192 32 128 ) ( 192 96 128 ) eden/genmetal_3 0 0 0.00 1 1 0 0 0 +} +} +// entity 1 +{ +"origin" "-64 320 128" +"classname" "light" +} +// entity 2 +{ +"classname" "Characters_EdenMale_Balthazar" +"scale" "1.0" +"model" "edenmale_balthazar.tik" +"targetname" "dude" +"origin" "-192.00 128.00 0.00" +} +// entity 3 +{ +"classname" "info_player_start" +"origin" "-192 0 0" +} +// entity 4 +{ +"classname" "info_pathnode" +"origin" "168 128 0" +"spawnflags" "8" +} +// entity 5 +{ +"angle" "-1" +"classname" "func_door" +// brush 0 +{ +( 292 192 0 ) ( 260 192 0 ) ( 260 32 0 ) eden/genmetal_3 0 0 0.00 1 1 0 0 0 +( 212 32 320 ) ( 212 192 320 ) ( 212 192 64 ) eden/WL_edendoor 64 0 0.00 1 1 0 0 0 +( 204 192 320 ) ( 204 32 320 ) ( 204 32 64 ) eden/WL_edendoor 64 0 0.00 1 1 0 0 0 +( 260 64 128 ) ( 260 96 128 ) ( 276 80 128 ) eden/genmetal_3 0 0 0.00 1 1 0 0 0 +( 260 64 0 ) ( 260 96 128 ) ( 276 80 64 ) eden/genmetal_3 0 0 0.00 1 1 0 0 0 +( 260 160 128 ) ( 260 192 0 ) ( 276 176 64 ) eden/genmetal_3 0 0 0.00 1 1 0 0 0 +} +} +// entity 6 +{ +"origin" "248 128 0" +"classname" "info_pathnode" +"spawnflags" "8" +} +// entity 7 +{ +"classname" "info_pathnode" +"origin" "384 128 0" +} +// entity 8 +{ +"origin" "576 128 0" +"classname" "info_pathnode" +"targetname" "dude_dest" +} +// entity 9 +{ +"classname" "info_pathnode" +"origin" "0 128 0" +} +// entity 10 +{ +"origin" "-192 128 0" +"classname" "info_pathnode" +} +// entity 11 +{ +"classname" "light" +"origin" "-64 -64 128" +} +// entity 12 +{ +"classname" "light" +"origin" "448 320 128" +} +// entity 13 +{ +"origin" "448 -64 128" +"classname" "light" +} +// entity 14 +{ +"thread" "dude_go_thread" +"classname" "trigger_useonce" +// brush 0 +{ +( 176 0 0 ) ( 160 0 0 ) ( 160 -64 0 ) common/trigger 0 0 0.00 1 1 0 128 0 +( 160 -64 128 ) ( 160 0 128 ) ( 176 0 128 ) common/trigger 0 0 0.00 1 1 0 128 0 +( 160 -64 32 ) ( 176 -64 32 ) ( 176 -64 0 ) common/trigger 0 0 0.00 1 1 0 128 0 +( 176 -64 32 ) ( 176 0 32 ) ( 176 0 0 ) common/trigger 0 0 0.00 1 1 0 128 0 +( 176 0 32 ) ( 160 0 32 ) ( 160 0 0 ) common/trigger 0 0 0.00 1 1 0 128 0 +( 160 0 96 ) ( 160 -64 96 ) ( 160 -64 64 ) common/trigger 0 0 0.00 1 1 0 128 0 +} +} diff --git a/fakk/maps/example/door.prt b/fakk/maps/example/door.prt new file mode 100644 index 0000000..d6b5b64 --- /dev/null +++ b/fakk/maps/example/door.prt @@ -0,0 +1,216 @@ +PRT1 +31 +67 +145 +4 0 9 0 (224 0 0 ) (640 0 0 ) (640 0 256 ) (224 0 256 ) +4 0 1 0 (224 192 0 ) (224 64 0 ) (224 96 128 ) (224 160 128 ) +4 1 2 0 (212 64 0 ) (212 96 128 ) (212 160 128 ) (212 192 0 ) +4 2 3 0 (204 192 0 ) (204 64 0 ) (204 96 128 ) (204 160 128 ) +4 3 8 0 (192 192 0 ) (192 64 0 ) (192 96 128 ) (192 160 128 ) +4 4 17 0 (0 0 192 ) (0 0 256 ) (0 512 256 ) (0 512 192 ) +4 4 13 0 (0 0 256 ) (0 0 192 ) (80 0 192 ) (80 0 256 ) +4 4 10 0 (80 0 192 ) (192 0 192 ) (192 0 256 ) (80 0 256 ) +4 4 5 0 (192 512 192 ) (192 496 192 ) (80 496 192 ) (80 512 192 ) +4 4 6 0 (48 496 192 ) (16 496 192 ) (16 512 192 ) (48 512 192 ) +4 4 8 0 (192 496 192 ) (192 0 192 ) (0 0 192 ) (0 496 192 ) +4 5 7 0 (192 496 64 ) (80 496 64 ) (80 512 64 ) (192 512 64 ) +4 5 8 0 (192 496 64 ) (192 496 192 ) (80 496 192 ) (80 496 64 ) +4 6 7 0 (48 496 64 ) (16 496 64 ) (16 512 64 ) (48 512 64 ) +4 6 8 0 (48 496 192 ) (16 496 192 ) (16 496 64 ) (48 496 64 ) +4 7 22 0 (0 512 0 ) (0 496 0 ) (0 496 64 ) (0 512 64 ) +4 7 8 0 (0 496 0 ) (192 496 0 ) (192 496 64 ) (0 496 64 ) +4 8 23 0 (0 0 0 ) (0 0 192 ) (0 496 192 ) (0 496 0 ) +4 8 13 0 (0 0 192 ) (0 0 0 ) (80 0 0 ) (80 0 192 ) +4 8 12 0 (80 0 0 ) (176 0 0 ) (176 0 128 ) (80 0 128 ) +4 8 10 0 (192 0 128 ) (192 0 192 ) (80 0 192 ) (80 0 128 ) +4 10 14 0 (80 -256 192 ) (80 -256 256 ) (80 -240 256 ) (80 -240 192 ) +4 10 13 0 (80 -240 256 ) (80 0 256 ) (80 0 128 ) (80 -240 128 ) +4 10 11 0 (192 -64 128 ) (192 -256 128 ) (176 -256 128 ) (176 -64 128 ) +4 10 12 0 (80 -256 128 ) (80 0 128 ) (176 0 128 ) (176 -256 128 ) +4 11 12 0 (176 -64 0 ) (176 -256 0 ) (176 -256 128 ) (176 -64 128 ) +4 12 16 0 (80 -240 0 ) (80 -256 0 ) (80 -256 64 ) (80 -240 64 ) +4 12 13 0 (80 0 0 ) (80 -240 0 ) (80 -240 128 ) (80 0 128 ) +4 13 25 0 (0 0 192 ) (0 0 0 ) (0 -240 0 ) (0 -240 192 ) +4 13 24 0 (0 -240 256 ) (0 0 256 ) (0 0 192 ) (0 -240 192 ) +4 13 15 0 (48 -240 192 ) (16 -240 192 ) (16 -240 64 ) (48 -240 64 ) +4 13 16 0 (0 -240 0 ) (80 -240 0 ) (80 -240 64 ) (0 -240 64 ) +4 13 14 0 (80 -240 192 ) (80 -240 256 ) (0 -240 256 ) (0 -240 192 ) +4 14 24 0 (0 -256 256 ) (0 -240 256 ) (0 -240 192 ) (0 -256 192 ) +4 14 15 0 (16 -240 192 ) (48 -240 192 ) (48 -256 192 ) (16 -256 192 ) +4 15 16 0 (16 -240 64 ) (48 -240 64 ) (48 -256 64 ) (16 -256 64 ) +4 16 30 0 (0 -240 64 ) (0 -240 0 ) (0 -256 0 ) (0 -256 64 ) +4 17 24 0 (-256 0 192 ) (0 0 192 ) (0 0 256 ) (-256 0 256 ) +4 17 23 0 (0 0 192 ) (-256 0 192 ) (-256 496 192 ) (0 496 192 ) +4 17 21 0 (-256 496 192 ) (-256 512 192 ) (-208 512 192 ) (-208 496 192 ) +4 17 20 0 (-176 512 192 ) (-144 512 192 ) (-144 496 192 ) (-176 496 192 ) +4 17 19 0 (-112 512 192 ) (-80 512 192 ) (-80 496 192 ) (-112 496 192 ) +4 17 18 0 (-48 512 192 ) (-16 512 192 ) (-16 496 192 ) (-48 496 192 ) +4 18 23 0 (-16 496 192 ) (-48 496 192 ) (-48 496 64 ) (-16 496 64 ) +4 18 22 0 (-16 496 64 ) (-48 496 64 ) (-48 512 64 ) (-16 512 64 ) +4 19 23 0 (-80 496 192 ) (-112 496 192 ) (-112 496 64 ) (-80 496 64 ) +4 19 22 0 (-80 496 64 ) (-112 496 64 ) (-112 512 64 ) (-80 512 64 ) +4 20 23 0 (-144 496 192 ) (-176 496 192 ) (-176 496 64 ) (-144 496 64 ) +4 20 22 0 (-144 496 64 ) (-176 496 64 ) (-176 512 64 ) (-144 512 64 ) +4 21 23 0 (-208 496 192 ) (-256 496 192 ) (-256 496 64 ) (-208 496 64 ) +4 21 22 0 (-208 496 64 ) (-256 496 64 ) (-256 512 64 ) (-208 512 64 ) +4 22 23 0 (0 496 0 ) (0 496 64 ) (-256 496 64 ) (-256 496 0 ) +4 23 25 0 (-256 0 0 ) (0 0 0 ) (0 0 192 ) (-256 0 192 ) +4 24 27 0 (-80 -256 192 ) (-112 -256 192 ) (-112 -240 192 ) (-80 -240 192 ) +4 24 28 0 (-144 -256 192 ) (-176 -256 192 ) (-176 -240 192 ) (-144 -240 192 ) +4 24 26 0 (-16 -256 192 ) (-48 -256 192 ) (-48 -240 192 ) (-16 -240 192 ) +4 24 29 0 (-208 -256 192 ) (-256 -256 192 ) (-256 -240 192 ) (-208 -240 192 ) +4 24 25 0 (-256 0 192 ) (0 0 192 ) (0 -240 192 ) (-256 -240 192 ) +4 25 30 0 (0 -240 0 ) (0 -240 64 ) (-256 -240 64 ) (-256 -240 0 ) +4 25 27 0 (-80 -240 192 ) (-112 -240 192 ) (-112 -240 64 ) (-80 -240 64 ) +4 25 28 0 (-144 -240 192 ) (-176 -240 192 ) (-176 -240 64 ) (-144 -240 64 ) +4 25 26 0 (-16 -240 192 ) (-48 -240 192 ) (-48 -240 64 ) (-16 -240 64 ) +4 25 29 0 (-208 -240 192 ) (-256 -240 192 ) (-256 -240 64 ) (-208 -240 64 ) +4 26 30 0 (-48 -240 64 ) (-16 -240 64 ) (-16 -256 64 ) (-48 -256 64 ) +4 27 30 0 (-112 -240 64 ) (-80 -240 64 ) (-80 -256 64 ) (-112 -256 64 ) +4 28 30 0 (-176 -240 64 ) (-144 -240 64 ) (-144 -256 64 ) (-176 -256 64 ) +4 29 30 0 (-256 -240 64 ) (-208 -240 64 ) (-208 -256 64 ) (-256 -256 64 ) +4 0 (224 512 0 ) (224 192 0 ) (224 160 128 ) (224 512 128 ) +3 0 (224 64 0 ) (224 64 128 ) (224 96 128 ) +4 0 (224 64 128 ) (224 64 256 ) (224 512 256 ) (224 512 128 ) +4 0 (224 64 0 ) (224 0 0 ) (224 0 256 ) (224 64 256 ) +4 0 (640 512 256 ) (224 512 256 ) (224 0 256 ) (640 0 256 ) +4 0 (640 0 0 ) (224 0 0 ) (224 512 0 ) (640 512 0 ) +4 0 (640 512 256 ) (640 512 0 ) (224 512 0 ) (224 512 256 ) +4 0 (640 0 0 ) (640 512 0 ) (640 512 256 ) (640 0 256 ) +4 1 (224 96 128 ) (212 96 128 ) (212 64 0 ) (224 64 0 ) +4 1 (224 192 0 ) (224 64 0 ) (212 64 0 ) (212 192 0 ) +4 1 (224 96 128 ) (224 160 128 ) (212 160 128 ) (212 96 128 ) +4 1 (212 192 0 ) (212 160 128 ) (224 160 128 ) (224 192 0 ) +3 2 (204 192 128 ) (204 192 0 ) (204 160 128 ) +3 2 (204 64 0 ) (204 64 128 ) (204 96 128 ) +4 2 (212 192 128 ) (212 192 0 ) (204 192 0 ) (204 192 128 ) +3 2 (212 192 0 ) (212 192 128 ) (212 160 128 ) +3 2 (212 96 128 ) (212 64 128 ) (212 64 0 ) +4 2 (204 64 128 ) (204 64 0 ) (212 64 0 ) (212 64 128 ) +4 2 (204 64 0 ) (204 192 0 ) (212 192 0 ) (212 64 0 ) +4 2 (204 64 128 ) (212 64 128 ) (212 192 128 ) (204 192 128 ) +4 3 (204 64 0 ) (204 96 128 ) (192 96 128 ) (192 64 0 ) +4 3 (192 64 0 ) (192 192 0 ) (204 192 0 ) (204 64 0 ) +4 3 (204 96 128 ) (204 160 128 ) (192 160 128 ) (192 96 128 ) +4 3 (192 160 128 ) (204 160 128 ) (204 192 0 ) (192 192 0 ) +4 4 (80 496 192 ) (48 496 192 ) (48 512 192 ) (80 512 192 ) +4 4 (16 496 192 ) (0 496 192 ) (0 512 192 ) (16 512 192 ) +4 4 (192 512 256 ) (192 512 192 ) (0 512 192 ) (0 512 256 ) +4 4 (192 512 192 ) (192 512 256 ) (192 0 256 ) (192 0 192 ) +4 4 (0 0 256 ) (192 0 256 ) (192 512 256 ) (0 512 256 ) +4 5 (80 512 192 ) (192 512 192 ) (192 512 64 ) (80 512 64 ) +4 5 (192 496 128 ) (192 512 128 ) (192 512 192 ) (192 496 192 ) +4 5 (192 512 64 ) (192 512 128 ) (192 496 128 ) (192 496 64 ) +4 5 (80 512 192 ) (80 512 64 ) (80 496 64 ) (80 496 192 ) +4 6 (48 496 192 ) (48 496 64 ) (48 512 64 ) (48 512 192 ) +4 6 (16 512 192 ) (16 512 64 ) (16 496 64 ) (16 496 192 ) +4 6 (16 512 192 ) (48 512 192 ) (48 512 64 ) (16 512 64 ) +4 7 (192 512 64 ) (192 496 64 ) (192 496 0 ) (192 512 0 ) +4 7 (0 496 0 ) (0 512 0 ) (192 512 0 ) (192 496 0 ) +4 7 (16 512 64 ) (0 512 64 ) (0 496 64 ) (16 496 64 ) +4 7 (80 512 64 ) (48 512 64 ) (48 496 64 ) (80 496 64 ) +4 7 (0 512 64 ) (192 512 64 ) (192 512 0 ) (0 512 0 ) +4 8 (176 0 0 ) (192 0 0 ) (192 0 128 ) (176 0 128 ) +4 8 (80 496 64 ) (48 496 64 ) (48 496 192 ) (80 496 192 ) +4 8 (16 496 64 ) (0 496 64 ) (0 496 192 ) (16 496 192 ) +4 8 (192 496 128 ) (192 160 128 ) (192 192 0 ) (192 496 0 ) +4 8 (192 96 128 ) (192 0 128 ) (192 0 0 ) (192 64 0 ) +4 8 (192 496 128 ) (192 496 192 ) (192 0 192 ) (192 0 128 ) +4 8 (192 0 0 ) (0 0 0 ) (0 496 0 ) (192 496 0 ) +4 9 (224 -256 0 ) (640 -256 0 ) (640 -256 256 ) (224 -256 256 ) +4 9 (640 -256 256 ) (640 -256 0 ) (640 0 0 ) (640 0 256 ) +4 9 (224 0 0 ) (640 0 0 ) (640 -256 0 ) (224 -256 0 ) +4 9 (224 -256 256 ) (640 -256 256 ) (640 0 256 ) (224 0 256 ) +4 9 (224 0 0 ) (224 -256 0 ) (224 -256 256 ) (224 0 256 ) +4 10 (80 -256 128 ) (80 -256 192 ) (80 -240 192 ) (80 -240 128 ) +4 10 (176 0 128 ) (192 0 128 ) (192 -64 128 ) (176 -64 128 ) +4 10 (192 -256 128 ) (192 -256 256 ) (80 -256 256 ) (80 -256 128 ) +4 10 (80 -256 256 ) (192 -256 256 ) (192 0 256 ) (80 0 256 ) +4 10 (192 0 128 ) (192 0 256 ) (192 -256 256 ) (192 -256 128 ) +4 11 (176 -256 0 ) (192 -256 0 ) (192 -256 128 ) (176 -256 128 ) +4 11 (192 -64 0 ) (192 -256 0 ) (176 -256 0 ) (176 -64 0 ) +4 11 (192 -64 128 ) (192 -256 128 ) (192 -256 0 ) (192 -64 0 ) +4 11 (192 -64 128 ) (192 -64 0 ) (176 -64 0 ) (176 -64 128 ) +4 12 (80 -256 64 ) (80 -256 128 ) (80 -240 128 ) (80 -240 64 ) +4 12 (176 0 128 ) (176 -64 128 ) (176 -64 0 ) (176 0 0 ) +4 12 (80 0 0 ) (176 0 0 ) (176 -256 0 ) (80 -256 0 ) +4 12 (80 -256 0 ) (176 -256 0 ) (176 -256 128 ) (80 -256 128 ) +4 13 (16 -240 192 ) (0 -240 192 ) (0 -240 64 ) (16 -240 64 ) +4 13 (80 -240 64 ) (80 -240 192 ) (48 -240 192 ) (48 -240 64 ) +4 13 (80 -240 256 ) (80 0 256 ) (0 0 256 ) (0 -240 256 ) +4 13 (0 -240 0 ) (0 0 0 ) (80 0 0 ) (80 -240 0 ) +4 14 (0 -240 192 ) (16 -240 192 ) (16 -256 192 ) (0 -256 192 ) +4 14 (48 -240 192 ) (80 -240 192 ) (80 -256 192 ) (48 -256 192 ) +4 14 (80 -256 192 ) (80 -256 256 ) (0 -256 256 ) (0 -256 192 ) +4 14 (80 -256 256 ) (80 -240 256 ) (0 -240 256 ) (0 -256 256 ) +4 15 (48 -240 192 ) (48 -256 192 ) (48 -256 64 ) (48 -240 64 ) +4 15 (48 -256 192 ) (16 -256 192 ) (16 -256 64 ) (48 -256 64 ) +4 15 (16 -240 64 ) (16 -256 64 ) (16 -256 192 ) (16 -240 192 ) +4 16 (0 -256 64 ) (16 -256 64 ) (16 -240 64 ) (0 -240 64 ) +4 16 (48 -256 64 ) (80 -256 64 ) (80 -240 64 ) (48 -240 64 ) +4 16 (0 -256 0 ) (0 -240 0 ) (80 -240 0 ) (80 -256 0 ) +4 16 (0 -256 0 ) (80 -256 0 ) (80 -256 64 ) (0 -256 64 ) +4 17 (-208 512 192 ) (-176 512 192 ) (-176 496 192 ) (-208 496 192 ) +4 17 (-144 512 192 ) (-112 512 192 ) (-112 496 192 ) (-144 496 192 ) +4 17 (-80 512 192 ) (-48 512 192 ) (-48 496 192 ) (-80 496 192 ) +4 17 (-16 512 192 ) (0 512 192 ) (0 496 192 ) (-16 496 192 ) +4 17 (0 512 256 ) (-256 512 256 ) (-256 0 256 ) (0 0 256 ) +4 17 (-256 512 256 ) (0 512 256 ) (0 512 192 ) (-256 512 192 ) +4 17 (-256 0 256 ) (-256 512 256 ) (-256 512 192 ) (-256 0 192 ) +4 18 (-16 496 192 ) (-16 496 64 ) (-16 512 64 ) (-16 512 192 ) +4 18 (-48 512 192 ) (-16 512 192 ) (-16 512 64 ) (-48 512 64 ) +4 18 (-48 512 192 ) (-48 512 64 ) (-48 496 64 ) (-48 496 192 ) +4 19 (-112 512 192 ) (-112 512 64 ) (-112 496 64 ) (-112 496 192 ) +4 19 (-112 512 192 ) (-80 512 192 ) (-80 512 64 ) (-112 512 64 ) +4 19 (-80 496 192 ) (-80 496 64 ) (-80 512 64 ) (-80 512 192 ) +4 20 (-176 512 192 ) (-176 512 64 ) (-176 496 64 ) (-176 496 192 ) +4 20 (-176 512 192 ) (-144 512 192 ) (-144 512 64 ) (-176 512 64 ) +4 20 (-144 496 192 ) (-144 496 64 ) (-144 512 64 ) (-144 512 192 ) +4 21 (-256 512 192 ) (-256 512 64 ) (-256 496 64 ) (-256 496 192 ) +4 21 (-256 512 192 ) (-208 512 192 ) (-208 512 64 ) (-256 512 64 ) +4 21 (-208 496 192 ) (-208 496 64 ) (-208 512 64 ) (-208 512 192 ) +4 22 (0 496 0 ) (-256 496 0 ) (-256 512 0 ) (0 512 0 ) +4 22 (0 512 64 ) (-16 512 64 ) (-16 496 64 ) (0 496 64 ) +4 22 (-48 512 64 ) (-80 512 64 ) (-80 496 64 ) (-48 496 64 ) +4 22 (-112 512 64 ) (-144 512 64 ) (-144 496 64 ) (-112 496 64 ) +4 22 (-176 512 64 ) (-208 512 64 ) (-208 496 64 ) (-176 496 64 ) +4 22 (-256 512 0 ) (-256 512 64 ) (0 512 64 ) (0 512 0 ) +4 22 (-256 512 64 ) (-256 512 0 ) (-256 496 0 ) (-256 496 64 ) +4 23 (0 0 0 ) (-256 0 0 ) (-256 496 0 ) (0 496 0 ) +4 23 (-176 496 64 ) (-208 496 64 ) (-208 496 192 ) (-176 496 192 ) +4 23 (-112 496 64 ) (-144 496 64 ) (-144 496 192 ) (-112 496 192 ) +4 23 (-48 496 64 ) (-80 496 64 ) (-80 496 192 ) (-48 496 192 ) +4 23 (-16 496 64 ) (-16 496 192 ) (0 496 192 ) (0 496 64 ) +4 23 (-256 496 192 ) (-256 496 0 ) (-256 0 0 ) (-256 0 192 ) +4 24 (-112 -256 192 ) (-144 -256 192 ) (-144 -240 192 ) (-112 -240 192 ) +4 24 (-48 -256 192 ) (-80 -256 192 ) (-80 -240 192 ) (-48 -240 192 ) +4 24 (-176 -256 192 ) (-208 -256 192 ) (-208 -240 192 ) (-176 -240 192 ) +4 24 (0 -240 192 ) (0 -256 192 ) (-16 -256 192 ) (-16 -240 192 ) +4 24 (0 -256 256 ) (0 0 256 ) (-256 0 256 ) (-256 -256 256 ) +4 24 (-256 0 256 ) (-256 0 192 ) (-256 -256 192 ) (-256 -256 256 ) +4 24 (0 -256 256 ) (-256 -256 256 ) (-256 -256 192 ) (0 -256 192 ) +4 25 (-112 -240 192 ) (-144 -240 192 ) (-144 -240 64 ) (-112 -240 64 ) +4 25 (-48 -240 192 ) (-80 -240 192 ) (-80 -240 64 ) (-48 -240 64 ) +4 25 (-176 -240 192 ) (-208 -240 192 ) (-208 -240 64 ) (-176 -240 64 ) +4 25 (0 -240 64 ) (0 -240 192 ) (-16 -240 192 ) (-16 -240 64 ) +4 25 (0 -240 0 ) (-256 -240 0 ) (-256 0 0 ) (0 0 0 ) +4 25 (-256 0 0 ) (-256 -240 0 ) (-256 -240 192 ) (-256 0 192 ) +4 26 (-48 -240 192 ) (-48 -240 64 ) (-48 -256 64 ) (-48 -256 192 ) +4 26 (-48 -256 64 ) (-16 -256 64 ) (-16 -256 192 ) (-48 -256 192 ) +4 26 (-16 -256 192 ) (-16 -256 64 ) (-16 -240 64 ) (-16 -240 192 ) +4 27 (-112 -256 64 ) (-80 -256 64 ) (-80 -256 192 ) (-112 -256 192 ) +4 27 (-80 -256 192 ) (-80 -256 64 ) (-80 -240 64 ) (-80 -240 192 ) +4 27 (-112 -240 192 ) (-112 -240 64 ) (-112 -256 64 ) (-112 -256 192 ) +4 28 (-144 -256 192 ) (-144 -256 64 ) (-144 -240 64 ) (-144 -240 192 ) +4 28 (-176 -256 64 ) (-144 -256 64 ) (-144 -256 192 ) (-176 -256 192 ) +4 28 (-176 -240 192 ) (-176 -240 64 ) (-176 -256 64 ) (-176 -256 192 ) +4 29 (-208 -256 192 ) (-208 -256 64 ) (-208 -240 64 ) (-208 -240 192 ) +4 29 (-256 -256 192 ) (-256 -256 64 ) (-208 -256 64 ) (-208 -256 192 ) +4 29 (-256 -240 192 ) (-256 -240 64 ) (-256 -256 64 ) (-256 -256 192 ) +4 30 (-256 -256 0 ) (-256 -240 0 ) (0 -240 0 ) (0 -256 0 ) +4 30 (-16 -256 64 ) (0 -256 64 ) (0 -240 64 ) (-16 -240 64 ) +4 30 (-208 -256 64 ) (-176 -256 64 ) (-176 -240 64 ) (-208 -240 64 ) +4 30 (-80 -256 64 ) (-48 -256 64 ) (-48 -240 64 ) (-80 -240 64 ) +4 30 (-144 -256 64 ) (-112 -256 64 ) (-112 -240 64 ) (-144 -240 64 ) +4 30 (-256 -256 64 ) (-256 -240 64 ) (-256 -240 0 ) (-256 -256 0 ) +4 30 (-256 -256 64 ) (-256 -256 0 ) (0 -256 0 ) (0 -256 64 ) diff --git a/fakk/maps/example/door.pth b/fakk/maps/example/door.pth new file mode 100644 index 0000000..8e85fa7 Binary files /dev/null and b/fakk/maps/example/door.pth differ diff --git a/fakk/maps/example/door.scr b/fakk/maps/example/door.scr new file mode 100644 index 0000000..68f4465 --- /dev/null +++ b/fakk/maps/example/door.scr @@ -0,0 +1,18 @@ +waitforplayer +start: + +end + +dude_go_thread: + +$dude thread dude_AIthread + +end + +dude_AIthread: +local.self walkto $dude_dest +waitFor local.self +local.self idle STAND_IDLE + +end + diff --git a/fakk/maps/example/doors.bsp b/fakk/maps/example/doors.bsp new file mode 100644 index 0000000..1b59506 Binary files /dev/null and b/fakk/maps/example/doors.bsp differ diff --git a/fakk/maps/example/doors.map b/fakk/maps/example/doors.map new file mode 100644 index 0000000..e8d34b2 --- /dev/null +++ b/fakk/maps/example/doors.map @@ -0,0 +1,330 @@ +{ +"classname" "worldspawn" +// brush 0 +{ +( 88 264 -8 ) ( -96 264 -8 ) ( -96 256 -8 ) common/areaportal 8 -8 0.00 1 1 805339136 16528 0 +( -96 256 264 ) ( -96 264 264 ) ( 88 264 264 ) common/areaportal 8 -8 0.00 1 1 805339136 16528 0 +( -96 256 8 ) ( 88 256 8 ) ( 88 256 0 ) common/areaportal 8 0 0.00 1 1 805339136 16528 0 +( 88 256 8 ) ( 88 264 8 ) ( 88 264 0 ) common/areaportal 8 0 0.00 1 1 805339136 16528 0 +( 88 264 8 ) ( -96 264 8 ) ( -96 264 0 ) common/areaportal 8 0 0.00 1 1 805339136 16528 0 +( -96 264 8 ) ( -96 256 8 ) ( -96 256 0 ) common/areaportal 8 0 0.00 1 1 805339136 16528 0 +} +// brush 1 +{ +( 96 784 -8 ) ( -88 784 -8 ) ( -88 776 -8 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( -88 776 264 ) ( -88 784 264 ) ( 96 784 264 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( -88 776 8 ) ( 96 776 8 ) ( 96 776 0 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( 96 776 8 ) ( 96 784 8 ) ( 96 784 0 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( 96 784 8 ) ( -88 784 8 ) ( -88 784 0 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( -88 784 8 ) ( -88 776 8 ) ( -88 776 0 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +} +// brush 2 +{ +( 264 784 -8 ) ( -264 784 -8 ) ( -264 248 -8 ) eden/WL_basement_2w 0 16 0.00 0.500000 0.500000 0 0 0 +( -264 248 264 ) ( -264 784 264 ) ( 264 784 264 ) eden/WL_basement_2w 0 16 0.00 0.500000 0.500000 0 0 0 +( -64 232 8 ) ( -64 768 8 ) ( -64 768 0 ) eden/WL_basement_2w -16 0 0.00 0.500000 0.500000 0 0 0 +( 264 792 8 ) ( -264 792 8 ) ( -264 792 0 ) eden/WL_basement_2w 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 784 8 ) ( -264 248 8 ) ( -264 248 0 ) eden/WL_basement_2w -16 0 0.00 0.500000 0.500000 0 0 0 +( -264 768 8 ) ( 264 768 8 ) ( -264 768 0 ) eden/WL_basement_2w 0 0 0.00 0.500000 0.500000 0 0 0 +} +// brush 3 +{ +( 592 784 -8 ) ( 64 784 -8 ) ( 64 248 -8 ) eden/WL_basement_2w -144 16 0.00 0.500000 0.500000 0 0 0 +( 64 248 264 ) ( 64 784 264 ) ( 592 784 264 ) eden/WL_basement_2w -144 16 0.00 0.500000 0.500000 0 0 0 +( 264 232 8 ) ( 264 768 8 ) ( 264 768 0 ) eden/WL_basement_2w -16 0 0.00 0.500000 0.500000 0 0 0 +( 592 792 8 ) ( 64 792 8 ) ( 64 792 0 ) eden/WL_basement_2w -144 0 0.00 0.500000 0.500000 0 0 0 +( 64 784 8 ) ( 64 248 8 ) ( 64 248 0 ) eden/WL_basement_2w -16 0 0.00 0.500000 0.500000 0 0 0 +( 64 768 8 ) ( 592 768 8 ) ( 64 768 0 ) eden/WL_basement_2w -144 0 0.00 0.500000 0.500000 0 0 0 +} +// brush 4 +{ +( 464 784 128 ) ( -64 784 128 ) ( -64 248 128 ) eden/WL_basement_2w 112 16 0.00 0.500000 0.500000 0 0 0 +( -64 248 264 ) ( -64 784 264 ) ( 464 784 264 ) eden/WL_basement_2w 112 16 0.00 0.500000 0.500000 0 0 0 +( 64 224 8 ) ( 64 760 8 ) ( 64 760 0 ) eden/WL_basement_2w -16 0 0.00 0.500000 0.500000 0 0 0 +( 424 792 8 ) ( -104 792 8 ) ( -104 792 0 ) eden/WL_basement_2w 112 0 0.00 0.500000 0.500000 0 0 0 +( -64 784 8 ) ( -64 248 8 ) ( -64 248 0 ) eden/WL_basement_2w -16 0 0.00 0.500000 0.500000 0 0 0 +( -64 768 8 ) ( 464 768 8 ) ( -64 768 0 ) eden/WL_basement_2w 112 0 0.00 0.500000 0.500000 0 0 0 +} +// brush 5 +{ +( 464 264 128 ) ( -64 264 128 ) ( -64 -272 128 ) eden/WL_basement_2w 112 0 0.00 0.500000 0.500000 0 0 0 +( -64 -272 264 ) ( -64 264 264 ) ( 464 264 264 ) eden/WL_basement_2w 112 0 0.00 0.500000 0.500000 0 0 0 +( 64 -296 8 ) ( 64 240 8 ) ( 64 240 0 ) eden/WL_basement_2w 0 0 0.00 0.500000 0.500000 0 0 0 +( 424 272 8 ) ( -104 272 8 ) ( -104 272 0 ) eden/WL_basement_2w 112 0 0.00 0.500000 0.500000 0 0 0 +( -64 264 8 ) ( -64 -272 8 ) ( -64 -272 0 ) eden/WL_basement_2w 0 0 0.00 0.500000 0.500000 0 0 0 +( -64 248 8 ) ( 464 248 8 ) ( -64 248 0 ) eden/WL_basement_2w 112 0 0.00 0.500000 0.500000 0 0 0 +} +// brush 6 +{ +( 592 264 -8 ) ( 64 264 -8 ) ( 64 -272 -8 ) eden/WL_basement_2w -144 0 0.00 0.500000 0.500000 0 0 0 +( 64 -272 264 ) ( 64 264 264 ) ( 592 264 264 ) eden/WL_basement_2w -144 0 0.00 0.500000 0.500000 0 0 0 +( 264 -288 8 ) ( 264 248 8 ) ( 264 248 0 ) eden/WL_basement_2w 0 0 0.00 0.500000 0.500000 0 0 0 +( 592 272 8 ) ( 64 272 8 ) ( 64 272 0 ) eden/WL_basement_2w -144 0 0.00 0.500000 0.500000 0 0 0 +( 64 264 8 ) ( 64 -272 8 ) ( 64 -272 0 ) eden/WL_basement_2w 0 0 0.00 0.500000 0.500000 0 0 0 +( 64 248 8 ) ( 592 248 8 ) ( 64 248 0 ) eden/WL_basement_2w -144 0 0.00 0.500000 0.500000 0 0 0 +} +// brush 7 +{ +( 264 1304 -8 ) ( -264 1304 -8 ) ( -264 768 -8 ) eden/WL_basement_2w 0 32 0.00 0.500000 0.500000 0 0 0 +( -264 768 264 ) ( -264 1304 264 ) ( 264 1304 264 ) eden/WL_basement_2w 0 32 0.00 0.500000 0.500000 0 0 0 +( -264 776 8 ) ( 264 776 8 ) ( 264 776 0 ) eden/WL_basement_2w 0 0 0.00 0.500000 0.500000 0 0 0 +( 264 1304 8 ) ( -264 1304 8 ) ( -264 1304 0 ) eden/WL_basement_2w 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 1304 8 ) ( -264 768 8 ) ( -264 768 0 ) eden/WL_basement_2w -32 0 0.00 0.500000 0.500000 0 0 0 +( -256 768 8 ) ( -256 1304 8 ) ( -256 768 0 ) eden/WL_basement_2w -32 0 0.00 0.500000 0.500000 0 0 0 +} +// brush 8 +{ +( 264 1304 -8 ) ( -264 1304 -8 ) ( -264 768 -8 ) eden/WL_basement_2w 0 32 0.00 0.500000 0.500000 0 0 0 +( -264 768 264 ) ( -264 1304 264 ) ( 264 1304 264 ) eden/WL_basement_2w 0 32 0.00 0.500000 0.500000 0 0 0 +( 264 768 8 ) ( 264 1304 8 ) ( 264 1304 0 ) eden/WL_basement_2w -32 0 0.00 0.500000 0.500000 0 0 0 +( 264 1304 8 ) ( -264 1304 8 ) ( -264 1304 0 ) eden/WL_basement_2w 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 1304 8 ) ( -264 768 8 ) ( -264 768 0 ) eden/WL_basement_2w -32 0 0.00 0.500000 0.500000 0 0 0 +( -264 1296 8 ) ( 264 1296 8 ) ( -264 1296 0 ) eden/WL_basement_2w 0 0 0.00 0.500000 0.500000 0 0 0 +} +// brush 9 +{ +( 264 1304 -8 ) ( -264 1304 -8 ) ( -264 768 -8 ) eden/WL_basement_2w 0 32 0.00 0.500000 0.500000 0 0 0 +( -264 768 264 ) ( -264 1304 264 ) ( 264 1304 264 ) eden/WL_basement_2w 0 32 0.00 0.500000 0.500000 0 0 0 +( -264 776 8 ) ( 264 776 8 ) ( 264 776 0 ) eden/WL_basement_2w 0 0 0.00 0.500000 0.500000 0 0 0 +( 264 768 8 ) ( 264 1304 8 ) ( 264 1304 0 ) eden/WL_basement_2w -32 0 0.00 0.500000 0.500000 0 0 0 +( 264 1304 8 ) ( -264 1304 8 ) ( -264 1304 0 ) eden/WL_basement_2w 0 0 0.00 0.500000 0.500000 0 0 0 +( 256 1304 8 ) ( 256 768 8 ) ( 256 1304 0 ) eden/WL_basement_2w -32 0 0.00 0.500000 0.500000 0 0 0 +} +// brush 10 +{ +( -264 768 264 ) ( -264 1304 264 ) ( 264 1304 264 ) eden/WL_basement_2w 0 32 0.00 0.500000 0.500000 0 0 0 +( -264 776 8 ) ( 264 776 8 ) ( 264 776 0 ) eden/WL_basement_2w 0 0 0.00 0.500000 0.500000 0 0 0 +( 264 768 8 ) ( 264 1304 8 ) ( 264 1304 0 ) eden/WL_basement_2w -32 0 0.00 0.500000 0.500000 0 0 0 +( 264 1304 8 ) ( -264 1304 8 ) ( -264 1304 0 ) eden/WL_basement_2w 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 1304 8 ) ( -264 768 8 ) ( -264 768 0 ) eden/WL_basement_2w -32 0 0.00 0.500000 0.500000 0 0 0 +( -264 1304 256 ) ( -264 768 256 ) ( 264 1304 256 ) eden/WL_basement_2w 0 32 0.00 0.500000 0.500000 0 0 0 +} +// brush 11 +{ +( 264 1304 -8 ) ( -264 1304 -8 ) ( -264 768 -8 ) eden/FL_edenhouse2 0 32 0.00 0.500000 0.500000 0 0 0 +( -264 776 8 ) ( 264 776 8 ) ( 264 776 0 ) eden/FL_edenhouse2 0 0 0.00 0.500000 0.500000 0 0 0 +( 264 768 8 ) ( 264 1304 8 ) ( 264 1304 0 ) eden/FL_edenhouse2 -32 0 0.00 0.500000 0.500000 0 0 0 +( 264 1304 8 ) ( -264 1304 8 ) ( -264 1304 0 ) eden/FL_edenhouse2 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 1304 8 ) ( -264 768 8 ) ( -264 768 0 ) eden/FL_edenhouse2 -32 0 0.00 0.500000 0.500000 0 0 0 +( -264 1304 0 ) ( 264 1304 0 ) ( -264 768 0 ) eden/FL_edenhouse2 0 32 0.00 0.500000 0.500000 0 0 0 +} +// brush 12 +{ +( 264 784 -8 ) ( -264 784 -8 ) ( -264 248 -8 ) eden/FL_edenhouse2 0 16 0.00 0.500000 0.500000 0 0 0 +( -264 256 8 ) ( 264 256 8 ) ( 264 256 0 ) eden/FL_edenhouse2 0 0 0.00 0.500000 0.500000 0 0 0 +( 264 248 8 ) ( 264 784 8 ) ( 264 784 0 ) eden/FL_edenhouse2 -16 0 0.00 0.500000 0.500000 0 0 0 +( 264 784 8 ) ( -264 784 8 ) ( -264 784 0 ) eden/FL_edenhouse2 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 784 8 ) ( -264 248 8 ) ( -264 248 0 ) eden/FL_edenhouse2 -16 0 0.00 0.500000 0.500000 0 0 0 +( -264 784 0 ) ( 264 784 0 ) ( -264 248 0 ) eden/FL_edenhouse2 0 16 0.00 0.500000 0.500000 0 0 0 +} +// brush 13 +{ +( -264 248 264 ) ( -264 784 264 ) ( 264 784 264 ) eden/WL_basement_2w 0 16 0.00 0.500000 0.500000 0 0 0 +( -264 256 8 ) ( 264 256 8 ) ( 264 256 0 ) eden/WL_basement_2w 0 0 0.00 0.500000 0.500000 0 0 0 +( 264 248 8 ) ( 264 784 8 ) ( 264 784 0 ) eden/WL_basement_2w -16 0 0.00 0.500000 0.500000 0 0 0 +( 264 784 8 ) ( -264 784 8 ) ( -264 784 0 ) eden/WL_basement_2w 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 784 8 ) ( -264 248 8 ) ( -264 248 0 ) eden/WL_basement_2w -16 0 0.00 0.500000 0.500000 0 0 0 +( -264 784 256 ) ( -264 248 256 ) ( 264 784 256 ) eden/WL_basement_2w 0 16 0.00 0.500000 0.500000 0 0 0 +} +// brush 14 +{ +( 264 784 -8 ) ( -264 784 -8 ) ( -264 248 -8 ) eden/WL_basement_2w 0 16 0.00 0.500000 0.500000 0 0 0 +( -264 248 264 ) ( -264 784 264 ) ( 264 784 264 ) eden/WL_basement_2w 0 16 0.00 0.500000 0.500000 0 0 0 +( -264 256 8 ) ( 264 256 8 ) ( 264 256 0 ) eden/WL_basement_2w 0 0 0.00 0.500000 0.500000 0 0 0 +( 264 248 8 ) ( 264 784 8 ) ( 264 784 0 ) eden/WL_basement_2w -16 0 0.00 0.500000 0.500000 0 0 0 +( 264 784 8 ) ( -264 784 8 ) ( -264 784 0 ) eden/WL_basement_2w 0 0 0.00 0.500000 0.500000 0 0 0 +( 256 784 8 ) ( 256 248 8 ) ( 256 784 0 ) eden/WL_basement_2w -16 0 0.00 0.500000 0.500000 0 0 0 +} +// brush 15 +{ +( 264 784 -8 ) ( -264 784 -8 ) ( -264 248 -8 ) eden/WL_basement_2w 0 16 0.00 0.500000 0.500000 0 0 0 +( -264 248 264 ) ( -264 784 264 ) ( 264 784 264 ) eden/WL_basement_2w 0 16 0.00 0.500000 0.500000 0 0 0 +( -264 256 8 ) ( 264 256 8 ) ( 264 256 0 ) eden/WL_basement_2w 0 0 0.00 0.500000 0.500000 0 0 0 +( 264 784 8 ) ( -264 784 8 ) ( -264 784 0 ) eden/WL_basement_2w 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 784 8 ) ( -264 248 8 ) ( -264 248 0 ) eden/WL_basement_2w -16 0 0.00 0.500000 0.500000 0 0 0 +( -256 248 8 ) ( -256 784 8 ) ( -256 248 0 ) eden/WL_basement_2w -16 0 0.00 0.500000 0.500000 0 0 0 +} +// brush 16 +{ +( 264 264 -8 ) ( -264 264 -8 ) ( -264 -272 -8 ) eden/WL_basement_2w 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 -272 264 ) ( -264 264 264 ) ( 264 264 264 ) eden/WL_basement_2w 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 -264 8 ) ( 264 -264 8 ) ( 264 -264 0 ) eden/WL_basement_2w 0 0 0.00 0.500000 0.500000 0 0 0 +( 264 264 8 ) ( -264 264 8 ) ( -264 264 0 ) eden/WL_basement_2w 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 264 8 ) ( -264 -272 8 ) ( -264 -272 0 ) eden/WL_basement_2w 0 0 0.00 0.500000 0.500000 0 0 0 +( -256 -272 8 ) ( -256 264 8 ) ( -256 -272 0 ) eden/WL_basement_2w 0 0 0.00 0.500000 0.500000 0 0 0 +} +// brush 17 +{ +( 264 264 -8 ) ( -264 264 -8 ) ( -264 -272 -8 ) eden/WL_basement_2w 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 -272 264 ) ( -264 264 264 ) ( 264 264 264 ) eden/WL_basement_2w 0 0 0.00 0.500000 0.500000 0 0 0 +( -64 -288 8 ) ( -64 248 8 ) ( -64 248 0 ) eden/WL_basement_2w 0 0 0.00 0.500000 0.500000 0 0 0 +( 264 272 8 ) ( -264 272 8 ) ( -264 272 0 ) eden/WL_basement_2w 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 264 8 ) ( -264 -272 8 ) ( -264 -272 0 ) eden/WL_basement_2w 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 248 8 ) ( 264 248 8 ) ( -264 248 0 ) eden/WL_basement_2w 0 0 0.00 0.500000 0.500000 0 0 0 +} +// brush 18 +{ +( 264 264 -8 ) ( -264 264 -8 ) ( -264 -272 -8 ) eden/WL_basement_2w 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 -272 264 ) ( -264 264 264 ) ( 264 264 264 ) eden/WL_basement_2w 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 -264 8 ) ( 264 -264 8 ) ( 264 -264 0 ) eden/WL_basement_2w 0 0 0.00 0.500000 0.500000 0 0 0 +( 264 -272 8 ) ( 264 264 8 ) ( 264 264 0 ) eden/WL_basement_2w 0 0 0.00 0.500000 0.500000 0 0 0 +( 264 264 8 ) ( -264 264 8 ) ( -264 264 0 ) eden/WL_basement_2w 0 0 0.00 0.500000 0.500000 0 0 0 +( 256 264 8 ) ( 256 -272 8 ) ( 256 264 0 ) eden/WL_basement_2w 0 0 0.00 0.500000 0.500000 0 0 0 +} +// brush 19 +{ +( 264 264 -8 ) ( -264 264 -8 ) ( -264 -272 -8 ) eden/WL_basement_2w 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 -272 264 ) ( -264 264 264 ) ( 264 264 264 ) eden/WL_basement_2w 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 -264 8 ) ( 264 -264 8 ) ( 264 -264 0 ) eden/WL_basement_2w 0 0 0.00 0.500000 0.500000 0 0 0 +( 264 -272 8 ) ( 264 264 8 ) ( 264 264 0 ) eden/WL_basement_2w 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 264 8 ) ( -264 -272 8 ) ( -264 -272 0 ) eden/WL_basement_2w 0 0 0.00 0.500000 0.500000 0 0 0 +( 264 -256 8 ) ( -264 -256 8 ) ( 264 -256 0 ) eden/WL_basement_2w 0 0 0.00 0.500000 0.500000 0 0 0 +} +// brush 20 +{ +( -264 -272 264 ) ( -264 264 264 ) ( 264 264 264 ) eden/WL_basement_2w 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 -264 8 ) ( 264 -264 8 ) ( 264 -264 0 ) eden/WL_basement_2w 0 0 0.00 0.500000 0.500000 0 0 0 +( 264 -272 8 ) ( 264 264 8 ) ( 264 264 0 ) eden/WL_basement_2w 0 0 0.00 0.500000 0.500000 0 0 0 +( 264 264 8 ) ( -264 264 8 ) ( -264 264 0 ) eden/WL_basement_2w 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 264 8 ) ( -264 -272 8 ) ( -264 -272 0 ) eden/WL_basement_2w 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 264 256 ) ( -264 -272 256 ) ( 264 264 256 ) eden/WL_basement_2w 0 0 0.00 0.500000 0.500000 0 0 0 +} +// brush 21 +{ +( 264 264 -8 ) ( -264 264 -8 ) ( -264 -272 -8 ) eden/FL_edenhouse2 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 -264 8 ) ( 264 -264 8 ) ( 264 -264 0 ) eden/FL_edenhouse2 0 0 0.00 0.500000 0.500000 0 0 0 +( 264 -272 8 ) ( 264 264 8 ) ( 264 264 0 ) eden/FL_edenhouse2 0 0 0.00 0.500000 0.500000 0 0 0 +( 264 264 8 ) ( -264 264 8 ) ( -264 264 0 ) eden/FL_edenhouse2 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 264 8 ) ( -264 -272 8 ) ( -264 -272 0 ) eden/FL_edenhouse2 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 264 0 ) ( 264 264 0 ) ( -264 -272 0 ) eden/FL_edenhouse2 0 0 0.00 0.500000 0.500000 0 0 0 +} +} +// entity 1 +{ +"classname" "func_door" +// brush 0 +{ +( 64 264 0 ) ( 0 264 0 ) ( 0 256 0 ) eden/door8 0 0 0.00 1 1 0 0 0 +( 0 256 128 ) ( 0 264 128 ) ( 64 264 128 ) eden/door8 0 0 0.00 1 1 0 0 0 +( 0 256 264 ) ( 64 256 264 ) ( 64 256 -8 ) eden/door8 0 0 0.00 1 1 0 0 0 +( 64 256 264 ) ( 64 264 264 ) ( 64 264 -8 ) eden/door8 0 0 0.00 1 1 0 0 0 +( 64 264 264 ) ( 0 264 264 ) ( 0 264 -8 ) eden/door8 0 0 0.00 1 1 0 0 0 +( 0 264 136 ) ( 0 256 136 ) ( 0 256 -136 ) eden/door8 0 0 0.00 1 1 0 0 0 +} +// brush 1 +{ +( 72 264 0 ) ( 56 264 0 ) ( 56 248 0 ) common/origin 0 -8 0.00 1 1 16777216 16512 0 +( 56 248 128 ) ( 56 264 128 ) ( 72 264 128 ) common/origin 0 -8 0.00 1 1 16777216 16512 0 +( 56 248 128 ) ( 72 248 128 ) ( 72 248 0 ) common/origin 0 0 0.00 1 1 16777216 16512 0 +( 72 248 128 ) ( 72 264 128 ) ( 72 264 0 ) common/origin 8 0 0.00 1 1 16777216 16512 0 +( 72 272 128 ) ( 56 272 128 ) ( 56 272 0 ) common/origin 0 0 0.00 1 1 16777216 16512 0 +( 56 264 128 ) ( 56 248 128 ) ( 56 248 0 ) common/origin 8 0 0.00 1 1 16777216 16512 0 +} +} +// entity 2 +{ +"angle" "180" +"classname" "func_door" +// brush 0 +{ +( -56 264 0 ) ( -72 264 0 ) ( -72 248 0 ) common/origin 0 -8 0.00 1 1 16777216 16512 0 +( -72 248 128 ) ( -72 264 128 ) ( -56 264 128 ) common/origin 0 -8 0.00 1 1 16777216 16512 0 +( -72 248 128 ) ( -56 248 128 ) ( -56 248 0 ) common/origin 0 0 0.00 1 1 16777216 16512 0 +( -56 248 128 ) ( -56 264 128 ) ( -56 264 0 ) common/origin 8 0 0.00 1 1 16777216 16512 0 +( -56 272 128 ) ( -72 272 128 ) ( -72 272 0 ) common/origin 0 0 0.00 1 1 16777216 16512 0 +( -72 264 128 ) ( -72 248 128 ) ( -72 248 0 ) common/origin 8 0 0.00 1 1 16777216 16512 0 +} +// brush 1 +{ +( 0 264 0 ) ( -64 264 0 ) ( -64 256 0 ) eden/door8 0 0 0.00 1 1 0 0 0 +( -64 256 128 ) ( -64 264 128 ) ( 0 264 128 ) eden/door8 0 0 0.00 1 1 0 0 0 +( -64 256 264 ) ( 0 256 264 ) ( 0 256 -8 ) eden/door8 0 0 0.00 1 1 0 0 0 +( 0 256 136 ) ( 0 264 136 ) ( 0 264 -136 ) eden/door8 0 0 0.00 1 1 0 0 0 +( 0 264 264 ) ( -64 264 264 ) ( -64 264 -8 ) eden/door8 0 0 0.00 1 1 0 0 0 +( -64 264 264 ) ( -64 256 264 ) ( -64 256 -8 ) eden/door8 0 0 0.00 1 1 0 0 0 +} +} +// entity 3 +{ +"classname" "func_rotatingdoor" +"spawnflags" "2" +"angle" "0" +// brush 0 +{ +( -56 784 0 ) ( -72 784 0 ) ( -72 768 0 ) common/origin 0 0 0.00 1 1 16777216 16512 0 +( -72 768 128 ) ( -72 784 128 ) ( -56 784 128 ) common/origin 0 0 0.00 1 1 16777216 16512 0 +( -72 768 128 ) ( -56 768 128 ) ( -56 768 0 ) common/origin 0 0 0.00 1 1 16777216 16512 0 +( -56 768 128 ) ( -56 784 128 ) ( -56 784 0 ) common/origin 0 0 0.00 1 1 16777216 16512 0 +( -56 792 128 ) ( -72 792 128 ) ( -72 792 0 ) common/origin 0 0 0.00 1 1 16777216 16512 0 +( -72 784 128 ) ( -72 768 128 ) ( -72 768 0 ) common/origin 0 0 0.00 1 1 16777216 16512 0 +} +// brush 1 +{ +( 0 784 0 ) ( -64 784 0 ) ( -64 776 0 ) eden/door8 0 0 0.00 1 1 0 0 0 +( -64 776 128 ) ( -64 784 128 ) ( 0 784 128 ) eden/door8 0 0 0.00 1 1 0 0 0 +( -64 776 264 ) ( 0 776 264 ) ( 0 776 -8 ) eden/door8 0 0 0.00 1 1 0 0 0 +( 0 776 136 ) ( 0 784 136 ) ( 0 784 -136 ) eden/door8 0 0 0.00 1 1 0 0 0 +( 0 784 264 ) ( -64 784 264 ) ( -64 784 -8 ) eden/door8 0 0 0.00 1 1 0 0 0 +( -64 784 264 ) ( -64 776 264 ) ( -64 776 -8 ) eden/door8 0 0 0.00 1 1 0 0 0 +} +} +// entity 4 +{ +"spawnflags" "0" +"classname" "func_rotatingdoor" +"angle" "180" +// brush 0 +{ +( 72 784 0 ) ( 56 784 0 ) ( 56 768 0 ) common/origin 0 0 0.00 1 1 16777216 16512 0 +( 56 768 128 ) ( 56 784 128 ) ( 72 784 128 ) common/origin 0 0 0.00 1 1 16777216 16512 0 +( 56 768 128 ) ( 72 768 128 ) ( 72 768 0 ) common/origin 0 0 0.00 1 1 16777216 16512 0 +( 72 768 128 ) ( 72 784 128 ) ( 72 784 0 ) common/origin 0 0 0.00 1 1 16777216 16512 0 +( 72 792 128 ) ( 56 792 128 ) ( 56 792 0 ) common/origin 0 0 0.00 1 1 16777216 16512 0 +( 56 784 128 ) ( 56 768 128 ) ( 56 768 0 ) common/origin 0 0 0.00 1 1 16777216 16512 0 +} +// brush 1 +{ +( 64 784 0 ) ( 0 784 0 ) ( 0 776 0 ) eden/door8 0 0 0.00 1 1 0 0 0 +( 0 776 128 ) ( 0 784 128 ) ( 64 784 128 ) eden/door8 0 0 0.00 1 1 0 0 0 +( 0 776 264 ) ( 64 776 264 ) ( 64 776 -8 ) eden/door8 0 0 0.00 1 1 0 0 0 +( 64 776 264 ) ( 64 784 264 ) ( 64 784 -8 ) eden/door8 0 0 0.00 1 1 0 0 0 +( 64 784 264 ) ( 0 784 264 ) ( 0 784 -8 ) eden/door8 0 0 0.00 1 1 0 0 0 +( 0 784 136 ) ( 0 776 136 ) ( 0 776 -136 ) eden/door8 0 0 0.00 1 1 0 0 0 +} +} +// entity 5 +{ +"classname" "light" +"light" "1000" +"origin" "0 0 128" +} +// entity 6 +{ +"classname" "info_player_start" +"angle" "90" +"origin" "0 -192 16" +} +// entity 7 +{ +"origin" "0 520 128" +"light" "1000" +"classname" "light" +} +// entity 8 +{ +"origin" "0 328 16" +"angle" "90" +"classname" "info_player_start" +} +// entity 9 +{ +"classname" "light" +"light" "1000" +"origin" "0 1040 128" +} +// entity 10 +{ +"classname" "info_player_start" +"angle" "90" +"origin" "0 848 16" +} diff --git a/fakk/maps/example/doors.prt b/fakk/maps/example/doors.prt new file mode 100644 index 0000000..74f5a02 --- /dev/null +++ b/fakk/maps/example/doors.prt @@ -0,0 +1,132 @@ +PRT1 +24 +40 +88 +4 0 12 0 (0 1024 0 ) (0 1024 256 ) (0 1296 256 ) (0 1296 0 ) +4 0 1 0 (0 1024 256 ) (0 1024 0 ) (256 1024 0 ) (256 1024 256 ) +4 1 13 0 (0 792 256 ) (0 1024 256 ) (0 1024 0 ) (0 792 0 ) +4 1 6 0 (0 792 0 ) (64 792 0 ) (64 792 128 ) (0 792 128 ) +4 2 8 0 (64 768 0 ) (64 272 0 ) (64 272 128 ) (64 768 128 ) +4 2 4 0 (64 272 128 ) (64 272 256 ) (64 768 256 ) (64 768 128 ) +4 3 11 0 (64 0 0 ) (256 0 0 ) (256 0 256 ) (64 0 256 ) +4 3 10 0 (64 248 0 ) (64 0 0 ) (64 0 128 ) (64 248 128 ) +4 3 5 0 (64 0 128 ) (64 0 256 ) (64 248 256 ) (64 248 128 ) +4 4 14 0 (0 272 256 ) (0 768 256 ) (0 768 128 ) (0 272 128 ) +4 4 8 0 (64 768 128 ) (64 272 128 ) (0 272 128 ) (0 768 128 ) +4 5 15 0 (0 0 128 ) (0 0 256 ) (0 248 256 ) (0 248 128 ) +4 5 11 0 (0 0 256 ) (0 0 128 ) (64 0 128 ) (64 0 256 ) +4 5 10 0 (64 248 128 ) (64 0 128 ) (0 0 128 ) (0 248 128 ) +4 6 16 0 (0 784 128 ) (0 792 128 ) (0 792 0 ) (0 784 0 ) +4 6 7 0 (0 784 0 ) (64 784 0 ) (64 784 128 ) (0 784 128 ) +4 7 17 0 (0 776 128 ) (0 784 128 ) (0 784 0 ) (0 776 0 ) +4 7 8 0 (0 776 0 ) (64 776 0 ) (64 776 128 ) (0 776 128 ) +4 8 18 0 (0 264 128 ) (0 776 128 ) (0 776 0 ) (0 264 0 ) +4 8 9 0 (0 264 0 ) (64 264 0 ) (64 264 128 ) (0 264 128 ) +4 9 19 0 (0 256 128 ) (0 264 128 ) (0 264 0 ) (0 256 0 ) +4 9 10 0 (0 256 0 ) (64 256 0 ) (64 256 128 ) (0 256 128 ) +4 10 20 0 (0 0 0 ) (0 0 128 ) (0 256 128 ) (0 256 0 ) +4 10 11 0 (0 0 128 ) (0 0 0 ) (64 0 0 ) (64 0 128 ) +4 11 23 0 (0 0 256 ) (0 0 0 ) (0 -256 0 ) (0 -256 256 ) +4 12 13 0 (0 1024 0 ) (0 1024 256 ) (-256 1024 256 ) (-256 1024 0 ) +4 13 16 0 (-64 792 128 ) (-64 792 0 ) (0 792 0 ) (0 792 128 ) +4 14 21 0 (-64 768 128 ) (-64 272 128 ) (-64 272 256 ) (-64 768 256 ) +4 14 18 0 (-64 272 128 ) (-64 768 128 ) (0 768 128 ) (0 272 128 ) +4 15 23 0 (0 0 128 ) (0 0 256 ) (-64 0 256 ) (-64 0 128 ) +4 15 22 0 (-64 248 128 ) (-64 0 128 ) (-64 0 256 ) (-64 248 256 ) +4 15 20 0 (0 0 128 ) (-64 0 128 ) (-64 248 128 ) (0 248 128 ) +4 16 17 0 (0 784 128 ) (-64 784 128 ) (-64 784 0 ) (0 784 0 ) +4 17 18 0 (0 776 128 ) (-64 776 128 ) (-64 776 0 ) (0 776 0 ) +4 18 21 0 (-64 768 0 ) (-64 272 0 ) (-64 272 128 ) (-64 768 128 ) +4 18 19 0 (0 264 128 ) (-64 264 128 ) (-64 264 0 ) (0 264 0 ) +4 19 20 0 (0 256 128 ) (-64 256 128 ) (-64 256 0 ) (0 256 0 ) +4 20 23 0 (-64 0 0 ) (0 0 0 ) (0 0 128 ) (-64 0 128 ) +4 20 22 0 (-64 248 0 ) (-64 0 0 ) (-64 0 128 ) (-64 248 128 ) +4 22 23 0 (-256 0 0 ) (-64 0 0 ) (-64 0 256 ) (-256 0 256 ) +4 0 (256 1296 256 ) (0 1296 256 ) (0 1024 256 ) (256 1024 256 ) +4 0 (256 1024 0 ) (0 1024 0 ) (0 1296 0 ) (256 1296 0 ) +4 0 (256 1296 256 ) (256 1296 0 ) (0 1296 0 ) (0 1296 256 ) +4 0 (256 1024 0 ) (256 1296 0 ) (256 1296 256 ) (256 1024 256 ) +4 1 (64 792 128 ) (64 792 256 ) (0 792 256 ) (0 792 128 ) +4 1 (64 792 0 ) (256 792 0 ) (256 792 256 ) (64 792 256 ) +4 1 (0 792 256 ) (256 792 256 ) (256 1024 256 ) (0 1024 256 ) +4 1 (0 792 0 ) (0 1024 0 ) (256 1024 0 ) (256 792 0 ) +4 1 (256 792 256 ) (256 792 0 ) (256 1024 0 ) (256 1024 256 ) +4 2 (64 768 256 ) (64 272 256 ) (256 272 256 ) (256 768 256 ) +4 2 (64 272 0 ) (64 768 0 ) (256 768 0 ) (256 272 0 ) +4 2 (256 768 256 ) (256 272 256 ) (256 272 0 ) (256 768 0 ) +4 2 (256 768 256 ) (256 768 0 ) (64 768 0 ) (64 768 256 ) +4 2 (64 272 256 ) (64 272 0 ) (256 272 0 ) (256 272 256 ) +4 3 (256 248 256 ) (256 248 0 ) (64 248 0 ) (64 248 256 ) +4 3 (256 248 256 ) (256 0 256 ) (256 0 0 ) (256 248 0 ) +4 3 (256 0 0 ) (64 0 0 ) (64 248 0 ) (256 248 0 ) +4 3 (64 248 256 ) (64 0 256 ) (256 0 256 ) (256 248 256 ) +4 4 (0 768 256 ) (64 768 256 ) (64 768 128 ) (0 768 128 ) +4 4 (64 272 256 ) (64 768 256 ) (0 768 256 ) (0 272 256 ) +4 4 (0 272 128 ) (64 272 128 ) (64 272 256 ) (0 272 256 ) +4 5 (0 248 256 ) (64 248 256 ) (64 248 128 ) (0 248 128 ) +4 5 (64 248 256 ) (0 248 256 ) (0 0 256 ) (64 0 256 ) +4 6 (0 784 128 ) (64 784 128 ) (64 792 128 ) (0 792 128 ) +4 6 (0 784 0 ) (0 792 0 ) (64 792 0 ) (64 784 0 ) +4 6 (64 784 128 ) (64 784 0 ) (64 792 0 ) (64 792 128 ) +4 7 (0 784 128 ) (0 776 128 ) (64 776 128 ) (64 784 128 ) +4 7 (0 776 0 ) (0 784 0 ) (64 784 0 ) (64 776 0 ) +4 7 (64 784 128 ) (64 776 128 ) (64 776 0 ) (64 784 0 ) +4 8 (0 272 128 ) (0 264 128 ) (64 264 128 ) (64 272 128 ) +4 8 (0 776 128 ) (0 768 128 ) (64 768 128 ) (64 776 128 ) +4 8 (0 264 0 ) (0 776 0 ) (64 776 0 ) (64 264 0 ) +4 8 (64 776 128 ) (64 768 128 ) (64 768 0 ) (64 776 0 ) +4 8 (64 272 128 ) (64 264 128 ) (64 264 0 ) (64 272 0 ) +4 9 (64 264 128 ) (64 256 128 ) (64 256 0 ) (64 264 0 ) +4 9 (0 256 0 ) (0 264 0 ) (64 264 0 ) (64 256 0 ) +4 9 (0 264 128 ) (0 256 128 ) (64 256 128 ) (64 264 128 ) +4 10 (64 256 128 ) (64 248 128 ) (64 248 0 ) (64 256 0 ) +4 10 (64 0 0 ) (0 0 0 ) (0 256 0 ) (64 256 0 ) +4 10 (0 256 128 ) (0 248 128 ) (64 248 128 ) (64 256 128 ) +4 11 (0 -256 256 ) (0 -256 0 ) (256 -256 0 ) (256 -256 256 ) +4 11 (256 -256 256 ) (256 -256 0 ) (256 0 0 ) (256 0 256 ) +4 11 (0 -256 0 ) (0 0 0 ) (256 0 0 ) (256 -256 0 ) +4 11 (256 0 256 ) (0 0 256 ) (0 -256 256 ) (256 -256 256 ) +4 12 (0 1296 256 ) (-256 1296 256 ) (-256 1024 256 ) (0 1024 256 ) +4 12 (0 1024 0 ) (-256 1024 0 ) (-256 1296 0 ) (0 1296 0 ) +4 12 (-256 1296 0 ) (-256 1024 0 ) (-256 1024 256 ) (-256 1296 256 ) +4 12 (0 1296 0 ) (-256 1296 0 ) (-256 1296 256 ) (0 1296 256 ) +4 13 (-64 792 256 ) (-256 792 256 ) (-256 792 0 ) (-64 792 0 ) +4 13 (0 792 256 ) (-64 792 256 ) (-64 792 128 ) (0 792 128 ) +4 13 (0 792 256 ) (0 1024 256 ) (-256 1024 256 ) (-256 792 256 ) +4 13 (-256 792 0 ) (-256 1024 0 ) (0 1024 0 ) (0 792 0 ) +4 13 (-256 1024 256 ) (-256 1024 0 ) (-256 792 0 ) (-256 792 256 ) +4 14 (0 768 256 ) (0 768 128 ) (-64 768 128 ) (-64 768 256 ) +4 14 (0 272 256 ) (0 768 256 ) (-64 768 256 ) (-64 272 256 ) +4 14 (-64 272 256 ) (-64 272 128 ) (0 272 128 ) (0 272 256 ) +4 15 (0 248 256 ) (0 248 128 ) (-64 248 128 ) (-64 248 256 ) +4 15 (0 248 256 ) (-64 248 256 ) (-64 0 256 ) (0 0 256 ) +4 16 (-64 792 128 ) (-64 792 0 ) (-64 784 0 ) (-64 784 128 ) +4 16 (0 784 128 ) (0 792 128 ) (-64 792 128 ) (-64 784 128 ) +4 16 (-64 784 0 ) (-64 792 0 ) (0 792 0 ) (0 784 0 ) +4 17 (-64 784 0 ) (-64 776 0 ) (-64 776 128 ) (-64 784 128 ) +4 17 (0 776 128 ) (0 784 128 ) (-64 784 128 ) (-64 776 128 ) +4 17 (-64 776 0 ) (-64 784 0 ) (0 784 0 ) (0 776 0 ) +4 18 (-64 272 0 ) (-64 264 0 ) (-64 264 128 ) (-64 272 128 ) +4 18 (-64 776 0 ) (-64 768 0 ) (-64 768 128 ) (-64 776 128 ) +4 18 (0 264 128 ) (0 272 128 ) (-64 272 128 ) (-64 264 128 ) +4 18 (0 768 128 ) (0 776 128 ) (-64 776 128 ) (-64 768 128 ) +4 18 (-64 264 0 ) (-64 776 0 ) (0 776 0 ) (0 264 0 ) +4 19 (-64 264 0 ) (-64 256 0 ) (-64 256 128 ) (-64 264 128 ) +4 19 (-64 256 0 ) (-64 264 0 ) (0 264 0 ) (0 256 0 ) +4 19 (0 256 128 ) (0 264 128 ) (-64 264 128 ) (-64 256 128 ) +4 20 (-64 256 0 ) (-64 248 0 ) (-64 248 128 ) (-64 256 128 ) +4 20 (0 0 0 ) (-64 0 0 ) (-64 256 0 ) (0 256 0 ) +4 20 (0 248 128 ) (0 256 128 ) (-64 256 128 ) (-64 248 128 ) +4 21 (-64 272 256 ) (-64 768 256 ) (-256 768 256 ) (-256 272 256 ) +4 21 (-256 272 0 ) (-256 768 0 ) (-64 768 0 ) (-64 272 0 ) +4 21 (-256 768 0 ) (-256 272 0 ) (-256 272 256 ) (-256 768 256 ) +4 21 (-256 768 0 ) (-256 768 256 ) (-64 768 256 ) (-64 768 0 ) +4 21 (-64 272 0 ) (-64 272 256 ) (-256 272 256 ) (-256 272 0 ) +4 22 (-256 248 0 ) (-256 248 256 ) (-64 248 256 ) (-64 248 0 ) +4 22 (-256 248 0 ) (-256 0 0 ) (-256 0 256 ) (-256 248 256 ) +4 22 (-64 0 0 ) (-256 0 0 ) (-256 248 0 ) (-64 248 0 ) +4 22 (-64 248 256 ) (-256 248 256 ) (-256 0 256 ) (-64 0 256 ) +4 23 (-256 -256 256 ) (-256 -256 0 ) (0 -256 0 ) (0 -256 256 ) +4 23 (-256 0 256 ) (-256 0 0 ) (-256 -256 0 ) (-256 -256 256 ) +4 23 (-256 -256 0 ) (-256 0 0 ) (0 0 0 ) (0 -256 0 ) +4 23 (0 0 256 ) (-256 0 256 ) (-256 -256 256 ) (0 -256 256 ) diff --git a/fakk/maps/example/earthquake.bsp b/fakk/maps/example/earthquake.bsp new file mode 100644 index 0000000..2c8571b Binary files /dev/null and b/fakk/maps/example/earthquake.bsp differ diff --git a/fakk/maps/example/earthquake.map b/fakk/maps/example/earthquake.map new file mode 100644 index 0000000..68fe37c --- /dev/null +++ b/fakk/maps/example/earthquake.map @@ -0,0 +1,100 @@ +{ +"classname" "worldspawn" +// brush 0 +{ +( 64 64 0 ) ( -64 64 0 ) ( -64 -64 0 ) eden/FL_underground 0 0 0.00 1 1 0 0 0 +( -64 -64 8 ) ( -64 64 8 ) ( 64 64 8 ) eden/FL_underground 0 0 0.00 1 1 0 0 0 +( -72 -64 8 ) ( 56 -64 8 ) ( 56 -64 0 ) eden/FL_underground 0 0 0.00 1 1 0 0 0 +( 64 -64 8 ) ( 64 64 8 ) ( 64 64 0 ) eden/FL_underground 0 0 0.00 1 1 0 0 0 +( 64 64 8 ) ( -64 64 8 ) ( -64 64 0 ) eden/FL_underground 0 0 0.00 1 1 0 0 0 +( -64 64 8 ) ( -64 -64 8 ) ( -64 -64 0 ) eden/FL_underground 0 0 0.00 1 1 0 0 0 +} +// brush 1 +{ +( 264 264 -8 ) ( -264 264 -8 ) ( -264 -272 -8 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 -272 264 ) ( -264 264 264 ) ( 264 264 264 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 -264 8 ) ( 264 -264 8 ) ( 264 -264 0 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( 264 264 8 ) ( -264 264 8 ) ( -264 264 0 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 264 8 ) ( -264 -272 8 ) ( -264 -272 0 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( -256 -272 8 ) ( -256 264 8 ) ( -256 -272 0 ) eden/FL_edenhouse2 0 0 0.00 1 1 0 0 0 +} +// brush 2 +{ +( 264 264 -8 ) ( -264 264 -8 ) ( -264 -272 -8 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 -272 264 ) ( -264 264 264 ) ( 264 264 264 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( 264 -272 8 ) ( 264 264 8 ) ( 264 264 0 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( 264 264 8 ) ( -264 264 8 ) ( -264 264 0 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 264 8 ) ( -264 -272 8 ) ( -264 -272 0 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 256 8 ) ( 264 256 8 ) ( -264 256 0 ) eden/FL_edenhouse2 0 0 0.00 1 1 0 0 0 +} +// brush 3 +{ +( 264 264 -8 ) ( -264 264 -8 ) ( -264 -272 -8 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 -272 264 ) ( -264 264 264 ) ( 264 264 264 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 -264 8 ) ( 264 -264 8 ) ( 264 -264 0 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( 264 -272 8 ) ( 264 264 8 ) ( 264 264 0 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( 264 264 8 ) ( -264 264 8 ) ( -264 264 0 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( 256 264 8 ) ( 256 -272 8 ) ( 256 264 0 ) eden/FL_edenhouse2 0 0 0.00 1 1 0 0 0 +} +// brush 4 +{ +( 264 264 -8 ) ( -264 264 -8 ) ( -264 -272 -8 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 -272 264 ) ( -264 264 264 ) ( 264 264 264 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 -264 8 ) ( 264 -264 8 ) ( 264 -264 0 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( 264 -272 8 ) ( 264 264 8 ) ( 264 264 0 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 264 8 ) ( -264 -272 8 ) ( -264 -272 0 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( 264 -256 8 ) ( -264 -256 8 ) ( 264 -256 0 ) eden/FL_edenhouse2 0 0 0.00 1 1 0 0 0 +} +// brush 5 +{ +( -264 -272 264 ) ( -264 264 264 ) ( 264 264 264 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 -264 8 ) ( 264 -264 8 ) ( 264 -264 0 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( 264 -272 8 ) ( 264 264 8 ) ( 264 264 0 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( 264 264 8 ) ( -264 264 8 ) ( -264 264 0 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 264 8 ) ( -264 -272 8 ) ( -264 -272 0 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 264 256 ) ( -264 -272 256 ) ( 264 264 256 ) eden/FL_edenhouse2 0 0 0.00 1 1 0 0 0 +} +// brush 6 +{ +( 264 264 -8 ) ( -264 264 -8 ) ( -264 -272 -8 ) eden/FL_edenhouse2 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 -264 8 ) ( 264 -264 8 ) ( 264 -264 0 ) eden/FL_edenhouse2 0 0 0.00 0.500000 0.500000 0 0 0 +( 264 -272 8 ) ( 264 264 8 ) ( 264 264 0 ) eden/FL_edenhouse2 0 0 0.00 0.500000 0.500000 0 0 0 +( 264 264 8 ) ( -264 264 8 ) ( -264 264 0 ) eden/FL_edenhouse2 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 264 8 ) ( -264 -272 8 ) ( -264 -272 0 ) eden/FL_edenhouse2 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 264 0 ) ( 264 264 0 ) ( -264 -272 0 ) eden/FL_edenhouse2 0 0 0.00 0.500000 0.500000 0 0 0 +} +} +// entity 1 +{ +"wait" "5" +"classname" "trigger_multiple" +"target" "t1" +// brush 0 +{ +( 64 64 8 ) ( -56 64 8 ) ( -56 -64 8 ) common/trigger 0 0 0.00 1 1 0 128 0 +( -56 -64 192 ) ( -56 64 192 ) ( 64 64 192 ) common/trigger 0 0 0.00 1 1 0 128 0 +( -56 -64 16 ) ( 64 -64 16 ) ( 64 -64 8 ) common/trigger 0 0 0.00 1 1 0 128 0 +( 64 -64 16 ) ( 64 64 16 ) ( 64 64 8 ) common/trigger 0 0 0.00 1 1 0 128 0 +( 64 64 16 ) ( -56 64 16 ) ( -56 64 8 ) common/trigger 0 0 0.00 1 1 0 128 0 +( -64 64 16 ) ( -64 -64 16 ) ( -64 -64 8 ) common/trigger 0 0 0.00 1 1 0 128 0 +} +} +// entity 2 +{ +"origin" "0 128 120" +"duration" "4" +"classname" "func_earthquake" +"targetname" "t1" +} +// entity 3 +{ +"classname" "light" +"light" "1000" +"origin" "0 0 128" +} +// entity 4 +{ +"classname" "info_player_start" +"angle" "90" +"origin" "0 -192 16" +} diff --git a/fakk/maps/example/earthquake.prt b/fakk/maps/example/earthquake.prt new file mode 100644 index 0000000..67779b6 --- /dev/null +++ b/fakk/maps/example/earthquake.prt @@ -0,0 +1,68 @@ +PRT1 +12 +20 +44 +4 0 6 0 (0 0 8 ) (0 0 256 ) (0 256 256 ) (0 256 8 ) +4 0 3 0 (0 0 256 ) (0 0 8 ) (256 0 8 ) (256 0 256 ) +4 0 2 0 (0 256 8 ) (64 256 8 ) (64 64 8 ) (0 64 8 ) +4 0 1 0 (64 256 8 ) (256 256 8 ) (256 0 8 ) (64 0 8 ) +4 1 4 0 (64 0 0 ) (256 0 0 ) (256 0 8 ) (64 0 8 ) +4 1 2 0 (64 256 0 ) (64 64 0 ) (64 64 8 ) (64 256 8 ) +4 2 7 0 (0 64 8 ) (0 256 8 ) (0 256 0 ) (0 64 0 ) +4 3 9 0 (0 0 256 ) (0 0 8 ) (0 -256 8 ) (0 -256 256 ) +4 3 5 0 (64 -256 8 ) (0 -256 8 ) (0 -64 8 ) (64 -64 8 ) +4 3 4 0 (256 -256 8 ) (64 -256 8 ) (64 0 8 ) (256 0 8 ) +4 4 5 0 (64 -64 0 ) (64 -256 0 ) (64 -256 8 ) (64 -64 8 ) +4 5 10 0 (0 -64 0 ) (0 -256 0 ) (0 -256 8 ) (0 -64 8 ) +4 6 9 0 (0 0 8 ) (0 0 256 ) (-256 0 256 ) (-256 0 8 ) +4 6 7 0 (-64 64 8 ) (-64 256 8 ) (0 256 8 ) (0 64 8 ) +4 6 8 0 (-64 0 8 ) (-256 0 8 ) (-256 256 8 ) (-64 256 8 ) +4 7 8 0 (-64 64 8 ) (-64 256 8 ) (-64 256 0 ) (-64 64 0 ) +4 8 11 0 (-64 0 8 ) (-256 0 8 ) (-256 0 0 ) (-64 0 0 ) +4 9 10 0 (0 -256 8 ) (-64 -256 8 ) (-64 -64 8 ) (0 -64 8 ) +4 9 11 0 (-64 -256 8 ) (-256 -256 8 ) (-256 0 8 ) (-64 0 8 ) +4 10 11 0 (-64 -64 0 ) (-64 -256 0 ) (-64 -256 8 ) (-64 -64 8 ) +4 0 (64 64 8 ) (64 0 8 ) (0 0 8 ) (0 64 8 ) +4 0 (0 0 256 ) (256 0 256 ) (256 256 256 ) (0 256 256 ) +4 0 (256 256 256 ) (256 256 8 ) (0 256 8 ) (0 256 256 ) +4 0 (256 0 256 ) (256 0 8 ) (256 256 8 ) (256 256 256 ) +4 1 (64 64 0 ) (64 0 0 ) (64 0 8 ) (64 64 8 ) +4 1 (256 0 8 ) (256 0 0 ) (256 256 0 ) (256 256 8 ) +4 1 (64 256 8 ) (256 256 8 ) (256 256 0 ) (64 256 0 ) +4 1 (256 0 0 ) (64 0 0 ) (64 256 0 ) (256 256 0 ) +4 2 (0 64 0 ) (0 256 0 ) (64 256 0 ) (64 64 0 ) +4 2 (64 256 8 ) (64 256 0 ) (0 256 0 ) (0 256 8 ) +4 2 (0 64 0 ) (64 64 0 ) (64 64 8 ) (0 64 8 ) +4 3 (0 -64 8 ) (0 0 8 ) (64 0 8 ) (64 -64 8 ) +4 3 (256 0 256 ) (0 0 256 ) (0 -256 256 ) (256 -256 256 ) +4 3 (256 -256 256 ) (256 -256 8 ) (256 0 8 ) (256 0 256 ) +4 3 (0 -256 256 ) (0 -256 8 ) (256 -256 8 ) (256 -256 256 ) +4 4 (64 0 0 ) (64 -64 0 ) (64 -64 8 ) (64 0 8 ) +4 4 (64 -256 0 ) (256 -256 0 ) (256 -256 8 ) (64 -256 8 ) +4 4 (256 -256 8 ) (256 -256 0 ) (256 0 0 ) (256 0 8 ) +4 4 (64 0 0 ) (256 0 0 ) (256 -256 0 ) (64 -256 0 ) +4 5 (0 -256 0 ) (0 -64 0 ) (64 -64 0 ) (64 -256 0 ) +4 5 (0 -256 8 ) (0 -256 0 ) (64 -256 0 ) (64 -256 8 ) +4 5 (0 -64 8 ) (64 -64 8 ) (64 -64 0 ) (0 -64 0 ) +4 6 (0 0 8 ) (-64 0 8 ) (-64 64 8 ) (0 64 8 ) +4 6 (0 256 256 ) (-256 256 256 ) (-256 0 256 ) (0 0 256 ) +4 6 (-256 0 8 ) (-256 0 256 ) (-256 256 256 ) (-256 256 8 ) +4 6 (0 256 256 ) (0 256 8 ) (-256 256 8 ) (-256 256 256 ) +4 7 (-64 64 0 ) (-64 256 0 ) (0 256 0 ) (0 64 0 ) +4 7 (-64 256 8 ) (0 256 8 ) (0 256 0 ) (-64 256 0 ) +4 7 (-64 64 8 ) (-64 64 0 ) (0 64 0 ) (0 64 8 ) +4 8 (-64 0 0 ) (-64 64 0 ) (-64 64 8 ) (-64 0 8 ) +4 8 (-64 256 8 ) (-64 256 0 ) (-256 256 0 ) (-256 256 8 ) +4 8 (-256 0 0 ) (-256 0 8 ) (-256 256 8 ) (-256 256 0 ) +4 8 (-64 0 0 ) (-256 0 0 ) (-256 256 0 ) (-64 256 0 ) +4 9 (-64 -64 8 ) (-64 0 8 ) (0 0 8 ) (0 -64 8 ) +4 9 (0 0 256 ) (-256 0 256 ) (-256 -256 256 ) (0 -256 256 ) +4 9 (-256 0 256 ) (-256 0 8 ) (-256 -256 8 ) (-256 -256 256 ) +4 9 (-256 -256 256 ) (-256 -256 8 ) (0 -256 8 ) (0 -256 256 ) +4 10 (0 -64 0 ) (0 -256 0 ) (-64 -256 0 ) (-64 -64 0 ) +4 10 (-64 -256 0 ) (0 -256 0 ) (0 -256 8 ) (-64 -256 8 ) +4 10 (0 -64 8 ) (0 -64 0 ) (-64 -64 0 ) (-64 -64 8 ) +4 11 (-64 0 8 ) (-64 -64 8 ) (-64 -64 0 ) (-64 0 0 ) +4 11 (-256 -256 8 ) (-256 -256 0 ) (-64 -256 0 ) (-64 -256 8 ) +4 11 (-256 0 8 ) (-256 0 0 ) (-256 -256 0 ) (-256 -256 8 ) +4 11 (-256 -256 0 ) (-256 0 0 ) (-64 0 0 ) (-64 -256 0 ) diff --git a/fakk/maps/example/explodeobject.bsp b/fakk/maps/example/explodeobject.bsp new file mode 100644 index 0000000..9ac4011 Binary files /dev/null and b/fakk/maps/example/explodeobject.bsp differ diff --git a/fakk/maps/example/explodeobject.map b/fakk/maps/example/explodeobject.map new file mode 100644 index 0000000..16712b6 --- /dev/null +++ b/fakk/maps/example/explodeobject.map @@ -0,0 +1,360 @@ +{ +"classname" "worldspawn" +// brush 0 +{ +( 224 192 0 ) ( 224 224 0 ) ( -480 224 0 ) eden/bedtrim -224 -32 90.00 1 1 0 0 0 +( -480 224 64 ) ( 224 224 64 ) ( 224 192 64 ) eden/bedtrim -224 -32 90.00 1 1 0 0 0 +( -480 224 256 ) ( -480 192 256 ) ( -480 192 0 ) eden/bedtrim -224 0 0.00 1 1 0 0 0 +( -480 192 256 ) ( 224 192 256 ) ( 224 192 0 ) common/skip 0 0 0.00 1 1 805306368 16512 0 +( 224 224 256 ) ( -480 224 256 ) ( -480 224 0 ) eden/bedtrim 224 0 -180.00 1 -1 0 0 0 +( -416 224 0 ) ( -416 192 0 ) ( -416 208 64 ) eden/bedtrim 224 0 -180.00 1 -1 0 0 0 +} +// brush 1 +{ +( 224 192 0 ) ( 224 224 0 ) ( -480 224 0 ) eden/bedtrim -224 -32 90.00 1 1 0 0 0 +( -480 224 64 ) ( 224 224 64 ) ( 224 192 64 ) eden/bedtrim -224 -32 90.00 1 1 0 0 0 +( -480 192 256 ) ( 224 192 256 ) ( 224 192 0 ) eden/bedtrim 224 0 -180.00 1 -1 0 0 0 +( 224 192 256 ) ( 224 224 256 ) ( 224 224 0 ) eden/bedtrim -224 0 0.00 1 1 0 0 0 +( 224 224 256 ) ( -480 224 256 ) ( -480 224 0 ) eden/bedtrim 224 0 -180.00 1 -1 0 0 0 +( -480 192 0 ) ( -480 224 0 ) ( -480 208 64 ) eden/bedtrim 224 0 -180.00 1 -1 0 0 0 +} +// brush 2 +{ +( 224 192 64 ) ( 224 224 64 ) ( -480 224 64 ) eden/edenmetalwall -224 -224 90.00 1 1 0 0 0 +( -480 224 320 ) ( 224 224 320 ) ( 224 192 320 ) eden/edenmetalwall -224 -224 90.00 1 1 0 0 0 +( -480 224 96 ) ( -480 192 96 ) ( -480 192 64 ) eden/edenmetalwall -224 64 0.00 1 1 0 0 0 +( -480 192 96 ) ( 224 192 96 ) ( 224 192 64 ) common/skip 0 0 0.00 1 1 805306368 16512 0 +( 224 224 96 ) ( -480 224 96 ) ( -480 224 64 ) eden/edenmetalwall 224 63 -180.00 1 -1 0 0 0 +( -416 224 64 ) ( -416 192 64 ) ( -416 208 320 ) eden/edenmetalwall 224 63 -180.00 1 -1 0 0 0 +} +// brush 3 +{ +( 224 192 64 ) ( 224 224 64 ) ( -480 224 64 ) eden/edenmetalwall -224 -224 90.00 1 1 0 0 0 +( -480 224 320 ) ( 224 224 320 ) ( 224 192 320 ) eden/edenmetalwall -224 -224 90.00 1 1 0 0 0 +( -480 192 96 ) ( 224 192 96 ) ( 224 192 64 ) eden/edenmetalwall 224 63 -180.00 1 -1 0 0 0 +( 224 192 96 ) ( 224 224 96 ) ( 224 224 64 ) eden/edenmetalwall -224 64 0.00 1 1 0 0 0 +( 224 224 96 ) ( -480 224 96 ) ( -480 224 64 ) eden/edenmetalwall 224 63 -180.00 1 -1 0 0 0 +( -480 192 64 ) ( -480 224 64 ) ( -480 208 320 ) eden/edenmetalwall 224 63 -180.00 1 -1 0 0 0 +} +// brush 4 + { + patchDef2 + { + eden/edenmetalwall + ( 3 3 0 536870912 0 ) +( +( ( -480 96 63.999992 0 0 ) ( -480 96 192 0 0.500000 ) ( -480 96 320 0 1 ) ) +( ( -384 96 63.999992 0.500000 0 ) ( -384 96 192 0.500000 0.500000 ) ( -384 96 320 0.500000 1 ) ) +( ( -384 192 63.999992 1 0 ) ( -384 192 192 1 0.500000 ) ( -384 192 320 1 1 ) ) +) + } + } +// brush 5 +{ +( -480 192 0 ) ( -512 192 0 ) ( -512 -512 0 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +( -512 -512 64 ) ( -512 192 64 ) ( -480 192 64 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +( -480 -512 256 ) ( -480 192 256 ) ( -480 192 0 ) common/skip 0 0 0.00 1 1 805306368 16512 0 +( -480 192 256 ) ( -512 192 256 ) ( -512 192 0 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +( -512 192 256 ) ( -512 -512 256 ) ( -512 -512 0 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +( -480 128 0 ) ( -512 128 0 ) ( -496 128 64 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +} +// brush 6 +{ +( -480 192 0 ) ( -512 192 0 ) ( -512 -512 0 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +( -512 -512 64 ) ( -512 192 64 ) ( -480 192 64 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +( -512 -512 256 ) ( -480 -512 256 ) ( -480 -512 0 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +( -480 -512 256 ) ( -480 192 256 ) ( -480 192 0 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +( -512 192 256 ) ( -512 -512 256 ) ( -512 -512 0 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +( -512 192 0 ) ( -480 192 0 ) ( -496 192 64 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +} +// brush 7 +{ +( -480 192 64 ) ( -512 192 64 ) ( -512 -512 64 ) eden/edenmetalwall 0 0 0.00 1 1 0 0 0 +( -512 -512 320 ) ( -512 192 320 ) ( -480 192 320 ) eden/edenmetalwall 0 0 0.00 1 1 0 0 0 +( -480 -512 96 ) ( -480 192 96 ) ( -480 192 64 ) common/skip 0 0 0.00 1 1 805306368 16512 0 +( -480 192 96 ) ( -512 192 96 ) ( -512 192 64 ) eden/edenmetalwall 0 64 0.00 1 1 0 0 0 +( -512 192 96 ) ( -512 -512 96 ) ( -512 -512 64 ) eden/edenmetalwall 0 64 0.00 1 1 0 0 0 +( -480 128 64 ) ( -512 128 64 ) ( -496 128 320 ) eden/edenmetalwall 0 64 0.00 1 1 0 0 0 +} +// brush 8 +{ +( -480 192 64 ) ( -512 192 64 ) ( -512 -512 64 ) eden/edenmetalwall 0 0 0.00 1 1 0 0 0 +( -512 -512 320 ) ( -512 192 320 ) ( -480 192 320 ) eden/edenmetalwall 0 0 0.00 1 1 0 0 0 +( -512 -512 96 ) ( -480 -512 96 ) ( -480 -512 64 ) eden/edenmetalwall 0 64 0.00 1 1 0 0 0 +( -480 -512 96 ) ( -480 192 96 ) ( -480 192 64 ) eden/edenmetalwall 0 64 0.00 1 1 0 0 0 +( -512 192 96 ) ( -512 -512 96 ) ( -512 -512 64 ) eden/edenmetalwall 0 64 0.00 1 1 0 0 0 +( -512 192 64 ) ( -480 192 64 ) ( -496 192 320 ) eden/edenmetalwall 0 64 0.00 1 1 0 0 0 +} +// brush 9 + { + patchDef2 + { + eden/bedtrim + ( 3 3 0 536870912 0 ) +( +( ( -480 96 0 0 0 ) ( -480 96 32 0 0.500000 ) ( -480 96 64 0 1 ) ) +( ( -384 96 0 0.500000 0 ) ( -384 96 32 0.500000 0.500000 ) ( -384 96 64 0.500000 1 ) ) +( ( -384 192 0 1 0 ) ( -384 192 32 1 0.500000 ) ( -384 192 64 1 1 ) ) +) + } + } +// brush 10 +{ +( 96 96 352 ) ( -32 96 352 ) ( -32 -416 352 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( -32 -416 416 ) ( -32 96 416 ) ( 96 96 416 ) we_cemetary_test/levelord_sky 0 0 0.00 1 1 0 0 0 +( -32 -416 416 ) ( 96 -416 416 ) ( 96 -416 352 ) we_cemetary_test/levelord_sky 0 0 0.00 1 1 0 0 0 +( 96 -416 416 ) ( 96 96 416 ) ( 96 96 352 ) we_cemetary_test/levelord_sky 0 0 0.00 1 1 0 0 0 +( 96 96 416 ) ( -32 96 416 ) ( -32 96 352 ) we_cemetary_test/levelord_sky 0 0 0.00 1 1 0 0 0 +( -32 96 416 ) ( -32 -416 416 ) ( -32 -416 352 ) we_cemetary_test/levelord_sky 0 0 0.00 1 1 0 0 0 +} +// brush 11 +{ +( -64 -416 304 ) ( -64 -448 304 ) ( 128 -448 304 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( 128 -448 352 ) ( -64 -448 352 ) ( -64 -416 352 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( 96 -416 352 ) ( -32 -416 352 ) ( -32 -416 320 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( 128 -448 352 ) ( 96 -416 352 ) ( 96 -416 320 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( -64 -448 320 ) ( -64 -448 352 ) ( 128 -448 352 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( -64 -448 320 ) ( -32 -416 320 ) ( -32 -416 352 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +} +// brush 12 +{ +( -32 128 304 ) ( -64 128 304 ) ( -64 -64 304 ) eden/FL_edenhouse 0 32 90.00 1 1 0 0 0 +( -64 -64 352 ) ( -64 128 352 ) ( -32 128 352 ) eden/FL_edenhouse 0 32 90.00 1 1 0 0 0 +( -32 -32 352 ) ( -32 96 352 ) ( -32 96 320 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( -64 -448 352 ) ( -32 -416 352 ) ( -32 -416 320 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( -64 128 320 ) ( -64 128 352 ) ( -64 -64 352 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( -64 128 320 ) ( -32 96 320 ) ( -32 96 352 ) eden/FL_edenhouse -64 0 -180.00 1 -1 0 0 0 +} +// brush 13 +{ +( 128 -64 304 ) ( 128 128 304 ) ( 96 128 304 ) eden/FL_edenhouse 0 -96 90.00 1 1 0 0 0 +( 96 128 352 ) ( 128 128 352 ) ( 128 -64 352 ) eden/FL_edenhouse 0 -96 90.00 1 1 0 0 0 +( 96 96 320 ) ( 96 96 352 ) ( 96 -32 352 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( 96 -416 320 ) ( 96 -416 352 ) ( 128 -448 352 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( 128 -64 352 ) ( 128 128 352 ) ( 128 128 320 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( 96 96 352 ) ( 96 96 320 ) ( 128 128 320 ) eden/FL_edenhouse -64 0 -180.00 1 -1 0 0 0 +} +// brush 14 +{ +( 128 128 304 ) ( -64 128 304 ) ( -64 96 304 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( -64 96 352 ) ( -64 128 352 ) ( 128 128 352 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( -32 96 320 ) ( -32 96 352 ) ( 96 96 352 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( 96 96 320 ) ( 96 96 352 ) ( 128 128 352 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( 128 128 352 ) ( -64 128 352 ) ( -64 128 320 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( -32 96 352 ) ( -32 96 320 ) ( -64 128 320 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +} +// brush 15 +{ +( 128 192 320 ) ( -64 192 320 ) ( -64 128 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( -64 128 352 ) ( -64 192 352 ) ( 128 192 352 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( -64 128 352 ) ( 128 128 352 ) ( 128 128 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( 128 128 352 ) ( 128 192 352 ) ( 128 192 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( 128 192 352 ) ( -64 192 352 ) ( -64 192 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( -64 192 352 ) ( -64 128 352 ) ( -64 128 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +} +// brush 16 +{ +( 192 192 320 ) ( 128 192 320 ) ( 128 -448 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( 128 -448 352 ) ( 128 192 352 ) ( 192 192 352 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( 128 -448 352 ) ( 192 -448 352 ) ( 192 -448 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( 192 -448 352 ) ( 192 192 352 ) ( 192 192 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( 192 192 352 ) ( 128 192 352 ) ( 128 192 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( 128 192 352 ) ( 128 -448 352 ) ( 128 -448 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +} +// brush 17 +{ +( 192 192 320 ) ( -480 192 320 ) ( -480 -512 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( -480 -512 352 ) ( -480 192 352 ) ( 192 192 352 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( -480 -512 352 ) ( 192 -512 352 ) ( 192 -512 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( 192 -512 352 ) ( 192 192 352 ) ( 192 192 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( 224 -448 352 ) ( -448 -448 352 ) ( -448 -448 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( -64 -256 320 ) ( -64 -128 320 ) ( -64 -192 352 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +} +// brush 18 +{ +( 192 192 320 ) ( -480 192 320 ) ( -480 -512 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( -480 -512 352 ) ( -480 192 352 ) ( 192 192 352 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( -480 -512 352 ) ( 192 -512 352 ) ( 192 -512 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( 192 192 352 ) ( -480 192 352 ) ( -480 192 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( -480 192 352 ) ( -480 -512 352 ) ( -480 -512 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( -64 -128 320 ) ( -64 -256 320 ) ( -64 -192 352 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +} +// brush 19 +{ +( 192 192 -32 ) ( -480 192 -32 ) ( -480 -512 -32 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( -480 -512 0 ) ( -480 192 0 ) ( 192 192 0 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( -480 -512 224 ) ( 192 -512 224 ) ( 192 -512 -32 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 192 -512 224 ) ( 192 192 224 ) ( 192 192 -32 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 192 192 224 ) ( -480 192 224 ) ( -480 192 -32 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( -480 192 224 ) ( -480 -512 224 ) ( -480 -512 -32 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +} +// brush 20 +{ +( -480 -512 64 ) ( -480 -544 64 ) ( 224 -544 64 ) eden/edenmetalwall -31 31 -90.00 1 1 0 0 0 +( 224 -544 320 ) ( -480 -544 320 ) ( -480 -512 320 ) eden/edenmetalwall -31 31 -90.00 1 1 0 0 0 +( 224 -544 96 ) ( 224 -512 96 ) ( 224 -512 64 ) eden/edenmetalwall -32 63 -180.00 1 -1 0 0 0 +( 224 -512 96 ) ( -480 -512 96 ) ( -480 -512 64 ) eden/edenmetalwall -32 62 0.00 1.000008 1 0 0 0 +( -480 -512 96 ) ( -480 -544 96 ) ( -480 -544 64 ) eden/edenmetalwall -33 63 -180.00 1 -1 0 0 0 +( -480 -544 96 ) ( 224 -544 96 ) ( 224 -544 64 ) eden/edenmetalwall -32 62 0.00 1.000008 1 0 0 0 +} +// brush 21 +{ +( -480 -512 0 ) ( -480 -544 0 ) ( 224 -544 0 ) eden/bedtrim -31 32 -90.00 1 1 0 0 0 +( 224 -544 64 ) ( -480 -544 64 ) ( -480 -512 64 ) eden/bedtrim -31 32 -90.00 1 1 0 0 0 +( 224 -544 256 ) ( 224 -512 256 ) ( 224 -512 0 ) eden/bedtrim -32 0 -180.00 1 -1 0 0 0 +( 224 -512 256 ) ( -480 -512 256 ) ( -480 -512 0 ) eden/bedtrim -32 0 0.00 1 1 0 0 0 +( -480 -512 256 ) ( -480 -544 256 ) ( -480 -544 0 ) eden/bedtrim -33 0 -180.00 1 -1 0 0 0 +( -480 -544 256 ) ( 224 -544 256 ) ( 224 -544 0 ) eden/bedtrim -32 0 0.00 1 1 0 0 0 +} +// brush 22 +{ +( 192 -512 0 ) ( 224 -512 0 ) ( 224 192 0 ) eden/bedtrim 160 0 -180.00 1 1 0 0 0 +( 224 192 64 ) ( 224 -512 64 ) ( 192 -512 64 ) eden/bedtrim 160 0 -180.00 1 1 0 0 0 +( 224 192 256 ) ( 192 192 256 ) ( 192 192 0 ) eden/bedtrim 160 0 -180.00 1 -1 0 0 0 +( 192 192 256 ) ( 192 -512 256 ) ( 192 -512 0 ) eden/bedtrim -64 0 -180.00 1 -1 0 0 0 +( 192 -512 256 ) ( 224 -512 256 ) ( 224 -512 0 ) eden/bedtrim 159 0 -180.00 1 -1 0 0 0 +( 224 -512 256 ) ( 224 192 256 ) ( 224 192 0 ) eden/bedtrim -64 0 -180.00 1 -1 0 0 0 +} +// brush 23 +{ +( 192 -512 64 ) ( 224 -512 64 ) ( 224 192 64 ) eden/edenmetalwall 160 63 -180.00 1 1 0 0 0 +( 224 192 320 ) ( 224 -512 320 ) ( 192 -512 320 ) eden/edenmetalwall 160 63 -180.00 1 1 0 0 0 +( 224 192 96 ) ( 192 192 96 ) ( 192 192 64 ) eden/edenmetalwall 160 64 -180.00 1 -1 0 0 0 +( 192 192 96 ) ( 192 -512 96 ) ( 192 -512 64 ) eden/edenmetalwall -64 62 -180.00 1 -1 0 0 0 +( 192 -512 96 ) ( 224 -512 96 ) ( 224 -512 64 ) eden/edenmetalwall 159 64 -180.00 1 -1 0 0 0 +( 224 -512 96 ) ( 224 192 96 ) ( 224 192 64 ) eden/edenmetalwall -64 62 -180.00 1 -1 0 0 0 +} +} +// entity 1 +{ +"origin" "-238.21 156.74 -5.80" +"spawnflags" "32" +"angle" "270" +"model" "obj_windstat.tik" +"scale" "1.0" +"classname" "func_explodeobject" +"health" "50" +} +// entity 2 +{ +"classname" "func_explodeobject" +"spawnflags" "40" +"health" "10" +// brush 0 +{ +( -8 128 120 ) ( -96 128 120 ) ( -96 56 120 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( -96 56 192 ) ( -96 128 192 ) ( -8 128 192 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( 80 32 128 ) ( 168 32 128 ) ( 168 32 120 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( 0 48 128 ) ( 0 120 128 ) ( 0 120 120 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( -8 128 128 ) ( -96 128 128 ) ( -96 128 120 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( -96 128 128 ) ( -96 56 128 ) ( -96 56 120 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +} +} +// entity 3 +{ +"classname" "func_multi_exploder" +"spawnflags" "12" +"targetname" "t1" +// brush 0 +{ +( 24 -64 0 ) ( -72 -64 0 ) ( -72 -288 0 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( -72 -288 144 ) ( -72 -64 144 ) ( 24 -64 144 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( -80 -288 8 ) ( 16 -288 8 ) ( 16 -288 0 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( 24 -288 8 ) ( 24 -64 8 ) ( 24 -64 0 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( 24 -64 8 ) ( -72 -64 8 ) ( -72 -64 0 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( -80 -64 8 ) ( -80 -288 8 ) ( -80 -288 0 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +} +} +// entity 4 +{ +"spawnflags" "8" +"classname" "func_explodeobject" +"debrismodel" "explrock.tik" +"severity" "3" +"health" "50" +// brush 0 +{ +( -160 -16 0 ) ( -320 -16 0 ) ( -320 -88 0 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( -320 -88 136 ) ( -320 -16 136 ) ( -160 -16 136 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( -320 -88 8 ) ( -160 -88 8 ) ( -160 -88 0 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( -160 -88 8 ) ( -160 -16 8 ) ( -160 -16 0 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( -160 -16 8 ) ( -320 -16 8 ) ( -320 -16 0 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( -320 -16 8 ) ( -320 -88 8 ) ( -320 -88 0 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +} +} +// entity 5 +{ +"classname" "light" +"spawnflags" "0" +"origin" "-352 56 168" +"light" "200" +"_color" "1.000000 0.724409 0.523622" +} +// entity 6 +{ +"classname" "info_player_start" +"angle" "45" +"origin" "-432 -464 24" +} +// entity 7 +{ +"origin" "8 56 168" +"spawnflags" "0" +"classname" "light" +"light" "200" +"_color" "0.629921 0.846457 1.000000" +} +// entity 8 +{ +"origin" "-344 -376 168" +"spawnflags" "0" +"classname" "light" +"light" "200" +} +// entity 9 +{ +"classname" "light" +"spawnflags" "0" +"origin" "8 -376 168" +"light" "200" +} +// entity 10 +{ +"light" "200" +"classname" "light" +"spawnflags" "0" +"origin" "-168 -160 168" +} +// entity 11 +{ +"severity" "3" +"health" "50" +"debrismodel" "explrock.tik" +"classname" "func_explodeobject" +"spawnflags" "20" +"target" "t1" +// brush 0 +{ +( -8 -376 80 ) ( -168 -376 80 ) ( -168 -448 80 ) eden/bedtrim -208 -40 0.00 1 1 0 0 0 +( -168 -448 136 ) ( -168 -376 136 ) ( -8 -376 136 ) eden/bedtrim -208 -40 0.00 1 1 0 0 0 +( -168 -448 8 ) ( -8 -448 8 ) ( -8 -448 0 ) eden/bedtrim -208 0 0.00 1 1 0 0 0 +( -112 -456 8 ) ( -112 -384 8 ) ( -112 -384 0 ) eden/bedtrim 232 0 0.00 1 1 0 0 0 +( -8 -376 8 ) ( -168 -376 8 ) ( -168 -376 0 ) eden/bedtrim -208 0 0.00 1 1 0 0 0 +( -168 -376 8 ) ( -168 -448 8 ) ( -168 -448 0 ) eden/bedtrim 232 0 0.00 1 1 0 0 0 +} +} +// entity 12 +{ +"spawnflags" "73" +"classname" "func_explodeobject" +"health" "10" +// brush 0 +{ +( -256 -208 120 ) ( -344 -208 120 ) ( -344 -280 120 ) eden/CL_edenroof3 -8 -80 0.00 1 1 0 0 0 +( -344 -280 192 ) ( -344 -208 192 ) ( -256 -208 192 ) eden/CL_edenroof3 -8 -80 0.00 1 1 0 0 0 +( -168 -304 128 ) ( -80 -304 128 ) ( -80 -304 120 ) eden/CL_edenroof3 -8 0 0.00 1 1 0 0 0 +( -248 -288 128 ) ( -248 -216 128 ) ( -248 -216 120 ) eden/CL_edenroof3 80 0 0.00 1 1 0 0 0 +( -256 -208 128 ) ( -344 -208 128 ) ( -344 -208 120 ) eden/CL_edenroof3 -8 0 0.00 1 1 0 0 0 +( -344 -208 128 ) ( -344 -280 128 ) ( -344 -280 120 ) eden/CL_edenroof3 80 0 0.00 1 1 0 0 0 +} +} diff --git a/fakk/maps/example/explodeobject.prt b/fakk/maps/example/explodeobject.prt new file mode 100644 index 0000000..63b4d74 --- /dev/null +++ b/fakk/maps/example/explodeobject.prt @@ -0,0 +1,96 @@ +PRT1 +16 +28 +64 +4 0 4 0 (128 0 304 ) (192 0 304 ) (192 0 320 ) (128 0 320 ) +4 0 3 0 (128 192 304 ) (192 192 304 ) (192 0 304 ) (128 0 304 ) +4 0 1 0 (128 192 320 ) (128 192 304 ) (128 128 304 ) (128 128 320 ) +4 1 8 0 (0 192 320 ) (0 192 304 ) (0 128 304 ) (0 128 320 ) +4 1 3 0 (0 192 304 ) (128 192 304 ) (128 128 304 ) (0 128 304 ) +4 2 9 0 (0 0 304 ) (0 0 352 ) (0 96 352 ) (0 96 304 ) +4 2 5 0 (0 0 352 ) (0 0 304 ) (96 0 304 ) (96 0 352 ) +4 2 3 0 (96 0 304 ) (0 0 304 ) (0 96 304 ) (96 96 304 ) +4 3 11 0 (0 0 0 ) (0 0 304 ) (0 192 304 ) (0 192 0 ) +4 3 7 0 (0 0 304 ) (0 0 0 ) (192 0 0 ) (192 0 304 ) +4 4 7 0 (128 0 304 ) (192 0 304 ) (192 -448 304 ) (128 -448 304 ) +4 4 6 0 (128 -448 304 ) (192 -448 304 ) (192 -448 320 ) (128 -448 320 ) +4 5 12 0 (0 0 352 ) (0 0 304 ) (0 -416 304 ) (0 -416 352 ) +4 5 7 0 (0 0 304 ) (96 0 304 ) (96 -416 304 ) (0 -416 304 ) +4 6 13 0 (0 -512 304 ) (0 -512 320 ) (0 -448 320 ) (0 -448 304 ) +4 6 7 0 (192 -448 304 ) (192 -512 304 ) (0 -512 304 ) (0 -448 304 ) +4 7 15 0 (0 -512 0 ) (0 -512 304 ) (0 0 304 ) (0 0 0 ) +4 8 11 0 (-64 128 304 ) (-64 192 304 ) (0 192 304 ) (0 128 304 ) +4 8 10 0 (-64 192 320 ) (-64 192 304 ) (-64 128 304 ) (-64 128 320 ) +4 9 12 0 (0 0 304 ) (0 0 352 ) (-32 0 352 ) (-32 0 304 ) +4 9 11 0 (0 0 304 ) (-32 0 304 ) (-32 96 304 ) (0 96 304 ) +4 10 14 0 (-480 0 320 ) (-480 0 304 ) (-64 0 304 ) (-64 0 320 ) +4 10 11 0 (-64 0 304 ) (-480 0 304 ) (-480 192 304 ) (-64 192 304 ) +4 11 15 0 (0 0 0 ) (0 0 304 ) (-480 0 304 ) (-480 0 0 ) +4 12 15 0 (-32 0 304 ) (0 0 304 ) (0 -416 304 ) (-32 -416 304 ) +4 13 15 0 (0 -512 304 ) (-64 -512 304 ) (-64 -448 304 ) (0 -448 304 ) +4 13 14 0 (-64 -448 304 ) (-64 -512 304 ) (-64 -512 320 ) (-64 -448 320 ) +4 14 15 0 (-64 -512 304 ) (-480 -512 304 ) (-480 0 304 ) (-64 0 304 ) +4 0 (128 96 304 ) (128 0 304 ) (128 0 320 ) (128 96 320 ) +4 0 (128 128 304 ) (128 96 304 ) (128 96 320 ) (128 128 320 ) +4 0 (192 0 320 ) (192 0 304 ) (192 192 304 ) (192 192 320 ) +4 0 (128 192 320 ) (192 192 320 ) (192 192 304 ) (128 192 304 ) +4 0 (192 0 320 ) (192 192 320 ) (128 192 320 ) (128 0 320 ) +4 1 (0 128 304 ) (128 128 304 ) (128 128 320 ) (0 128 320 ) +4 1 (128 192 320 ) (128 192 304 ) (0 192 304 ) (0 192 320 ) +4 1 (128 192 320 ) (0 192 320 ) (0 128 320 ) (128 128 320 ) +4 2 (96 96 352 ) (0 96 352 ) (0 0 352 ) (96 0 352 ) +4 2 (0 96 352 ) (96 96 352 ) (96 96 304 ) (0 96 304 ) +4 2 (96 0 352 ) (96 0 304 ) (96 96 304 ) (96 96 352 ) +4 3 (192 192 304 ) (192 192 0 ) (0 192 0 ) (0 192 304 ) +4 3 (192 0 304 ) (192 0 0 ) (192 192 0 ) (192 192 304 ) +4 3 (0 128 304 ) (0 96 304 ) (128 96 304 ) (128 128 304 ) +4 3 (96 96 304 ) (96 0 304 ) (128 0 304 ) (128 96 304 ) +4 3 (0 192 0 ) (192 192 0 ) (192 0 0 ) (0 0 0 ) +4 4 (128 0 304 ) (128 -448 304 ) (128 -448 320 ) (128 0 320 ) +4 4 (192 -448 320 ) (192 -448 304 ) (192 0 304 ) (192 0 320 ) +4 4 (192 0 320 ) (128 0 320 ) (128 -448 320 ) (192 -448 320 ) +4 5 (96 -416 352 ) (96 0 352 ) (0 0 352 ) (0 -416 352 ) +4 5 (96 0 352 ) (96 -416 352 ) (96 -416 304 ) (96 0 304 ) +4 5 (0 -416 304 ) (96 -416 304 ) (96 -416 352 ) (0 -416 352 ) +4 6 (192 -448 320 ) (192 -512 320 ) (192 -512 304 ) (192 -448 304 ) +4 6 (0 -512 320 ) (0 -512 304 ) (192 -512 304 ) (192 -512 320 ) +4 6 (96 -448 320 ) (128 -448 320 ) (128 -448 304 ) (96 -448 304 ) +4 6 (96 -448 320 ) (96 -448 304 ) (0 -448 304 ) (0 -448 320 ) +4 6 (0 -512 320 ) (192 -512 320 ) (192 -448 320 ) (0 -448 320 ) +4 7 (0 -512 304 ) (0 -512 0 ) (192 -512 0 ) (192 -512 304 ) +4 7 (192 -512 304 ) (192 -512 0 ) (192 0 0 ) (192 0 304 ) +4 7 (96 -448 304 ) (128 -448 304 ) (128 0 304 ) (96 0 304 ) +4 7 (0 -416 304 ) (0 -448 304 ) (96 -448 304 ) (96 -416 304 ) +4 7 (0 0 0 ) (192 0 0 ) (192 -512 0 ) (0 -512 0 ) +4 8 (-64 128 320 ) (-64 128 304 ) (0 128 304 ) (0 128 320 ) +4 8 (-64 192 304 ) (-64 192 320 ) (0 192 320 ) (0 192 304 ) +4 8 (0 192 320 ) (-64 192 320 ) (-64 128 320 ) (0 128 320 ) +4 9 (0 96 352 ) (-32 96 352 ) (-32 0 352 ) (0 0 352 ) +4 9 (0 96 304 ) (-32 96 304 ) (-32 96 352 ) (0 96 352 ) +4 9 (-32 96 352 ) (-32 96 304 ) (-32 0 304 ) (-32 0 352 ) +4 10 (-480 192 320 ) (-480 192 304 ) (-480 0 304 ) (-480 0 320 ) +4 10 (-64 192 320 ) (-64 192 304 ) (-480 192 304 ) (-480 192 320 ) +4 10 (-64 128 320 ) (-64 96 320 ) (-64 96 304 ) (-64 128 304 ) +4 10 (-64 96 320 ) (-64 0 320 ) (-64 0 304 ) (-64 96 304 ) +4 10 (-64 0 320 ) (-64 192 320 ) (-480 192 320 ) (-480 0 320 ) +4 11 (-480 192 0 ) (-480 192 304 ) (0 192 304 ) (0 192 0 ) +4 11 (-480 192 304 ) (-480 192 0 ) (-480 0 0 ) (-480 0 304 ) +4 11 (0 96 304 ) (0 128 304 ) (-64 128 304 ) (-64 96 304 ) +4 11 (-32 96 304 ) (-64 96 304 ) (-64 0 304 ) (-32 0 304 ) +4 11 (0 0 0 ) (-480 0 0 ) (-480 192 0 ) (0 192 0 ) +4 12 (0 -416 352 ) (-32 -416 352 ) (-32 -416 304 ) (0 -416 304 ) +4 12 (-32 -416 352 ) (0 -416 352 ) (0 0 352 ) (-32 0 352 ) +4 12 (-32 0 304 ) (-32 -416 304 ) (-32 -416 352 ) (-32 0 352 ) +4 13 (-64 -512 304 ) (0 -512 304 ) (0 -512 320 ) (-64 -512 320 ) +4 13 (0 -448 320 ) (0 -448 304 ) (-64 -448 304 ) (-64 -448 320 ) +4 13 (0 -448 320 ) (-64 -448 320 ) (-64 -512 320 ) (0 -512 320 ) +4 14 (-480 -512 320 ) (-480 -512 304 ) (-64 -512 304 ) (-64 -512 320 ) +4 14 (-480 0 320 ) (-480 0 304 ) (-480 -512 304 ) (-480 -512 320 ) +4 14 (-64 -416 320 ) (-64 -448 320 ) (-64 -448 304 ) (-64 -416 304 ) +4 14 (-64 -416 320 ) (-64 -416 304 ) (-64 0 304 ) (-64 0 320 ) +4 14 (-480 0 320 ) (-480 -512 320 ) (-64 -512 320 ) (-64 0 320 ) +4 15 (-480 0 304 ) (-480 0 0 ) (-480 -512 0 ) (-480 -512 304 ) +4 15 (-480 -512 304 ) (-480 -512 0 ) (0 -512 0 ) (0 -512 304 ) +4 15 (0 -448 304 ) (0 -416 304 ) (-64 -416 304 ) (-64 -448 304 ) +4 15 (-32 -416 304 ) (-32 0 304 ) (-64 0 304 ) (-64 -416 304 ) +4 15 (0 -512 0 ) (-480 -512 0 ) (-480 0 0 ) (0 0 0 ) diff --git a/fakk/maps/example/exploder.bsp b/fakk/maps/example/exploder.bsp new file mode 100644 index 0000000..578ccc8 Binary files /dev/null and b/fakk/maps/example/exploder.bsp differ diff --git a/fakk/maps/example/exploder.map b/fakk/maps/example/exploder.map new file mode 100644 index 0000000..f23782b --- /dev/null +++ b/fakk/maps/example/exploder.map @@ -0,0 +1,99 @@ +{ +"classname" "worldspawn" +// brush 0 +{ +( 64 64 0 ) ( -64 64 0 ) ( -64 -64 0 ) eden/FL_underground 0 0 0.00 1 1 0 0 0 +( -64 -64 8 ) ( -64 64 8 ) ( 64 64 8 ) eden/FL_underground 0 0 0.00 1 1 0 0 0 +( -72 -64 8 ) ( 56 -64 8 ) ( 56 -64 0 ) eden/FL_underground 0 0 0.00 1 1 0 0 0 +( 64 -64 8 ) ( 64 64 8 ) ( 64 64 0 ) eden/FL_underground 0 0 0.00 1 1 0 0 0 +( 64 64 8 ) ( -64 64 8 ) ( -64 64 0 ) eden/FL_underground 0 0 0.00 1 1 0 0 0 +( -64 64 8 ) ( -64 -64 8 ) ( -64 -64 0 ) eden/FL_underground 0 0 0.00 1 1 0 0 0 +} +// brush 1 +{ +( 264 264 -8 ) ( -264 264 -8 ) ( -264 -272 -8 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 -272 264 ) ( -264 264 264 ) ( 264 264 264 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 -264 8 ) ( 264 -264 8 ) ( 264 -264 0 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( 264 264 8 ) ( -264 264 8 ) ( -264 264 0 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 264 8 ) ( -264 -272 8 ) ( -264 -272 0 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( -256 -272 8 ) ( -256 264 8 ) ( -256 -272 0 ) eden/FL_edenhouse2 0 0 0.00 1 1 0 0 0 +} +// brush 2 +{ +( 264 264 -8 ) ( -264 264 -8 ) ( -264 -272 -8 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 -272 264 ) ( -264 264 264 ) ( 264 264 264 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( 264 -272 8 ) ( 264 264 8 ) ( 264 264 0 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( 264 264 8 ) ( -264 264 8 ) ( -264 264 0 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 264 8 ) ( -264 -272 8 ) ( -264 -272 0 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 256 8 ) ( 264 256 8 ) ( -264 256 0 ) eden/FL_edenhouse2 0 0 0.00 1 1 0 0 0 +} +// brush 3 +{ +( 264 264 -8 ) ( -264 264 -8 ) ( -264 -272 -8 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 -272 264 ) ( -264 264 264 ) ( 264 264 264 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 -264 8 ) ( 264 -264 8 ) ( 264 -264 0 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( 264 -272 8 ) ( 264 264 8 ) ( 264 264 0 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( 264 264 8 ) ( -264 264 8 ) ( -264 264 0 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( 256 264 8 ) ( 256 -272 8 ) ( 256 264 0 ) eden/FL_edenhouse2 0 0 0.00 1 1 0 0 0 +} +// brush 4 +{ +( 264 264 -8 ) ( -264 264 -8 ) ( -264 -272 -8 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 -272 264 ) ( -264 264 264 ) ( 264 264 264 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 -264 8 ) ( 264 -264 8 ) ( 264 -264 0 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( 264 -272 8 ) ( 264 264 8 ) ( 264 264 0 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 264 8 ) ( -264 -272 8 ) ( -264 -272 0 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( 264 -256 8 ) ( -264 -256 8 ) ( 264 -256 0 ) eden/FL_edenhouse2 0 0 0.00 1 1 0 0 0 +} +// brush 5 +{ +( -264 -272 264 ) ( -264 264 264 ) ( 264 264 264 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 -264 8 ) ( 264 -264 8 ) ( 264 -264 0 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( 264 -272 8 ) ( 264 264 8 ) ( 264 264 0 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( 264 264 8 ) ( -264 264 8 ) ( -264 264 0 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 264 8 ) ( -264 -272 8 ) ( -264 -272 0 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 264 256 ) ( -264 -272 256 ) ( 264 264 256 ) eden/FL_edenhouse2 0 0 0.00 1 1 0 0 0 +} +// brush 6 +{ +( 264 264 -8 ) ( -264 264 -8 ) ( -264 -272 -8 ) eden/FL_edenhouse2 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 -264 8 ) ( 264 -264 8 ) ( 264 -264 0 ) eden/FL_edenhouse2 0 0 0.00 0.500000 0.500000 0 0 0 +( 264 -272 8 ) ( 264 264 8 ) ( 264 264 0 ) eden/FL_edenhouse2 0 0 0.00 0.500000 0.500000 0 0 0 +( 264 264 8 ) ( -264 264 8 ) ( -264 264 0 ) eden/FL_edenhouse2 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 264 8 ) ( -264 -272 8 ) ( -264 -272 0 ) eden/FL_edenhouse2 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 264 0 ) ( 264 264 0 ) ( -264 -272 0 ) eden/FL_edenhouse2 0 0 0.00 0.500000 0.500000 0 0 0 +} +} +// entity 1 +{ +"wait" "5" +"classname" "trigger_multiple" +"target" "t1" +// brush 0 +{ +( 64 64 8 ) ( -56 64 8 ) ( -56 -64 8 ) common/trigger 0 0 0.00 1 1 0 128 0 +( -56 -64 192 ) ( -56 64 192 ) ( 64 64 192 ) common/trigger 0 0 0.00 1 1 0 128 0 +( -56 -64 16 ) ( 64 -64 16 ) ( 64 -64 8 ) common/trigger 0 0 0.00 1 1 0 128 0 +( 64 -64 16 ) ( 64 64 16 ) ( 64 64 8 ) common/trigger 0 0 0.00 1 1 0 128 0 +( 64 64 16 ) ( -56 64 16 ) ( -56 64 8 ) common/trigger 0 0 0.00 1 1 0 128 0 +( -64 64 16 ) ( -64 -64 16 ) ( -64 -64 8 ) common/trigger 0 0 0.00 1 1 0 128 0 +} +} +// entity 2 +{ +"origin" "0 192 112" +"classname" "func_exploder" +"targetname" "t1" +} +// entity 3 +{ +"classname" "light" +"light" "1000" +"origin" "0 0 128" +} +// entity 4 +{ +"classname" "info_player_start" +"angle" "90" +"origin" "0 -192 16" +} diff --git a/fakk/maps/example/exploder.prt b/fakk/maps/example/exploder.prt new file mode 100644 index 0000000..67779b6 --- /dev/null +++ b/fakk/maps/example/exploder.prt @@ -0,0 +1,68 @@ +PRT1 +12 +20 +44 +4 0 6 0 (0 0 8 ) (0 0 256 ) (0 256 256 ) (0 256 8 ) +4 0 3 0 (0 0 256 ) (0 0 8 ) (256 0 8 ) (256 0 256 ) +4 0 2 0 (0 256 8 ) (64 256 8 ) (64 64 8 ) (0 64 8 ) +4 0 1 0 (64 256 8 ) (256 256 8 ) (256 0 8 ) (64 0 8 ) +4 1 4 0 (64 0 0 ) (256 0 0 ) (256 0 8 ) (64 0 8 ) +4 1 2 0 (64 256 0 ) (64 64 0 ) (64 64 8 ) (64 256 8 ) +4 2 7 0 (0 64 8 ) (0 256 8 ) (0 256 0 ) (0 64 0 ) +4 3 9 0 (0 0 256 ) (0 0 8 ) (0 -256 8 ) (0 -256 256 ) +4 3 5 0 (64 -256 8 ) (0 -256 8 ) (0 -64 8 ) (64 -64 8 ) +4 3 4 0 (256 -256 8 ) (64 -256 8 ) (64 0 8 ) (256 0 8 ) +4 4 5 0 (64 -64 0 ) (64 -256 0 ) (64 -256 8 ) (64 -64 8 ) +4 5 10 0 (0 -64 0 ) (0 -256 0 ) (0 -256 8 ) (0 -64 8 ) +4 6 9 0 (0 0 8 ) (0 0 256 ) (-256 0 256 ) (-256 0 8 ) +4 6 7 0 (-64 64 8 ) (-64 256 8 ) (0 256 8 ) (0 64 8 ) +4 6 8 0 (-64 0 8 ) (-256 0 8 ) (-256 256 8 ) (-64 256 8 ) +4 7 8 0 (-64 64 8 ) (-64 256 8 ) (-64 256 0 ) (-64 64 0 ) +4 8 11 0 (-64 0 8 ) (-256 0 8 ) (-256 0 0 ) (-64 0 0 ) +4 9 10 0 (0 -256 8 ) (-64 -256 8 ) (-64 -64 8 ) (0 -64 8 ) +4 9 11 0 (-64 -256 8 ) (-256 -256 8 ) (-256 0 8 ) (-64 0 8 ) +4 10 11 0 (-64 -64 0 ) (-64 -256 0 ) (-64 -256 8 ) (-64 -64 8 ) +4 0 (64 64 8 ) (64 0 8 ) (0 0 8 ) (0 64 8 ) +4 0 (0 0 256 ) (256 0 256 ) (256 256 256 ) (0 256 256 ) +4 0 (256 256 256 ) (256 256 8 ) (0 256 8 ) (0 256 256 ) +4 0 (256 0 256 ) (256 0 8 ) (256 256 8 ) (256 256 256 ) +4 1 (64 64 0 ) (64 0 0 ) (64 0 8 ) (64 64 8 ) +4 1 (256 0 8 ) (256 0 0 ) (256 256 0 ) (256 256 8 ) +4 1 (64 256 8 ) (256 256 8 ) (256 256 0 ) (64 256 0 ) +4 1 (256 0 0 ) (64 0 0 ) (64 256 0 ) (256 256 0 ) +4 2 (0 64 0 ) (0 256 0 ) (64 256 0 ) (64 64 0 ) +4 2 (64 256 8 ) (64 256 0 ) (0 256 0 ) (0 256 8 ) +4 2 (0 64 0 ) (64 64 0 ) (64 64 8 ) (0 64 8 ) +4 3 (0 -64 8 ) (0 0 8 ) (64 0 8 ) (64 -64 8 ) +4 3 (256 0 256 ) (0 0 256 ) (0 -256 256 ) (256 -256 256 ) +4 3 (256 -256 256 ) (256 -256 8 ) (256 0 8 ) (256 0 256 ) +4 3 (0 -256 256 ) (0 -256 8 ) (256 -256 8 ) (256 -256 256 ) +4 4 (64 0 0 ) (64 -64 0 ) (64 -64 8 ) (64 0 8 ) +4 4 (64 -256 0 ) (256 -256 0 ) (256 -256 8 ) (64 -256 8 ) +4 4 (256 -256 8 ) (256 -256 0 ) (256 0 0 ) (256 0 8 ) +4 4 (64 0 0 ) (256 0 0 ) (256 -256 0 ) (64 -256 0 ) +4 5 (0 -256 0 ) (0 -64 0 ) (64 -64 0 ) (64 -256 0 ) +4 5 (0 -256 8 ) (0 -256 0 ) (64 -256 0 ) (64 -256 8 ) +4 5 (0 -64 8 ) (64 -64 8 ) (64 -64 0 ) (0 -64 0 ) +4 6 (0 0 8 ) (-64 0 8 ) (-64 64 8 ) (0 64 8 ) +4 6 (0 256 256 ) (-256 256 256 ) (-256 0 256 ) (0 0 256 ) +4 6 (-256 0 8 ) (-256 0 256 ) (-256 256 256 ) (-256 256 8 ) +4 6 (0 256 256 ) (0 256 8 ) (-256 256 8 ) (-256 256 256 ) +4 7 (-64 64 0 ) (-64 256 0 ) (0 256 0 ) (0 64 0 ) +4 7 (-64 256 8 ) (0 256 8 ) (0 256 0 ) (-64 256 0 ) +4 7 (-64 64 8 ) (-64 64 0 ) (0 64 0 ) (0 64 8 ) +4 8 (-64 0 0 ) (-64 64 0 ) (-64 64 8 ) (-64 0 8 ) +4 8 (-64 256 8 ) (-64 256 0 ) (-256 256 0 ) (-256 256 8 ) +4 8 (-256 0 0 ) (-256 0 8 ) (-256 256 8 ) (-256 256 0 ) +4 8 (-64 0 0 ) (-256 0 0 ) (-256 256 0 ) (-64 256 0 ) +4 9 (-64 -64 8 ) (-64 0 8 ) (0 0 8 ) (0 -64 8 ) +4 9 (0 0 256 ) (-256 0 256 ) (-256 -256 256 ) (0 -256 256 ) +4 9 (-256 0 256 ) (-256 0 8 ) (-256 -256 8 ) (-256 -256 256 ) +4 9 (-256 -256 256 ) (-256 -256 8 ) (0 -256 8 ) (0 -256 256 ) +4 10 (0 -64 0 ) (0 -256 0 ) (-64 -256 0 ) (-64 -64 0 ) +4 10 (-64 -256 0 ) (0 -256 0 ) (0 -256 8 ) (-64 -256 8 ) +4 10 (0 -64 8 ) (0 -64 0 ) (-64 -64 0 ) (-64 -64 8 ) +4 11 (-64 0 8 ) (-64 -64 8 ) (-64 -64 0 ) (-64 0 0 ) +4 11 (-256 -256 8 ) (-256 -256 0 ) (-64 -256 0 ) (-64 -256 8 ) +4 11 (-256 0 8 ) (-256 0 0 ) (-256 -256 0 ) (-256 -256 8 ) +4 11 (-256 -256 0 ) (-256 0 0 ) (-64 0 0 ) (-64 -256 0 ) diff --git a/fakk/maps/example/explodingwall.bsp b/fakk/maps/example/explodingwall.bsp new file mode 100644 index 0000000..12f4efc Binary files /dev/null and b/fakk/maps/example/explodingwall.bsp differ diff --git a/fakk/maps/example/explodingwall.map b/fakk/maps/example/explodingwall.map new file mode 100644 index 0000000..9d8d7af --- /dev/null +++ b/fakk/maps/example/explodingwall.map @@ -0,0 +1,356 @@ +{ +"classname" "worldspawn" +// brush 0 +{ +( -128 136 64 ) ( 128 136 64 ) ( 128 136 208 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( 128 120 64 ) ( -128 120 64 ) ( -128 120 208 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( 64 120 187 ) ( 64 136 187 ) ( 147 136 139 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( 64 120 77 ) ( 64 136 77 ) ( -19 136 29 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( 64 136 120 ) ( 64 120 120 ) ( 64 136 24 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +} +// brush 1 +{ +( -128 136 0 ) ( -128 120 0 ) ( 128 120 0 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( -128 136 64 ) ( 128 136 64 ) ( 128 136 208 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( 256 136 64 ) ( 256 120 64 ) ( 256 120 208 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( 128 120 64 ) ( -128 120 64 ) ( -128 120 208 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( 64 120 187 ) ( 64 136 187 ) ( 147 136 139 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( -16 120 45 ) ( -16 136 45 ) ( -99 136 93 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( 64 136 77 ) ( 64 120 77 ) ( -19 136 29 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +} +// brush 2 +{ +( -128 136 0 ) ( -128 120 0 ) ( 128 120 0 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( -128 136 64 ) ( 128 136 64 ) ( 128 136 208 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( 128 120 64 ) ( -128 120 64 ) ( -128 120 208 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( -56 120 104 ) ( -56 136 104 ) ( -56 136 200 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( -16 136 45 ) ( -16 120 45 ) ( -99 136 93 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +} +// brush 3 +{ +( -128 136 0 ) ( -128 120 0 ) ( 128 120 0 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( -128 136 64 ) ( 128 136 64 ) ( 128 136 208 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( 128 120 64 ) ( -128 120 64 ) ( -128 120 208 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( -256 120 64 ) ( -256 136 64 ) ( -256 136 208 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( -8 120 187 ) ( -8 136 187 ) ( 75 136 235 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( -56 136 104 ) ( -56 120 104 ) ( -56 136 200 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +} +// brush 4 +{ +( 128 120 248 ) ( -128 120 248 ) ( -128 136 248 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( -128 136 64 ) ( 128 136 64 ) ( 128 136 208 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( 128 120 64 ) ( -128 120 64 ) ( -128 120 208 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( -256 120 64 ) ( -256 136 64 ) ( -256 136 208 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( 64 120 187 ) ( 64 136 187 ) ( 147 136 139 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( -8 136 187 ) ( -8 120 187 ) ( 75 136 235 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +} +// brush 5 +{ +( 128 120 248 ) ( -128 120 248 ) ( -128 136 248 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( -128 136 64 ) ( 128 136 64 ) ( 128 136 208 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( 256 136 64 ) ( 256 120 64 ) ( 256 120 208 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( 128 120 64 ) ( -128 120 64 ) ( -128 120 208 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( 64 136 187 ) ( 64 120 187 ) ( 147 136 139 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +} +// brush 6 +{ +( 128 320 8 ) ( -128 320 8 ) ( -128 304 8 ) eden/WL_darkbrick 0 128 0.00 1 1 0 0 0 +( -128 304 256 ) ( -128 320 256 ) ( 128 320 256 ) eden/WL_darkbrick 0 128 0.00 1 1 0 0 0 +( -128 304 192 ) ( 128 304 192 ) ( 128 304 48 ) eden/WL_darkbrick 0 0 0.00 1 1 0 0 0 +( 256 304 192 ) ( 256 320 192 ) ( 256 320 48 ) eden/WL_darkbrick -128 0 0.00 1 1 0 0 0 +( 128 320 192 ) ( -128 320 192 ) ( -128 320 48 ) eden/WL_darkbrick 0 0 0.00 1 1 0 0 0 +( -256 320 192 ) ( -256 304 192 ) ( -256 304 48 ) eden/WL_darkbrick -128 0 0.00 1 1 0 0 0 +} +// brush 7 +{ +( 64 0 0 ) ( -64 0 0 ) ( -64 -128 0 ) eden/FL_underground 0 -64 0.00 1 1 0 0 0 +( -64 -128 8 ) ( -64 0 8 ) ( 64 0 8 ) eden/FL_underground 0 -64 0.00 1 1 0 0 0 +( -72 -128 8 ) ( 56 -128 8 ) ( 56 -128 0 ) eden/FL_underground 0 0 0.00 1 1 0 0 0 +( 64 -128 8 ) ( 64 0 8 ) ( 64 0 0 ) eden/FL_underground 64 0 0.00 1 1 0 0 0 +( 64 0 8 ) ( -64 0 8 ) ( -64 0 0 ) eden/FL_underground 0 0 0.00 1 1 0 0 0 +( -64 0 8 ) ( -64 -128 8 ) ( -64 -128 0 ) eden/FL_underground 64 0 0.00 1 1 0 0 0 +} +// brush 8 +{ +( 264 264 -8 ) ( -264 264 -8 ) ( -264 -272 -8 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 -272 264 ) ( -264 264 264 ) ( 264 264 264 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 -264 8 ) ( 264 -264 8 ) ( 264 -264 0 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( 264 264 8 ) ( -264 264 8 ) ( -264 264 0 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 264 8 ) ( -264 -272 8 ) ( -264 -272 0 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( -256 -272 8 ) ( -256 264 8 ) ( -256 -272 0 ) eden/FL_edenhouse2 0 0 0.00 1 1 0 0 0 +} +// brush 9 +{ +( 264 264 -8 ) ( -264 264 -8 ) ( -264 -272 -8 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 -272 264 ) ( -264 264 264 ) ( 264 264 264 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( 264 -272 8 ) ( 264 264 8 ) ( 264 264 0 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( 264 264 8 ) ( -264 264 8 ) ( -264 264 0 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 264 8 ) ( -264 -272 8 ) ( -264 -272 0 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 256 8 ) ( 264 256 8 ) ( -264 256 0 ) eden/FL_edenhouse2 0 0 0.00 1 1 0 0 0 +} +// brush 10 +{ +( 264 264 -8 ) ( -264 264 -8 ) ( -264 -272 -8 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 -272 264 ) ( -264 264 264 ) ( 264 264 264 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 -264 8 ) ( 264 -264 8 ) ( 264 -264 0 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( 264 -272 8 ) ( 264 264 8 ) ( 264 264 0 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( 264 264 8 ) ( -264 264 8 ) ( -264 264 0 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( 256 264 8 ) ( 256 -272 8 ) ( 256 264 0 ) eden/FL_edenhouse2 0 0 0.00 1 1 0 0 0 +} +// brush 11 +{ +( 264 264 -8 ) ( -264 264 -8 ) ( -264 -272 -8 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 -272 264 ) ( -264 264 264 ) ( 264 264 264 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 -264 8 ) ( 264 -264 8 ) ( 264 -264 0 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( 264 -272 8 ) ( 264 264 8 ) ( 264 264 0 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 264 8 ) ( -264 -272 8 ) ( -264 -272 0 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( 264 -256 8 ) ( -264 -256 8 ) ( 264 -256 0 ) eden/FL_edenhouse2 0 0 0.00 1 1 0 0 0 +} +// brush 12 +{ +( -264 -272 264 ) ( -264 264 264 ) ( 264 264 264 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 -264 8 ) ( 264 -264 8 ) ( 264 -264 0 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( 264 -272 8 ) ( 264 264 8 ) ( 264 264 0 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( 264 264 8 ) ( -264 264 8 ) ( -264 264 0 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 264 8 ) ( -264 -272 8 ) ( -264 -272 0 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 264 256 ) ( -264 -272 256 ) ( 264 264 256 ) eden/FL_edenhouse2 0 0 0.00 1 1 0 0 0 +} +// brush 13 +{ +( 264 264 -8 ) ( -264 264 -8 ) ( -264 -272 -8 ) eden/FL_edenhouse2 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 -264 8 ) ( 264 -264 8 ) ( 264 -264 0 ) eden/FL_edenhouse2 0 0 0.00 0.500000 0.500000 0 0 0 +( 264 -272 8 ) ( 264 264 8 ) ( 264 264 0 ) eden/FL_edenhouse2 0 0 0.00 0.500000 0.500000 0 0 0 +( 264 264 8 ) ( -264 264 8 ) ( -264 264 0 ) eden/FL_edenhouse2 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 264 8 ) ( -264 -272 8 ) ( -264 -272 0 ) eden/FL_edenhouse2 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 264 0 ) ( 264 264 0 ) ( -264 -272 0 ) eden/FL_edenhouse2 0 0 0.00 0.500000 0.500000 0 0 0 +} +} +// entity 1 +{ +"classname" "func_explodingwall" +"targetname" "t1" +"random_velocity" "140 70 140" +"base_velocity" "0 -200 280" +"land_angles" "0 0 90" +"angle" "90" +// brush 0 +{ +( -31 136 174 ) ( -31 120 174 ) ( -56 120 159 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( -56 120 72 ) ( -56 136 72 ) ( -56 136 159 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( -31 120 174 ) ( -1 120 117 ) ( -56 120 72 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( -1 136 117 ) ( -31 136 174 ) ( -56 136 159 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( -1 136 117 ) ( -1 120 117 ) ( -31 120 174 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( 88 136 136 ) ( -80 136 144 ) ( 4 120 140 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +} +} +// entity 2 +{ +"classname" "func_explodingwall" +"targetname" "t1" +"random_velocity" "140 70 140" +"base_velocity" "0 -200 280" +"land_angles" "0 0 90" +"angle" "90" +// brush 0 +{ +( -56 120 72 ) ( -56 136 72 ) ( -56 136 159 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( -31 120 174 ) ( -1 120 117 ) ( -56 120 72 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( -1 136 117 ) ( -31 136 174 ) ( -56 136 159 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( -1 136 117 ) ( -1 120 117 ) ( -31 120 174 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( -1 120 117 ) ( -1 136 117 ) ( -56 136 72 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( -80 136 144 ) ( 88 136 136 ) ( 4 120 140 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( 96 136 24 ) ( -88 136 128 ) ( 4 120 76 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +} +} +// entity 3 +{ +"classname" "func_explodingwall" +"targetname" "t1" +"random_velocity" "140 70 140" +"base_velocity" "0 -200 280" +"land_angles" "0 0 90" +"angle" "90" +// brush 0 +{ +( -56 120 72 ) ( -56 136 72 ) ( -56 136 159 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( -31 120 174 ) ( -1 120 117 ) ( -56 120 72 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( -1 136 117 ) ( -31 136 174 ) ( -56 136 159 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( -1 120 117 ) ( -1 136 117 ) ( -56 136 72 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( -88 136 128 ) ( 96 136 24 ) ( 4 120 76 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +} +} +// entity 4 +{ +"classname" "func_explodingwall" +"targetname" "t1" +"random_velocity" "140 70 140" +"base_velocity" "0 -200 280" +"land_angles" "0 0 90" +"angle" "90" +// brush 0 +{ +( -56 136 72 ) ( -56 120 72 ) ( -56 120 68 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( -56 120 68 ) ( -4 120 38 ) ( -4 136 38 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( 30 120 58 ) ( 30 136 58 ) ( -4 136 38 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( -1 120 117 ) ( 30 120 58 ) ( -4 120 38 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( 30 136 58 ) ( -1 136 117 ) ( -56 136 72 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( -1 120 117 ) ( -1 136 117 ) ( 30 136 58 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( -1 136 117 ) ( -1 120 117 ) ( -56 120 72 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( -88 136 128 ) ( 96 136 24 ) ( 4 120 76 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +} +} +// entity 5 +{ +"classname" "func_explodingwall" +"targetname" "t1" +"random_velocity" "140 70 140" +"base_velocity" "0 -200 280" +"land_angles" "0 0 90" +"angle" "90" +// brush 0 +{ +( -1 120 117 ) ( 30 120 58 ) ( -4 120 38 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( 30 136 58 ) ( -1 136 117 ) ( -56 136 72 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( -1 120 117 ) ( -1 136 117 ) ( 30 136 58 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( -1 136 117 ) ( -1 120 117 ) ( -56 120 72 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( 96 136 24 ) ( -88 136 128 ) ( 4 120 76 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +} +} +// entity 6 +{ +"classname" "func_explodingwall" +"base_velocity" "0 -200 280" +"land_angles" "0 0 90" +"random_velocity" "140 70 140" +"targetname" "t1" +"angle" "90" +// brush 0 +{ +( 30 120 58 ) ( -1 120 117 ) ( 64 120 170 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( -1 136 117 ) ( 30 136 58 ) ( 64 136 77 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( -1 136 117 ) ( -1 120 117 ) ( 30 120 58 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( -1 120 117 ) ( -1 136 117 ) ( 64 136 170 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( -80 136 144 ) ( 88 136 136 ) ( 4 120 140 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( 32 136 232 ) ( 32 136 24 ) ( 32 120 128 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( 96 136 96 ) ( -16 136 32 ) ( 40 120 64 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +} +} +// entity 7 +{ +"classname" "func_explodingwall" +"base_velocity" "0 -200 280" +"land_angles" "0 0 90" +"random_velocity" "140 70 140" +"targetname" "t1" +"angle" "90" +// brush 0 +{ +( 30 136 58 ) ( 30 120 58 ) ( 64 120 77 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( 64 120 170 ) ( 64 136 170 ) ( 64 136 77 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( 30 120 58 ) ( -1 120 117 ) ( 64 120 170 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( -1 136 117 ) ( 30 136 58 ) ( 64 136 77 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( -80 136 144 ) ( 88 136 136 ) ( 4 120 140 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( 32 136 24 ) ( 32 136 232 ) ( 32 120 128 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( 96 136 24 ) ( -88 136 128 ) ( 4 120 76 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +} +} +// entity 8 +{ +"classname" "func_explodingwall" +"base_velocity" "0 -200 280" +"land_angles" "0 0 90" +"random_velocity" "140 70 140" +"targetname" "t1" +"angle" "90" +// brush 0 +{ +( 64 120 170 ) ( 64 136 170 ) ( 64 136 77 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( 30 120 58 ) ( -1 120 117 ) ( 64 120 170 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( -1 136 117 ) ( 30 136 58 ) ( 64 136 77 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( -1 120 117 ) ( -1 136 117 ) ( 64 136 170 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( 88 136 136 ) ( -80 136 144 ) ( 4 120 140 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( 24 136 24 ) ( 24 136 232 ) ( 24 120 128 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +} +} +// entity 9 +{ +"classname" "func_explodingwall" +"base_velocity" "0 -200 280" +"land_angles" "0 0 90" +"random_velocity" "140 70 140" +"targetname" "t1" +"angle" "90" +// brush 0 +{ +( -1 120 117 ) ( -31 120 174 ) ( 28 120 208 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( -31 136 174 ) ( -1 136 117 ) ( 64 136 170 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( -1 120 117 ) ( -1 136 117 ) ( -31 136 174 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( -1 136 117 ) ( -1 120 117 ) ( 64 120 170 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( -80 136 144 ) ( 88 136 136 ) ( 4 120 140 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +} +} +// entity 10 +{ +"classname" "func_explodingwall" +"base_velocity" "0 -200 280" +"land_angles" "0 0 90" +"random_velocity" "140 70 140" +"targetname" "t1" +"angle" "90" +// brush 0 +{ +( 64 120 187 ) ( 28 120 208 ) ( 28 136 208 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( 64 136 170 ) ( 64 120 170 ) ( 64 120 187 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( -1 120 117 ) ( -31 120 174 ) ( 28 120 208 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( -31 136 174 ) ( -1 136 117 ) ( 64 136 170 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( -1 136 117 ) ( -1 120 117 ) ( 64 120 170 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( 32 136 24 ) ( 32 136 232 ) ( 32 120 128 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +} +} +// entity 11 +{ +"classname" "func_explodingwall" +"base_velocity" "0 -200 280" +"land_angles" "0 0 90" +"random_velocity" "140 70 140" +"targetname" "t1" +"angle" "90" +// brush 0 +{ +( 64 120 187 ) ( 28 120 208 ) ( 28 136 208 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( -31 120 174 ) ( -31 136 174 ) ( 28 136 208 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( -1 120 117 ) ( -31 120 174 ) ( 28 120 208 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( -31 136 174 ) ( -1 136 117 ) ( 64 136 170 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( -1 120 117 ) ( -1 136 117 ) ( -31 136 174 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( -1 136 117 ) ( -1 120 117 ) ( 64 120 170 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( 88 136 136 ) ( -80 136 144 ) ( 4 120 140 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +( 32 136 232 ) ( 32 136 24 ) ( 32 120 128 ) eden/WL_basement_2w 0 0 0.00 1 1 0 0 0 +} +} +// entity 12 +{ +"target" "t1" +"classname" "trigger_multiple" +"wait" "5" +// brush 0 +{ +( 64 0 8 ) ( -56 0 8 ) ( -56 -128 8 ) common/trigger 0 0 0.00 1 1 0 128 0 +( -56 -128 192 ) ( -56 0 192 ) ( 64 0 192 ) common/trigger 0 0 0.00 1 1 0 128 0 +( -56 -128 16 ) ( 64 -128 16 ) ( 64 -128 8 ) common/trigger 0 0 0.00 1 1 0 128 0 +( 64 -128 16 ) ( 64 0 16 ) ( 64 0 8 ) common/trigger 0 0 0.00 1 1 0 128 0 +( 64 0 16 ) ( -56 0 16 ) ( -56 0 8 ) common/trigger 0 0 0.00 1 1 0 128 0 +( -64 0 16 ) ( -64 -128 16 ) ( -64 -128 8 ) common/trigger 0 0 0.00 1 1 0 128 0 +} +} +// entity 13 +{ +"origin" "0 0 128" +"light" "1000" +"classname" "light" +} +// entity 14 +{ +"origin" "0 -192 16" +"angle" "90" +"classname" "info_player_start" +} diff --git a/fakk/maps/example/explodingwall.prt b/fakk/maps/example/explodingwall.prt new file mode 100644 index 0000000..a3633f2 --- /dev/null +++ b/fakk/maps/example/explodingwall.prt @@ -0,0 +1,98 @@ +PRT1 +14 +24 +70 +4 0 7 0 (0 136 0 ) (0 136 256 ) (0 256 256 ) (0 256 0 ) +5 0 2 0 (0 136 191.626495 ) (0 136 39.987961 ) (64 136 77 ) (64 136 187 ) (28 136 207.819275 ) +4 0 1 0 (0 136 256 ) (0 136 248 ) (256 136 248 ) (256 136 256 ) +4 1 8 0 (0 120 248 ) (0 120 256 ) (0 136 256 ) (0 136 248 ) +4 1 3 0 (0 120 256 ) (0 120 248 ) (256 120 248 ) (256 120 256 ) +4 2 9 0 (0 120 39.987957 ) (0 120 191.626511 ) (0 136 191.626495 ) (0 136 39.987961 ) +5 2 3 0 (0 120 191.626495 ) (0 120 39.987961 ) (64 120 77 ) (64 120 187 ) (28 120 207.819275 ) +4 3 10 0 (0 0 0 ) (0 0 256 ) (0 120 256 ) (0 120 0 ) +4 3 5 0 (64 0 0 ) (256 0 0 ) (256 0 8 ) (64 0 8 ) +4 3 4 0 (0 0 256 ) (0 0 8 ) (256 0 8 ) (256 0 256 ) +4 4 11 0 (0 0 256 ) (0 0 8 ) (0 -256 8 ) (0 -256 256 ) +4 4 6 0 (64 -256 8 ) (0 -256 8 ) (0 -128 8 ) (64 -128 8 ) +4 4 5 0 (256 -256 8 ) (64 -256 8 ) (64 0 8 ) (256 0 8 ) +4 5 6 0 (64 -128 0 ) (64 -256 0 ) (64 -256 8 ) (64 -128 8 ) +4 6 12 0 (0 -128 0 ) (0 -256 0 ) (0 -256 8 ) (0 -128 8 ) +5 7 9 0 (0 136 39.987953 ) (0 136 191.626495 ) (-56 136 159.240967 ) (-56 136 68.132530 ) (-3.666669 136 37.867470 ) +4 7 8 0 (0 136 248 ) (0 136 256 ) (-256 136 256 ) (-256 136 248 ) +4 8 10 0 (-256 120 248 ) (0 120 248 ) (0 120 256 ) (-256 120 256 ) +5 9 10 0 (0 120 39.987953 ) (0 120 191.626495 ) (-56 120 159.240967 ) (-56 120 68.132530 ) (-3.666669 120 37.867470 ) +4 10 13 0 (-64 0 8 ) (-256 0 8 ) (-256 0 0 ) (-64 0 0 ) +4 10 11 0 (0 0 8 ) (0 0 256 ) (-256 0 256 ) (-256 0 8 ) +4 11 12 0 (0 -256 8 ) (-64 -256 8 ) (-64 -128 8 ) (0 -128 8 ) +4 11 13 0 (-64 -256 8 ) (-256 -256 8 ) (-256 0 8 ) (-64 0 8 ) +4 12 13 0 (-64 -128 0 ) (-64 -256 0 ) (-64 -256 8 ) (-64 -128 8 ) +3 0 (0 136 224.012039 ) (0 136 191.626495 ) (28 136 207.819275 ) +4 0 (0 136 248 ) (0 136 224.012039 ) (64 136 187 ) (64 136 248 ) +4 0 (0 136 39.987961 ) (0 136 0 ) (64 136 0 ) (64 136 77 ) +4 0 (64 136 0 ) (256 136 0 ) (256 136 248 ) (64 136 248 ) +4 0 (256 256 256 ) (0 256 256 ) (0 136 256 ) (256 136 256 ) +4 0 (256 136 0 ) (0 136 0 ) (0 256 0 ) (256 256 0 ) +4 0 (256 256 256 ) (256 256 0 ) (0 256 0 ) (0 256 256 ) +4 0 (256 136 0 ) (256 256 0 ) (256 256 256 ) (256 136 256 ) +4 1 (0 136 248 ) (64 136 248 ) (64 120 248 ) (0 120 248 ) +4 1 (64 136 248 ) (256 136 248 ) (256 120 248 ) (64 120 248 ) +4 1 (256 120 256 ) (256 120 248 ) (256 136 248 ) (256 136 256 ) +4 1 (0 120 256 ) (256 120 256 ) (256 136 256 ) (0 136 256 ) +4 2 (28 120 207.819458 ) (64 120 187 ) (64 136 187 ) (28 136 207.819458 ) +4 2 (64 136 77 ) (64 136 187 ) (64 120 187 ) (64 120 77 ) +4 2 (0 136 39.988037 ) (64 136 77 ) (64 120 77 ) (0 120 39.988037 ) +4 2 (0 120 191.626389 ) (28 120 207.819443 ) (28 136 207.819443 ) (0 136 191.626389 ) +4 3 (0 0 8 ) (0 0 0 ) (64 0 0 ) (64 0 8 ) +4 3 (0 120 0 ) (256 120 0 ) (256 0 0 ) (0 0 0 ) +4 3 (64 120 248 ) (256 120 248 ) (256 120 0 ) (64 120 0 ) +4 3 (64 120 77 ) (64 120 0 ) (0 120 0 ) (0 120 39.987961 ) +4 3 (64 120 248 ) (64 120 187 ) (0 120 224.012039 ) (0 120 248 ) +3 3 (28 120 207.819275 ) (0 120 191.626495 ) (0 120 224.012039 ) +4 3 (256 0 256 ) (256 0 0 ) (256 120 0 ) (256 120 256 ) +4 3 (0 0 256 ) (256 0 256 ) (256 120 256 ) (0 120 256 ) +4 4 (0 -128 8 ) (0 0 8 ) (64 0 8 ) (64 -128 8 ) +4 4 (256 0 256 ) (0 0 256 ) (0 -256 256 ) (256 -256 256 ) +4 4 (256 -256 256 ) (256 -256 8 ) (256 0 8 ) (256 0 256 ) +4 4 (0 -256 256 ) (0 -256 8 ) (256 -256 8 ) (256 -256 256 ) +4 5 (64 0 0 ) (64 -128 0 ) (64 -128 8 ) (64 0 8 ) +4 5 (64 -256 0 ) (256 -256 0 ) (256 -256 8 ) (64 -256 8 ) +4 5 (256 -256 8 ) (256 -256 0 ) (256 0 0 ) (256 0 8 ) +4 5 (64 0 0 ) (256 0 0 ) (256 -256 0 ) (64 -256 0 ) +4 6 (0 -256 0 ) (0 -128 0 ) (64 -128 0 ) (64 -256 0 ) +4 6 (0 -256 8 ) (0 -256 0 ) (64 -256 0 ) (64 -256 8 ) +4 6 (0 -128 8 ) (64 -128 8 ) (64 -128 0 ) (0 -128 0 ) +4 7 (-56 136 248 ) (-256 136 248 ) (-256 136 0 ) (-56 136 0 ) +3 7 (-56 136 68.132530 ) (-56 136 7.602408 ) (-3.666669 136 37.867470 ) +4 7 (0 136 0 ) (0 136 39.987953 ) (-56 136 7.602408 ) (-56 136 0 ) +4 7 (0 136 191.626495 ) (0 136 248 ) (-56 136 248 ) (-56 136 159.240967 ) +4 7 (0 256 256 ) (-256 256 256 ) (-256 136 256 ) (0 136 256 ) +4 7 (0 136 0 ) (-256 136 0 ) (-256 256 0 ) (0 256 0 ) +4 7 (-256 256 0 ) (-256 136 0 ) (-256 136 256 ) (-256 256 256 ) +4 7 (0 256 0 ) (-256 256 0 ) (-256 256 256 ) (0 256 256 ) +4 8 (-56 120 248 ) (-256 120 248 ) (-256 136 248 ) (-56 136 248 ) +4 8 (0 120 248 ) (-56 120 248 ) (-56 136 248 ) (0 136 248 ) +4 8 (0 136 256 ) (-256 136 256 ) (-256 120 256 ) (0 120 256 ) +4 8 (-256 136 248 ) (-256 120 248 ) (-256 120 256 ) (-256 136 256 ) +4 9 (-56 120 68.132530 ) (-56 120 159.240952 ) (-56 136 159.240967 ) (-56 136 68.132530 ) +4 9 (-3.666928 136 37.867622 ) (0 136 39.988255 ) (0 120 39.988247 ) (-3.666920 120 37.867619 ) +4 9 (0 120 191.626297 ) (0 136 191.626297 ) (-56 136 159.240723 ) (-56 120 159.240723 ) +4 9 (-3.666125 136 37.867592 ) (-3.666126 120 37.867592 ) (-56 120 68.132957 ) (-56 136 68.132957 ) +4 10 (0 0 0 ) (0 0 8 ) (-64 0 8 ) (-64 0 0 ) +4 10 (0 0 0 ) (-256 0 0 ) (-256 120 0 ) (0 120 0 ) +4 10 (-56 120 159.240967 ) (-56 120 248 ) (0 120 248 ) (0 120 191.626495 ) +4 10 (-56 120 7.602408 ) (0 120 39.987953 ) (0 120 0 ) (-56 120 0 ) +3 10 (-3.666669 120 37.867470 ) (-56 120 7.602408 ) (-56 120 68.132530 ) +4 10 (-256 120 248 ) (-56 120 248 ) (-56 120 0 ) (-256 120 0 ) +4 10 (-256 120 256 ) (-256 120 0 ) (-256 0 0 ) (-256 0 256 ) +4 10 (0 120 256 ) (-256 120 256 ) (-256 0 256 ) (0 0 256 ) +4 11 (-64 -128 8 ) (-64 0 8 ) (0 0 8 ) (0 -128 8 ) +4 11 (0 0 256 ) (-256 0 256 ) (-256 -256 256 ) (0 -256 256 ) +4 11 (-256 0 256 ) (-256 0 8 ) (-256 -256 8 ) (-256 -256 256 ) +4 11 (-256 -256 256 ) (-256 -256 8 ) (0 -256 8 ) (0 -256 256 ) +4 12 (0 -128 0 ) (0 -256 0 ) (-64 -256 0 ) (-64 -128 0 ) +4 12 (-64 -256 0 ) (0 -256 0 ) (0 -256 8 ) (-64 -256 8 ) +4 12 (0 -128 8 ) (0 -128 0 ) (-64 -128 0 ) (-64 -128 8 ) +4 13 (-64 0 8 ) (-64 -128 8 ) (-64 -128 0 ) (-64 0 0 ) +4 13 (-256 -256 8 ) (-256 -256 0 ) (-64 -256 0 ) (-64 -256 8 ) +4 13 (-256 0 8 ) (-256 0 0 ) (-256 -256 0 ) (-256 -256 8 ) +4 13 (-256 -256 0 ) (-256 0 0 ) (-64 0 0 ) (-64 -256 0 ) diff --git a/fakk/maps/example/fallingrock.bsp b/fakk/maps/example/fallingrock.bsp new file mode 100644 index 0000000..04cc399 Binary files /dev/null and b/fakk/maps/example/fallingrock.bsp differ diff --git a/fakk/maps/example/fallingrock.map b/fakk/maps/example/fallingrock.map new file mode 100644 index 0000000..358b667 --- /dev/null +++ b/fakk/maps/example/fallingrock.map @@ -0,0 +1,300 @@ +{ +"classname" "worldspawn" +// brush 0 +{ +( 264 -248 0 ) ( 112 -248 0 ) ( 112 -416 0 ) tom/wl_wood_dark 0 0 0.00 1 1 0 0 0 +( 112 -416 8 ) ( 112 -248 8 ) ( 264 -248 8 ) tom/wl_wood_dark 0 0 0.00 1 1 0 0 0 +( 112 -416 8 ) ( 264 -416 8 ) ( 264 -416 -56 ) tom/wl_wood_dark 0 0 0.00 1 1 0 0 0 +( 264 -416 64 ) ( 264 -248 64 ) ( 264 -248 0 ) tom/wl_wood_dark 0 0 0.00 1 1 0 0 0 +( 264 -248 64 ) ( 112 -248 64 ) ( 112 -248 0 ) tom/wl_wood_dark 0 0 0.00 1 1 0 0 0 +( 112 -248 8 ) ( 112 -416 8 ) ( 112 -416 -56 ) tom/wl_wood_dark 0 0 0.00 1 1 0 0 0 +} +// brush 1 +{ +( -128 0 0 ) ( -320 0 0 ) ( -320 -192 0 ) tom/fl_wgmarb 0 0 0.00 1 1 0 0 0 +( -320 -192 32 ) ( -320 0 32 ) ( -128 0 32 ) tom/fl_wgmarb 0 0 0.00 1 1 0 0 0 +( -320 -192 96 ) ( -128 -192 96 ) ( -128 -192 0 ) tom/fl_wgmarb 0 0 0.00 1 1 0 0 0 +( -128 -192 32 ) ( -128 0 32 ) ( -128 0 -64 ) tom/fl_wgmarb 0 0 0.00 1 1 0 0 0 +( -128 0 32 ) ( -320 0 32 ) ( -320 0 -64 ) tom/fl_wgmarb 0 0 0.00 1 1 0 0 0 +( -320 0 96 ) ( -320 -192 96 ) ( -320 -192 0 ) tom/fl_wgmarb 0 0 0.00 1 1 0 0 0 +} +// brush 2 +{ +( -128 192 0 ) ( -320 192 0 ) ( -320 0 0 ) tom/fl_wgmarb 0 0 0.00 1 1 0 0 0 +( -128 0 32 ) ( -320 0 32 ) ( -320 192 96 ) tom/fl_wgmarb 0 0 0.00 1 1 0 0 0 +( -320 0 32 ) ( -128 0 32 ) ( -128 0 0 ) tom/fl_wgmarb 0 0 0.00 1 1 0 0 0 +( -128 0 96 ) ( -128 192 96 ) ( -128 192 -96 ) tom/fl_wgmarb 0 0 0.00 1 1 0 0 0 +( -128 192 128 ) ( -320 192 128 ) ( -320 192 -64 ) tom/fl_wgmarb 0 0 0.00 1 1 0 0 0 +( -320 192 192 ) ( -320 0 192 ) ( -320 0 0 ) tom/fl_wgmarb 0 0 0.00 1 1 0 0 0 +} +// brush 3 +{ +( 64 192 0 ) ( -128 192 0 ) ( -128 0 0 ) tom/fl_wgmarb 0 0 0.00 1 1 0 0 0 +( -128 0 96 ) ( -128 192 96 ) ( 64 192 192 ) tom/fl_wgmarb 0 0 0.00 1 1 0 0 0 +( -128 0 128 ) ( 64 0 128 ) ( 64 0 0 ) tom/fl_wgmarb 0 0 0.00 1 1 0 0 0 +( 64 0 192 ) ( 64 192 192 ) ( 64 192 0 ) tom/fl_wgmarb 0 0 0.00 1 1 0 0 0 +( 64 192 128 ) ( -128 192 128 ) ( -128 192 0 ) tom/fl_wgmarb 0 0 0.00 1 1 0 0 0 +( -128 192 96 ) ( -128 0 96 ) ( -128 0 0 ) tom/fl_wgmarb 0 0 0.00 1 1 0 0 0 +} +// brush 4 +{ +( 64 0 0 ) ( -128 0 0 ) ( -128 -192 0 ) tom/fl_wgmarb 0 0 0.00 1 1 0 0 0 +( 64 -192 224 ) ( -128 -192 224 ) ( -128 0 192 ) tom/fl_wgmarb 0 0 0.00 1 1 0 0 0 +( -128 -192 224 ) ( 64 -192 224 ) ( 64 -192 0 ) tom/fl_wgmarb 0 0 0.00 1 1 0 0 0 +( 64 -192 128 ) ( 64 0 128 ) ( 64 0 0 ) tom/fl_wgmarb 0 0 0.00 1 1 0 0 0 +( 64 0 192 ) ( -128 0 192 ) ( -128 0 0 ) tom/fl_wgmarb 0 0 0.00 1 1 0 0 0 +( -128 0 128 ) ( -128 -192 128 ) ( -128 -192 0 ) tom/fl_wgmarb 0 0 0.00 1 1 0 0 0 +} +// brush 5 +{ +( 256 0 0 ) ( 64 0 0 ) ( 64 -192 0 ) tom/fl_wgmarb 0 0 0.00 1 1 0 0 0 +( 64 0 192 ) ( 256 0 288 ) ( 256 -192 320 ) tom/fl_wgmarb 0 0 0.00 1 1 0 0 0 +( 64 -192 320 ) ( 256 -192 320 ) ( 256 -192 0 ) tom/fl_wgmarb 0 0 0.00 1 1 0 0 0 +( 256 -192 128 ) ( 256 0 128 ) ( 256 0 0 ) tom/fl_wgmarb 0 0 0.00 1 1 0 0 0 +( 256 0 288 ) ( 64 0 192 ) ( 64 0 0 ) tom/fl_wgmarb 0 0 0.00 1 1 0 0 0 +( 64 0 224 ) ( 64 -192 224 ) ( 64 -192 0 ) tom/fl_wgmarb 0 0 0.00 1 1 0 0 0 +} +// brush 6 +{ +( 256 192 0 ) ( 64 192 0 ) ( 64 0 0 ) tom/fl_wgmarb 0 0 0.00 1 1 0 0 0 +( 64 192 544 ) ( 256 192 544 ) ( 256 0 320 ) tom/fl_wgmarb 0 0 0.00 1 1 0 0 0 +( 64 0 320 ) ( 256 0 320 ) ( 256 0 0 ) tom/fl_wgmarb 0 0 0.00 1 1 0 0 0 +( 256 0 -128 ) ( 256 192 -128 ) ( 256 192 -256 ) tom/fl_wgmarb 0 0 0.00 1 1 0 0 0 +( 256 192 544 ) ( 64 192 544 ) ( 64 192 0 ) tom/fl_wgmarb 0 0 0.00 1 1 0 0 0 +( 64 192 128 ) ( 64 0 128 ) ( 64 0 0 ) tom/fl_wgmarb 0 0 0.00 1 1 0 0 0 +} +// brush 7 +{ +( 256 384 0 ) ( 64 384 0 ) ( 64 192 0 ) tom/fl_wgmarb 0 0 0.00 1 1 0 0 0 +( 256 192 544 ) ( 64 192 544 ) ( 64 384 640 ) tom/fl_wgmarb 0 0 0.00 1 1 0 0 0 +( 64 192 544 ) ( 256 192 544 ) ( 256 192 0 ) tom/fl_wgmarb 0 0 0.00 1 1 0 0 0 +( 256 192 512 ) ( 256 384 640 ) ( 256 384 0 ) tom/fl_wgmarb 0 0 0.00 1 1 0 0 0 +( 256 384 128 ) ( 64 384 128 ) ( 64 384 0 ) tom/fl_wgmarb 0 0 0.00 1 1 0 0 0 +( 64 384 640 ) ( 64 192 640 ) ( 64 192 0 ) tom/fl_wgmarb 0 0 0.00 1 1 0 0 0 +} +// brush 8 +{ +( 64 384 0 ) ( -128 384 0 ) ( -128 192 0 ) tom/fl_wgmarb 0 0 0.00 1 1 0 0 0 +( 64 384 640 ) ( 64 192 640 ) ( -128 192 768 ) tom/fl_wgmarb 0 0 0.00 1 1 0 0 0 +( -128 192 128 ) ( 64 192 128 ) ( 64 192 0 ) tom/fl_wgmarb 0 0 0.00 1 1 0 0 0 +( 64 192 640 ) ( 64 384 640 ) ( 64 384 0 ) tom/fl_wgmarb 0 0 0.00 1 1 0 0 0 +( 64 384 128 ) ( -128 384 128 ) ( -128 384 0 ) tom/fl_wgmarb 0 0 0.00 1 1 0 0 0 +( -128 384 128 ) ( -128 192 128 ) ( -128 192 0 ) tom/fl_wgmarb 0 0 0.00 1 1 0 0 0 +} +// brush 9 +{ +( -128 384 0 ) ( -320 384 0 ) ( -320 192 0 ) tom/fl_wgmarb 0 0 0.00 1 1 0 0 0 +( -320 192 1024 ) ( -320 384 1024 ) ( -128 384 768 ) tom/fl_wgmarb 0 0 0.00 1 1 0 0 0 +( -320 192 128 ) ( -128 192 128 ) ( -128 192 0 ) tom/fl_wgmarb 0 0 0.00 1 1 0 0 0 +( -128 192 128 ) ( -128 384 128 ) ( -128 384 0 ) tom/fl_wgmarb 0 0 0.00 1 1 0 0 0 +( -128 384 128 ) ( -320 384 128 ) ( -320 384 0 ) tom/fl_wgmarb 0 0 0.00 1 1 0 0 0 +( -320 384 1024 ) ( -320 192 1024 ) ( -320 192 0 ) tom/fl_wgmarb 0 0 0.00 1 1 0 0 0 +} +// brush 10 +{ +( 512 512 -32 ) ( -312 512 -32 ) ( -312 -512 -32 ) tom/right_thingie 0 0 0.00 1 1 0 0 0 +( -312 -512 1568 ) ( -312 512 1568 ) ( 512 512 1568 ) tom/right_thingie 0 0 0.00 1 1 0 0 0 +( -304 -520 32 ) ( 520 -520 32 ) ( 520 -520 0 ) tom/right_thingie 0 0 0.00 1 1 0 0 0 +( 512 520 32 ) ( -312 520 32 ) ( -312 520 0 ) tom/right_thingie 0 0 0.00 1 1 0 0 0 +( -520 512 32 ) ( -520 -512 32 ) ( -520 -512 0 ) tom/right_thingie 0 0 0.00 1 1 0 0 0 +( -512 -512 32 ) ( -512 512 32 ) ( -512 -512 0 ) tom/wl_wood_dark 0 0 0.00 1 1 0 0 0 +} +// brush 11 +{ +( 512 512 -32 ) ( -312 512 -32 ) ( -312 -512 -32 ) tom/right_thingie 0 0 0.00 1 1 0 0 0 +( -312 -512 1568 ) ( -312 512 1568 ) ( 512 512 1568 ) tom/right_thingie 0 0 0.00 1 1 0 0 0 +( 520 -520 32 ) ( 520 504 32 ) ( 520 504 0 ) tom/right_thingie 0 0 0.00 1 1 0 0 0 +( 512 520 32 ) ( -312 520 32 ) ( -312 520 0 ) tom/right_thingie 0 0 0.00 1 1 0 0 0 +( -520 512 32 ) ( -520 -512 32 ) ( -520 -512 0 ) tom/right_thingie 0 0 0.00 1 1 0 0 0 +( -312 512 32 ) ( 512 512 32 ) ( -312 512 0 ) tom/wl_wood_dark 0 0 0.00 1 1 0 0 0 +} +// brush 12 +{ +( 512 512 -32 ) ( -312 512 -32 ) ( -312 -512 -32 ) tom/right_thingie 0 0 0.00 1 1 0 0 0 +( -312 -512 1568 ) ( -312 512 1568 ) ( 512 512 1568 ) tom/right_thingie 0 0 0.00 1 1 0 0 0 +( -304 -520 32 ) ( 520 -520 32 ) ( 520 -520 0 ) tom/right_thingie 0 0 0.00 1 1 0 0 0 +( 520 -520 32 ) ( 520 504 32 ) ( 520 504 0 ) tom/right_thingie 0 0 0.00 1 1 0 0 0 +( 512 520 32 ) ( -312 520 32 ) ( -312 520 0 ) tom/right_thingie 0 0 0.00 1 1 0 0 0 +( 512 504 32 ) ( 512 -520 32 ) ( 512 504 0 ) tom/wl_wood_dark 0 0 0.00 1 1 0 0 0 +} +// brush 13 +{ +( 512 512 -32 ) ( -312 512 -32 ) ( -312 -512 -32 ) tom/right_thingie 0 0 0.00 1 1 0 0 0 +( -312 -512 1568 ) ( -312 512 1568 ) ( 512 512 1568 ) tom/right_thingie 0 0 0.00 1 1 0 0 0 +( -304 -520 32 ) ( 520 -520 32 ) ( 520 -520 0 ) tom/right_thingie 0 0 0.00 1 1 0 0 0 +( 520 -520 32 ) ( 520 504 32 ) ( 520 504 0 ) tom/right_thingie 0 0 0.00 1 1 0 0 0 +( -520 512 32 ) ( -520 -512 32 ) ( -520 -512 0 ) tom/right_thingie 0 0 0.00 1 1 0 0 0 +( 520 -512 32 ) ( -304 -512 32 ) ( 520 -512 0 ) tom/wl_wood_dark 0 0 0.00 1 1 0 0 0 +} +// brush 14 +{ +( -312 -512 1576 ) ( -312 512 1576 ) ( 512 512 1576 ) tom/wl_wood_dark 0 0 0.00 1 1 0 0 0 +( -304 -520 1192 ) ( 520 -520 1192 ) ( 520 -520 1184 ) tom/wl_wood_dark 0 0 0.00 1 1 0 0 0 +( 520 -520 1192 ) ( 520 504 1192 ) ( 520 504 1184 ) tom/wl_wood_dark 0 0 0.00 1 1 0 0 0 +( 512 520 1192 ) ( -312 520 1192 ) ( -312 520 1184 ) tom/wl_wood_dark 0 0 0.00 1 1 0 0 0 +( -520 512 1192 ) ( -520 -512 1192 ) ( -520 -512 1184 ) tom/wl_wood_dark 0 0 0.00 1 1 0 0 0 +( -312 512 1568 ) ( -312 -512 1568 ) ( 512 512 1568 ) tom/wl_wood_dark 0 0 0.00 1 1 0 0 0 +} +// brush 15 +{ +( 512 512 -8 ) ( -312 512 -8 ) ( -312 -512 -8 ) tom/fl_wgmarb 0 0 0.00 1 1 0 0 0 +( -304 -520 8 ) ( 520 -520 8 ) ( 520 -520 0 ) tom/fl_wgmarb 0 0 0.00 1 1 0 0 0 +( 520 -520 8 ) ( 520 504 8 ) ( 520 504 0 ) tom/fl_wgmarb 0 0 0.00 1 1 0 0 0 +( 512 520 8 ) ( -312 520 8 ) ( -312 520 0 ) tom/fl_wgmarb 0 0 0.00 1 1 0 0 0 +( -520 512 8 ) ( -520 -512 8 ) ( -520 -512 0 ) tom/fl_wgmarb 0 0 0.00 1 1 0 0 0 +( -312 512 0 ) ( 512 512 0 ) ( -312 -512 0 ) tom/fl_wgmarb 0 0 0.00 1 1 0 0 0 +} +} +// entity 1 +{ +"target" "t10" +"classname" "trigger_multiple" +// brush 0 +{ +( 264 -248 0 ) ( 112 -248 0 ) ( 112 -416 0 ) common/trigger 0 0 0.00 1 1 0 128 0 +( 112 -416 152 ) ( 112 -248 152 ) ( 264 -248 152 ) common/trigger 0 0 0.00 1 1 0 128 0 +( 112 -416 8 ) ( 264 -416 8 ) ( 264 -416 0 ) common/trigger 0 0 0.00 1 1 0 128 0 +( 264 -416 8 ) ( 264 -248 8 ) ( 264 -248 0 ) common/trigger 0 0 0.00 1 1 0 128 0 +( 264 -248 8 ) ( 112 -248 8 ) ( 112 -248 0 ) common/trigger 0 0 0.00 1 1 0 128 0 +( 112 -248 8 ) ( 112 -416 8 ) ( 112 -416 0 ) common/trigger 0 0 0.00 1 1 0 128 0 +} +} +// entity 2 +{ +"targetname" "t10" +"target" "t9" +"classname" "func_fallingrock" +"spawnflags" "1" +// brush 0 +{ +( -152 296 1216 ) ( -248 296 1216 ) ( -248 200 1216 ) tom/wl_wood_dark 0 0 0.00 1 1 0 0 0 +( -248 200 1280 ) ( -248 296 1280 ) ( -152 296 1280 ) tom/wl_wood_dark 0 0 0.00 1 1 0 0 0 +( -280 232 1280 ) ( -184 232 1280 ) ( -184 232 1264 ) tom/wl_wood_dark 0 0 0.00 1 1 0 0 0 +( -184 232 1280 ) ( -184 328 1280 ) ( -184 328 1264 ) tom/wl_wood_dark 0 0 0.00 1 1 0 0 0 +( -152 296 1280 ) ( -248 296 1280 ) ( -248 296 1264 ) tom/wl_wood_dark 0 0 0.00 1 1 0 0 0 +( -248 296 1280 ) ( -248 200 1280 ) ( -248 200 1264 ) tom/wl_wood_dark 0 0 0.00 1 1 0 0 0 +} +} +// entity 3 +{ +"target" "t1" +"origin" "-144 264 824" +"classname" "info_waypoint" +"targetname" "t9" +} +// entity 4 +{ +"origin" "136 264 776" +"classname" "light" +} +// entity 5 +{ +"origin" "336 -304 0" +"angle" "135" +"classname" "info_player_start" +} +// entity 6 +{ +"classname" "light" +"origin" "-216 264 1064" +} +// entity 7 +{ +"origin" "136 -88 424" +"classname" "light" +} +// entity 8 +{ +"classname" "light" +"origin" "-216 -88 328" +} +// entity 9 +{ +"origin" "-216 -344 328" +"classname" "light" +} +// entity 10 +{ +"classname" "light" +"origin" "136 -312 328" +} +// entity 11 +{ +"origin" "424 -312 328" +"classname" "light" +} +// entity 12 +{ +"classname" "light" +"origin" "392 104 328" +} +// entity 13 +{ +"origin" "-24 72 456" +"classname" "light" +} +// entity 14 +{ +"target" "t2" +"targetname" "t1" +"classname" "info_waypoint" +"origin" "-24 264 712" +} +// entity 15 +{ +"target" "t3" +"targetname" "t2" +"origin" "168 296 600" +"classname" "info_waypoint" +} +// entity 16 +{ +"target" "t4" +"targetname" "t3" +"classname" "info_waypoint" +"origin" "152 72 408" +} +// entity 17 +{ +"target" "t5" +"targetname" "t4" +"origin" "168 -88 264" +"classname" "info_waypoint" +} +// entity 18 +{ +"target" "t6" +"targetname" "t5" +"classname" "info_waypoint" +"origin" "-40 -104 216" +} +// entity 19 +{ +"target" "t7" +"targetname" "t6" +"origin" "-40 112 176" +"classname" "info_waypoint" +} +// entity 20 +{ +"target" "t8" +"targetname" "t7" +"classname" "info_waypoint" +"origin" "-256 104 96" +} +// entity 21 +{ +"targetname" "t8" +"origin" "-248 -88 40" +"classname" "info_waypoint" +} +// entity 22 +{ +"origin" "-128 192 1256" +"classname" "light" +} +// entity 23 +{ +"classname" "light" +"origin" "-256 296 1256" +} diff --git a/fakk/maps/example/fallingrock.prt b/fakk/maps/example/fallingrock.prt new file mode 100644 index 0000000..fe326cd --- /dev/null +++ b/fakk/maps/example/fallingrock.prt @@ -0,0 +1,145 @@ +PRT1 +23 +49 +92 +4 0 7 0 (256 0 0 ) (512 0 0 ) (512 0 1568 ) (256 0 1568 ) +3 0 3 0 (256 192 544 ) (256 384 768 ) (256 384 640 ) +4 0 2 0 (256 0 320 ) (256 0 1568 ) (256 384 1568 ) (256 384 768 ) +4 0 1 0 (256 512 1568 ) (256 512 0 ) (256 384 0 ) (256 384 1568 ) +4 1 4 0 (64 512 0 ) (64 384 0 ) (64 384 1568 ) (64 512 1568 ) +4 1 3 0 (64 384 768 ) (64 384 640 ) (256 384 640 ) (256 384 768 ) +4 1 2 0 (64 384 1568 ) (64 384 768 ) (256 384 768 ) (256 384 1568 ) +4 2 8 0 (256 0 320 ) (256 0 1568 ) (64 0 1568 ) (64 0 320 ) +4 2 6 0 (64 0 320 ) (64 0 1568 ) (64 192 1568 ) (64 192 544 ) +5 2 5 0 (64 192 1568 ) (64 384 1568 ) (64 384 768 ) (64 274.285736 640 ) (64 192 640 ) +4 2 3 0 (64 192.001160 544 ) (64 384 768 ) (256 384 768 ) (256 192 544 ) +3 3 5 0 (64 274.285736 640 ) (64 384 768 ) (64 384 640 ) +4 4 14 0 (0 384 1568 ) (0 512 1568 ) (0 512 0 ) (0 384 0 ) +4 4 5 0 (64 384 640 ) (64 384 1568 ) (0 384 1568 ) (0 384 682.666748 ) +4 5 15 0 (0 192 1568 ) (0 384 1568 ) (0 384 682.666748 ) (0 192 682.666687 ) +4 5 6 0 (64 192 640 ) (64 192 1568 ) (0 192 1568 ) (0 192 682.666748 ) +4 6 16 0 (0 0 160 ) (0 0 1568 ) (0 192 1568 ) (0 192 160 ) +4 6 8 0 (0 0 1568 ) (0 0 192 ) (64 0 192 ) (64 0 1568 ) +4 7 9 0 (256 -192 0 ) (512 -192 0 ) (512 -192 1568 ) (256 -192 1568 ) +4 7 8 0 (256 -192 320 ) (256 -192 1568 ) (256 0 1568 ) (256 0 288 ) +4 8 19 0 (0 0 1568 ) (0 0 192 ) (0 -192 224 ) (0 -192 1568 ) +5 8 9 0 (0 -192 1568 ) (0 -192 224 ) (64 -192 224 ) (256 -192 320 ) (256 -192 1568 ) +4 9 22 0 (0 -248 1568 ) (0 -192 1568 ) (0 -192 0 ) (0 -248 0 ) +4 9 11 0 (264 -248 0 ) (512 -248 0 ) (512 -248 8 ) (264 -248 8 ) +4 9 13 0 (0 -248 0 ) (112 -248 0 ) (112 -248 8 ) (0 -248 8 ) +4 9 10 0 (512 -248 8 ) (512 -248 1568 ) (0 -248 1568 ) (0 -248 8 ) +4 10 22 0 (0 -512 1568 ) (0 -248 1568 ) (0 -248 8 ) (0 -512 8 ) +4 10 11 0 (264 -248 8 ) (512 -248 8 ) (512 -416 8 ) (264 -416 8 ) +4 10 12 0 (512 -512 8 ) (112 -512 8 ) (112 -416 8 ) (512 -416 8 ) +4 10 13 0 (112 -512 8 ) (0 -512 8 ) (0 -248 8 ) (112 -248 8 ) +4 11 12 0 (264 -416 0 ) (512 -416 0 ) (512 -416 8 ) (264 -416 8 ) +4 12 13 0 (112 -512 0 ) (112 -512 8 ) (112 -416 8 ) (112 -416 0 ) +4 13 22 0 (0 -248 8 ) (0 -248 0 ) (0 -512 0 ) (0 -512 8 ) +5 14 15 0 (0 384 682.666687 ) (0 384 1568 ) (-320 384 1568 ) (-320 384 1024 ) (-128 384 768 ) +4 14 18 0 (-512 384 1568 ) (-512 384 0 ) (-320 384 0 ) (-320 384 1568 ) +4 15 17 0 (-320 192 1568 ) (-320 192 1024 ) (-128 192 768 ) (-128 192 1568 ) +4 15 16 0 (-128 192 768 ) (0 192 682.666687 ) (0 192 1568 ) (-128 192 1568 ) +4 15 18 0 (-320 192 1568 ) (-320 384 1568 ) (-320 384 1024 ) (-320 192 1024 ) +4 16 19 0 (0 0 192 ) (0 0 1568 ) (-128 0 1568 ) (-128 0 192 ) +4 16 17 0 (-128 192 1568 ) (-128 192 96 ) (-128 0 96 ) (-128 0 1568 ) +4 17 20 0 (-128 0 1568 ) (-320 0 1568 ) (-320 0 32 ) (-128 0 32 ) +4 17 18 0 (-320 0 1568 ) (-320 192 1568 ) (-320 192 96 ) (-320 0 32 ) +4 18 21 0 (-512 0 32 ) (-512 0 0 ) (-320 0 0 ) (-320 0 32 ) +4 18 20 0 (-320 0 1568 ) (-512 0 1568 ) (-512 0 32 ) (-320 0 32 ) +4 19 22 0 (0 -192 224 ) (0 -192 1568 ) (-128 -192 1568 ) (-128 -192 224 ) +4 19 20 0 (-128 -192 224 ) (-128 -192 1568 ) (-128 0 1568 ) (-128 0 192 ) +4 20 22 0 (-512 -192 1568 ) (-512 -192 32 ) (-128 -192 32 ) (-128 -192 1568 ) +4 20 21 0 (-320 -192 32 ) (-512 -192 32 ) (-512 0 32 ) (-320 0 32 ) +4 21 22 0 (-512 -192 32 ) (-512 -192 0 ) (-320 -192 0 ) (-320 -192 32 ) +5 0 (256 384 0 ) (256 0 0 ) (256 0 320 ) (256 192 544 ) (256 384 640 ) +4 0 (512 512 1568 ) (256 512 1568 ) (256 0 1568 ) (512 0 1568 ) +4 0 (512 0 0 ) (256 0 0 ) (256 512 0 ) (512 512 0 ) +4 0 (256 512 1568 ) (512 512 1568 ) (512 512 0 ) (256 512 0 ) +4 0 (512 512 1568 ) (512 0 1568 ) (512 0 0 ) (512 512 0 ) +4 1 (64 384 640 ) (64 384 0 ) (256 384 0 ) (256 384 640 ) +4 1 (64 512 1568 ) (256 512 1568 ) (256 512 0 ) (64 512 0 ) +4 1 (64 384 0 ) (64 512 0 ) (256 512 0 ) (256 384 0 ) +4 1 (64 384 1568 ) (256 384 1568 ) (256 512 1568 ) (64 512 1568 ) +3 2 (64 274.285736 640 ) (64 192 544 ) (64 192 640 ) +4 2 (64 0 320 ) (64 192.001160 544 ) (256 192 544 ) (256 0 320 ) +4 2 (64 384 1568 ) (64 0 1568 ) (256 0 1568 ) (256 384 1568 ) +3 3 (64 192 544 ) (64 274.285736 640 ) (64 384 640 ) +4 3 (256 192 544 ) (64 192 544 ) (64 384 640 ) (256 384 640 ) +4 4 (0 384 0 ) (64 384 0 ) (64 384 640 ) (0 384 682.666748 ) +4 4 (0 384 1568 ) (64 384 1568 ) (64 512 1568 ) (0 512 1568 ) +4 4 (0 384 0 ) (0 512 0 ) (64 512 0 ) (64 384 0 ) +4 4 (64 512 1568 ) (64 512 0 ) (0 512 0 ) (0 512 1568 ) +4 5 (0 384 1568 ) (0 192 1568 ) (64 192 1568 ) (64 384 1568 ) +4 5 (64 192 640 ) (0 192 682.666931 ) (0 384 682.666504 ) (64 384 640 ) +3 6 (0 0 192 ) (0 0 160 ) (64 0 192 ) +4 6 (64 192 192 ) (64 192 544 ) (64 0 320 ) (64 0 192 ) +4 6 (0 192 1568 ) (0 0 1568 ) (64 0 1568 ) (64 192 1568 ) +4 6 (0 192 160 ) (0 192 682.666748 ) (64 192 640 ) (64 192 192 ) +4 6 (0 192 160 ) (64 192 192 ) (64 0 192 ) (0 0 160 ) +4 7 (256 0 0 ) (256 -192 0 ) (256 -192 320 ) (256 0 288 ) +4 7 (512 0 1568 ) (256 0 1568 ) (256 -192 1568 ) (512 -192 1568 ) +4 7 (256 0 0 ) (512 0 0 ) (512 -192 0 ) (256 -192 0 ) +4 7 (512 -192 1568 ) (512 -192 0 ) (512 0 0 ) (512 0 1568 ) +4 8 (256 0 288 ) (256 -192 320 ) (64 -192 224 ) (64 0 192 ) +4 8 (256 0 1568 ) (0 0 1568 ) (0 -192 1568 ) (256 -192 1568 ) +4 8 (64 0 192 ) (64 0 320 ) (256 0 320 ) (256 0 288 ) +4 8 (0 0 192 ) (64 0 192 ) (64 -192 224 ) (0 -192 224 ) +4 9 (112 -248 0 ) (264 -248 0 ) (264 -248 8 ) (112 -248 8 ) +4 9 (512 -248 1568 ) (512 -192 1568 ) (0 -192 1568 ) (0 -248 1568 ) +3 9 (64 -192 224 ) (0 -192 192 ) (0 -192 224 ) +4 9 (256 -192 320 ) (256 -192 0 ) (0 -192 0 ) (0 -192 192 ) +4 9 (0 -248 0 ) (0 -192 0 ) (512 -192 0 ) (512 -248 0 ) +4 9 (512 -192 1568 ) (512 -248 1568 ) (512 -248 0 ) (512 -192 0 ) +4 10 (112 -416 8 ) (112 -248 8 ) (264 -248 8 ) (264 -416 8 ) +4 10 (512 -512 8 ) (512 -512 1568 ) (0 -512 1568 ) (0 -512 8 ) +4 10 (512 -512 1568 ) (512 -248 1568 ) (0 -248 1568 ) (0 -512 1568 ) +4 10 (512 -248 8 ) (512 -248 1568 ) (512 -512 1568 ) (512 -512 8 ) +4 11 (512 -248 8 ) (512 -416 8 ) (512 -416 0 ) (512 -248 0 ) +4 11 (264 -248 0 ) (512 -248 0 ) (512 -416 0 ) (264 -416 0 ) +4 11 (264 -416 0 ) (264 -416 8 ) (264 -248 8 ) (264 -248 0 ) +4 12 (264 -416 8 ) (264 -416 0 ) (112 -416 0 ) (112 -416 8 ) +4 12 (112 -512 0 ) (512 -512 0 ) (512 -512 8 ) (112 -512 8 ) +4 12 (512 -416 0 ) (512 -512 0 ) (112 -512 0 ) (112 -416 0 ) +4 12 (512 -416 8 ) (512 -512 8 ) (512 -512 0 ) (512 -416 0 ) +4 13 (112 -416 0 ) (112 -248 0 ) (112 -248 8 ) (112 -416 8 ) +4 13 (0 -512 0 ) (0 -248 0 ) (112 -248 0 ) (112 -512 0 ) +4 13 (0 -512 0 ) (112 -512 0 ) (112 -512 8 ) (0 -512 8 ) +3 14 (-320 384 1024 ) (-320 384 896 ) (-128 384 768 ) +4 14 (-320 384 0 ) (0 384 0 ) (0 384 682.666687 ) (-320 384 896 ) +4 14 (0 512 1568 ) (-512 512 1568 ) (-512 384 1568 ) (0 384 1568 ) +4 14 (-512 384 0 ) (-512 512 0 ) (0 512 0 ) (0 384 0 ) +4 14 (-512 512 0 ) (-512 384 0 ) (-512 384 1568 ) (-512 512 1568 ) +4 14 (-512 512 1568 ) (0 512 1568 ) (0 512 0 ) (-512 512 0 ) +4 15 (0 192 682.666565 ) (-128 192 768 ) (-128 384 768 ) (0 384 682.666565 ) +4 15 (0 192 1568 ) (0 384 1568 ) (-320 384 1568 ) (-320 192 1568 ) +4 15 (-128 384 768 ) (-128 192 768 ) (-320 192 1024 ) (-320 384 1024 ) +4 16 (0 0 160 ) (0 0 192 ) (-128 0 192 ) (-128 0 96 ) +4 16 (-128 192 96 ) (-128 192 768 ) (0 192 682.666687 ) (0 192 160 ) +4 16 (0 192 1568 ) (-128 192 1568 ) (-128 0 1568 ) (0 0 1568 ) +4 16 (-128 0 96 ) (-128 192 96 ) (0 192 160 ) (0 0 160 ) +3 17 (-128 192 768 ) (-320 192 896 ) (-320 192 1024 ) +4 17 (-128 192 768 ) (-128 192 96 ) (-320 192 96 ) (-320 192 896 ) +4 17 (-128 192 1568 ) (-320 192 1568 ) (-320 0 1568 ) (-128 0 1568 ) +3 17 (-128 0 96 ) (-128 0 32 ) (-128 192 96 ) +4 17 (-320 0 32 ) (-320 192 96 ) (-128 192 96 ) (-128 0 32 ) +4 18 (-320 0 32 ) (-320 0 0 ) (-320 192 0 ) (-320 192 96 ) +4 18 (-320 192 1024 ) (-320 192 896 ) (-320 384 896 ) (-320 384 1024 ) +4 18 (-320 192 896 ) (-320 192 0 ) (-320 384 0 ) (-320 384 896 ) +4 18 (-320 384 1568 ) (-512 384 1568 ) (-512 0 1568 ) (-320 0 1568 ) +4 18 (-320 0 0 ) (-512 0 0 ) (-512 384 0 ) (-320 384 0 ) +4 18 (-512 0 0 ) (-512 0 1568 ) (-512 384 1568 ) (-512 384 0 ) +4 19 (0 0 1568 ) (-128 0 1568 ) (-128 -192 1568 ) (0 -192 1568 ) +4 19 (0 -192 224 ) (-128 -192 224 ) (-128 0 192 ) (0 0 192 ) +4 20 (-128 -192 32 ) (-320 -192 32 ) (-320 0 32 ) (-128 0 32 ) +4 20 (-128 0 192 ) (-128 -192 224 ) (-128 -192 32 ) (-128 0 32 ) +4 20 (-512 0 1568 ) (-512 0 32 ) (-512 -192 32 ) (-512 -192 1568 ) +4 20 (-128 0 1568 ) (-512 0 1568 ) (-512 -192 1568 ) (-128 -192 1568 ) +4 21 (-512 0 32 ) (-512 0 0 ) (-512 -192 0 ) (-512 -192 32 ) +4 21 (-512 -192 0 ) (-512 0 0 ) (-320 0 0 ) (-320 -192 0 ) +4 21 (-320 0 32 ) (-320 -192 32 ) (-320 -192 0 ) (-320 0 0 ) +4 22 (0 -512 1568 ) (0 -192 1568 ) (-512 -192 1568 ) (-512 -512 1568 ) +4 22 (-320 -192 32 ) (0 -192 32 ) (0 -192 0 ) (-320 -192 0 ) +4 22 (-128 -192 224 ) (0 -192 224 ) (0 -192 32 ) (-128 -192 32 ) +4 22 (-512 -512 0 ) (-512 -192 0 ) (0 -192 0 ) (0 -512 0 ) +4 22 (-512 -192 0 ) (-512 -512 0 ) (-512 -512 1568 ) (-512 -192 1568 ) +4 22 (-512 -512 0 ) (0 -512 0 ) (0 -512 1568 ) (-512 -512 1568 ) diff --git a/fakk/maps/example/fulcrum.bsp b/fakk/maps/example/fulcrum.bsp new file mode 100644 index 0000000..3987fab Binary files /dev/null and b/fakk/maps/example/fulcrum.bsp differ diff --git a/fakk/maps/example/fulcrum.map b/fakk/maps/example/fulcrum.map new file mode 100644 index 0000000..5bc01f3 --- /dev/null +++ b/fakk/maps/example/fulcrum.map @@ -0,0 +1,490 @@ +{ +"classname" "worldspawn" +// brush 0 +{ +( -64 -264 0 ) ( -320 -264 0 ) ( -320 -384 0 ) eden/woodfloor 0 -8 0.00 1 1 0 0 0 +( -320 -384 16 ) ( -320 -264 16 ) ( -64 -264 16 ) eden/woodfloor 0 -8 0.00 1 1 0 0 0 +( -320 -384 96 ) ( -64 -384 96 ) ( -64 -384 0 ) eden/woodfloor 0 -24 0.00 1 1 0 0 0 +( -64 -384 96 ) ( -64 -264 96 ) ( -64 -264 0 ) eden/woodfloor 72 -24 0.00 1 1 0 0 0 +( -64 -264 96 ) ( -320 -264 96 ) ( -320 -264 0 ) eden/woodfloor 0 -24 0.00 1 1 0 0 0 +( -320 -264 96 ) ( -320 -384 96 ) ( -320 -384 0 ) eden/woodfloor 72 -24 0.00 1 1 0 0 0 +} +// brush 1 +{ +( -48 -264 16 ) ( -304 -264 16 ) ( -304 -384 16 ) eden/woodfloor -16 -8 0.00 1 1 0 0 0 +( -304 -384 32 ) ( -304 -264 32 ) ( -48 -264 32 ) eden/woodfloor -16 -8 0.00 1 1 0 0 0 +( -304 -384 112 ) ( -48 -384 112 ) ( -48 -384 16 ) eden/woodfloor -16 -8 0.00 1 1 0 0 0 +( -64 -384 112 ) ( -64 -264 112 ) ( -64 -264 16 ) eden/woodfloor 72 -8 0.00 1 1 0 0 0 +( -48 -264 112 ) ( -304 -264 112 ) ( -304 -264 16 ) eden/woodfloor -16 -8 0.00 1 1 0 0 0 +( -304 -264 112 ) ( -304 -384 112 ) ( -304 -384 16 ) eden/woodfloor 72 -8 0.00 1 1 0 0 0 +} +// brush 2 +{ +( -32 -264 32 ) ( -288 -264 32 ) ( -288 -384 32 ) eden/woodfloor -32 -8 0.00 1 1 0 0 0 +( -288 -384 48 ) ( -288 -264 48 ) ( -32 -264 48 ) eden/woodfloor -32 -8 0.00 1 1 0 0 0 +( -288 -384 128 ) ( -32 -384 128 ) ( -32 -384 32 ) eden/woodfloor -32 8 0.00 1 1 0 0 0 +( -64 -384 128 ) ( -64 -264 128 ) ( -64 -264 32 ) eden/woodfloor 72 8 0.00 1 1 0 0 0 +( -32 -264 128 ) ( -288 -264 128 ) ( -288 -264 32 ) eden/woodfloor -32 8 0.00 1 1 0 0 0 +( -288 -264 128 ) ( -288 -384 128 ) ( -288 -384 32 ) eden/woodfloor 72 8 0.00 1 1 0 0 0 +} +// brush 3 +{ +( -16 -264 48 ) ( -272 -264 48 ) ( -272 -384 48 ) eden/woodfloor -48 -8 0.00 1 1 0 0 0 +( -272 -384 64 ) ( -272 -264 64 ) ( -16 -264 64 ) eden/woodfloor -48 -8 0.00 1 1 0 0 0 +( -272 -384 144 ) ( -16 -384 144 ) ( -16 -384 48 ) eden/woodfloor -48 24 0.00 1 1 0 0 0 +( -64 -384 144 ) ( -64 -264 144 ) ( -64 -264 48 ) eden/woodfloor 72 24 0.00 1 1 0 0 0 +( -16 -264 144 ) ( -272 -264 144 ) ( -272 -264 48 ) eden/woodfloor -48 24 0.00 1 1 0 0 0 +( -272 -264 144 ) ( -272 -384 144 ) ( -272 -384 48 ) eden/woodfloor 72 24 0.00 1 1 0 0 0 +} +// brush 4 +{ +( 0 -264 64 ) ( -256 -264 64 ) ( -256 -384 64 ) eden/woodfloor -64 -8 0.00 1 1 0 0 0 +( -256 -384 80 ) ( -256 -264 80 ) ( 0 -264 80 ) eden/woodfloor -64 -8 0.00 1 1 0 0 0 +( -256 -384 160 ) ( 0 -384 160 ) ( 0 -384 64 ) eden/woodfloor -64 -24 0.00 1 1 0 0 0 +( -64 -384 160 ) ( -64 -264 160 ) ( -64 -264 64 ) eden/woodfloor 72 -24 0.00 1 1 0 0 0 +( 0 -264 160 ) ( -256 -264 160 ) ( -256 -264 64 ) eden/woodfloor -64 -24 0.00 1 1 0 0 0 +( -256 -264 160 ) ( -256 -384 160 ) ( -256 -384 64 ) eden/woodfloor 72 -24 0.00 1 1 0 0 0 +} +// brush 5 +{ +( 16 -264 80 ) ( -240 -264 80 ) ( -240 -384 80 ) eden/woodfloor -80 -8 0.00 1 1 0 0 0 +( -240 -384 96 ) ( -240 -264 96 ) ( 16 -264 96 ) eden/woodfloor -80 -8 0.00 1 1 0 0 0 +( -240 -384 176 ) ( 16 -384 176 ) ( 16 -384 80 ) eden/woodfloor -80 -8 0.00 1 1 0 0 0 +( -64 -384 176 ) ( -64 -264 176 ) ( -64 -264 80 ) eden/woodfloor 72 -8 0.00 1 1 0 0 0 +( 16 -264 176 ) ( -240 -264 176 ) ( -240 -264 80 ) eden/woodfloor -80 -8 0.00 1 1 0 0 0 +( -240 -264 176 ) ( -240 -384 176 ) ( -240 -384 80 ) eden/woodfloor 72 -8 0.00 1 1 0 0 0 +} +// brush 6 +{ +( 32 -264 96 ) ( -224 -264 96 ) ( -224 -384 96 ) eden/woodfloor -96 -8 0.00 1 1 0 0 0 +( -224 -384 112 ) ( -224 -264 112 ) ( 32 -264 112 ) eden/woodfloor -96 -8 0.00 1 1 0 0 0 +( -224 -384 192 ) ( 32 -384 192 ) ( 32 -384 96 ) eden/woodfloor -96 8 0.00 1 1 0 0 0 +( -64 -384 192 ) ( -64 -264 192 ) ( -64 -264 96 ) eden/woodfloor 72 8 0.00 1 1 0 0 0 +( 32 -264 192 ) ( -224 -264 192 ) ( -224 -264 96 ) eden/woodfloor -96 8 0.00 1 1 0 0 0 +( -224 -264 192 ) ( -224 -384 192 ) ( -224 -384 96 ) eden/woodfloor 72 8 0.00 1 1 0 0 0 +} +// brush 7 +{ +( 48 -264 112 ) ( -208 -264 112 ) ( -208 -384 112 ) eden/woodfloor -112 -8 0.00 1 1 0 0 0 +( -208 -384 128 ) ( -208 -264 128 ) ( 48 -264 128 ) eden/woodfloor -112 -8 0.00 1 1 0 0 0 +( -208 -384 208 ) ( 48 -384 208 ) ( 48 -384 112 ) eden/woodfloor -112 24 0.00 1 1 0 0 0 +( -64 -384 208 ) ( -64 -264 208 ) ( -64 -264 112 ) eden/woodfloor 72 24 0.00 1 1 0 0 0 +( 48 -264 208 ) ( -208 -264 208 ) ( -208 -264 112 ) eden/woodfloor -112 24 0.00 1 1 0 0 0 +( -208 -264 208 ) ( -208 -384 208 ) ( -208 -384 112 ) eden/woodfloor 72 24 0.00 1 1 0 0 0 +} +// brush 8 +{ +( 64 -264 128 ) ( -192 -264 128 ) ( -192 -384 128 ) eden/woodfloor 0 -8 0.00 1 1 0 0 0 +( -192 -384 144 ) ( -192 -264 144 ) ( 64 -264 144 ) eden/woodfloor 0 -8 0.00 1 1 0 0 0 +( -192 -384 224 ) ( 64 -384 224 ) ( 64 -384 128 ) eden/woodfloor 0 -24 0.00 1 1 0 0 0 +( -64 -376 224 ) ( -64 -256 224 ) ( -64 -256 128 ) eden/woodfloor 72 -24 0.00 1 1 0 0 0 +( 64 -264 224 ) ( -192 -264 224 ) ( -192 -264 128 ) eden/woodfloor 0 -24 0.00 1 1 0 0 0 +( -192 -264 224 ) ( -192 -384 224 ) ( -192 -384 128 ) eden/woodfloor 72 -24 0.00 1 1 0 0 0 +} +// brush 9 +{ +( 80 -264 144 ) ( -176 -264 144 ) ( -176 -384 144 ) eden/woodfloor -16 -8 0.00 1 1 0 0 0 +( -176 -384 160 ) ( -176 -264 160 ) ( 80 -264 160 ) eden/woodfloor -16 -8 0.00 1 1 0 0 0 +( -176 -384 240 ) ( 80 -384 240 ) ( 80 -384 144 ) eden/woodfloor -16 -8 0.00 1 1 0 0 0 +( -64 -376 240 ) ( -64 -256 240 ) ( -64 -256 144 ) eden/woodfloor 72 -8 0.00 1 1 0 0 0 +( 80 -264 240 ) ( -176 -264 240 ) ( -176 -264 144 ) eden/woodfloor -16 -8 0.00 1 1 0 0 0 +( -176 -264 240 ) ( -176 -384 240 ) ( -176 -384 144 ) eden/woodfloor 72 -8 0.00 1 1 0 0 0 +} +// brush 10 +{ +( 96 -264 160 ) ( -160 -264 160 ) ( -160 -384 160 ) eden/woodfloor -32 -8 0.00 1 1 0 0 0 +( -160 -384 176 ) ( -160 -264 176 ) ( 96 -264 176 ) eden/woodfloor -32 -8 0.00 1 1 0 0 0 +( -160 -384 256 ) ( 96 -384 256 ) ( 96 -384 160 ) eden/woodfloor -32 8 0.00 1 1 0 0 0 +( -64 -376 256 ) ( -64 -256 256 ) ( -64 -256 160 ) eden/woodfloor 72 8 0.00 1 1 0 0 0 +( 96 -264 256 ) ( -160 -264 256 ) ( -160 -264 160 ) eden/woodfloor -32 8 0.00 1 1 0 0 0 +( -160 -264 256 ) ( -160 -384 256 ) ( -160 -384 160 ) eden/woodfloor 72 8 0.00 1 1 0 0 0 +} +// brush 11 +{ +( 96 64 160 ) ( -160 64 160 ) ( -160 -56 160 ) eden/woodfloor -32 0 0.00 1 1 0 0 0 +( -160 -56 176 ) ( -160 64 176 ) ( 96 64 176 ) eden/woodfloor -32 0 0.00 1 1 0 0 0 +( -160 -56 256 ) ( 96 -56 256 ) ( 96 -56 160 ) eden/woodfloor -32 8 0.00 1 1 0 0 0 +( -64 -48 256 ) ( -64 72 256 ) ( -64 72 160 ) eden/woodfloor 0 8 0.00 1 1 0 0 0 +( 96 64 256 ) ( -160 64 256 ) ( -160 64 160 ) eden/woodfloor -32 8 0.00 1 1 0 0 0 +( -160 64 256 ) ( -160 -56 256 ) ( -160 -56 160 ) eden/woodfloor 0 8 0.00 1 1 0 0 0 +} +// brush 12 +{ +( 80 64 144 ) ( -176 64 144 ) ( -176 -56 144 ) eden/woodfloor -16 0 0.00 1 1 0 0 0 +( -176 -56 160 ) ( -176 64 160 ) ( 80 64 160 ) eden/woodfloor -16 0 0.00 1 1 0 0 0 +( -176 -56 240 ) ( 80 -56 240 ) ( 80 -56 144 ) eden/woodfloor -16 -8 0.00 1 1 0 0 0 +( -64 -48 240 ) ( -64 72 240 ) ( -64 72 144 ) eden/woodfloor 0 -8 0.00 1 1 0 0 0 +( 80 64 240 ) ( -176 64 240 ) ( -176 64 144 ) eden/woodfloor -16 -8 0.00 1 1 0 0 0 +( -176 64 240 ) ( -176 -56 240 ) ( -176 -56 144 ) eden/woodfloor 0 -8 0.00 1 1 0 0 0 +} +// brush 13 +{ +( 64 64 128 ) ( -192 64 128 ) ( -192 -56 128 ) eden/woodfloor 0 0 0.00 1 1 0 0 0 +( -192 -56 144 ) ( -192 64 144 ) ( 64 64 144 ) eden/woodfloor 0 0 0.00 1 1 0 0 0 +( -192 -56 224 ) ( 64 -56 224 ) ( 64 -56 128 ) eden/woodfloor 0 -24 0.00 1 1 0 0 0 +( -64 -48 224 ) ( -64 72 224 ) ( -64 72 128 ) eden/woodfloor 0 -24 0.00 1 1 0 0 0 +( 64 64 224 ) ( -192 64 224 ) ( -192 64 128 ) eden/woodfloor 0 -24 0.00 1 1 0 0 0 +( -192 64 224 ) ( -192 -56 224 ) ( -192 -56 128 ) eden/woodfloor 0 -24 0.00 1 1 0 0 0 +} +// brush 14 +{ +( 48 64 112 ) ( -208 64 112 ) ( -208 -56 112 ) eden/woodfloor -112 0 0.00 1 1 0 0 0 +( -208 -56 128 ) ( -208 64 128 ) ( 48 64 128 ) eden/woodfloor -112 0 0.00 1 1 0 0 0 +( -208 -56 208 ) ( 48 -56 208 ) ( 48 -56 112 ) eden/woodfloor -112 24 0.00 1 1 0 0 0 +( -64 -56 208 ) ( -64 64 208 ) ( -64 64 112 ) eden/woodfloor 0 24 0.00 1 1 0 0 0 +( 48 64 208 ) ( -208 64 208 ) ( -208 64 112 ) eden/woodfloor -112 24 0.00 1 1 0 0 0 +( -208 64 208 ) ( -208 -56 208 ) ( -208 -56 112 ) eden/woodfloor 0 24 0.00 1 1 0 0 0 +} +// brush 15 +{ +( 32 64 96 ) ( -224 64 96 ) ( -224 -56 96 ) eden/woodfloor -96 0 0.00 1 1 0 0 0 +( -224 -56 112 ) ( -224 64 112 ) ( 32 64 112 ) eden/woodfloor -96 0 0.00 1 1 0 0 0 +( -224 -56 192 ) ( 32 -56 192 ) ( 32 -56 96 ) eden/woodfloor -96 8 0.00 1 1 0 0 0 +( -64 -56 192 ) ( -64 64 192 ) ( -64 64 96 ) eden/woodfloor 0 8 0.00 1 1 0 0 0 +( 32 64 192 ) ( -224 64 192 ) ( -224 64 96 ) eden/woodfloor -96 8 0.00 1 1 0 0 0 +( -224 64 192 ) ( -224 -56 192 ) ( -224 -56 96 ) eden/woodfloor 0 8 0.00 1 1 0 0 0 +} +// brush 16 +{ +( 16 64 80 ) ( -240 64 80 ) ( -240 -56 80 ) eden/woodfloor -80 0 0.00 1 1 0 0 0 +( -240 -56 96 ) ( -240 64 96 ) ( 16 64 96 ) eden/woodfloor -80 0 0.00 1 1 0 0 0 +( -240 -56 176 ) ( 16 -56 176 ) ( 16 -56 80 ) eden/woodfloor -80 -8 0.00 1 1 0 0 0 +( -64 -56 176 ) ( -64 64 176 ) ( -64 64 80 ) eden/woodfloor 0 -8 0.00 1 1 0 0 0 +( 16 64 176 ) ( -240 64 176 ) ( -240 64 80 ) eden/woodfloor -80 -8 0.00 1 1 0 0 0 +( -240 64 176 ) ( -240 -56 176 ) ( -240 -56 80 ) eden/woodfloor 0 -8 0.00 1 1 0 0 0 +} +// brush 17 +{ +( 0 64 64 ) ( -256 64 64 ) ( -256 -56 64 ) eden/woodfloor -64 0 0.00 1 1 0 0 0 +( -256 -56 80 ) ( -256 64 80 ) ( 0 64 80 ) eden/woodfloor -64 0 0.00 1 1 0 0 0 +( -256 -56 160 ) ( 0 -56 160 ) ( 0 -56 64 ) eden/woodfloor -64 -24 0.00 1 1 0 0 0 +( -64 -56 160 ) ( -64 64 160 ) ( -64 64 64 ) eden/woodfloor 0 -24 0.00 1 1 0 0 0 +( 0 64 160 ) ( -256 64 160 ) ( -256 64 64 ) eden/woodfloor -64 -24 0.00 1 1 0 0 0 +( -256 64 160 ) ( -256 -56 160 ) ( -256 -56 64 ) eden/woodfloor 0 -24 0.00 1 1 0 0 0 +} +// brush 18 +{ +( -16 64 48 ) ( -272 64 48 ) ( -272 -56 48 ) eden/woodfloor -48 0 0.00 1 1 0 0 0 +( -272 -56 64 ) ( -272 64 64 ) ( -16 64 64 ) eden/woodfloor -48 0 0.00 1 1 0 0 0 +( -272 -56 144 ) ( -16 -56 144 ) ( -16 -56 48 ) eden/woodfloor -48 24 0.00 1 1 0 0 0 +( -64 -56 144 ) ( -64 64 144 ) ( -64 64 48 ) eden/woodfloor 0 24 0.00 1 1 0 0 0 +( -16 64 144 ) ( -272 64 144 ) ( -272 64 48 ) eden/woodfloor -48 24 0.00 1 1 0 0 0 +( -272 64 144 ) ( -272 -56 144 ) ( -272 -56 48 ) eden/woodfloor 0 24 0.00 1 1 0 0 0 +} +// brush 19 +{ +( -32 64 32 ) ( -288 64 32 ) ( -288 -56 32 ) eden/woodfloor -32 0 0.00 1 1 0 0 0 +( -288 -56 48 ) ( -288 64 48 ) ( -32 64 48 ) eden/woodfloor -32 0 0.00 1 1 0 0 0 +( -288 -56 128 ) ( -32 -56 128 ) ( -32 -56 32 ) eden/woodfloor -32 8 0.00 1 1 0 0 0 +( -64 -56 128 ) ( -64 64 128 ) ( -64 64 32 ) eden/woodfloor 0 8 0.00 1 1 0 0 0 +( -32 64 128 ) ( -288 64 128 ) ( -288 64 32 ) eden/woodfloor -32 8 0.00 1 1 0 0 0 +( -288 64 128 ) ( -288 -56 128 ) ( -288 -56 32 ) eden/woodfloor 0 8 0.00 1 1 0 0 0 +} +// brush 20 +{ +( -48 64 16 ) ( -304 64 16 ) ( -304 -56 16 ) eden/woodfloor -16 0 0.00 1 1 0 0 0 +( -304 -56 32 ) ( -304 64 32 ) ( -48 64 32 ) eden/woodfloor -16 0 0.00 1 1 0 0 0 +( -304 -56 112 ) ( -48 -56 112 ) ( -48 -56 16 ) eden/woodfloor -16 -8 0.00 1 1 0 0 0 +( -64 -56 112 ) ( -64 64 112 ) ( -64 64 16 ) eden/woodfloor 0 -8 0.00 1 1 0 0 0 +( -48 64 112 ) ( -304 64 112 ) ( -304 64 16 ) eden/woodfloor -16 -8 0.00 1 1 0 0 0 +( -304 64 112 ) ( -304 -56 112 ) ( -304 -56 16 ) eden/woodfloor 0 -8 0.00 1 1 0 0 0 +} +// brush 21 +{ +( -64 64 0 ) ( -320 64 0 ) ( -320 -56 0 ) eden/woodfloor 0 0 0.00 1 1 0 0 0 +( -320 -56 16 ) ( -320 64 16 ) ( -64 64 16 ) eden/woodfloor 0 0 0.00 1 1 0 0 0 +( -320 -56 96 ) ( -64 -56 96 ) ( -64 -56 0 ) eden/woodfloor 0 -24 0.00 1 1 0 0 0 +( -64 -56 96 ) ( -64 64 96 ) ( -64 64 0 ) eden/woodfloor 0 -24 0.00 1 1 0 0 0 +( -64 64 96 ) ( -320 64 96 ) ( -320 64 0 ) eden/woodfloor 0 -24 0.00 1 1 0 0 0 +( -320 64 96 ) ( -320 -56 96 ) ( -320 -56 0 ) eden/woodfloor 0 -24 0.00 1 1 0 0 0 +} +// brush 22 +{ +( 224 192 0 ) ( 224 224 0 ) ( -480 224 0 ) eden/bedtrim -224 -32 90.00 1 1 0 0 0 +( -480 224 64 ) ( 224 224 64 ) ( 224 192 64 ) eden/bedtrim -224 -32 90.00 1 1 0 0 0 +( -480 224 256 ) ( -480 192 256 ) ( -480 192 0 ) eden/bedtrim -224 0 0.00 1 1 0 0 0 +( -480 192 256 ) ( 224 192 256 ) ( 224 192 0 ) common/skip 0 0 0.00 1 1 805306368 16512 0 +( 224 224 256 ) ( -480 224 256 ) ( -480 224 0 ) eden/bedtrim 224 0 -180.00 1 -1 0 0 0 +( -416 224 0 ) ( -416 192 0 ) ( -416 208 64 ) eden/bedtrim 224 0 -180.00 1 -1 0 0 0 +} +// brush 23 +{ +( 224 192 0 ) ( 224 224 0 ) ( -480 224 0 ) eden/bedtrim -224 -32 90.00 1 1 0 0 0 +( -480 224 64 ) ( 224 224 64 ) ( 224 192 64 ) eden/bedtrim -224 -32 90.00 1 1 0 0 0 +( -480 192 256 ) ( 224 192 256 ) ( 224 192 0 ) eden/bedtrim 224 0 -180.00 1 -1 0 0 0 +( 224 192 256 ) ( 224 224 256 ) ( 224 224 0 ) eden/bedtrim -224 0 0.00 1 1 0 0 0 +( 224 224 256 ) ( -480 224 256 ) ( -480 224 0 ) eden/bedtrim 224 0 -180.00 1 -1 0 0 0 +( -480 192 0 ) ( -480 224 0 ) ( -480 208 64 ) eden/bedtrim 224 0 -180.00 1 -1 0 0 0 +} +// brush 24 +{ +( 224 192 64 ) ( 224 224 64 ) ( -480 224 64 ) eden/edenmetalwall -224 -224 90.00 1 1 0 0 0 +( -480 224 320 ) ( 224 224 320 ) ( 224 192 320 ) eden/edenmetalwall -224 -224 90.00 1 1 0 0 0 +( -480 224 96 ) ( -480 192 96 ) ( -480 192 64 ) eden/edenmetalwall -224 64 0.00 1 1 0 0 0 +( -480 192 96 ) ( 224 192 96 ) ( 224 192 64 ) common/skip 0 0 0.00 1 1 805306368 16512 0 +( 224 224 96 ) ( -480 224 96 ) ( -480 224 64 ) eden/edenmetalwall 224 63 -180.00 1 -1 0 0 0 +( -416 224 64 ) ( -416 192 64 ) ( -416 208 320 ) eden/edenmetalwall 224 63 -180.00 1 -1 0 0 0 +} +// brush 25 +{ +( 224 192 64 ) ( 224 224 64 ) ( -480 224 64 ) eden/edenmetalwall -224 -224 90.00 1 1 0 0 0 +( -480 224 640 ) ( 224 224 640 ) ( 224 192 640 ) eden/edenmetalwall -224 -224 90.00 1 1 0 0 0 +( -480 192 96 ) ( 224 192 96 ) ( 224 192 64 ) eden/edenmetalwall 224 63 -180.00 1 -1 0 0 0 +( 224 192 96 ) ( 224 224 96 ) ( 224 224 64 ) eden/edenmetalwall -224 64 0.00 1 1 0 0 0 +( 224 224 96 ) ( -480 224 96 ) ( -480 224 64 ) eden/edenmetalwall 224 63 -180.00 1 -1 0 0 0 +( -480 192 384 ) ( -480 224 384 ) ( -480 208 640 ) eden/edenmetalwall 224 63 -180.00 1 -1 0 0 0 +} +// brush 26 + { + patchDef2 + { + eden/edenmetalwall + ( 3 3 0 536870912 0 ) +( +( ( -480 96 63.999981 0 0 ) ( -480 96 352.000061 0 0.500000 ) ( -480 96 640 0 1 ) ) +( ( -384 96 63.999981 0.500000 0 ) ( -384 96 352.000061 0.500000 0.500000 ) ( -384 96 640 0.500000 1 ) ) +( ( -384 192 63.999981 1 0 ) ( -384 192 352.000061 1 0.500000 ) ( -384 192 640 1 1 ) ) +) + } + } +// brush 27 +{ +( -480 192 0 ) ( -512 192 0 ) ( -512 -512 0 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +( -512 -512 64 ) ( -512 192 64 ) ( -480 192 64 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +( -480 -512 256 ) ( -480 192 256 ) ( -480 192 0 ) common/skip 0 0 0.00 1 1 805306368 16512 0 +( -480 192 256 ) ( -512 192 256 ) ( -512 192 0 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +( -512 192 256 ) ( -512 -512 256 ) ( -512 -512 0 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +( -480 128 0 ) ( -512 128 0 ) ( -496 128 64 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +} +// brush 28 +{ +( -480 192 0 ) ( -512 192 0 ) ( -512 -512 0 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +( -512 -512 64 ) ( -512 192 64 ) ( -480 192 64 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +( -512 -512 256 ) ( -480 -512 256 ) ( -480 -512 0 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +( -480 -512 256 ) ( -480 192 256 ) ( -480 192 0 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +( -512 192 256 ) ( -512 -512 256 ) ( -512 -512 0 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +( -512 192 0 ) ( -480 192 0 ) ( -496 192 64 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +} +// brush 29 +{ +( -480 192 64 ) ( -512 192 64 ) ( -512 -512 64 ) eden/edenmetalwall 0 0 0.00 1 1 0 0 0 +( -512 -512 320 ) ( -512 192 320 ) ( -480 192 320 ) eden/edenmetalwall 0 0 0.00 1 1 0 0 0 +( -480 -512 96 ) ( -480 192 96 ) ( -480 192 64 ) common/skip 0 0 0.00 1 1 805306368 16512 0 +( -480 192 96 ) ( -512 192 96 ) ( -512 192 64 ) eden/edenmetalwall 0 64 0.00 1 1 0 0 0 +( -512 192 96 ) ( -512 -512 96 ) ( -512 -512 64 ) eden/edenmetalwall 0 64 0.00 1 1 0 0 0 +( -480 128 64 ) ( -512 128 64 ) ( -496 128 320 ) eden/edenmetalwall 0 64 0.00 1 1 0 0 0 +} +// brush 30 +{ +( -480 192 64 ) ( -512 192 64 ) ( -512 -512 64 ) eden/edenmetalwall 0 0 0.00 1 1 0 0 0 +( -512 -512 640 ) ( -512 192 640 ) ( -480 192 640 ) eden/edenmetalwall 0 0 0.00 1 1 0 0 0 +( -512 -512 96 ) ( -480 -512 96 ) ( -480 -512 64 ) eden/edenmetalwall 0 64 0.00 1 1 0 0 0 +( -480 -512 416 ) ( -480 192 416 ) ( -480 192 384 ) eden/edenmetalwall 0 64 0.00 1 1 0 0 0 +( -512 192 96 ) ( -512 -512 96 ) ( -512 -512 64 ) eden/edenmetalwall 0 64 0.00 1 1 0 0 0 +( -512 192 64 ) ( -480 192 64 ) ( -496 192 320 ) eden/edenmetalwall 0 64 0.00 1 1 0 0 0 +} +// brush 31 + { + patchDef2 + { + eden/bedtrim + ( 3 3 0 536870912 0 ) +( +( ( -480 96 0 0 0 ) ( -480 96 32 0 0.500000 ) ( -480 96 64 0 1 ) ) +( ( -384 96 0 0.500000 0 ) ( -384 96 32 0.500000 0.500000 ) ( -384 96 64 0.500000 1 ) ) +( ( -384 192 0 1 0 ) ( -384 192 32 1 0.500000 ) ( -384 192 64 1 1 ) ) +) + } + } +// brush 32 +{ +( 192 192 608 ) ( -480 192 608 ) ( -480 -512 608 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( -480 -512 640 ) ( -480 192 640 ) ( 192 192 640 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( -480 -512 640 ) ( 192 -512 640 ) ( 192 -512 608 ) eden/CL_edenroof3 0 -96 0.00 1 1 0 0 0 +( 192 192 640 ) ( -480 192 640 ) ( -480 192 608 ) eden/CL_edenroof3 0 -96 0.00 1 1 0 0 0 +( -480 192 640 ) ( -480 -512 640 ) ( -480 -512 608 ) eden/CL_edenroof3 0 -96 0.00 1 1 0 0 0 +( 216 -112 608 ) ( 216 -240 608 ) ( 216 -176 640 ) eden/CL_edenroof3 0 -96 0.00 1 1 0 0 0 +} +// brush 33 +{ +( 192 192 -32 ) ( -480 192 -32 ) ( -480 -512 -32 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( -480 -512 0 ) ( -480 192 0 ) ( 192 192 0 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( -480 -512 224 ) ( 192 -512 224 ) ( 192 -512 -32 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 192 -512 224 ) ( 192 192 224 ) ( 192 192 -32 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 192 192 224 ) ( -480 192 224 ) ( -480 192 -32 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( -480 192 224 ) ( -480 -512 224 ) ( -480 -512 -32 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +} +// brush 34 +{ +( -480 -512 64 ) ( -480 -544 64 ) ( 224 -544 64 ) eden/edenmetalwall -31 31 -90.00 1 1 0 0 0 +( 224 -544 640 ) ( -480 -544 640 ) ( -480 -512 640 ) eden/edenmetalwall -31 31 -90.00 1 1 0 0 0 +( 224 -544 96 ) ( 224 -512 96 ) ( 224 -512 64 ) eden/edenmetalwall -32 63 -180.00 1 -1 0 0 0 +( 224 -512 96 ) ( -480 -512 96 ) ( -480 -512 64 ) eden/edenmetalwall -32 62 0.00 1.000008 1 0 0 0 +( -480 -512 416 ) ( -480 -544 416 ) ( -480 -544 384 ) eden/edenmetalwall -33 63 -180.00 1 -1 0 0 0 +( -480 -544 96 ) ( 224 -544 96 ) ( 224 -544 64 ) eden/edenmetalwall -32 62 0.00 1.000008 1 0 0 0 +} +// brush 35 +{ +( -480 -512 0 ) ( -480 -544 0 ) ( 224 -544 0 ) eden/bedtrim -31 32 -90.00 1 1 0 0 0 +( 224 -544 64 ) ( -480 -544 64 ) ( -480 -512 64 ) eden/bedtrim -31 32 -90.00 1 1 0 0 0 +( 224 -544 256 ) ( 224 -512 256 ) ( 224 -512 0 ) eden/bedtrim -32 0 -180.00 1 -1 0 0 0 +( 224 -512 256 ) ( -480 -512 256 ) ( -480 -512 0 ) eden/bedtrim -32 0 0.00 1 1 0 0 0 +( -480 -512 256 ) ( -480 -544 256 ) ( -480 -544 0 ) eden/bedtrim -33 0 -180.00 1 -1 0 0 0 +( -480 -544 256 ) ( 224 -544 256 ) ( 224 -544 0 ) eden/bedtrim -32 0 0.00 1 1 0 0 0 +} +// brush 36 +{ +( 192 -512 0 ) ( 224 -512 0 ) ( 224 192 0 ) eden/bedtrim 160 0 -180.00 1 1 0 0 0 +( 224 192 64 ) ( 224 -512 64 ) ( 192 -512 64 ) eden/bedtrim 160 0 -180.00 1 1 0 0 0 +( 224 192 256 ) ( 192 192 256 ) ( 192 192 0 ) eden/bedtrim 160 0 -180.00 1 -1 0 0 0 +( 192 192 256 ) ( 192 -512 256 ) ( 192 -512 0 ) eden/bedtrim -64 0 -180.00 1 -1 0 0 0 +( 192 -512 256 ) ( 224 -512 256 ) ( 224 -512 0 ) eden/bedtrim 159 0 -180.00 1 -1 0 0 0 +( 224 -512 256 ) ( 224 192 256 ) ( 224 192 0 ) eden/bedtrim -64 0 -180.00 1 -1 0 0 0 +} +// brush 37 +{ +( 192 -512 64 ) ( 224 -512 64 ) ( 224 192 64 ) eden/edenmetalwall 160 63 -180.00 1 1 0 0 0 +( 224 192 640 ) ( 224 -512 640 ) ( 192 -512 640 ) eden/edenmetalwall 160 63 -180.00 1 1 0 0 0 +( 224 192 96 ) ( 192 192 96 ) ( 192 192 64 ) eden/edenmetalwall 160 64 -180.00 1 -1 0 0 0 +( 192 192 416 ) ( 192 -512 416 ) ( 192 -512 384 ) eden/edenmetalwall -64 62 -180.00 1 -1 0 0 0 +( 192 -512 96 ) ( 224 -512 96 ) ( 224 -512 64 ) eden/edenmetalwall 159 64 -180.00 1 -1 0 0 0 +( 224 -512 96 ) ( 224 192 96 ) ( 224 192 64 ) eden/edenmetalwall -64 62 -180.00 1 -1 0 0 0 +} +} +// entity 1 +{ +"limit" "45" +"spawnflags" "2" +"classname" "func_fulcrum" +// brush 0 +{ +( 176 -256 152 ) ( 8 -256 152 ) ( 8 -416 152 ) eden/edentable 112 101 0.00 -1.500000 1.500000 0 0 0 +( 8 -416 168 ) ( 8 -256 168 ) ( 176 -256 168 ) eden/edentable 112 101 0.00 -1.500000 1.500000 0 0 0 +( 24 -424 168 ) ( 192 -424 168 ) ( 192 -424 152 ) eden/edentable 112 64 0.00 -1.500000 0.125000 0 0 0 +( 168 -416 168 ) ( 168 -256 168 ) ( 168 -256 152 ) eden/edentable 101 64 0.00 -1.500000 0.125000 0 0 0 +( 144 -232 168 ) ( -24 -232 168 ) ( -24 -232 152 ) eden/edentable 112 64 0.00 -1.500000 0.125000 0 0 0 +( -24 -232 168 ) ( -24 -392 168 ) ( -24 -392 152 ) eden/edentable 101 64 0.00 -1.500000 0.125000 0 0 0 +} +} +// entity 2 +{ +"limit" "45" +"classname" "func_fulcrum" +// brush 0 +{ +( 176 72 152 ) ( 8 72 152 ) ( 8 -88 152 ) eden/edentable 112 64 0.00 -1.500000 1.500000 0 0 0 +( 8 -88 168 ) ( 8 72 168 ) ( 176 72 168 ) eden/edentable 112 64 0.00 -1.500000 1.500000 0 0 0 +( 24 -96 168 ) ( 192 -96 168 ) ( 192 -96 152 ) eden/edentable 112 64 0.00 -1.500000 0.125000 0 0 0 +( 168 -88 168 ) ( 168 72 168 ) ( 168 72 152 ) eden/edentable 64 64 0.00 -1.500000 0.125000 0 0 0 +( 144 96 168 ) ( -24 96 168 ) ( -24 96 152 ) eden/edentable 112 64 0.00 -1.500000 0.125000 0 0 0 +( -24 96 168 ) ( -24 -64 168 ) ( -24 -64 152 ) eden/edentable 64 64 0.00 -1.500000 0.125000 0 0 0 +} +} +// entity 3 +{ +"classname" "script_object" +"targetname" "movinlight2" +// brush 0 +{ +( 16 -368 144 ) ( 0 -368 144 ) ( 0 -384 144 ) common/skip 32 16 0.00 1 1 805306368 16512 0 +( 0 -384 160 ) ( 0 -368 160 ) ( 16 -368 160 ) common/skip 32 16 0.00 1 1 805306368 16512 0 +( 0 -384 240 ) ( 16 -384 240 ) ( 16 -384 144 ) common/skip 32 -48 0.00 1 1 805306368 16512 0 +( 16 -384 240 ) ( 16 -368 240 ) ( 16 -368 144 ) common/skip -16 -48 0.00 1 1 805306368 16512 0 +( 16 -368 240 ) ( 0 -368 240 ) ( 0 -368 144 ) common/skip 32 -48 0.00 1 1 805306368 16512 0 +( 0 -368 240 ) ( 0 -384 240 ) ( 0 -384 144 ) common/skip -16 -48 0.00 1 1 805306368 16512 0 +} +} +// entity 4 +{ +"classname" "script_object" +"targetname" "movinlight1" +// brush 0 +{ +( -344 64 144 ) ( -360 64 144 ) ( -360 48 144 ) common/skip 0 0 0.00 1 1 805306368 16512 0 +( -360 48 160 ) ( -360 64 160 ) ( -344 64 160 ) common/skip 0 0 0.00 1 1 805306368 16512 0 +( -360 48 240 ) ( -344 48 240 ) ( -344 48 144 ) common/skip 0 -48 0.00 1 1 805306368 16512 0 +( -344 48 240 ) ( -344 64 240 ) ( -344 64 144 ) common/skip 0 -48 0.00 1 1 805306368 16512 0 +( -344 64 240 ) ( -360 64 240 ) ( -360 64 144 ) common/skip 0 -48 0.00 1 1 805306368 16512 0 +( -360 64 240 ) ( -360 48 240 ) ( -360 48 144 ) common/skip 0 -48 0.00 1 1 805306368 16512 0 +} +} +// entity 5 +{ +"_color" "1.000000 0.724409 0.523622" +"light" "200" +"origin" "-352 56 168" +"spawnflags" "0" +"classname" "light" +} +// entity 6 +{ +"origin" "-416 -176 24" +"angle" "0" +"classname" "info_player_start" +} +// entity 7 +{ +"_color" "0.629921 0.846457 1.000000" +"light" "200" +"classname" "light" +"spawnflags" "0" +"origin" "8 56 168" +} +// entity 8 +{ +"light" "200" +"classname" "light" +"spawnflags" "0" +"origin" "-344 -376 168" +} +// entity 9 +{ +"light" "200" +"origin" "8 -376 168" +"spawnflags" "0" +"classname" "light" +} +// entity 10 +{ +"origin" "-168 -160 168" +"spawnflags" "0" +"classname" "light" +"light" "200" +} +// entity 11 +{ +"classname" "light" +"spawnflags" "0" +"origin" "-352 56 384" +"light" "200" +"_color" "1.000000 0.724409 0.523622" +} +// entity 12 +{ +"origin" "8 56 384" +"spawnflags" "0" +"classname" "light" +"light" "200" +"_color" "0.629921 0.846457 1.000000" +} +// entity 13 +{ +"origin" "-344 -376 384" +"spawnflags" "0" +"classname" "light" +"light" "200" +} +// entity 14 +{ +"classname" "light" +"spawnflags" "0" +"origin" "8 -376 384" +"light" "200" +} +// entity 15 +{ +"light" "200" +"classname" "light" +"spawnflags" "0" +"origin" "-168 -160 384" +} diff --git a/fakk/maps/example/fulcrum.prt b/fakk/maps/example/fulcrum.prt new file mode 100644 index 0000000..9714f97 --- /dev/null +++ b/fakk/maps/example/fulcrum.prt @@ -0,0 +1,289 @@ +PRT1 +43 +124 +161 +4 0 3 0 (0 0 0 ) (0 0 608 ) (0 64 608 ) (0 64 0 ) +4 0 2 0 (0 64 608 ) (0 192 608 ) (0 192 0 ) (0 64 0 ) +4 0 1 0 (0 0 608 ) (0 0 0 ) (192 0 0 ) (192 0 608 ) +4 1 16 0 (0 -512 0 ) (0 -512 608 ) (0 0 608 ) (0 0 0 ) +4 2 10 0 (-240 64 96 ) (-256 64 96 ) (-256 64 80 ) (-240 64 80 ) +4 2 9 0 (-224 64 96 ) (-224 64 112 ) (-256 64 112 ) (-256 64 96 ) +4 2 11 0 (-272 64 112 ) (-272 64 64 ) (-256 64 64 ) (-256 64 112 ) +4 2 8 0 (-208 64 128 ) (-272 64 128 ) (-272 64 112 ) (-208 64 112 ) +4 2 12 0 (-272 64 128 ) (-288 64 128 ) (-288 64 48 ) (-272 64 48 ) +4 2 7 0 (-192 64 128 ) (-192 64 144 ) (-288 64 144 ) (-288 64 128 ) +4 2 13 0 (-304 64 144 ) (-304 64 32 ) (-288 64 32 ) (-288 64 144 ) +4 2 6 0 (-176 64 160 ) (-304 64 160 ) (-304 64 144 ) (-176 64 144 ) +4 2 14 0 (-304 64 160 ) (-320 64 160 ) (-320 64 16 ) (-304 64 16 ) +4 2 5 0 (-160 64 160 ) (-160 64 176 ) (-320 64 176 ) (-320 64 160 ) +4 2 15 0 (-480 64 176 ) (-480 64 0 ) (-320 64 0 ) (-320 64 176 ) +4 2 4 0 (-64 64 608 ) (-480 64 608 ) (-480 64 176 ) (-64 64 176 ) +4 2 3 0 (0 64 0 ) (0 64 608 ) (-64 64 608 ) (-64 64 0 ) +4 3 16 0 (0 0 0 ) (0 0 608 ) (-64 0 608 ) (-64 0 0 ) +4 3 4 0 (-64 64 608 ) (-64 64 176 ) (-64 0 176 ) (-64 0 608 ) +4 4 17 0 (-64 0 176 ) (-64 0 608 ) (-480 0 608 ) (-480 0 176 ) +4 4 5 0 (-320 64 176 ) (-160 64 176 ) (-160 0 176 ) (-320 0 176 ) +4 4 15 0 (-480 0 176 ) (-480 64 176 ) (-320 64 176 ) (-320 0 176 ) +4 5 18 0 (-160 0 176 ) (-320 0 176 ) (-320 0 160 ) (-160 0 160 ) +4 5 6 0 (-304 64 160 ) (-176 64 160 ) (-176 0 160 ) (-304 0 160 ) +4 5 14 0 (-320 0 160 ) (-320 64 160 ) (-304 64 160 ) (-304 0 160 ) +4 5 15 0 (-320 0 160 ) (-320 0 176 ) (-320 64 176 ) (-320 64 160 ) +4 6 19 0 (-176 0 144 ) (-176 0 160 ) (-304 0 160 ) (-304 0 144 ) +4 6 7 0 (-288 64 144 ) (-192 64 144 ) (-192 0 144 ) (-288 0 144 ) +4 6 13 0 (-304 0 144 ) (-304 64 144 ) (-288 64 144 ) (-288 0 144 ) +4 6 14 0 (-304 0 144 ) (-304 0 160 ) (-304 64 160 ) (-304 64 144 ) +4 7 20 0 (-192 0 144 ) (-288 0 144 ) (-288 0 128 ) (-192 0 128 ) +4 7 8 0 (-272 64 128 ) (-208 64 128 ) (-208 0 128 ) (-272 0 128 ) +4 7 12 0 (-288 0 128 ) (-288 64 128 ) (-272 64 128 ) (-272 0 128 ) +4 7 13 0 (-288 0 128 ) (-288 0 144 ) (-288 64 144 ) (-288 64 128 ) +4 8 21 0 (-208 0 112 ) (-208 0 128 ) (-272 0 128 ) (-272 0 112 ) +4 8 9 0 (-256 64 112 ) (-224 64 112 ) (-224 0 112 ) (-256 0 112 ) +4 8 11 0 (-272 0 112 ) (-272 64 112 ) (-256 64 112 ) (-256 0 112 ) +4 8 12 0 (-272 0 112 ) (-272 0 128 ) (-272 64 128 ) (-272 64 112 ) +4 9 22 0 (-224 0 112 ) (-256 0 112 ) (-256 0 96 ) (-224 0 96 ) +4 9 10 0 (-256 0 96 ) (-256 64 96 ) (-240 64 96 ) (-240 0 96 ) +4 9 11 0 (-256 0 96 ) (-256 0 112 ) (-256 64 112 ) (-256 64 96 ) +4 10 23 0 (-256 0 96 ) (-256 0 80 ) (-240 0 80 ) (-240 0 96 ) +4 10 11 0 (-256 0 80 ) (-256 0 96 ) (-256 64 96 ) (-256 64 80 ) +4 11 24 0 (-256 0 112 ) (-272 0 112 ) (-272 0 64 ) (-256 0 64 ) +4 11 12 0 (-272 0 64 ) (-272 0 112 ) (-272 64 112 ) (-272 64 64 ) +4 12 25 0 (-288 0 128 ) (-288 0 48 ) (-272 0 48 ) (-272 0 128 ) +4 12 13 0 (-288 0 48 ) (-288 0 128 ) (-288 64 128 ) (-288 64 48 ) +4 13 26 0 (-288 0 144 ) (-304 0 144 ) (-304 0 32 ) (-288 0 32 ) +4 13 14 0 (-304 0 32 ) (-304 0 144 ) (-304 64 144 ) (-304 64 32 ) +4 14 27 0 (-320 0 160 ) (-320 0 16 ) (-304 0 16 ) (-304 0 160 ) +4 14 15 0 (-320 0 16 ) (-320 0 160 ) (-320 64 160 ) (-320 64 16 ) +4 15 28 0 (-320 0 176 ) (-480 0 176 ) (-480 0 0 ) (-320 0 0 ) +4 16 42 0 (-64 -384 0 ) (-64 -512 0 ) (-64 -512 608 ) (-64 -384 608 ) +4 16 30 0 (-64 -384 176 ) (-64 -384 608 ) (-64 -264 608 ) (-64 -264 176 ) +4 16 29 0 (-64 -56 0 ) (-64 -264 0 ) (-64 -264 608 ) (-64 -56 608 ) +4 16 17 0 (-64 0 608 ) (-64 0 176 ) (-64 -56 176 ) (-64 -56 608 ) +4 17 29 0 (-64 -56 176 ) (-64 -56 608 ) (-480 -56 608 ) (-480 -56 176 ) +4 17 18 0 (-160 -56 176 ) (-320 -56 176 ) (-320 0 176 ) (-160 0 176 ) +4 17 28 0 (-320 -56 176 ) (-480 -56 176 ) (-480 0 176 ) (-320 0 176 ) +4 18 29 0 (-160 -56 176 ) (-320 -56 176 ) (-320 -56 160 ) (-160 -56 160 ) +4 18 19 0 (-304 0 160 ) (-176 0 160 ) (-176 -56 160 ) (-304 -56 160 ) +4 18 27 0 (-320 -56 160 ) (-320 0 160 ) (-304 0 160 ) (-304 -56 160 ) +4 18 28 0 (-320 -56 160 ) (-320 -56 176 ) (-320 0 176 ) (-320 0 160 ) +4 19 29 0 (-176 -56 144 ) (-176 -56 160 ) (-304 -56 160 ) (-304 -56 144 ) +4 19 20 0 (-288 0 144 ) (-192 0 144 ) (-192 -56 144 ) (-288 -56 144 ) +4 19 26 0 (-304 -56 144 ) (-304 0 144 ) (-288 0 144 ) (-288 -56 144 ) +4 19 27 0 (-304 -56 144 ) (-304 -56 160 ) (-304 0 160 ) (-304 0 144 ) +4 20 29 0 (-192 -56 144 ) (-288 -56 144 ) (-288 -56 128 ) (-192 -56 128 ) +4 20 21 0 (-272 0 128 ) (-208 0 128 ) (-208 -56 128 ) (-272 -56 128 ) +4 20 25 0 (-288 -56 128 ) (-288 0 128 ) (-272 0 128 ) (-272 -56 128 ) +4 20 26 0 (-288 -56 128 ) (-288 -56 144 ) (-288 0 144 ) (-288 0 128 ) +4 21 29 0 (-208 -56 112 ) (-208 -56 128 ) (-272 -56 128 ) (-272 -56 112 ) +4 21 22 0 (-256 0 112 ) (-224 0 112 ) (-224 -56 112 ) (-256 -56 112 ) +4 21 24 0 (-272 -56 112 ) (-272 0 112 ) (-256 0 112 ) (-256 -56 112 ) +4 21 25 0 (-272 -56 112 ) (-272 -56 128 ) (-272 0 128 ) (-272 0 112 ) +4 22 29 0 (-224 -56 112 ) (-256 -56 112 ) (-256 -56 96 ) (-224 -56 96 ) +4 22 23 0 (-256 -56 96 ) (-256 0 96 ) (-240 0 96 ) (-240 -56 96 ) +4 22 24 0 (-256 -56 96 ) (-256 -56 112 ) (-256 0 112 ) (-256 0 96 ) +4 23 29 0 (-256 -56 96 ) (-256 -56 80 ) (-240 -56 80 ) (-240 -56 96 ) +4 23 24 0 (-256 -56 80 ) (-256 -56 96 ) (-256 0 96 ) (-256 0 80 ) +4 24 29 0 (-256 -56 112 ) (-272 -56 112 ) (-272 -56 64 ) (-256 -56 64 ) +4 24 25 0 (-272 -56 64 ) (-272 -56 112 ) (-272 0 112 ) (-272 0 64 ) +4 25 29 0 (-288 -56 128 ) (-288 -56 48 ) (-272 -56 48 ) (-272 -56 128 ) +4 25 26 0 (-288 -56 48 ) (-288 -56 128 ) (-288 0 128 ) (-288 0 48 ) +4 26 29 0 (-288 -56 144 ) (-304 -56 144 ) (-304 -56 32 ) (-288 -56 32 ) +4 26 27 0 (-304 -56 32 ) (-304 -56 144 ) (-304 0 144 ) (-304 0 32 ) +4 27 29 0 (-320 -56 160 ) (-320 -56 16 ) (-304 -56 16 ) (-304 -56 160 ) +4 27 28 0 (-320 -56 16 ) (-320 -56 160 ) (-320 0 160 ) (-320 0 16 ) +4 28 29 0 (-320 -56 176 ) (-480 -56 176 ) (-480 -56 0 ) (-320 -56 0 ) +4 29 41 0 (-320 -264 16 ) (-480 -264 16 ) (-480 -264 0 ) (-320 -264 0 ) +4 29 40 0 (-304 -264 32 ) (-480 -264 32 ) (-480 -264 16 ) (-304 -264 16 ) +4 29 39 0 (-480 -264 48 ) (-480 -264 32 ) (-288 -264 32 ) (-288 -264 48 ) +4 29 38 0 (-480 -264 64 ) (-480 -264 48 ) (-272 -264 48 ) (-272 -264 64 ) +4 29 37 0 (-480 -264 80 ) (-480 -264 64 ) (-256 -264 64 ) (-256 -264 80 ) +4 29 36 0 (-480 -264 96 ) (-480 -264 80 ) (-240 -264 80 ) (-240 -264 96 ) +4 29 34 0 (-208 -264 608 ) (-224 -264 608 ) (-224 -264 112 ) (-208 -264 112 ) +4 29 35 0 (-224 -264 608 ) (-480 -264 608 ) (-480 -264 96 ) (-224 -264 96 ) +4 29 33 0 (-192 -264 608 ) (-208 -264 608 ) (-208 -264 128 ) (-192 -264 128 ) +4 29 32 0 (-176 -264 608 ) (-192 -264 608 ) (-192 -264 144 ) (-176 -264 144 ) +4 29 31 0 (-160 -264 608 ) (-176 -264 608 ) (-176 -264 160 ) (-160 -264 160 ) +4 29 30 0 (-64 -264 176 ) (-64 -264 608 ) (-160 -264 608 ) (-160 -264 176 ) +4 30 42 0 (-64 -384 176 ) (-64 -384 608 ) (-160 -384 608 ) (-160 -384 176 ) +4 30 31 0 (-160 -384 176 ) (-160 -384 608 ) (-160 -264 608 ) (-160 -264 176 ) +4 31 42 0 (-160 -384 608 ) (-176 -384 608 ) (-176 -384 160 ) (-160 -384 160 ) +4 31 32 0 (-176 -384 160 ) (-176 -384 608 ) (-176 -264 608 ) (-176 -264 160 ) +4 32 42 0 (-176 -384 608 ) (-192 -384 608 ) (-192 -384 144 ) (-176 -384 144 ) +4 32 33 0 (-192 -384 144 ) (-192 -384 608 ) (-192 -264 608 ) (-192 -264 144 ) +4 33 42 0 (-192 -384 608 ) (-208 -384 608 ) (-208 -384 128 ) (-192 -384 128 ) +4 33 34 0 (-208 -384 128 ) (-208 -384 608 ) (-208 -264 608 ) (-208 -264 128 ) +4 34 42 0 (-208 -384 608 ) (-224 -384 608 ) (-224 -384 112 ) (-208 -384 112 ) +4 34 35 0 (-224 -384 112 ) (-224 -384 608 ) (-224 -264 608 ) (-224 -264 112 ) +4 35 42 0 (-224 -384 608 ) (-480 -384 608 ) (-480 -384 96 ) (-224 -384 96 ) +4 35 36 0 (-480 -384 96 ) (-480 -264 96 ) (-240 -264 96 ) (-240 -384 96 ) +4 36 42 0 (-480 -384 96 ) (-480 -384 80 ) (-240 -384 80 ) (-240 -384 96 ) +4 36 37 0 (-480 -384 80 ) (-480 -264 80 ) (-256 -264 80 ) (-256 -384 80 ) +4 37 42 0 (-480 -384 80 ) (-480 -384 64 ) (-256 -384 64 ) (-256 -384 80 ) +4 37 38 0 (-480 -384 64 ) (-480 -264 64 ) (-272 -264 64 ) (-272 -384 64 ) +4 38 42 0 (-480 -384 64 ) (-480 -384 48 ) (-272 -384 48 ) (-272 -384 64 ) +4 38 39 0 (-480 -384 48 ) (-480 -264 48 ) (-288 -264 48 ) (-288 -384 48 ) +4 39 42 0 (-480 -384 48 ) (-480 -384 32 ) (-288 -384 32 ) (-288 -384 48 ) +4 39 40 0 (-304 -384 32 ) (-480 -384 32 ) (-480 -264 32 ) (-304 -264 32 ) +4 40 42 0 (-304 -384 32 ) (-480 -384 32 ) (-480 -384 16 ) (-304 -384 16 ) +4 40 41 0 (-320 -384 16 ) (-480 -384 16 ) (-480 -264 16 ) (-320 -264 16 ) +4 41 42 0 (-320 -384 16 ) (-480 -384 16 ) (-480 -384 0 ) (-320 -384 0 ) +4 0 (0 0 608 ) (192 0 608 ) (192 192 608 ) (0 192 608 ) +4 0 (192 192 608 ) (192 192 0 ) (0 192 0 ) (0 192 608 ) +4 0 (192 0 608 ) (192 0 0 ) (192 192 0 ) (192 192 608 ) +4 0 (0 192 0 ) (192 192 0 ) (192 0 0 ) (0 0 0 ) +4 1 (0 -512 608 ) (192 -512 608 ) (192 0 608 ) (0 0 608 ) +4 1 (0 -512 608 ) (0 -512 0 ) (192 -512 0 ) (192 -512 608 ) +4 1 (192 -512 608 ) (192 -512 0 ) (192 0 0 ) (192 0 608 ) +4 1 (0 0 0 ) (192 0 0 ) (192 -512 0 ) (0 -512 0 ) +4 2 (-224 64 80 ) (-224 64 96 ) (-240 64 96 ) (-240 64 80 ) +4 2 (-256 64 64 ) (-224 64 64 ) (-224 64 80 ) (-256 64 80 ) +4 2 (-224 64 64 ) (-208 64 64 ) (-208 64 112 ) (-224 64 112 ) +4 2 (-272 64 64 ) (-272 64 48 ) (-208 64 48 ) (-208 64 64 ) +4 2 (-192 64 48 ) (-192 64 128 ) (-208 64 128 ) (-208 64 48 ) +4 2 (-288 64 32 ) (-192 64 32 ) (-192 64 48 ) (-288 64 48 ) +4 2 (-192 64 32 ) (-176 64 32 ) (-176 64 144 ) (-192 64 144 ) +4 2 (-304 64 32 ) (-304 64 16 ) (-176 64 16 ) (-176 64 32 ) +4 2 (-160 64 16 ) (-160 64 160 ) (-176 64 160 ) (-176 64 16 ) +4 2 (-320 64 0 ) (-160 64 0 ) (-160 64 16 ) (-320 64 16 ) +4 2 (-160 64 0 ) (-64 64 0 ) (-64 64 176 ) (-160 64 176 ) +4 2 (0 64 0 ) (-480 64 0 ) (-480 192 0 ) (0 192 0 ) +4 2 (-480 64 0 ) (-480 64 608 ) (-480 192 608 ) (-480 192 0 ) +4 2 (0 192 608 ) (0 192 0 ) (-480 192 0 ) (-480 192 608 ) +4 2 (0 192 608 ) (-480 192 608 ) (-480 64 608 ) (0 64 608 ) +4 3 (-64 64 176 ) (-64 64 0 ) (-64 0 0 ) (-64 0 176 ) +4 3 (0 64 608 ) (-64 64 608 ) (-64 0 608 ) (0 0 608 ) +4 3 (0 0 0 ) (-64 0 0 ) (-64 64 0 ) (0 64 0 ) +4 4 (-160 64 176 ) (-64 64 176 ) (-64 0 176 ) (-160 0 176 ) +4 4 (-480 64 608 ) (-480 64 176 ) (-480 0 176 ) (-480 0 608 ) +4 4 (-64 0 608 ) (-64 64 608 ) (-480 64 608 ) (-480 0 608 ) +4 5 (-176 64 160 ) (-160 64 160 ) (-160 0 160 ) (-176 0 160 ) +4 5 (-160 64 160 ) (-160 64 176 ) (-160 0 176 ) (-160 0 160 ) +4 6 (-192 64 144 ) (-176 64 144 ) (-176 0 144 ) (-192 0 144 ) +4 6 (-176 64 144 ) (-176 64 160 ) (-176 0 160 ) (-176 0 144 ) +4 7 (-208 64 128 ) (-192 64 128 ) (-192 0 128 ) (-208 0 128 ) +4 7 (-192 64 128 ) (-192 64 144 ) (-192 0 144 ) (-192 0 128 ) +4 8 (-224 64 112 ) (-208 64 112 ) (-208 0 112 ) (-224 0 112 ) +4 8 (-208 64 112 ) (-208 64 128 ) (-208 0 128 ) (-208 0 112 ) +4 9 (-240 64 96 ) (-224 64 96 ) (-224 0 96 ) (-240 0 96 ) +4 9 (-224 64 96 ) (-224 64 112 ) (-224 0 112 ) (-224 0 96 ) +4 10 (-256 0 80 ) (-256 64 80 ) (-240 64 80 ) (-240 0 80 ) +4 10 (-240 64 96 ) (-240 0 96 ) (-240 0 80 ) (-240 64 80 ) +4 11 (-256 64 80 ) (-256 0 80 ) (-256 0 64 ) (-256 64 64 ) +4 11 (-272 0 64 ) (-272 64 64 ) (-256 64 64 ) (-256 0 64 ) +4 12 (-272 64 64 ) (-272 0 64 ) (-272 0 48 ) (-272 64 48 ) +4 12 (-288 0 48 ) (-288 64 48 ) (-272 64 48 ) (-272 0 48 ) +4 13 (-288 64 48 ) (-288 0 48 ) (-288 0 32 ) (-288 64 32 ) +4 13 (-304 0 32 ) (-304 64 32 ) (-288 64 32 ) (-288 0 32 ) +4 14 (-304 64 32 ) (-304 0 32 ) (-304 0 16 ) (-304 64 16 ) +4 14 (-320 0 16 ) (-320 64 16 ) (-304 64 16 ) (-304 0 16 ) +4 15 (-320 64 16 ) (-320 0 16 ) (-320 0 0 ) (-320 64 0 ) +4 15 (-480 64 176 ) (-480 64 0 ) (-480 0 0 ) (-480 0 176 ) +4 15 (-480 0 0 ) (-480 64 0 ) (-320 64 0 ) (-320 0 0 ) +4 16 (-64 -264 0 ) (-64 -384 0 ) (-64 -384 16 ) (-64 -264 16 ) +4 16 (-64 -384 16 ) (-64 -384 32 ) (-64 -264 32 ) (-64 -264 16 ) +4 16 (-64 -384 32 ) (-64 -384 176 ) (-64 -264 176 ) (-64 -264 32 ) +4 16 (-64 0 176 ) (-64 0 0 ) (-64 -56 0 ) (-64 -56 176 ) +4 16 (0 0 608 ) (-64 0 608 ) (-64 -512 608 ) (0 -512 608 ) +4 16 (-64 -512 608 ) (-64 -512 0 ) (0 -512 0 ) (0 -512 608 ) +4 16 (0 -512 0 ) (-64 -512 0 ) (-64 0 0 ) (0 0 0 ) +4 17 (-64 -56 176 ) (-160 -56 176 ) (-160 0 176 ) (-64 0 176 ) +4 17 (-480 0 608 ) (-480 0 176 ) (-480 -56 176 ) (-480 -56 608 ) +4 17 (-64 0 608 ) (-480 0 608 ) (-480 -56 608 ) (-64 -56 608 ) +4 18 (-176 0 160 ) (-160 0 160 ) (-160 -56 160 ) (-176 -56 160 ) +4 18 (-160 0 160 ) (-160 0 176 ) (-160 -56 176 ) (-160 -56 160 ) +4 19 (-192 0 144 ) (-176 0 144 ) (-176 -56 144 ) (-192 -56 144 ) +4 19 (-176 0 144 ) (-176 0 160 ) (-176 -56 160 ) (-176 -56 144 ) +4 20 (-208 0 128 ) (-192 0 128 ) (-192 -56 128 ) (-208 -56 128 ) +4 20 (-192 0 128 ) (-192 0 144 ) (-192 -56 144 ) (-192 -56 128 ) +4 21 (-224 0 112 ) (-208 0 112 ) (-208 -56 112 ) (-224 -56 112 ) +4 21 (-208 0 112 ) (-208 0 128 ) (-208 -56 128 ) (-208 -56 112 ) +4 22 (-240 0 96 ) (-224 0 96 ) (-224 -56 96 ) (-240 -56 96 ) +4 22 (-224 0 96 ) (-224 0 112 ) (-224 -56 112 ) (-224 -56 96 ) +4 23 (-256 -56 80 ) (-256 0 80 ) (-240 0 80 ) (-240 -56 80 ) +4 23 (-240 0 96 ) (-240 -56 96 ) (-240 -56 80 ) (-240 0 80 ) +4 24 (-256 0 80 ) (-256 -56 80 ) (-256 -56 64 ) (-256 0 64 ) +4 24 (-272 -56 64 ) (-272 0 64 ) (-256 0 64 ) (-256 -56 64 ) +4 25 (-272 0 64 ) (-272 -56 64 ) (-272 -56 48 ) (-272 0 48 ) +4 25 (-288 -56 48 ) (-288 0 48 ) (-272 0 48 ) (-272 -56 48 ) +4 26 (-288 0 48 ) (-288 -56 48 ) (-288 -56 32 ) (-288 0 32 ) +4 26 (-304 -56 32 ) (-304 0 32 ) (-288 0 32 ) (-288 -56 32 ) +4 27 (-304 0 32 ) (-304 -56 32 ) (-304 -56 16 ) (-304 0 16 ) +4 27 (-320 -56 16 ) (-320 0 16 ) (-304 0 16 ) (-304 -56 16 ) +4 28 (-320 0 16 ) (-320 -56 16 ) (-320 -56 0 ) (-320 0 0 ) +4 28 (-480 0 176 ) (-480 0 0 ) (-480 -56 0 ) (-480 -56 176 ) +4 28 (-320 -56 0 ) (-480 -56 0 ) (-480 0 0 ) (-320 0 0 ) +4 29 (-64 -264 0 ) (-64 -264 16 ) (-320 -264 16 ) (-320 -264 0 ) +4 29 (-64 -264 16 ) (-64 -264 32 ) (-304 -264 32 ) (-304 -264 16 ) +4 29 (-288 -264 32 ) (-160 -264 32 ) (-160 -264 48 ) (-288 -264 48 ) +4 29 (-272 -264 48 ) (-176 -264 48 ) (-176 -264 64 ) (-272 -264 64 ) +4 29 (-256 -264 64 ) (-192 -264 64 ) (-192 -264 80 ) (-256 -264 80 ) +4 29 (-240 -264 80 ) (-208 -264 80 ) (-208 -264 96 ) (-240 -264 96 ) +4 29 (-224 -264 112 ) (-224 -264 96 ) (-208 -264 96 ) (-208 -264 112 ) +4 29 (-208 -264 128 ) (-208 -264 80 ) (-192 -264 80 ) (-192 -264 128 ) +4 29 (-192 -264 144 ) (-192 -264 64 ) (-176 -264 64 ) (-176 -264 144 ) +4 29 (-176 -264 160 ) (-176 -264 48 ) (-160 -264 48 ) (-160 -264 160 ) +4 29 (-64 -264 32 ) (-64 -264 176 ) (-160 -264 176 ) (-160 -264 32 ) +4 29 (-64 -56 608 ) (-480 -56 608 ) (-480 -264 608 ) (-64 -264 608 ) +4 29 (-240 -56 96 ) (-224 -56 96 ) (-224 -56 80 ) (-240 -56 80 ) +4 29 (-224 -56 80 ) (-224 -56 64 ) (-256 -56 64 ) (-256 -56 80 ) +4 29 (-224 -56 64 ) (-224 -56 112 ) (-208 -56 112 ) (-208 -56 64 ) +4 29 (-272 -56 64 ) (-208 -56 64 ) (-208 -56 48 ) (-272 -56 48 ) +4 29 (-208 -56 128 ) (-192 -56 128 ) (-192 -56 48 ) (-208 -56 48 ) +4 29 (-192 -56 48 ) (-192 -56 32 ) (-288 -56 32 ) (-288 -56 48 ) +4 29 (-192 -56 32 ) (-192 -56 144 ) (-176 -56 144 ) (-176 -56 32 ) +4 29 (-304 -56 32 ) (-176 -56 32 ) (-176 -56 16 ) (-304 -56 16 ) +4 29 (-176 -56 160 ) (-160 -56 160 ) (-160 -56 16 ) (-176 -56 16 ) +4 29 (-160 -56 16 ) (-160 -56 0 ) (-320 -56 0 ) (-320 -56 16 ) +4 29 (-160 -56 0 ) (-160 -56 176 ) (-64 -56 176 ) (-64 -56 0 ) +4 29 (-480 -56 608 ) (-480 -56 0 ) (-480 -264 0 ) (-480 -264 608 ) +4 29 (-64 -264 0 ) (-480 -264 0 ) (-480 -56 0 ) (-64 -56 0 ) +4 30 (-64 -264 608 ) (-160 -264 608 ) (-160 -384 608 ) (-64 -384 608 ) +4 30 (-64 -384 176 ) (-160 -384 176 ) (-160 -264 176 ) (-64 -264 176 ) +4 31 (-160 -264 608 ) (-176 -264 608 ) (-176 -384 608 ) (-160 -384 608 ) +4 31 (-160 -264 160 ) (-160 -264 176 ) (-160 -384 176 ) (-160 -384 160 ) +4 31 (-176 -384 160 ) (-176 -264 160 ) (-160 -264 160 ) (-160 -384 160 ) +4 32 (-176 -264 608 ) (-192 -264 608 ) (-192 -384 608 ) (-176 -384 608 ) +4 32 (-176 -264 144 ) (-176 -264 160 ) (-176 -384 160 ) (-176 -384 144 ) +4 32 (-192 -384 144 ) (-192 -264 144 ) (-176 -264 144 ) (-176 -384 144 ) +4 33 (-192 -264 608 ) (-208 -264 608 ) (-208 -384 608 ) (-192 -384 608 ) +4 33 (-192 -264 128 ) (-192 -264 144 ) (-192 -384 144 ) (-192 -384 128 ) +4 33 (-208 -384 128 ) (-208 -264 128 ) (-192 -264 128 ) (-192 -384 128 ) +4 34 (-208 -264 608 ) (-224 -264 608 ) (-224 -384 608 ) (-208 -384 608 ) +4 34 (-208 -264 112 ) (-208 -264 128 ) (-208 -384 128 ) (-208 -384 112 ) +4 34 (-224 -384 112 ) (-224 -264 112 ) (-208 -264 112 ) (-208 -384 112 ) +4 35 (-240 -264 96 ) (-224 -264 96 ) (-224 -384 96 ) (-240 -384 96 ) +4 35 (-224 -264 112 ) (-224 -384 112 ) (-224 -384 96 ) (-224 -264 96 ) +4 35 (-480 -264 608 ) (-480 -264 96 ) (-480 -384 96 ) (-480 -384 608 ) +4 35 (-224 -264 608 ) (-480 -264 608 ) (-480 -384 608 ) (-224 -384 608 ) +4 36 (-256 -264 80 ) (-240 -264 80 ) (-240 -384 80 ) (-256 -384 80 ) +4 36 (-480 -264 96 ) (-480 -264 80 ) (-480 -384 80 ) (-480 -384 96 ) +4 36 (-240 -264 96 ) (-240 -384 96 ) (-240 -384 80 ) (-240 -264 80 ) +4 37 (-272 -264 64 ) (-256 -264 64 ) (-256 -384 64 ) (-272 -384 64 ) +4 37 (-480 -264 80 ) (-480 -264 64 ) (-480 -384 64 ) (-480 -384 80 ) +4 37 (-256 -264 80 ) (-256 -384 80 ) (-256 -384 64 ) (-256 -264 64 ) +4 38 (-288 -264 48 ) (-272 -264 48 ) (-272 -384 48 ) (-288 -384 48 ) +4 38 (-480 -264 64 ) (-480 -264 48 ) (-480 -384 48 ) (-480 -384 64 ) +4 38 (-272 -264 64 ) (-272 -384 64 ) (-272 -384 48 ) (-272 -264 48 ) +4 39 (-288 -384 32 ) (-304 -384 32 ) (-304 -264 32 ) (-288 -264 32 ) +4 39 (-480 -264 48 ) (-480 -264 32 ) (-480 -384 32 ) (-480 -384 48 ) +4 39 (-288 -264 48 ) (-288 -384 48 ) (-288 -384 32 ) (-288 -264 32 ) +4 40 (-304 -384 16 ) (-320 -384 16 ) (-320 -264 16 ) (-304 -264 16 ) +4 40 (-480 -264 32 ) (-480 -264 16 ) (-480 -384 16 ) (-480 -384 32 ) +4 40 (-304 -264 32 ) (-304 -384 32 ) (-304 -384 16 ) (-304 -264 16 ) +4 41 (-480 -264 16 ) (-480 -264 0 ) (-480 -384 0 ) (-480 -384 16 ) +4 41 (-320 -384 0 ) (-480 -384 0 ) (-480 -264 0 ) (-320 -264 0 ) +4 41 (-320 -264 16 ) (-320 -384 16 ) (-320 -384 0 ) (-320 -264 0 ) +4 42 (-64 -384 608 ) (-480 -384 608 ) (-480 -512 608 ) (-64 -512 608 ) +4 42 (-480 -384 608 ) (-480 -384 0 ) (-480 -512 0 ) (-480 -512 608 ) +4 42 (-320 -384 0 ) (-320 -384 16 ) (-64 -384 16 ) (-64 -384 0 ) +4 42 (-304 -384 16 ) (-304 -384 32 ) (-64 -384 32 ) (-64 -384 16 ) +4 42 (-288 -384 48 ) (-160 -384 48 ) (-160 -384 32 ) (-288 -384 32 ) +4 42 (-272 -384 64 ) (-176 -384 64 ) (-176 -384 48 ) (-272 -384 48 ) +4 42 (-256 -384 80 ) (-192 -384 80 ) (-192 -384 64 ) (-256 -384 64 ) +4 42 (-240 -384 96 ) (-208 -384 96 ) (-208 -384 80 ) (-240 -384 80 ) +4 42 (-208 -384 112 ) (-208 -384 96 ) (-224 -384 96 ) (-224 -384 112 ) +4 42 (-192 -384 128 ) (-192 -384 80 ) (-208 -384 80 ) (-208 -384 128 ) +4 42 (-176 -384 144 ) (-176 -384 64 ) (-192 -384 64 ) (-192 -384 144 ) +4 42 (-160 -384 160 ) (-160 -384 48 ) (-176 -384 48 ) (-176 -384 160 ) +4 42 (-160 -384 32 ) (-160 -384 176 ) (-64 -384 176 ) (-64 -384 32 ) +4 42 (-480 -512 608 ) (-480 -512 0 ) (-64 -512 0 ) (-64 -512 608 ) +4 42 (-64 -512 0 ) (-480 -512 0 ) (-480 -384 0 ) (-64 -384 0 ) diff --git a/fakk/maps/example/fulcrum.scr b/fakk/maps/example/fulcrum.scr new file mode 100644 index 0000000..4cf02db --- /dev/null +++ b/fakk/maps/example/fulcrum.scr @@ -0,0 +1,12 @@ +end +waitforplayer +wait 5 +loop: +cuecamera $cam1 0 +wait 5 +cuecamera $cam2 0 +wait 5 +cueplayer 0 +wait 5 +//goto loop +end \ No newline at end of file diff --git a/fakk/maps/example/funcspawn.bsp b/fakk/maps/example/funcspawn.bsp new file mode 100644 index 0000000..4e34638 Binary files /dev/null and b/fakk/maps/example/funcspawn.bsp differ diff --git a/fakk/maps/example/funcspawn.map b/fakk/maps/example/funcspawn.map new file mode 100644 index 0000000..73d4c2e --- /dev/null +++ b/fakk/maps/example/funcspawn.map @@ -0,0 +1,114 @@ +{ +"classname" "worldspawn" +// brush 0 +{ +( 320 320 0 ) ( -320 320 0 ) ( -320 -320 0 ) eden/WL_neweden_1 0 0 0.00 1 1 0 0 0 +( -320 -320 576 ) ( -320 320 576 ) ( 320 320 576 ) eden/WL_neweden_1 0 0 0.00 1 1 0 0 0 +( -320 -320 8 ) ( 320 -320 8 ) ( 320 -320 0 ) eden/WL_neweden_1 0 0 0.00 1 1 0 0 0 +( 320 320 8 ) ( -320 320 8 ) ( -320 320 0 ) eden/WL_neweden_1 0 0 0.00 1 1 0 0 0 +( -320 320 8 ) ( -320 -320 8 ) ( -320 -320 0 ) eden/WL_neweden_1 0 0 0.00 1 1 0 0 0 +( -312 -320 8 ) ( -312 320 8 ) ( -312 -320 0 ) eden/WL_neweden_1 0 0 0.00 1 1 0 0 0 +} +// brush 1 +{ +( 320 320 0 ) ( -320 320 0 ) ( -320 -320 0 ) eden/WL_neweden_1 0 0 0.00 1 1 0 0 0 +( -320 -320 576 ) ( -320 320 576 ) ( 320 320 576 ) eden/WL_neweden_1 0 0 0.00 1 1 0 0 0 +( 320 -320 8 ) ( 320 320 8 ) ( 320 320 0 ) eden/WL_neweden_1 0 0 0.00 1 1 0 0 0 +( 320 320 8 ) ( -320 320 8 ) ( -320 320 0 ) eden/WL_neweden_1 0 0 0.00 1 1 0 0 0 +( -320 320 8 ) ( -320 -320 8 ) ( -320 -320 0 ) eden/WL_neweden_1 0 0 0.00 1 1 0 0 0 +( -320 312 8 ) ( 320 312 8 ) ( -320 312 0 ) eden/WL_neweden_1 0 0 0.00 1 1 0 0 0 +} +// brush 2 +{ +( 320 320 0 ) ( -320 320 0 ) ( -320 -320 0 ) eden/WL_neweden_1 0 0 0.00 1 1 0 0 0 +( -320 -320 576 ) ( -320 320 576 ) ( 320 320 576 ) eden/WL_neweden_1 0 0 0.00 1 1 0 0 0 +( -320 -320 8 ) ( 320 -320 8 ) ( 320 -320 0 ) eden/WL_neweden_1 0 0 0.00 1 1 0 0 0 +( 320 -320 8 ) ( 320 320 8 ) ( 320 320 0 ) eden/WL_neweden_1 0 0 0.00 1 1 0 0 0 +( 320 320 8 ) ( -320 320 8 ) ( -320 320 0 ) eden/WL_neweden_1 0 0 0.00 1 1 0 0 0 +( 312 320 8 ) ( 312 -320 8 ) ( 312 320 0 ) eden/WL_neweden_1 0 0 0.00 1 1 0 0 0 +} +// brush 3 +{ +( 320 320 0 ) ( -320 320 0 ) ( -320 -320 0 ) eden/WL_neweden_1 0 0 0.00 1 1 0 0 0 +( -320 -320 576 ) ( -320 320 576 ) ( 320 320 576 ) eden/WL_neweden_1 0 0 0.00 1 1 0 0 0 +( -320 -320 8 ) ( 320 -320 8 ) ( 320 -320 0 ) eden/WL_neweden_1 0 0 0.00 1 1 0 0 0 +( 320 -320 8 ) ( 320 320 8 ) ( 320 320 0 ) eden/WL_neweden_1 0 0 0.00 1 1 0 0 0 +( -320 320 8 ) ( -320 -320 8 ) ( -320 -320 0 ) eden/WL_neweden_1 0 0 0.00 1 1 0 0 0 +( 320 -312 8 ) ( -320 -312 8 ) ( 320 -312 0 ) eden/WL_neweden_1 0 0 0.00 1 1 0 0 0 +} +// brush 4 +{ +( -320 -320 576 ) ( -320 320 576 ) ( 320 320 576 ) eden/genmetal_1 0 0 0.00 1 1 0 0 0 +( -320 -320 8 ) ( 320 -320 8 ) ( 320 -320 0 ) eden/genmetal_1 0 0 0.00 1 1 0 0 0 +( 320 -320 8 ) ( 320 320 8 ) ( 320 320 0 ) eden/genmetal_1 0 0 0.00 1 1 0 0 0 +( 320 320 8 ) ( -320 320 8 ) ( -320 320 0 ) eden/genmetal_1 0 0 0.00 1 1 0 0 0 +( -320 320 8 ) ( -320 -320 8 ) ( -320 -320 0 ) eden/genmetal_1 0 0 0.00 1 1 0 0 0 +( -320 320 568 ) ( -320 -320 568 ) ( 320 320 568 ) eden/genmetal_1 0 0 0.00 1 1 0 0 0 +} +// brush 5 +{ +( 320 320 0 ) ( -320 320 0 ) ( -320 -320 0 ) eden/fl_street1 0 0 0.00 1 1 0 0 0 +( -320 -320 8 ) ( 320 -320 8 ) ( 320 -320 0 ) eden/fl_street1 0 0 0.00 1 1 0 0 0 +( 320 -320 8 ) ( 320 320 8 ) ( 320 320 0 ) eden/fl_street1 0 0 0.00 1 1 0 0 0 +( 320 320 8 ) ( -320 320 8 ) ( -320 320 0 ) eden/fl_street1 0 0 0.00 1 1 0 0 0 +( -320 320 8 ) ( -320 -320 8 ) ( -320 -320 0 ) eden/fl_street1 0 0 0.00 1 1 0 0 0 +( -320 320 8 ) ( 320 320 8 ) ( -320 -320 8 ) eden/fl_street1 0 0 0.00 1 1 0 0 0 +} +} +// entity 1 +{ +"origin" "16 -120 112" +"classname" "light" +} +// entity 2 +{ +"origin" "224 120 112" +"classname" "light" +} +// entity 3 +{ +"origin" "-136 112 112" +"classname" "light" +} +// entity 4 +{ +"classname" "trigger_once" +"target" "t1" +// brush 0 +{ +( 312 -64 8 ) ( -296 -64 8 ) ( -296 -72 8 ) common/trigger 0 0 0.00 1 1 0 128 0 +( -296 -72 320 ) ( -296 -64 320 ) ( 312 -64 320 ) common/trigger 0 0 0.00 1 1 0 128 0 +( -296 -72 40 ) ( 312 -72 40 ) ( 312 -72 8 ) common/trigger 0 0 0.00 1 1 0 128 0 +( 312 -72 40 ) ( 312 -64 40 ) ( 312 -64 8 ) common/trigger 0 0 0.00 1 1 0 128 0 +( 312 -64 40 ) ( -296 -64 40 ) ( -296 -64 8 ) common/trigger 0 0 0.00 1 1 0 128 0 +( -312 -64 40 ) ( -312 -72 40 ) ( -312 -72 8 ) common/trigger 0 0 0.00 1 1 0 128 0 +} +} +// entity 5 +{ +"classname" "func_spawn" +"targetname" "t1" +"origin" "0 256 448" +"modelname" "creeper.tik" +} +// entity 6 +{ +"origin" "0 -240 8" +"angle" "90" +"classname" "info_player_start" +} +// entity 7 +{ +"classname" "light" +"origin" "24 -128 296" +} +// entity 8 +{ +"classname" "light" +"origin" "232 112 296" +} +// entity 9 +{ +"classname" "light" +"origin" "-128 104 296" +} diff --git a/fakk/maps/example/funcspawn.prt b/fakk/maps/example/funcspawn.prt new file mode 100644 index 0000000..ed54b51 --- /dev/null +++ b/fakk/maps/example/funcspawn.prt @@ -0,0 +1,24 @@ +PRT1 +4 +4 +16 +4 0 2 0 (0 0 8 ) (0 0 568 ) (0 312 568 ) (0 312 8 ) +4 0 1 0 (0 0 568 ) (0 0 8 ) (312 0 8 ) (312 0 568 ) +4 1 3 0 (0 0 568 ) (0 0 8 ) (0 -312 8 ) (0 -312 568 ) +4 2 3 0 (0 0 8 ) (0 0 568 ) (-312 0 568 ) (-312 0 8 ) +4 0 (312 0 568 ) (312 0 8 ) (312 312 8 ) (312 312 568 ) +4 0 (312 312 568 ) (312 312 8 ) (0 312 8 ) (0 312 568 ) +4 0 (312 0 8 ) (0 0 8 ) (0 312 8 ) (312 312 8 ) +4 0 (0 0 568 ) (312 0 568 ) (312 312 568 ) (0 312 568 ) +4 1 (0 -312 568 ) (0 -312 8 ) (312 -312 8 ) (312 -312 568 ) +4 1 (312 -312 568 ) (312 -312 8 ) (312 0 8 ) (312 0 568 ) +4 1 (0 -312 8 ) (0 0 8 ) (312 0 8 ) (312 -312 8 ) +4 1 (312 0 568 ) (0 0 568 ) (0 -312 568 ) (312 -312 568 ) +4 2 (0 312 568 ) (0 312 8 ) (-312 312 8 ) (-312 312 568 ) +4 2 (-312 0 8 ) (-312 0 568 ) (-312 312 568 ) (-312 312 8 ) +4 2 (0 0 8 ) (-312 0 8 ) (-312 312 8 ) (0 312 8 ) +4 2 (0 312 568 ) (-312 312 568 ) (-312 0 568 ) (0 0 568 ) +4 3 (-312 -312 568 ) (-312 -312 8 ) (0 -312 8 ) (0 -312 568 ) +4 3 (-312 0 568 ) (-312 0 8 ) (-312 -312 8 ) (-312 -312 568 ) +4 3 (-312 -312 8 ) (-312 0 8 ) (0 0 8 ) (0 -312 8 ) +4 3 (0 0 568 ) (-312 0 568 ) (-312 -312 568 ) (0 -312 568 ) diff --git a/fakk/maps/example/gibs_and_health.bsp b/fakk/maps/example/gibs_and_health.bsp new file mode 100644 index 0000000..d46880f Binary files /dev/null and b/fakk/maps/example/gibs_and_health.bsp differ diff --git a/fakk/maps/example/gibs_and_health.map b/fakk/maps/example/gibs_and_health.map new file mode 100644 index 0000000..d167626 --- /dev/null +++ b/fakk/maps/example/gibs_and_health.map @@ -0,0 +1,1422 @@ +{ +"classname" "worldspawn" +// brush 0 +{ +( 152 560 64 ) ( 152 576 64 ) ( 136 576 64 ) eden/genmetal 0 8 0.00 1 1 0 0 0 +( 136 576 240 ) ( 152 576 240 ) ( 152 560 240 ) eden/genmetal 0 8 0.00 1 1 0 0 0 +( 136 576 256 ) ( 136 560 256 ) ( 136 560 0 ) eden/genmetal -32 0 0.00 1 1 0 0 0 +( 136 568 256 ) ( 152 568 256 ) ( 152 568 0 ) eden/genmetal 24 0 0.00 1 1 0 0 0 +( 152 568 256 ) ( 152 584 256 ) ( 152 584 0 ) eden/genmetal -32 0 0.00 1 1 0 0 0 +( 152 576 256 ) ( 136 576 256 ) ( 136 576 0 ) eden/genmetal 56 0 -180.00 1 -1 0 0 0 +} +// brush 1 +{ +( 184 560 64 ) ( 184 576 64 ) ( 168 576 64 ) eden/genmetal 0 -8 0.00 1 1 0 0 0 +( 168 576 240 ) ( 184 576 240 ) ( 184 560 240 ) eden/genmetal 0 -8 0.00 1 1 0 0 0 +( 168 584 256 ) ( 168 568 256 ) ( 168 568 0 ) eden/genmetal -32 0 0.00 1 1 0 0 0 +( 168 568 256 ) ( 184 568 256 ) ( 184 568 0 ) eden/genmetal 40 0 0.00 1 1 0 0 0 +( 184 560 256 ) ( 184 576 256 ) ( 184 576 0 ) eden/genmetal -32 0 0.00 1 1 0 0 0 +( 184 576 256 ) ( 168 576 256 ) ( 168 576 0 ) eden/genmetal 72 0 -180.00 1 -1 0 0 0 +} +// brush 2 +{ +( 176 576 272 ) ( 144 576 272 ) ( 144 576 16 ) eden/genmetal 32 16 0.00 1 1 0 0 0 +( 168 568 272 ) ( 168 584 272 ) ( 168 584 16 ) eden/genmetal -32 16 0.00 1 1 0 0 0 +( 136 568 256 ) ( 168 568 256 ) ( 168 568 0 ) eden/genmetal 32 16 0.00 1 1 0 0 0 +( 152 584 272 ) ( 152 568 272 ) ( 152 568 16 ) eden/genmetal -32 16 0.00 1 1 0 0 0 +( 144 576 80 ) ( 176 576 80 ) ( 176 560 80 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( 176 560 64 ) ( 176 576 64 ) ( 144 576 64 ) eden/genmetal 0 -64 90.00 1 1 0 0 0 +} +// brush 3 +{ +( 176 576 432 ) ( 144 576 432 ) ( 144 576 176 ) eden/genmetal 32 48 0.00 1 1 0 0 0 +( 168 568 432 ) ( 168 584 432 ) ( 168 584 176 ) eden/genmetal -32 48 0.00 1 1 0 0 0 +( 136 568 416 ) ( 168 568 416 ) ( 168 568 160 ) eden/genmetal 32 48 0.00 1 1 0 0 0 +( 152 584 432 ) ( 152 568 432 ) ( 152 568 176 ) eden/genmetal -32 48 0.00 1 1 0 0 0 +( 144 576 240 ) ( 176 576 240 ) ( 176 560 240 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( 176 560 224 ) ( 176 576 224 ) ( 144 576 224 ) eden/genmetal 0 -64 90.00 1 1 0 0 0 +} +// brush 4 +{ +( 168 576 240 ) ( 152 576 240 ) ( 152 576 64 ) otto/ottolight 35 -16 90.00 -2.250000 -0.500000 0 0 0 +( 168 568 240 ) ( 168 576 240 ) ( 168 576 64 ) otto/ottolight 35 16 90.00 -2.250000 -0.500000 0 0 0 +( 152 572 240 ) ( 168 572 240 ) ( 168 572 64 ) otto/ottolight 35 -16 90.00 -2.250000 -0.500000 0 0 0 +( 152 576 240 ) ( 152 568 240 ) ( 152 568 64 ) otto/ottolight 35 16 90.00 -2.250000 -0.500000 0 0 0 +( 152 576 224 ) ( 168 576 224 ) ( 168 568 224 ) otto/ottolight 35 -16 90.00 -2.250000 -0.500000 0 0 0 +( 168 568 80 ) ( 168 576 80 ) ( 152 576 80 ) otto/ottolight 6 16 0.00 2.250000 0.500000 0 0 0 +} +// brush 5 +{ +( 152 -768 64 ) ( 152 -768 240 ) ( 168 -768 240 ) otto/ottolight 35 -16 90.00 -2.250000 -0.500000 0 0 0 +( 168 -768 64 ) ( 168 -768 240 ) ( 168 -760 240 ) otto/ottolight 34 16 90.00 -2.250000 -0.500000 0 0 0 +( 168 -764 64 ) ( 168 -764 240 ) ( 152 -764 240 ) otto/ottolight 35 -16 90.00 -2.250000 -0.500000 0 0 0 +( 152 -760 64 ) ( 152 -760 240 ) ( 152 -768 240 ) otto/ottolight 34 16 90.00 -2.250000 -0.500000 0 0 0 +( 168 -760 224 ) ( 168 -768 224 ) ( 152 -768 224 ) otto/ottolight 34 -16 90.00 -2.250000 -0.500000 0 0 0 +( 152 -768 80 ) ( 168 -768 80 ) ( 168 -760 80 ) otto/ottolight 5 16 0.00 2.250000 0.500000 0 0 0 +} +// brush 6 +{ +( 144 -768 176 ) ( 144 -768 432 ) ( 176 -768 432 ) eden/genmetal 32 48 0.00 1 1 0 0 0 +( 168 -776 176 ) ( 168 -776 432 ) ( 168 -760 432 ) eden/genmetal -96 48 0.00 1 1 0 0 0 +( 168 -760 160 ) ( 168 -760 416 ) ( 136 -760 416 ) eden/genmetal 32 48 0.00 1 1 0 0 0 +( 152 -760 176 ) ( 152 -760 432 ) ( 152 -776 432 ) eden/genmetal -96 48 0.00 1 1 0 0 0 +( 176 -752 240 ) ( 176 -768 240 ) ( 144 -768 240 ) eden/genmetal -64 0 0.00 1 1 0 0 0 +( 144 -768 224 ) ( 176 -768 224 ) ( 176 -752 224 ) eden/genmetal 64 -63 90.00 1 1 0 0 0 +} +// brush 7 +{ +( 144 -768 16 ) ( 144 -768 272 ) ( 176 -768 272 ) eden/genmetal 32 16 0.00 1 1 0 0 0 +( 168 -776 16 ) ( 168 -776 272 ) ( 168 -760 272 ) eden/genmetal -96 16 0.00 1 1 0 0 0 +( 168 -760 0 ) ( 168 -760 256 ) ( 136 -760 256 ) eden/genmetal 32 16 0.00 1 1 0 0 0 +( 152 -760 16 ) ( 152 -760 272 ) ( 152 -776 272 ) eden/genmetal -96 16 0.00 1 1 0 0 0 +( 176 -752 80 ) ( 176 -768 80 ) ( 144 -768 80 ) eden/genmetal -64 0 0.00 1 1 0 0 0 +( 144 -768 64 ) ( 176 -768 64 ) ( 176 -752 64 ) eden/genmetal 64 -63 90.00 1 1 0 0 0 +} +// brush 8 +{ +( 168 -768 64 ) ( 184 -768 64 ) ( 184 -752 64 ) eden/genmetal -64 -8 0.00 1 1 0 0 0 +( 184 -752 240 ) ( 184 -768 240 ) ( 168 -768 240 ) eden/genmetal -64 -8 0.00 1 1 0 0 0 +( 168 -760 0 ) ( 168 -760 256 ) ( 168 -776 256 ) eden/genmetal -96 0 0.00 1 1 0 0 0 +( 184 -760 0 ) ( 184 -760 256 ) ( 168 -760 256 ) eden/genmetal 40 0 0.00 1 1 0 0 0 +( 184 -768 0 ) ( 184 -768 256 ) ( 184 -752 256 ) eden/genmetal -96 0 0.00 1 1 0 0 0 +( 168 -768 0 ) ( 168 -768 256 ) ( 184 -768 256 ) eden/genmetal 71 0 -180.00 1 -1 0 0 0 +} +// brush 9 +{ +( 136 -768 64 ) ( 152 -768 64 ) ( 152 -752 64 ) eden/genmetal -64 8 0.00 1 1 0 0 0 +( 152 -752 240 ) ( 152 -768 240 ) ( 136 -768 240 ) eden/genmetal -64 8 0.00 1 1 0 0 0 +( 136 -752 0 ) ( 136 -752 256 ) ( 136 -768 256 ) eden/genmetal -96 0 0.00 1 1 0 0 0 +( 152 -760 0 ) ( 152 -760 256 ) ( 136 -760 256 ) eden/genmetal 24 0 0.00 1 1 0 0 0 +( 152 -776 0 ) ( 152 -776 256 ) ( 152 -760 256 ) eden/genmetal -96 0 0.00 1 1 0 0 0 +( 136 -768 0 ) ( 136 -768 256 ) ( 152 -768 256 ) eden/genmetal 55 0 -180.00 1 -1 0 0 0 +} +// brush 10 +{ +( 832 -120 64 ) ( 832 -104 64 ) ( 816 -104 64 ) eden/genmetal -64 8 0.00 1 1 0 0 0 +( 816 -104 240 ) ( 832 -104 240 ) ( 832 -120 240 ) eden/genmetal -64 8 0.00 1 1 0 0 0 +( 816 -120 0 ) ( 816 -120 256 ) ( 832 -120 256 ) eden/genmetal -64 0 0.00 1 1 0 0 0 +( 824 -104 0 ) ( 824 -104 256 ) ( 824 -120 256 ) eden/genmetal -8 0 0.00 1 1 0 0 0 +( 840 -104 0 ) ( 840 -104 256 ) ( 824 -104 256 ) eden/genmetal -64 0 0.00 1 1 0 0 0 +( 832 -120 0 ) ( 832 -120 256 ) ( 832 -104 256 ) eden/genmetal -8 0 0.00 1 1 0 0 0 +} +// brush 11 +{ +( 832 -88 64 ) ( 832 -72 64 ) ( 816 -72 64 ) eden/genmetal -64 -8 0.00 1 1 0 0 0 +( 816 -72 240 ) ( 832 -72 240 ) ( 832 -88 240 ) eden/genmetal -64 -8 0.00 1 1 0 0 0 +( 824 -88 0 ) ( 824 -88 256 ) ( 840 -88 256 ) eden/genmetal -64 0 0.00 1 1 0 0 0 +( 824 -72 0 ) ( 824 -72 256 ) ( 824 -88 256 ) eden/genmetal 8 0 0.00 1 1 0 0 0 +( 832 -72 0 ) ( 832 -72 256 ) ( 816 -72 256 ) eden/genmetal -64 0 0.00 1 1 0 0 0 +( 832 -88 0 ) ( 832 -88 256 ) ( 832 -72 256 ) eden/genmetal 8 0 0.00 1 1 0 0 0 +} +// brush 12 +{ +( 832 -112 16 ) ( 832 -112 272 ) ( 832 -80 272 ) eden/genmetal 0 16 0.00 1 1 0 0 0 +( 840 -88 16 ) ( 840 -88 272 ) ( 824 -88 272 ) eden/genmetal -64 16 0.00 1 1 0 0 0 +( 824 -88 0 ) ( 824 -88 256 ) ( 824 -120 256 ) eden/genmetal 0 16 0.00 1 1 0 0 0 +( 824 -104 16 ) ( 824 -104 272 ) ( 840 -104 272 ) eden/genmetal -64 16 0.00 1 1 0 0 0 +( 816 -80 80 ) ( 832 -80 80 ) ( 832 -112 80 ) eden/genmetal -64 0 0.00 1 1 0 0 0 +( 832 -112 64 ) ( 832 -80 64 ) ( 816 -80 64 ) eden/genmetal -64 0 0.00 1 1 0 0 0 +} +// brush 13 +{ +( 832 -112 176 ) ( 832 -112 432 ) ( 832 -80 432 ) eden/genmetal 0 48 0.00 1 1 0 0 0 +( 840 -88 176 ) ( 840 -88 432 ) ( 824 -88 432 ) eden/genmetal -64 48 0.00 1 1 0 0 0 +( 824 -88 160 ) ( 824 -88 416 ) ( 824 -120 416 ) eden/genmetal 0 48 0.00 1 1 0 0 0 +( 824 -104 176 ) ( 824 -104 432 ) ( 840 -104 432 ) eden/genmetal -64 48 0.00 1 1 0 0 0 +( 816 -80 240 ) ( 832 -80 240 ) ( 832 -112 240 ) eden/genmetal -64 0 0.00 1 1 0 0 0 +( 832 -112 224 ) ( 832 -80 224 ) ( 816 -80 224 ) eden/genmetal -64 0 0.00 1 1 0 0 0 +} +// brush 14 +{ +( 832 -104 64 ) ( 832 -104 240 ) ( 832 -88 240 ) otto/ottolight 35 16 90.00 -2.250000 -0.500000 0 0 0 +( 832 -88 64 ) ( 832 -88 240 ) ( 824 -88 240 ) otto/ottolight 34 16 90.00 -2.250000 -0.500000 0 0 0 +( 828 -88 64 ) ( 828 -88 240 ) ( 828 -104 240 ) otto/ottolight 35 16 90.00 -2.250000 -0.500000 0 0 0 +( 824 -104 64 ) ( 824 -104 240 ) ( 832 -104 240 ) otto/ottolight 34 16 90.00 -2.250000 -0.500000 0 0 0 +( 824 -88 224 ) ( 832 -88 224 ) ( 832 -104 224 ) otto/ottolight 34 16 90.00 -2.250000 -0.500000 0 0 0 +( 832 -104 80 ) ( 832 -88 80 ) ( 824 -88 80 ) otto/ottolight 34 16 90.00 -2.250000 -0.500000 0 0 0 +} +// brush 15 +{ +( -512 -88 240 ) ( -512 -104 240 ) ( -512 -104 64 ) otto/ottolight 35 16 90.00 -2.250000 -0.500000 0 0 0 +( -504 -88 240 ) ( -512 -88 240 ) ( -512 -88 64 ) otto/ottolight 35 16 90.00 -2.250000 -0.500000 0 0 0 +( -508 -104 240 ) ( -508 -88 240 ) ( -508 -88 64 ) otto/ottolight 35 16 90.00 -2.250000 -0.500000 0 0 0 +( -512 -104 240 ) ( -504 -104 240 ) ( -504 -104 64 ) otto/ottolight 35 16 90.00 -2.250000 -0.500000 0 0 0 +( -512 -104 224 ) ( -512 -88 224 ) ( -504 -88 224 ) otto/ottolight 35 16 90.00 -2.250000 -0.500000 0 0 0 +( -504 -88 80 ) ( -512 -88 80 ) ( -512 -104 80 ) otto/ottolight 35 16 90.00 -2.250000 -0.500000 0 0 0 +} +// brush 16 +{ +( -512 -80 432 ) ( -512 -112 432 ) ( -512 -112 176 ) eden/genmetal 0 48 0.00 1 1 0 0 0 +( -504 -88 432 ) ( -520 -88 432 ) ( -520 -88 176 ) eden/genmetal 0 48 0.00 1 1 0 0 0 +( -504 -120 416 ) ( -504 -88 416 ) ( -504 -88 160 ) eden/genmetal 0 48 0.00 1 1 0 0 0 +( -520 -104 432 ) ( -504 -104 432 ) ( -504 -104 176 ) eden/genmetal 0 48 0.00 1 1 0 0 0 +( -512 -112 240 ) ( -512 -80 240 ) ( -496 -80 240 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( -496 -80 224 ) ( -512 -80 224 ) ( -512 -112 224 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +} +// brush 17 +{ +( -512 -80 272 ) ( -512 -112 272 ) ( -512 -112 16 ) eden/genmetal 0 16 0.00 1 1 0 0 0 +( -504 -88 272 ) ( -520 -88 272 ) ( -520 -88 16 ) eden/genmetal 0 16 0.00 1 1 0 0 0 +( -504 -120 256 ) ( -504 -88 256 ) ( -504 -88 0 ) eden/genmetal 0 16 0.00 1 1 0 0 0 +( -520 -104 272 ) ( -504 -104 272 ) ( -504 -104 16 ) eden/genmetal 0 16 0.00 1 1 0 0 0 +( -512 -112 80 ) ( -512 -80 80 ) ( -496 -80 80 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( -496 -80 64 ) ( -512 -80 64 ) ( -512 -112 64 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +} +// brush 18 +{ +( -496 -72 64 ) ( -512 -72 64 ) ( -512 -88 64 ) eden/genmetal 0 -8 0.00 1 1 0 0 0 +( -512 -88 240 ) ( -512 -72 240 ) ( -496 -72 240 ) eden/genmetal 0 -8 0.00 1 1 0 0 0 +( -520 -88 256 ) ( -504 -88 256 ) ( -504 -88 0 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( -504 -88 256 ) ( -504 -72 256 ) ( -504 -72 0 ) eden/genmetal 8 0 0.00 1 1 0 0 0 +( -496 -72 256 ) ( -512 -72 256 ) ( -512 -72 0 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( -512 -72 256 ) ( -512 -88 256 ) ( -512 -88 0 ) eden/genmetal 8 0 0.00 1 1 0 0 0 +} +// brush 19 +{ +( -496 -104 64 ) ( -512 -104 64 ) ( -512 -120 64 ) eden/genmetal 0 8 0.00 1 1 0 0 0 +( -512 -120 240 ) ( -512 -104 240 ) ( -496 -104 240 ) eden/genmetal 0 8 0.00 1 1 0 0 0 +( -512 -120 256 ) ( -496 -120 256 ) ( -496 -120 0 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( -504 -120 256 ) ( -504 -104 256 ) ( -504 -104 0 ) eden/genmetal -8 0 0.00 1 1 0 0 0 +( -504 -104 256 ) ( -520 -104 256 ) ( -520 -104 0 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( -512 -104 256 ) ( -512 -120 256 ) ( -512 -120 0 ) eden/genmetal -8 0 0.00 1 1 0 0 0 +} +// brush 20 +{ +( 128 704 -96 ) ( 128 672 -96 ) ( 128 672 -128 ) eden/edenmetalwall 0 0 0.00 1 1 0 0 0 +( 352 704 -96 ) ( 128 704 -96 ) ( 128 704 -128 ) eden/edenmetalwall 64 0 0.00 1 1 0 0 0 +( 384 672 -96 ) ( 384 704 -96 ) ( 384 704 -128 ) eden/edenmetalwall 0 0 0.00 1 1 0 0 0 +( 128 672 -96 ) ( 352 672 -96 ) ( 352 672 -128 ) eden/edenmetalwall 64 0 0.00 1 1 0 0 0 +( 128 672 -96 ) ( 128 704 -96 ) ( 352 704 -96 ) eden/edenmetalwall 64 0 0.00 1 1 0 0 0 +( 352 704 -128 ) ( 128 704 -128 ) ( 128 672 -128 ) eden/edenmetalwall 64 0 0.00 1 1 0 0 0 +} +// brush 21 + { + patchDef2 + { + eden/edenmetalwall + ( 9 3 0 536870912 0 subdivisions 90.458153 ) +( +( ( -344 -568 288 0 0 ) ( -344 -568 496 0 0.812500 ) ( 72 -184 496 0 3.437500 ) ) +( ( -312 -600 288 0.125000 0 ) ( -312 -600 496 0.125000 0.812500 ) ( 104 -216 496 0.125000 3.437500 ) ) +( ( -280 -568 288 0.250000 0 ) ( -280 -568 464 0.250000 0.812500 ) ( 104 -216 464 0.250000 3.437500 ) ) +( ( -248 -536 288 0.375000 0 ) ( -248 -536 432 0.375000 0.812500 ) ( 104 -216 432 0.375000 3.437500 ) ) +( ( -280 -504 288 0.500000 0 ) ( -280 -504 432 0.500000 0.812500 ) ( 72 -184 432 0.500000 3.437500 ) ) +( ( -312 -472 288 0.625000 0 ) ( -312 -472 432 0.625000 0.812500 ) ( 40 -152 432 0.625000 3.437500 ) ) +( ( -344 -504 288 0.750000 0 ) ( -344 -504 464 0.750000 0.812500 ) ( 40 -152 464 0.750000 3.437500 ) ) +( ( -376 -536 288 0.875000 0 ) ( -376 -536 496 0.875000 0.812500 ) ( 40 -152 496 0.875000 3.437500 ) ) +( ( -344 -568 288 1 0 ) ( -344 -568 496 1 0.812500 ) ( 72 -184 496 1 3.437500 ) ) +) + } + } +// brush 22 + { + patchDef2 + { + eden/edenmetalwall + ( 9 3 0 536870912 0 subdivisions 90.458153 ) +( +( ( 88 -8 496 0 3.437500 ) ( -328 376 496 0 0.812500 ) ( -328 376 288 0 0 ) ) +( ( 120 24 496 0.125000 3.437500 ) ( -296 408 496 0.125000 0.812500 ) ( -296 408 288 0.125000 0 ) ) +( ( 120 24 464 0.250000 3.437500 ) ( -264 376 464 0.250000 0.812500 ) ( -264 376 288 0.250000 0 ) ) +( ( 120 24 432 0.375000 3.437500 ) ( -232 344 432 0.375000 0.812500 ) ( -232 344 288 0.375000 0 ) ) +( ( 88 -8 432 0.500000 3.437500 ) ( -264 312 432 0.500000 0.812500 ) ( -264 312 288 0.500000 0 ) ) +( ( 56 -40 432 0.625000 3.437500 ) ( -296 280 432 0.625000 0.812500 ) ( -296 280 288 0.625000 0 ) ) +( ( 56 -40 464 0.750000 3.437500 ) ( -328 312 464 0.750000 0.812500 ) ( -328 312 288 0.750000 0 ) ) +( ( 56 -40 496 0.875000 3.437500 ) ( -360 344 496 0.875000 0.812500 ) ( -360 344 288 0.875000 0 ) ) +( ( 88 -8 496 1 3.437500 ) ( -328 376 496 1 0.812500 ) ( -328 376 288 1 0 ) ) +) + } + } +// brush 23 + { + patchDef2 + { + eden/edenmetalwall + ( 9 3 0 536870912 0 subdivisions 90.458153 ) +( +( ( 648 376 288 0 0 ) ( 648 376 496 0 0.812500 ) ( 232 -8 496 0 3.437500 ) ) +( ( 616 408 288 0.125000 0 ) ( 616 408 496 0.125000 0.812500 ) ( 200 24 496 0.125000 3.437500 ) ) +( ( 584 376 288 0.250000 0 ) ( 584 376 464 0.250000 0.812500 ) ( 200 24 464 0.250000 3.437500 ) ) +( ( 552 344 288 0.375000 0 ) ( 552 344 432 0.375000 0.812500 ) ( 200 24 432 0.375000 3.437500 ) ) +( ( 584 312 288 0.500000 0 ) ( 584 312 432 0.500000 0.812500 ) ( 232 -8 432 0.500000 3.437500 ) ) +( ( 616 280 288 0.625000 0 ) ( 616 280 432 0.625000 0.812500 ) ( 264 -40 432 0.625000 3.437500 ) ) +( ( 648 312 288 0.750000 0 ) ( 648 312 464 0.750000 0.812500 ) ( 264 -40 464 0.750000 3.437500 ) ) +( ( 680 344 288 0.875000 0 ) ( 680 344 496 0.875000 0.812500 ) ( 264 -40 496 0.875000 3.437500 ) ) +( ( 648 376 288 1 0 ) ( 648 376 496 1 0.812500 ) ( 232 -8 496 1 3.437500 ) ) +) + } + } +// brush 24 + { + patchDef2 + { + eden/edenmetalwall + ( 9 3 0 536870912 0 subdivisions 90.458153 ) +( +( ( 248 -184 496 0 3.437500 ) ( 664 -568 496 0 0.812500 ) ( 664 -568 288 0 0 ) ) +( ( 216 -216 496 0.125000 3.437500 ) ( 632 -600 496 0.125000 0.812500 ) ( 632 -600 288 0.125000 0 ) ) +( ( 216 -216 464 0.250000 3.437500 ) ( 600 -568 464 0.250000 0.812500 ) ( 600 -568 288 0.250000 0 ) ) +( ( 216 -216 432 0.375000 3.437500 ) ( 568 -536 432 0.375000 0.812500 ) ( 568 -536 288 0.375000 0 ) ) +( ( 248 -184 432 0.500000 3.437500 ) ( 600 -504 432 0.500000 0.812500 ) ( 600 -504 288 0.500000 0 ) ) +( ( 280 -152 432 0.625000 3.437500 ) ( 632 -472 432 0.625000 0.812500 ) ( 632 -472 288 0.625000 0 ) ) +( ( 280 -152 464 0.750000 3.437500 ) ( 664 -504 464 0.750000 0.812500 ) ( 664 -504 288 0.750000 0 ) ) +( ( 280 -152 496 0.875000 3.437500 ) ( 696 -536 496 0.875000 0.812500 ) ( 696 -536 288 0.875000 0 ) ) +( ( 248 -184 496 1 3.437500 ) ( 664 -568 496 1 0.812500 ) ( 664 -568 288 1 0 ) ) +) + } + } +// brush 25 +{ +( 280 -144 408 ) ( 280 -144 504 ) ( 280 -48 504 ) eden/edenmetalwall 8 24 0.00 1 1 0 0 0 +( 280 -48 496 ) ( 232 -64 496 ) ( 232 -64 408 ) eden/edenmetalwall -216 24 0.00 1 1 0 0 0 +( 232 -64 496 ) ( 232 -128 496 ) ( 232 -128 408 ) eden/edenmetalwall 8 24 0.00 1 1 0 0 0 +( 280 -144 408 ) ( 232 -128 408 ) ( 232 -128 496 ) eden/edenmetalwall -216 24 0.00 1 1 0 0 0 +( 224 -48 496 ) ( 288 -48 496 ) ( 288 -144 496 ) eden/edenmetalwall -200 8 0.00 1 1 0 0 0 +( 288 -144 408 ) ( 288 -48 408 ) ( 224 -48 408 ) eden/edenmetalwall 64 193 -180.00 1 1 0 0 0 +} +// brush 26 +{ +( 208 24 504 ) ( 112 24 504 ) ( 112 24 408 ) eden/edenmetalwall -72 24 0.00 1 1 0 0 0 +( 192 -24 408 ) ( 192 -24 496 ) ( 208 24 496 ) eden/edenmetalwall -120 24 0.00 1 1 0 0 0 +( 128 -24 408 ) ( 128 -24 496 ) ( 192 -24 496 ) eden/edenmetalwall -72 24 0.00 1 1 0 0 0 +( 128 -24 496 ) ( 128 -24 408 ) ( 112 24 408 ) eden/edenmetalwall -120 24 0.00 1 1 0 0 0 +( 112 32 496 ) ( 208 32 496 ) ( 208 -32 496 ) eden/edenmetalwall -88 104 0.00 1 1 0 0 0 +( 208 -32 408 ) ( 208 32 408 ) ( 112 32 408 ) eden/edenmetalwall -192 -47 90.00 1 1 0 0 0 +} +// brush 27 +{ +( 40 -48 408 ) ( 112 24 408 ) ( 112 24 496 ) eden/edenmetalwall -160 0 0.00 1 1 0 0 0 +( 40 -48 496 ) ( 88 -64 496 ) ( 88 -64 408 ) eden/edenmetalwall -16 0 0.00 1 1 0 0 0 +( 88 -64 496 ) ( 128 -24 496 ) ( 128 -24 408 ) eden/edenmetalwall -160 0 0.00 1 1 0 0 0 +( 112 24 408 ) ( 128 -24 408 ) ( 128 -24 496 ) eden/edenmetalwall -160 0 0.00 1 1 0 0 0 +( 40 -48 496 ) ( 80 0 496 ) ( 128 -16 496 ) eden/edenmetalwall -16 160 0.00 1 1 0 0 0 +( 88 -64 408 ) ( 128 -16 408 ) ( 80 0 408 ) eden/edenmetalwall -16 160 0.00 1 1 0 0 0 +} +// brush 28 +{ +( 208 24 496 ) ( 208 24 408 ) ( 280 -48 408 ) eden/edenmetalwall -160 0 0.00 1 1 0 0 0 +( 232 -64 408 ) ( 232 -64 496 ) ( 280 -48 496 ) eden/edenmetalwall -160 0 0.00 1 1 0 0 0 +( 192 -24 408 ) ( 192 -24 496 ) ( 232 -64 496 ) eden/edenmetalwall -160 0 0.00 1 1 0 0 0 +( 192 -24 496 ) ( 192 -24 408 ) ( 208 24 408 ) eden/edenmetalwall -160 0 0.00 1 1 0 0 0 +( 192 -16 496 ) ( 240 0 496 ) ( 280 -48 496 ) eden/edenmetalwall -160 160 0.00 1 1 0 0 0 +( 240 0 408 ) ( 192 -16 408 ) ( 232 -64 408 ) eden/edenmetalwall -160 160 0.00 1 1 0 0 0 +} +// brush 29 +{ +( 232 -128 408 ) ( 192 -176 408 ) ( 240 -192 408 ) eden/edenmetalwall -160 0 0.00 1 1 0 0 0 +( 280 -144 496 ) ( 240 -192 496 ) ( 192 -176 496 ) eden/edenmetalwall -160 0 0.00 1 1 0 0 0 +( 208 -216 408 ) ( 192 -168 408 ) ( 192 -168 496 ) eden/edenmetalwall 0 0 0.00 1 1 0 0 0 +( 232 -128 496 ) ( 192 -168 496 ) ( 192 -168 408 ) eden/edenmetalwall 0 0 0.00 1 1 0 0 0 +( 280 -144 496 ) ( 232 -128 496 ) ( 232 -128 408 ) eden/edenmetalwall -160 0 0.00 1 1 0 0 0 +( 280 -144 408 ) ( 208 -216 408 ) ( 208 -216 496 ) eden/edenmetalwall 0 0 0.00 1 1 0 0 0 +} +// brush 30 +{ +( 112 -224 408 ) ( 208 -224 408 ) ( 208 -160 408 ) eden/edenmetalwall 0 -47 90.00 1 1 0 0 0 +( 208 -160 496 ) ( 208 -224 496 ) ( 112 -224 496 ) eden/edenmetalwall -88 -88 0.00 1 1 0 0 0 +( 112 -216 408 ) ( 128 -168 408 ) ( 128 -168 496 ) eden/edenmetalwall 72 24 0.00 1 1 0 0 0 +( 192 -168 496 ) ( 128 -168 496 ) ( 128 -168 408 ) eden/edenmetalwall -72 24 0.00 1 1 0 0 0 +( 208 -216 496 ) ( 192 -168 496 ) ( 192 -168 408 ) eden/edenmetalwall 72 24 0.00 1 1 0 0 0 +( 112 -216 408 ) ( 112 -216 504 ) ( 208 -216 504 ) eden/edenmetalwall -72 24 0.00 1 1 0 0 0 +} +// brush 31 +{ +( 112 -216 496 ) ( 112 -216 408 ) ( 40 -144 408 ) eden/edenmetalwall 0 0 0.00 1 1 0 0 0 +( 88 -128 408 ) ( 88 -128 496 ) ( 40 -144 496 ) eden/edenmetalwall 0 0 0.00 1 1 0 0 0 +( 128 -168 408 ) ( 128 -168 496 ) ( 88 -128 496 ) eden/edenmetalwall 0 0 0.00 1 1 0 0 0 +( 128 -168 496 ) ( 128 -168 408 ) ( 112 -216 408 ) eden/edenmetalwall 0 0 0.00 1 1 0 0 0 +( 128 -176 496 ) ( 80 -192 496 ) ( 40 -143.999954 496 ) eden/edenmetalwall 0 0 0.00 1 1 0 0 0 +( 80 -192 408 ) ( 128 -176 408 ) ( 88 -127.999954 408 ) eden/edenmetalwall 0 0 0.00 1 1 0 0 0 +} +// brush 32 +{ +( 96 -48 408 ) ( 32 -48 408 ) ( 32 -144 408 ) eden/edenmetalwall 0 0 0.00 1 1 0 0 0 +( 32 -144 496 ) ( 32 -48 496 ) ( 96 -48 496 ) eden/edenmetalwall 0 0 0.00 1 1 0 0 0 +( 88 -128 496 ) ( 88 -128 408 ) ( 40 -144 408 ) eden/edenmetalwall 0 24 0.00 1 1 0 0 0 +( 88 -128 408 ) ( 88 -128 496 ) ( 88 -64 496 ) eden/edenmetalwall 0 24 0.00 1 1 0 0 0 +( 88 -64 408 ) ( 88 -64 496 ) ( 40 -48 496 ) eden/edenmetalwall 0 24 0.00 1 1 0 0 0 +( 40 -48 504 ) ( 40 -144 504 ) ( 40 -144 408 ) eden/edenmetalwall 0 24 0.00 1 1 0 0 0 +} +// brush 33 + { + patchDef2 + { + eden/edenmetalwall + ( 3 3 0 536870912 0 ) +( +( ( 32 -96 400 0 0 ) ( 16 -240 400 0 0.093750 ) ( 160 -224 400 0 0.187500 ) ) +( ( 64 -96 400 0.156250 0 ) ( 72 -184 400 0.156250 0.093750 ) ( 160 -200 400 0.156250 0.187500 ) ) +( ( 96 -96 400 0.312500 0 ) ( 96 -160 400 0.312500 0.093750 ) ( 160 -160 400 0.312500 0.187500 ) ) +) + } + } +// brush 34 + { + patchDef2 + { + eden/edenmetalwall + ( 3 3 0 536870912 0 ) +( +( ( 160 -224 400 0 0.187500 ) ( 304 -240 400 0 0.093750 ) ( 288 -96 400 0 0 ) ) +( ( 160 -200 400 0.156250 0.187500 ) ( 248 -184 400 0.156250 0.093750 ) ( 256 -96 400 0.156250 0 ) ) +( ( 160 -160 400 0.312500 0.187500 ) ( 224 -160 400 0.312500 0.093750 ) ( 224 -96 400 0.312500 0 ) ) +) + } + } +// brush 35 + { + patchDef2 + { + eden/edenmetalwall + ( 3 3 0 536870912 0 ) +( +( ( 288 -96 400 0 0 ) ( 304 48 400 0 0.093750 ) ( 160 32 400 0 0.187500 ) ) +( ( 256 -96 400 0.156250 0 ) ( 248 -8 400 0.156250 0.093750 ) ( 160 8 400 0.156250 0.187500 ) ) +( ( 224 -96 400 0.312500 0 ) ( 224 -32 400 0.312500 0.093750 ) ( 160 -32 400 0.312500 0.187500 ) ) +) + } + } +// brush 36 + { + patchDef2 + { + eden/edenmetalwall + ( 3 3 0 536870912 0 ) +( +( ( 160 32 400 0 0.187500 ) ( 16 48 400 0 0.093750 ) ( 32 -96 400 0 0 ) ) +( ( 160 8 400 0.156250 0.187500 ) ( 72 -8 400 0.156250 0.093750 ) ( 64 -96 400 0.156250 0 ) ) +( ( 160 -32 400 0.312500 0.187500 ) ( 96 -32 400 0.312500 0.093750 ) ( 96 -96 400 0.312500 0 ) ) +) + } + } +// brush 37 + { + patchDef2 + { + eden/edenmetalwall + ( 9 3 0 536870912 0 ) +( +( ( 95.999992 -96.000008 496 0 0.375000 ) ( 95.999992 -96.000008 448 0 0.187500 ) ( 95.999992 -96.000008 400 0 0 ) ) +( ( 96 -160 496 0.125000 0.375000 ) ( 96 -160 448 0.125000 0.187500 ) ( 96 -160 400 0.125000 0 ) ) +( ( 160 -159.999969 496 0.250000 0.375000 ) ( 160 -159.999969 448 0.250000 0.187500 ) ( 160 -159.999969 400 0.250000 0 ) ) +( ( 224 -160 496 0.375000 0.375000 ) ( 224 -160 448 0.375000 0.187500 ) ( 224 -160 400 0.375000 0 ) ) +( ( 223.999969 -96.000008 496 0.500000 0.375000 ) ( 223.999969 -96.000008 448 0.500000 0.187500 ) ( 223.999969 -96.000008 400 0.500000 0 ) ) +( ( 224 -31.999996 496 0.625000 0.375000 ) ( 224 -31.999996 448 0.625000 0.187500 ) ( 224 -31.999996 400 0.625000 0 ) ) +( ( 160 -32 496 0.750000 0.375000 ) ( 160 -32 448 0.750000 0.187500 ) ( 160 -32 400 0.750000 0 ) ) +( ( 96 -31.999996 496 0.875000 0.375000 ) ( 96 -31.999996 448 0.875000 0.187500 ) ( 96 -31.999996 400 0.875000 0 ) ) +( ( 95.999992 -96.000008 496 1 0.375000 ) ( 95.999992 -96.000008 448 1 0.187500 ) ( 95.999992 -96.000008 400 1 0 ) ) +) + } + } +// brush 38 + { + patchDef2 + { + eden/edenmetalwall + ( 9 3 0 536870912 0 subdivisions 90.501022 ) +( +( ( 160 576 288 0 0 ) ( 160 576 496 0 0.812500 ) ( 160 32 496 0 3.437500 ) ) +( ( 128 576 288 0.125000 0 ) ( 128 576 496 0.125000 0.812500 ) ( 128 32 496 0.125000 3.437500 ) ) +( ( 128 544 288 0.250000 0 ) ( 128 544 464 0.250000 0.812500 ) ( 128 32 464 0.250000 3.437500 ) ) +( ( 128 512 288 0.375000 0 ) ( 128 512 432 0.375000 0.812500 ) ( 128 32 432 0.375000 3.437500 ) ) +( ( 160 512 288 0.500000 0 ) ( 160 512 432 0.500000 0.812500 ) ( 160 32 432 0.500000 3.437500 ) ) +( ( 192 512 288 0.625000 0 ) ( 192 512 432 0.625000 0.812500 ) ( 192 32 432 0.625000 3.437500 ) ) +( ( 192 544 288 0.750000 0 ) ( 192 544 464 0.750000 0.812500 ) ( 192 32 464 0.750000 3.437500 ) ) +( ( 192 576 288 0.875000 0 ) ( 192 576 496 0.875000 0.812500 ) ( 192 32 496 0.875000 3.437500 ) ) +( ( 160 576 288 1 0 ) ( 160 576 496 1 0.812500 ) ( 160 32 496 1 3.437500 ) ) +) + } + } +// brush 39 + { + patchDef2 + { + eden/edenmetalwall + ( 9 3 0 536870912 0 subdivisions 91.251312 ) +( +( ( 160 -224 496 0 3.437500 ) ( 160 -768 496 0 0.812500 ) ( 160 -768 288 0 0 ) ) +( ( 128 -224 496 0.125000 3.437500 ) ( 128 -768 496 0.125000 0.812500 ) ( 128 -768 288 0.125000 0 ) ) +( ( 128 -224 464 0.250000 3.437500 ) ( 128 -736 464 0.250000 0.812500 ) ( 128 -736 288 0.250000 0 ) ) +( ( 128 -224 432 0.375000 3.437500 ) ( 128 -704 432 0.375000 0.812500 ) ( 128 -704 288 0.375000 0 ) ) +( ( 160 -224 432 0.500000 3.437500 ) ( 160 -704 432 0.500000 0.812500 ) ( 160 -704 288 0.500000 0 ) ) +( ( 192 -224 432 0.625000 3.437500 ) ( 192 -704 432 0.625000 0.812500 ) ( 192 -704 288 0.625000 0 ) ) +( ( 192 -224 464 0.750000 3.437500 ) ( 192 -736 464 0.750000 0.812500 ) ( 192 -736 288 0.750000 0 ) ) +( ( 192 -224 496 0.875000 3.437500 ) ( 192 -768 496 0.875000 0.812500 ) ( 192 -768 288 0.875000 0 ) ) +( ( 160 -224 496 1 3.437500 ) ( 160 -768 496 1 0.812500 ) ( 160 -768 288 1 0 ) ) +) + } + } +// brush 40 + { + patchDef2 + { + eden/edenmetalwall + ( 9 3 0 536870912 0 subdivisions 90.458153 ) +( +( ( 288 -96 496 0 3.437500 ) ( 832 -96 496 0 0.812500 ) ( 832 -96 288 0 0 ) ) +( ( 288 -128 496 0.125000 3.437500 ) ( 832 -128 496 0.125000 0.812500 ) ( 832 -128 288 0.125000 0 ) ) +( ( 288 -128 464 0.250000 3.437500 ) ( 800 -128 464 0.250000 0.812500 ) ( 800 -128 288 0.250000 0 ) ) +( ( 288 -128 432 0.375000 3.437500 ) ( 768 -128 432 0.375000 0.812500 ) ( 768 -128 288 0.375000 0 ) ) +( ( 288 -96 432 0.500000 3.437500 ) ( 768 -96 432 0.500000 0.812500 ) ( 768 -96 288 0.500000 0 ) ) +( ( 288 -64 432 0.625000 3.437500 ) ( 768 -64 432 0.625000 0.812500 ) ( 768 -64 288 0.625000 0 ) ) +( ( 288 -64 464 0.750000 3.437500 ) ( 800 -64 464 0.750000 0.812500 ) ( 800 -64 288 0.750000 0 ) ) +( ( 288 -64 496 0.875000 3.437500 ) ( 832 -64 496 0.875000 0.812500 ) ( 832 -64 288 0.875000 0 ) ) +( ( 288 -96 496 1 3.437500 ) ( 832 -96 496 1 0.812500 ) ( 832 -96 288 1 0 ) ) +) + } + } +// brush 41 + { + patchDef2 + { + eden/edenmetalwall + ( 9 3 0 536870912 0 subdivisions 91.251312 ) +( +( ( -512 -96 288 0 0 ) ( -512 -96 496 0 0.812500 ) ( 32 -96 496 0 3.437500 ) ) +( ( -512 -128 288 0.125000 0 ) ( -512 -128 496 0.125000 0.812500 ) ( 32 -128 496 0.125000 3.437500 ) ) +( ( -480 -128 288 0.250000 0 ) ( -480 -128 464 0.250000 0.812500 ) ( 32 -128 464 0.250000 3.437500 ) ) +( ( -448 -128 288 0.375000 0 ) ( -448 -128 432 0.375000 0.812500 ) ( 32 -128 432 0.375000 3.437500 ) ) +( ( -448 -96 288 0.500000 0 ) ( -448 -96 432 0.500000 0.812500 ) ( 32 -96 432 0.500000 3.437500 ) ) +( ( -448 -64 288 0.625000 0 ) ( -448 -64 432 0.625000 0.812500 ) ( 32 -64 432 0.625000 3.437500 ) ) +( ( -480 -64 288 0.750000 0 ) ( -480 -64 464 0.750000 0.812500 ) ( 32 -64 464 0.750000 3.437500 ) ) +( ( -512 -64 288 0.875000 0 ) ( -512 -64 496 0.875000 0.812500 ) ( 32 -64 496 0.875000 3.437500 ) ) +( ( -512 -96 288 1 0 ) ( -512 -96 496 1 0.812500 ) ( 32 -96 496 1 3.437500 ) ) +) + } + } +// brush 42 +{ +( 8 -576 -128 ) ( -8 -576 -128 ) ( -8 -584 -128 ) eden/genmetal 24 0 0.00 1 1 0 0 0 +( -8 -584 8 ) ( -8 -576 8 ) ( 8 -576 8 ) eden/genmetal 24 0 0.00 1 1 0 0 0 +( -8 -584 8 ) ( 8 -584 8 ) ( 8 -584 -128 ) eden/genmetal 24 0 0.00 1 1 0 0 0 +( 8 -584 8 ) ( 8 -576 8 ) ( 8 -576 -128 ) eden/genmetal 24 0 0.00 1 1 0 0 0 +( 8 -576 8 ) ( -8 -576 8 ) ( -8 -576 -128 ) eden/genmetal 24 0 0.00 1 1 0 0 0 +( -8 -576 8 ) ( -8 -584 8 ) ( -8 -584 -128 ) eden/genmetal 24 0 0.00 1 1 0 0 0 +} +// brush 43 +{ +( 0 -352 8 ) ( 0 -776 8 ) ( 0 -776 -128 ) eden/genmetal 32 0 0.00 1 1 0 0 0 +( 8 -344 8 ) ( -120 -344 8 ) ( -120 -344 -128 ) eden/genmetal 32 0 0.00 1 1 0 0 0 +( 8 -768 8 ) ( 8 -344 8 ) ( 8 -344 -128 ) eden/genmetal 32 0 0.00 1 1 0 0 0 +( 8 -344 -128 ) ( -120 -344 -128 ) ( -120 -768 -128 ) eden/genmetal 32 0 0.00 1 1 0 0 0 +( -120 -576 8 ) ( -120 -344 -112 ) ( 8 -460 -52 ) eden/genmetal 32 0 0.00 1 1 0 0 0 +( 8 -576 -128 ) ( 0 -576 -128 ) ( 4 -576 8 ) eden/genmetal 32 0 0.00 1 1 0 0 0 +} +// brush 44 +{ +( 0 328 0 ) ( -8 328 0 ) ( -8 224 0 ) eden/genmetal 24 0 0.00 1 1 0 0 0 +( -8 224 8 ) ( -8 328 8 ) ( 0 328 8 ) eden/genmetal 24 0 0.00 1 1 0 0 0 +( -16 -576 8 ) ( -8 -576 8 ) ( -8 -576 -128 ) eden/genmetal 24 0 0.00 1 1 0 0 0 +( 0 224 8 ) ( 0 328 8 ) ( 0 328 -128 ) eden/genmetal 24 0 0.00 1 1 0 0 0 +( 0 328 8 ) ( -8 328 8 ) ( -8 328 -128 ) eden/genmetal 24 0 0.00 1 1 0 0 0 +( -8 120 8 ) ( -8 16 8 ) ( -8 16 -128 ) eden/genmetal 24 0 0.00 1 1 0 0 0 +} +// brush 45 +{ +( 8 0 -120 ) ( 0 0 -120 ) ( 0 320 8 ) eden/genmetal 24 0 0.00 1 1 0 0 0 +( 0 0 -128 ) ( 8 0 -128 ) ( 8 512 -128 ) eden/genmetal 24 0 0.00 1 1 0 0 0 +( 8 320 8 ) ( 0 320 8 ) ( 0 512 8 ) eden/genmetal 24 0 0.00 1 1 0 0 0 +( 0 -8 -112 ) ( 0 -8 -128 ) ( 0 512 -128 ) eden/genmetal 32 0 0.00 1 1 0 0 0 +( 8 0 -128 ) ( 0 0 -128 ) ( 0 0 -120 ) eden/genmetal 24 0 0.00 1 1 0 0 0 +( 8 -8 -128 ) ( 8 -8 -112 ) ( 8 312 8 ) eden/genmetal 32 0 0.00 1 1 0 0 0 +( 0 328 -128 ) ( 8 328 -128 ) ( 4 328 8 ) eden/genmetal 32 0 0.00 1 1 0 0 0 +} +// brush 46 +{ +( -544 192 496 ) ( -544 -352 496 ) ( -544 -352 240 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( -512 192 496 ) ( -544 192 496 ) ( -544 192 240 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( -512 -384 496 ) ( -512 160 496 ) ( -512 160 240 ) eden/WL_edenhouse 0 0 0.00 1 1 0 0 0 +( -544 -384 496 ) ( -512 -384 496 ) ( -512 -384 240 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( -544 -352 496 ) ( -544 192 496 ) ( -512 192 496 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( -512 192 288 ) ( -544 192 288 ) ( -544 -352 288 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +} +// brush 47 +{ +( 832 192 544 ) ( 832 -352 544 ) ( 832 -352 288 ) eden/WL_edenhouse 0 0 0.00 1 1 0 0 0 +( 864 192 496 ) ( 832 192 496 ) ( 832 192 240 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( 864 -384 496 ) ( 864 160 496 ) ( 864 160 240 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( 832 -384 496 ) ( 864 -384 496 ) ( 864 -384 240 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( 832 -352 496 ) ( 832 192 496 ) ( 864 192 496 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( 864 192 288 ) ( 832 192 288 ) ( 832 -352 288 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +} +// brush 48 +{ +( 448 -800 288 ) ( 448 -768 288 ) ( -96 -768 288 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( -96 -768 496 ) ( 448 -768 496 ) ( 448 -800 496 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( -128 -768 544 ) ( -128 -800 544 ) ( -128 -800 288 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( -128 -800 496 ) ( 416 -800 496 ) ( 416 -800 240 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( 448 -800 544 ) ( 448 -768 544 ) ( 448 -768 288 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( 448 -768 496 ) ( -96 -768 496 ) ( -96 -768 240 ) eden/WL_edenhouse 0 0 0.00 1 1 0 0 0 +} +// brush 49 +{ +( 448 576 288 ) ( 448 608 288 ) ( -96 608 288 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( -96 608 496 ) ( 448 608 496 ) ( 448 576 496 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( -128 608 544 ) ( -128 576 544 ) ( -128 576 288 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( -128 576 496 ) ( 416 576 496 ) ( 416 576 240 ) eden/WL_edenhouse 0 0 0.00 1 1 0 0 0 +( 448 576 544 ) ( 448 608 544 ) ( 448 608 288 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( 448 608 496 ) ( -96 608 496 ) ( -96 608 240 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +} +// brush 50 +{ +( 448 -768 544 ) ( 448 -800 544 ) ( 448 -800 288 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( 832 -384 240 ) ( 832 -384 496 ) ( 448 -768 496 ) eden/WL_edenhouse 0 0 0.00 1 1 0 0 0 +( 864 -384 240 ) ( 864 -384 496 ) ( 832 -384 496 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( 864 -384 496 ) ( 864 -384 240 ) ( 448 -800 240 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( 832 -384 496 ) ( 832 -416 496 ) ( 448 -800 496 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( 832 -416 288 ) ( 832 -384 288 ) ( 448 -768 288 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +} +// brush 51 +{ +( -128 -800 288 ) ( -128 -800 544 ) ( -128 -768 544 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( -128 -768 496 ) ( -512 -384 496 ) ( -512 -384 240 ) eden/WL_edenhouse 0 0 0.00 1 1 0 0 0 +( -512 -384 496 ) ( -544 -384 496 ) ( -544 -384 240 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( -128 -800 240 ) ( -544 -384 240 ) ( -544 -384 496 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( -128 -800 496 ) ( -512 -416 496 ) ( -512 -384 496 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( -128 -768 288 ) ( -512 -384 288 ) ( -512 -416 288 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +} +// brush 52 +{ +( -512 224 288 ) ( -512 192 288 ) ( -128 576 288 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( -512 192 496 ) ( -512 224 496 ) ( -128 608 496 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( -544 192 496 ) ( -544 192 240 ) ( -128 608 240 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( -544 192 240 ) ( -544 192 496 ) ( -512 192 496 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( -512 192 240 ) ( -512 192 496 ) ( -128 576 496 ) eden/WL_edenhouse 0 0 0.00 1 1 0 0 0 +( -128 576 544 ) ( -128 608 544 ) ( -128 608 288 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +} +// brush 53 +{ +( 448 576 288 ) ( 832 192 288 ) ( 832 224 288 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( 448 608 496 ) ( 832 224 496 ) ( 832 192 496 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( 448 608 240 ) ( 864 192 240 ) ( 864 192 496 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( 832 192 496 ) ( 864 192 496 ) ( 864 192 240 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( 448 576 496 ) ( 832 192 496 ) ( 832 192 240 ) eden/WL_edenhouse 0 0 0.00 1 1 0 0 0 +( 448 608 288 ) ( 448 608 544 ) ( 448 576 544 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +} +// brush 54 +{ +( -512 192 496 ) ( -496 208 496 ) ( -504 200 512 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( 832 -384 480 ) ( 800 -416 480 ) ( 816 -400 736 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( 832 576 736 ) ( -544 576 736 ) ( -544 576 480 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( 832 -768 736 ) ( 832 640 736 ) ( 832 640 480 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( -544 -768 736 ) ( 832 -768 736 ) ( 832 -768 480 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( -544 -768 512 ) ( -544 640 512 ) ( 832 640 512 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( 832 640 496 ) ( -544 640 496 ) ( -544 -768 496 ) eden/WL_edenhouse 0 0 0.00 1 1 0 0 0 +( 448 576 480 ) ( 480 544 480 ) ( 464 560 736 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( -512 352 480 ) ( -512 432 480 ) ( -512 392 512 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( -128 -768 496 ) ( -144 -752 496 ) ( -136 -760 512 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +} +// brush 55 +{ +( 624 -384.000244 256 ) ( 600 192.000046 256 ) ( 576 -384.000244 256 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( -448 -352 400 ) ( -448 -352 384 ) ( -512 -384 384 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( -448 -352 384 ) ( -448 -352 400 ) ( -448 160 400 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( -448 160 384 ) ( -448 160 400 ) ( -512 192 400 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( -512 192 384 ) ( -512 -384 384 ) ( -512 -384 352 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( 544 -384.000244 288 ) ( 576 192.000046 288 ) ( 608 -384.000244 288 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +} +// brush 56 +{ +( 624 -767.999939 256 ) ( 600 -351.999878 256 ) ( 576 -767.999939 256 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( -128 -768 400 ) ( -128 -768 384 ) ( -512 -384.000427 384 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( -448 -352 384 ) ( -448 -352 400 ) ( -512 -384 400 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( -448 -352 400 ) ( -448 -352 384 ) ( -96 -704 384 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( -96 -704 224 ) ( -96 -704 208 ) ( -128 -768 208 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( 544 -767.999939 288 ) ( 576 -351.999878 288 ) ( 608 -767.999939 288 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +} +// brush 57 +{ +( -128 -768 352 ) ( -128 -768 384 ) ( 448 -768 384 ) eden/genmetal 32 0 0.00 1 1 0 0 0 +( 416 -704 96 ) ( 416 -704 80 ) ( 448 -768 80 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( -96 -704 400 ) ( -96 -704 384 ) ( 416 -704 384 ) eden/genmetal 32 0 0.00 1 1 0 0 0 +( -96 -704 208 ) ( -96 -704 224 ) ( -128 -768 224 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( -128 -768 256 ) ( 448 -768 256 ) ( 448 -704 256 ) eden/genmetal 0 -64 90.00 1 1 0 0 0 +( 544 -768 288 ) ( 576 -704 288 ) ( 608 -768 288 ) eden/genmetal 0 -64 90.00 1 1 0 0 0 +} +// brush 58 +{ +( 768 -320 256 ) ( 384 -704 256 ) ( 448 -768 256 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( 416 -704 80 ) ( 416 -704 96 ) ( 448 -768 96 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( 416 -704 96 ) ( 416 -704 80 ) ( 768 -352 80 ) eden/genmetal -32 0 0.00 1 1 0 0 0 +( 768 -352 224 ) ( 768 -352 208 ) ( 832 -384 208 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( 832 -384 384 ) ( 448 -768 384 ) ( 448 -768 400 ) eden/genmetal -32 0 0.00 1 1 0 0 0 +( 544 -768.000061 288 ) ( 576 -352 288 ) ( 608 -768.000061 288 ) eden/genmetal -32 0 0.00 1 1 0 0 0 +} +// brush 59 +{ +( 832 -384 352 ) ( 832 -384 384 ) ( 832 192 384 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( 768 160 96 ) ( 768 160 80 ) ( 832 192 80 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( 768 -352 272 ) ( 768 -352 256 ) ( 768 160 256 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( 768 -352 208 ) ( 768 -352 224 ) ( 832 -384 224 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( 832 -384 256 ) ( 832 192 256 ) ( 768 192 256 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( 544 -384 288 ) ( 576 192.000504 288 ) ( 608 -384 288 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +} +// brush 60 +{ +( 448 576 400 ) ( 448 576 384 ) ( 832 192 384 ) eden/genmetal -64 0 0.00 1 1 0 0 0 +( 768 160 80 ) ( 768 160 96 ) ( 832 192 96 ) eden/genmetal -32 0 0.00 1 1 0 0 0 +( 768 160 272 ) ( 768 160 256 ) ( 416 512 256 ) eden/genmetal -64 0 0.00 1 1 0 0 0 +( 416 512 96 ) ( 416 512 80 ) ( 448 576 80 ) eden/genmetal -32 0 0.00 1 1 0 0 0 +( 448 576 256 ) ( 384 512 256 ) ( 768 128 256 ) eden/genmetal 0 32 0.00 1 1 0 0 0 +( 544 159.999893 288 ) ( 576 576 288 ) ( 608 159.999893 288 ) eden/genmetal 0 32 0.00 1 1 0 0 0 +} +// brush 61 +{ +( 448 576 208 ) ( -128 576 208 ) ( -128 576 176 ) eden/genmetal 32 0 0.00 1 1 0 0 0 +( 416 512 80 ) ( 416 512 96 ) ( 448 576 96 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( 416 512 400 ) ( 416 512 384 ) ( -96 512 384 ) eden/genmetal 32 0 0.00 1 1 0 0 0 +( -96 512 224 ) ( -96 512 208 ) ( -128 576 208 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( 448 512 256 ) ( 448 576 256 ) ( -128 576 256 ) eden/genmetal 0 -64 90.00 1 1 0 0 0 +( 544 512 288 ) ( 576 576 288 ) ( 608 512 288 ) eden/genmetal 0 -64 90.00 1 1 0 0 0 +} +// brush 62 +{ +( 624 159.999817 256 ) ( 600 576 256 ) ( 576 159.999817 256 ) eden/genmetal 0 32 0.00 1 1 0 0 0 +( -96 512 208 ) ( -96 512 224 ) ( -128 576 224 ) eden/genmetal -32 0 0.00 1 1 0 0 0 +( -448 160 384 ) ( -448 160 400 ) ( -96 512 400 ) eden/genmetal -64 0 0.00 1 1 0 0 0 +( -448 160 400 ) ( -448 160 384 ) ( -512 192 384 ) eden/genmetal -32 0 0.00 1 1 0 0 0 +( -512 192 384 ) ( -128 576 384 ) ( -128 576 400 ) eden/genmetal -64 0 0.00 1 1 0 0 0 +( 544 159.999817 288 ) ( 576 576 288 ) ( 608 159.999817 288 ) eden/genmetal -64 0 0.00 1 1 0 0 0 +} +// brush 63 +{ +( 320 192 0 ) ( 320 64 0 ) ( 320 64 -128 ) eden/edentable 64 0 0.00 -1 1 0 0 0 +( 448 192 0 ) ( 320 192 0 ) ( 320 192 -128 ) eden/edentable 64 0 0.00 -1 1 0 0 0 +( 448 64 0 ) ( 448 192 0 ) ( 448 192 -128 ) eden/edentable 64 0 0.00 -1 1 0 0 0 +( 320 64 0 ) ( 448 64 0 ) ( 448 64 -128 ) eden/edentable 64 0 0.00 -1 1 0 0 0 +( 320 64 0 ) ( 320 192 0 ) ( 448 192 0 ) eden/edentable 64 64 0.00 -1 1 0 0 0 +( 448 192 -128 ) ( 320 192 -128 ) ( 320 64 -128 ) eden/edentable 64 64 0.00 -1 1 0 0 0 +} +// brush 64 +{ +( 136 -8 -128 ) ( 136 -8 -112 ) ( 136 312 8 ) eden/genmetal 32 0 0.00 1 1 0 0 0 +( 136 0 -128 ) ( 128 0 -128 ) ( 128 0 -120 ) eden/genmetal 24 0 0.00 1 1 0 0 0 +( 128 -8 -112 ) ( 128 -8 -128 ) ( 128 512 -128 ) eden/genmetal 32 0 0.00 1 1 0 0 0 +( 256 512 8 ) ( 128 512 8 ) ( 128 512 -128 ) eden/genmetal 24 0 0.00 1 1 0 0 0 +( 136 320 8 ) ( 128 320 8 ) ( 128 512 8 ) eden/genmetal 24 0 0.00 1 1 0 0 0 +( 128 0 -128 ) ( 136 0 -128 ) ( 136 512 -128 ) eden/genmetal 24 0 0.00 1 1 0 0 0 +( 136 0 -120 ) ( 128 0 -120 ) ( 128 320 8 ) eden/genmetal 24 0 0.00 1 1 0 0 0 +} +// brush 65 +{ +( 128 -352 8 ) ( 128 -776 8 ) ( 128 -776 -128 ) eden/genmetal 32 0 0.00 1 1 0 0 0 +( 136 -344 8 ) ( 8 -344 8 ) ( 8 -344 -128 ) eden/genmetal 32 0 0.00 1 1 0 0 0 +( 136 -768 8 ) ( 136 -344 8 ) ( 136 -344 -128 ) eden/genmetal 32 0 0.00 1 1 0 0 0 +( 8 -768 8 ) ( 136 -768 8 ) ( 136 -768 -128 ) eden/genmetal 32 0 0.00 1 1 0 0 0 +( 8 -768 8 ) ( 8 -344 8 ) ( 136 -344 8 ) eden/genmetal 32 0 0.00 1 1 0 0 0 +( 136 -344 -128 ) ( 8 -344 -128 ) ( 8 -768 -128 ) eden/genmetal 32 0 0.00 1 1 0 0 0 +( 8 -576 8 ) ( 8 -344 -112 ) ( 136 -460 -52 ) eden/genmetal 32 0 0.00 1 1 0 0 0 +} +// brush 66 +{ +( 0 -352 -96 ) ( 0 -384 -96 ) ( 0 -384 -224 ) eden/FL_edenhouse3 -64 -96 0.00 1 1 0 0 0 +( 128 -352 -96 ) ( 0 -352 -96 ) ( 0 -352 -224 ) eden/FL_edenhouse2 0 -96 0.00 1 1 0 0 0 +( 128 -384 -96 ) ( 128 -352 -96 ) ( 128 -352 -224 ) eden/FL_edenhouse2 0 0 0.00 1 1 0 0 0 +( 0 -384 -96 ) ( 128 -384 -96 ) ( 128 -384 -224 ) eden/FL_edenhouse3 0 -96 0.00 1 1 0 0 0 +( 0 -384 -112 ) ( 0 -352 -112 ) ( 128 -352 -112 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 0 -304 -128 ) ( 0 -384 -128 ) ( 128 -344 -128 ) eden/FL_edenhouse3 0 64 0.00 1 1 0 0 0 +} +// brush 67 +{ +( 0 -416 -96 ) ( 0 -384 -96 ) ( 128 -384 -96 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 0 -416 -48 ) ( 128 -416 -48 ) ( 128 -416 -176 ) eden/FL_edenhouse3 0 -48 0.00 1 1 0 0 0 +( 128 -416 -48 ) ( 128 -384 -48 ) ( 128 -384 -176 ) eden/FL_edenhouse2 0 0 0.00 1 1 0 0 0 +( 128 -384 -48 ) ( 0 -384 -48 ) ( 0 -384 -176 ) eden/FL_edenhouse2 0 -48 0.00 1 1 0 0 0 +( 0 -384 -48 ) ( 0 -416 -48 ) ( 0 -416 -176 ) eden/FL_edenhouse3 -32 -48 0.00 1 1 0 0 0 +( 112 -416 -128 ) ( 80 -384 -128 ) ( 48 -416 -128 ) eden/FL_edenhouse3 -32 -48 0.00 1 1 0 0 0 +} +// brush 68 +{ +( 112 -448 -128 ) ( 80 -416 -128 ) ( 48 -448 -128 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 0 -448 -80 ) ( 0 -416 -80 ) ( 128 -416 -80 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 0 -448 -48 ) ( 128 -448 -48 ) ( 128 -448 -176 ) eden/FL_edenhouse3 0 -48 0.00 1 1 0 0 0 +( 128 -448 -48 ) ( 128 -416 -48 ) ( 128 -416 -176 ) eden/FL_edenhouse2 0 0 0.00 1 1 0 0 0 +( 128 -416 -48 ) ( 0 -416 -48 ) ( 0 -416 -176 ) eden/FL_edenhouse2 0 -48 0.00 1 1 0 0 0 +( 0 -416 -48 ) ( 0 -448 -48 ) ( 0 -448 -176 ) eden/FL_edenhouse3 0 -48 0.00 1 1 0 0 0 +} +// brush 69 +{ +( 0 -480 -64 ) ( 0 -448 -64 ) ( 128 -448 -64 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 0 -480 -48 ) ( 128 -480 -48 ) ( 128 -480 -176 ) eden/FL_edenhouse3 0 -48 0.00 1 1 0 0 0 +( 128 -480 -48 ) ( 128 -448 -48 ) ( 128 -448 -176 ) eden/FL_edenhouse2 0 0 0.00 1 1 0 0 0 +( 128 -448 -48 ) ( 0 -448 -48 ) ( 0 -448 -176 ) eden/FL_edenhouse2 0 -48 0.00 1 1 0 0 0 +( 0 -448 -48 ) ( 0 -480 -48 ) ( 0 -480 -176 ) eden/FL_edenhouse3 -96 -48 0.00 1 1 0 0 0 +( 112 -480 -128 ) ( 80 -448 -128 ) ( 48 -480 -128 ) eden/FL_edenhouse3 -96 -48 0.00 1 1 0 0 0 +} +// brush 70 +{ +( 0 -480 0 ) ( 0 -512 0 ) ( 0 -512 -128 ) eden/FL_edenhouse3 -64 0 0.00 1 1 0 0 0 +( 128 -480 0 ) ( 0 -480 0 ) ( 0 -480 -128 ) eden/FL_edenhouse2 0 0 0.00 1 1 0 0 0 +( 128 -512 0 ) ( 128 -480 0 ) ( 128 -480 -128 ) eden/FL_edenhouse2 -64 0 0.00 1 1 0 0 0 +( 0 -512 0 ) ( 128 -512 0 ) ( 128 -512 -128 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 0 -512 -48 ) ( 0 -480 -48 ) ( 128 -480 -48 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 128 -480 -128 ) ( 0 -480 -128 ) ( 0 -512 -128 ) eden/FL_edenhouse3 0 64 0.00 1 1 0 0 0 +} +// brush 71 +{ +( 128 -512 -128 ) ( 0 -512 -128 ) ( 0 -544 -128 ) eden/FL_edenhouse3 0 32 0.00 1 1 0 0 0 +( 0 -544 -32 ) ( 0 -512 -32 ) ( 128 -512 -32 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 0 -544 0 ) ( 128 -544 0 ) ( 128 -544 -128 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 128 -544 0 ) ( 128 -512 0 ) ( 128 -512 -128 ) eden/FL_edenhouse2 -32 0 0.00 1 1 0 0 0 +( 128 -512 0 ) ( 0 -512 0 ) ( 0 -512 -128 ) eden/FL_edenhouse2 0 0 0.00 1 1 0 0 0 +( 0 -512 0 ) ( 0 -544 0 ) ( 0 -544 -128 ) eden/FL_edenhouse3 -32 0 0.00 1 1 0 0 0 +} +// brush 72 +{ +( 0 -544 0 ) ( 0 -576 0 ) ( 0 -576 -128 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 128 -544 0 ) ( 0 -544 0 ) ( 0 -544 -128 ) eden/FL_edenhouse2 0 0 0.00 1 1 0 0 0 +( 128 -576 0 ) ( 128 -544 0 ) ( 128 -544 -128 ) eden/FL_edenhouse2 0 0 0.00 1 1 0 0 0 +( 0 -576 0 ) ( 128 -576 0 ) ( 128 -576 -128 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 0 -576 -16 ) ( 0 -544 -16 ) ( 128 -544 -16 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 128 -544 -128 ) ( 0 -544 -128 ) ( 0 -576 -128 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +} +// brush 73 +{ +( 128 -512 -128 ) ( 0 -512 -128 ) ( 0 -704 -128 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 0 -704 0 ) ( 0 -512 0 ) ( 128 -512 0 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 0 -704 0 ) ( 128 -704 0 ) ( 128 -704 -128 ) eden/FL_edenhouse2 0 0 0.00 1 1 0 0 0 +( 128 -704 0 ) ( 128 -512 0 ) ( 128 -512 -128 ) eden/FL_edenhouse2 0 0 0.00 1 1 0 0 0 +( 144 -576 0 ) ( 16 -576 0 ) ( 16 -576 -128 ) eden/FL_edenhouse2 0 0 0.00 1 1 0 0 0 +( 0 -512 0 ) ( 0 -704 0 ) ( 0 -704 -128 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +} +// brush 74 +{ +( 144 0 -128 ) ( 96 320 -128 ) ( 48 0 -128 ) eden/FL_edenhouse2 0 0 0.00 1 1 0 0 0 +( 128 0 -128 ) ( 0 0 -128 ) ( 0 320 0 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 128 0 -256 ) ( 128 0 -128 ) ( 128 320 0 ) eden/FL_edenhouse2 0 0 0.00 1 1 0 0 0 +( 128 320 0 ) ( 0 320 0 ) ( 0 320 -128 ) eden/FL_edenhouse2 0 0 0.00 1 1 0 0 0 +( 0 0 -128 ) ( 0 0 -256 ) ( 0 320 -128 ) eden/FL_edenhouse2 0 0 0.00 1 1 0 0 0 +} +// brush 75 +{ +( 0 512 0 ) ( 0 320 0 ) ( 0 320 -128 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 128 512 0 ) ( 0 512 0 ) ( 0 512 -128 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 128 320 0 ) ( 128 512 0 ) ( 128 512 -128 ) eden/FL_edenhouse2 0 0 0.00 1 1 0 0 0 +( 0 320 0 ) ( 128 320 0 ) ( 128 320 -128 ) eden/FL_edenhouse2 0 0 0.00 1 1 0 0 0 +( 0 320 0 ) ( 0 512 0 ) ( 128 512 0 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 128 512 -128 ) ( 0 512 -128 ) ( 0 320 -128 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +} +// brush 76 +{ +( 832 -384 -160 ) ( 800 -416 -160 ) ( 816 -400 96 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 832 576 96 ) ( -544 576 96 ) ( -544 576 -160 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 832 -768 96 ) ( 832 640 96 ) ( 832 640 -160 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( -544 -768 96 ) ( 832 -768 96 ) ( 832 -768 -160 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( -544 -768 -128 ) ( -544 640 -128 ) ( 832 640 -128 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 832 640 -160 ) ( -544 640 -160 ) ( -544 -768 -160 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 448 576 -160 ) ( 480 544 -160 ) ( 464 560 96 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 0 336 -160 ) ( 0 416 -160 ) ( 0 376 -128 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +} +// brush 77 +{ +( -512 192 -32 ) ( -480 224 -32 ) ( -496 208 224 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( -512 640 224 ) ( -512 -768 224 ) ( -512 -768 -32 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 832 576 224 ) ( -544 576 224 ) ( -544 576 -32 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( -544 -768 224 ) ( 832 -768 224 ) ( 832 -768 -32 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( -544 -768 0 ) ( -544 640 0 ) ( 832 640 0 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 832 640 -128 ) ( -544 640 -128 ) ( -544 -768 -128 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( -128 -768 -32 ) ( -160 -736 -32 ) ( -144 -752 224 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 0 416 -32 ) ( 0 336 -32 ) ( 0 376 0 ) eden/FL_edenhouse2 0 0 0.00 1 1 0 0 0 +} +// brush 78 +{ +( -512 192 0 ) ( -128 576 0 ) ( -128 576 16 ) eden/genmetal -64 0 0.00 1 1 0 0 0 +( -448 160 16 ) ( -448 160 0 ) ( -512 192 0 ) eden/genmetal -32 0 0.00 1 1 0 0 0 +( -448 160 0 ) ( -448 160 16 ) ( -96 512 16 ) eden/genmetal -64 0 0.00 1 1 0 0 0 +( -96 512 0 ) ( -96 512 16 ) ( -128 576 16 ) eden/genmetal -32 0 0.00 1 1 0 0 0 +( -448 128 0 ) ( -64 512 0 ) ( -128 576 0 ) eden/genmetal 0 32 0.00 1 1 0 0 0 +( -432 159.999817 8 ) ( -420 576 8 ) ( -408 159.999817 8 ) eden/genmetal 0 32 0.00 1 1 0 0 0 +} +// brush 79 +{ +( 448 512 -128 ) ( 448 576 -128 ) ( -128 576 -128 ) eden/genmetal 0 -64 90.00 1 1 0 0 0 +( -128 576 8 ) ( 448 576 8 ) ( 448 512 8 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( -96 512 16 ) ( -96 512 0 ) ( -128 576 0 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( 416 512 16 ) ( 416 512 0 ) ( -96 512 0 ) eden/genmetal 32 0 0.00 1 1 0 0 0 +( 416 512 -128 ) ( 416 512 -112 ) ( 448 576 -112 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( 448 576 0 ) ( -128 576 0 ) ( -128 576 -32 ) eden/genmetal 32 0 0.00 1 1 0 0 0 +} +// brush 80 +{ +( -432 159.999832 8 ) ( -420 576.000183 8 ) ( -408 159.999832 8 ) eden/genmetal 0 32 0.00 1 1 0 0 0 +( 448 576 -128 ) ( 384 512 -128 ) ( 768 128 -128 ) eden/genmetal 0 32 0.00 1 1 0 0 0 +( 416 512 -112 ) ( 416 512 -128 ) ( 448 576 -128 ) eden/genmetal -32 0 0.00 1 1 0 0 0 +( 768 160 -112 ) ( 768 160 -128 ) ( 416 512 -128 ) eden/genmetal -64 0 0.00 1 1 0 0 0 +( 768 160 -128 ) ( 768 160 -112 ) ( 832 192 -112 ) eden/genmetal -32 0 0.00 1 1 0 0 0 +( 448 576 16 ) ( 448 576 0 ) ( 832 192 0 ) eden/genmetal -64 0 0.00 1 1 0 0 0 +} +// brush 81 +{ +( 832 -384 -128 ) ( 832 192 -128 ) ( 768 192 -128 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( 768 192 8 ) ( 832 192 8 ) ( 832 -384 8 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( 768 -352 0 ) ( 768 -352 16 ) ( 832 -384 16 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( 768 -352 -112 ) ( 768 -352 -128 ) ( 768 160 -128 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( 768 160 -112 ) ( 768 160 -128 ) ( 832 192 -128 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( 832 -384 -32 ) ( 832 -384 0 ) ( 832 192 0 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +} +// brush 82 +{ +( -432 -768.000244 8 ) ( -420 -351.999817 8 ) ( -408 -768.000244 8 ) eden/genmetal -32 0 0.00 1 1 0 0 0 +( 832 -384 0 ) ( 448 -768 0 ) ( 448 -768 16 ) eden/genmetal -32 0 0.00 1 1 0 0 0 +( 768 -352 16 ) ( 768 -352 0 ) ( 832 -384 0 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( 416 -704 -112 ) ( 416 -704 -128 ) ( 768 -352 -128 ) eden/genmetal -32 0 0.00 1 1 0 0 0 +( 416 -704 -128 ) ( 416 -704 -112 ) ( 448 -768 -112 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( 768 -320 -128 ) ( 384 -704 -128 ) ( 448 -768 -128 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +} +// brush 83 +{ +( -128 -768 -128 ) ( 448 -768 -128 ) ( 448 -704 -128 ) eden/genmetal 0 -64 90.00 1 1 0 0 0 +( 448 -704 8 ) ( 448 -768 8 ) ( -128 -768 8 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( -96 -704 0 ) ( -96 -704 16 ) ( -128 -768 16 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( -96 -704 16 ) ( -96 -704 0 ) ( 416 -704 0 ) eden/genmetal 32 0 0.00 1 1 0 0 0 +( 416 -704 -112 ) ( 416 -704 -128 ) ( 448 -768 -128 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( -128 -768 -32 ) ( -128 -768 0 ) ( 448 -768 0 ) eden/genmetal 32 0 0.00 1 1 0 0 0 +} +// brush 84 +{ +( -128 -768 0 ) ( -64 -704 0 ) ( -448 -320.000427 0 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( -96 -704 16 ) ( -96 -704 0 ) ( -128 -768 0 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( -448 -352 16 ) ( -448 -352 0 ) ( -96 -704 0 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( -448 -352 0 ) ( -448 -352 16 ) ( -512 -384 16 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( -128 -768 16 ) ( -128 -768 0 ) ( -512 -384.000427 0 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( -432 -767.999939 8 ) ( -420 -351.999878 8 ) ( -408 -767.999939 8 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +} +// brush 85 +{ +( -512 192 0 ) ( -512 -384 0 ) ( -512 -384 -32 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( -448 160 0 ) ( -448 160 16 ) ( -512 192 16 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( -448 -352 0 ) ( -448 -352 16 ) ( -448 160 16 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( -448 -352 16 ) ( -448 -352 0 ) ( -512 -384 0 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( -512 -384 8 ) ( -512 192 8 ) ( -448 192 8 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( -448 192 0 ) ( -512 192 0 ) ( -512 -384 0 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +} +// brush 86 +{ +( 448 576 0 ) ( 832 192 0 ) ( 832 224 0 ) eden/WL_edentown2 0 0 0.00 1 1 0 0 0 +( 448 608 256 ) ( 832 224 256 ) ( 832 192 256 ) eden/WL_edentown2 0 0 0.00 1 1 0 0 0 +( 448 608 0 ) ( 864 192 0 ) ( 864 192 256 ) eden/WL_edentown2 0 0 0.00 1 1 0 0 0 +( 832 192 256 ) ( 864 192 256 ) ( 864 192 0 ) eden/WL_edentown2 0 0 0.00 1 1 0 0 0 +( 448 576 256 ) ( 832 192 256 ) ( 832 192 0 ) eden/WL_edentown2 0 0 0.00 1 1 0 0 0 +( 448 608 0 ) ( 448 608 256 ) ( 448 576 256 ) eden/WL_edentown2 0 0 0.00 1 1 0 0 0 +} +// brush 87 +{ +( -512 224 0 ) ( -512 192 0 ) ( -128 576 0 ) eden/WL_edentown2 -64 0 0.00 1 1 0 0 0 +( -512 192 256 ) ( -512 224 256 ) ( -128 608 256 ) eden/WL_edentown2 -64 0 0.00 1 1 0 0 0 +( -544 192 256 ) ( -544 192 0 ) ( -128 608 0 ) eden/WL_edentown2 0 0 0.00 1 1 0 0 0 +( -544 192 0 ) ( -544 192 256 ) ( -512 192 256 ) eden/WL_edentown2 -64 0 0.00 1 1 0 0 0 +( -512 192 0 ) ( -512 192 256 ) ( -128 576 256 ) eden/WL_edentown2 0 0 0.00 1 1 0 0 0 +( -128 576 256 ) ( -128 608 256 ) ( -128 608 0 ) eden/WL_edentown2 0 0 0.00 1 1 0 0 0 +} +// brush 88 +{ +( -128 -800 0 ) ( -128 -800 256 ) ( -128 -768 256 ) eden/WL_edentown2 0 0 0.00 1 1 0 0 0 +( -128 -768 256 ) ( -512 -384 256 ) ( -512 -384 0 ) eden/WL_edentown2 0 0 0.00 1 1 0 0 0 +( -512 -384 256 ) ( -544 -384 256 ) ( -544 -384 0 ) eden/WL_edentown2 -64 0 0.00 1 1 0 0 0 +( -128 -800 0 ) ( -544 -384 0 ) ( -544 -384 256 ) eden/WL_edentown2 0 0 0.00 1 1 0 0 0 +( -128 -800 256 ) ( -512 -416 256 ) ( -512 -384 256 ) eden/WL_edentown2 -64 0 0.00 1 1 0 0 0 +( -128 -768 0 ) ( -512 -384 0 ) ( -512 -416 0 ) eden/WL_edentown2 -64 0 0.00 1 1 0 0 0 +} +// brush 89 +{ +( 448 -768 256 ) ( 448 -800 256 ) ( 448 -800 0 ) eden/WL_edentown2 0 0 0.00 1 1 0 0 0 +( 832 -384 0 ) ( 832 -384 256 ) ( 448 -768 256 ) eden/WL_edentown2 0 0 0.00 1 1 0 0 0 +( 864 -384 0 ) ( 864 -384 256 ) ( 832 -384 256 ) eden/WL_edentown2 0 0 0.00 1 1 0 0 0 +( 864 -384 256 ) ( 864 -384 0 ) ( 448 -800 0 ) eden/WL_edentown2 0 0 0.00 1 1 0 0 0 +( 832 -384 256 ) ( 832 -416 256 ) ( 448 -800 256 ) eden/WL_edentown2 0 0 0.00 1 1 0 0 0 +( 832 -416 0 ) ( 832 -384 0 ) ( 448 -768 0 ) eden/WL_edentown2 0 0 0.00 1 1 0 0 0 +} +// brush 90 +{ +( 448 576 0 ) ( 448 608 0 ) ( -96 608 0 ) eden/WL_edentown2 0 0 0.00 1 1 0 0 0 +( -96 608 256 ) ( 448 608 256 ) ( 448 576 256 ) eden/WL_edentown2 0 0 0.00 1 1 0 0 0 +( -128 608 256 ) ( -128 576 256 ) ( -128 576 0 ) eden/WL_edentown2 -64 0 0.00 1 1 0 0 0 +( -128 576 256 ) ( 416 576 256 ) ( 416 576 0 ) eden/WL_edentown2 64 0 0.00 1 1 0 0 0 +( 448 576 256 ) ( 448 608 256 ) ( 448 608 0 ) eden/WL_edentown2 -64 0 0.00 1 1 0 0 0 +( 448 608 256 ) ( -96 608 256 ) ( -96 608 0 ) eden/WL_edentown2 64 0 -180.00 1 -1 0 0 0 +} +// brush 91 +{ +( 448 -800 0 ) ( 448 -768 0 ) ( -96 -768 0 ) eden/WL_edentown2 32 0 0.00 1 1 0 0 0 +( -96 -768 256 ) ( 448 -768 256 ) ( 448 -800 256 ) eden/WL_edentown2 32 0 0.00 1 1 0 0 0 +( -128 -768 256 ) ( -128 -800 256 ) ( -128 -800 0 ) eden/WL_edentown2 -32 0 0.00 1 1 0 0 0 +( -128 -800 256 ) ( 416 -800 256 ) ( 416 -800 0 ) eden/WL_edentown2 64 0 0.00 1 1 0 0 0 +( 448 -800 256 ) ( 448 -768 256 ) ( 448 -768 0 ) eden/WL_edentown2 -32 0 0.00 1 1 0 0 0 +( 448 -768 256 ) ( -96 -768 256 ) ( -96 -768 0 ) eden/WL_edentown2 63 0 -180.00 1 -1 0 0 0 +} +// brush 92 +{ +( 832 192 256 ) ( 832 -352 256 ) ( 832 -352 0 ) eden/WL_edentown2 0 0 0.00 1 1 0 0 0 +( 864 192 256 ) ( 832 192 256 ) ( 832 192 0 ) eden/WL_edentown2 -96 0 0.00 1 1 0 0 0 +( 864 -384 256 ) ( 864 160 256 ) ( 864 160 0 ) eden/WL_edentown2 0 0 0.00 1 1 0 0 0 +( 832 -384 256 ) ( 864 -384 256 ) ( 864 -384 0 ) eden/WL_edentown2 -96 0 0.00 1 1 0 0 0 +( 832 -352 256 ) ( 832 192 256 ) ( 864 192 256 ) eden/WL_edentown2 -96 0 0.00 1 1 0 0 0 +( 864 192 0 ) ( 832 192 0 ) ( 832 -352 0 ) eden/WL_edentown2 -96 0 0.00 1 1 0 0 0 +} +// brush 93 +{ +( -544 192 256 ) ( -544 -352 256 ) ( -544 -352 0 ) eden/WL_edentown2 0 0 0.00 1 1 0 0 0 +( -512 192 256 ) ( -544 192 256 ) ( -544 192 0 ) eden/WL_edentown2 0 0 0.00 1 1 0 0 0 +( -512 -384 256 ) ( -512 160 256 ) ( -512 160 0 ) eden/WL_edentown2 0 0 0.00 1 1 0 0 0 +( -544 -384 256 ) ( -512 -384 256 ) ( -512 -384 0 ) eden/WL_edentown2 0 0 0.00 1 1 0 0 0 +( -544 -352 256 ) ( -544 192 256 ) ( -512 192 256 ) eden/WL_edentown2 0 0 0.00 1 1 0 0 0 +( -512 192 0 ) ( -544 192 0 ) ( -544 -352 0 ) eden/WL_edentown2 0 0 0.00 1 1 0 0 0 +} +} +// entity 1 +{ +"classname" "Enemies_Lympthorn_female" +"scale" "1.0" +"model" "lympthorn_f.tik" +"origin" "352.00 -352.00 -128.00" +} +// entity 2 +{ +"origin" "352.00 -160.00 -128.00" +"model" "lympthorn_f.tik" +"scale" "1.0" +"classname" "Enemies_Lympthorn_female" +} +// entity 3 +{ +"origin" "491.00 -181.00 -128.00" +"model" "item_healthplant.tik" +"scale" "1.0" +"classname" "Health_HealthPlant" +} +// entity 4 +{ +"origin" "491.00 -261.00 -128.00" +"model" "item_healthplant.tik" +"scale" "1.0" +"classname" "Health_HealthPlant" +} +// entity 5 +{ +"origin" "491.00 -341.00 -128.00" +"model" "item_healthplant.tik" +"scale" "1.0" +"classname" "Health_HealthPlant" +} +// entity 6 +{ +"classname" "light" +"_color" "0.710744 0.987603 1.000000" +"origin" "-500 -96 200" +} +// entity 7 +{ +"origin" "184 424 -128" +"classname" "info_pathnode" +} +// entity 8 +{ +"origin" "624 -464 -128" +"angle" "135" +"classname" "info_player_start" +} +// entity 9 +{ +"type" "patchCapped" +"classname" "func_group" +// brush 0 + { + patchDef2 + { + eden/edenmetalwall + ( 9 3 0 536870912 0 ) +( +( ( 32 -96 400 0 0 ) ( 32 -96 448 0 0.406250 ) ( 32 -96 496 0 0.812500 ) ) +( ( 16 -240 400 0.500000 0 ) ( 16 -240 448 0.500000 0.406250 ) ( 16 -240 496 0.500000 0.812500 ) ) +( ( 160 -224 400 1 0 ) ( 160 -224 448 1 0.406250 ) ( 160 -224 496 1 0.812500 ) ) +( ( 304 -240 400 1.500000 0 ) ( 304 -240 448 1.500000 0.406250 ) ( 304 -240 496 1.500000 0.812500 ) ) +( ( 288 -96 400 2 0 ) ( 288 -96 448 2 0.406250 ) ( 288 -96 496 2 0.812500 ) ) +( ( 304 48 400 2.500000 0 ) ( 304 48 448 2.500000 0.406250 ) ( 304 48 496 2.500000 0.812500 ) ) +( ( 160 32 400 3 0 ) ( 160 32 448 3 0.406250 ) ( 160 32 496 3 0.812500 ) ) +( ( 16 48 400 3.500000 0 ) ( 16 48 448 3.500000 0.406250 ) ( 16 48 496 3.500000 0.812500 ) ) +( ( 32 -96 400 4 0 ) ( 32 -96 448 4 0.406250 ) ( 32 -96 496 4 0.812500 ) ) +) + } + } +} +// entity 10 +{ +"classname" "info_pathnode" +"origin" "360 424 -128" +} +// entity 11 +{ +"classname" "info_pathnode" +"origin" "184 232 -128" +} +// entity 12 +{ +"origin" "360 232 -128" +"classname" "info_pathnode" +} +// entity 13 +{ +"classname" "info_pathnode" +"origin" "184 72 -128" +} +// entity 14 +{ +"origin" "184 -120 -128" +"classname" "info_pathnode" +} +// entity 15 +{ +"classname" "info_pathnode" +"origin" "360 -120 -128" +} +// entity 16 +{ +"origin" "184 -280 -128" +"classname" "info_pathnode" +} +// entity 17 +{ +"classname" "info_pathnode" +"origin" "360 -280 -128" +} +// entity 18 +{ +"classname" "info_pathnode" +"origin" "184 -472 -128" +} +// entity 19 +{ +"origin" "360 -472 -128" +"classname" "info_pathnode" +} +// entity 20 +{ +"classname" "info_pathnode" +"origin" "184 -632 -128" +} +// entity 21 +{ +"origin" "360 -632 -128" +"classname" "info_pathnode" +} +// entity 22 +{ +"origin" "536 -120 -128" +"classname" "info_pathnode" +} +// entity 23 +{ +"classname" "info_pathnode" +"origin" "536 -312 -128" +} +// entity 24 +{ +"classname" "info_pathnode" +"origin" "536 -472 -128" +} +// entity 25 +{ +"classname" "info_pathnode" +"origin" "696 88 -128" +} +// entity 26 +{ +"classname" "info_pathnode" +"origin" "696 -72 -128" +} +// entity 27 +{ +"origin" "696 -264 -128" +"classname" "info_pathnode" +} +// entity 28 +{ +"classname" "info_pathnode" +"origin" "536 232 -128" +} +// entity 29 +{ +"classname" "info_pathnode" +"origin" "536 40 -128" +} +// entity 30 +{ +"classname" "info_pathnode" +"origin" "72 -280 -128" +} +// entity 31 +{ +"origin" "72 -56 -128" +"classname" "info_pathnode" +} +// entity 32 +{ +"origin" "72 -344 -112" +"classname" "info_pathnode" +} +// entity 33 +{ +"classname" "info_pathnode" +"origin" "72 -408 -80" +} +// entity 34 +{ +"origin" "72 -472 -48" +"classname" "info_pathnode" +} +// entity 35 +{ +"classname" "info_pathnode" +"origin" "72 -536 -16" +} +// entity 36 +{ +"origin" "72 -568 0" +"classname" "info_pathnode" +} +// entity 37 +{ +"classname" "info_pathnode" +"origin" "72 -696 0" +} +// entity 38 +{ +"origin" "-56 -664 0" +"classname" "info_pathnode" +} +// entity 39 +{ +"classname" "info_pathnode" +"origin" "72 -24 -128" +} +// entity 40 +{ +"origin" "72 72 -80" +"classname" "info_pathnode" +} +// entity 41 +{ +"classname" "info_pathnode" +"origin" "72 312 0" +} +// entity 42 +{ +"origin" "72 440 0" +"classname" "info_pathnode" +} +// entity 43 +{ +"classname" "info_pathnode" +"origin" "-88 440 0" +} +// entity 44 +{ +"classname" "info_pathnode" +"origin" "-88 -376 0" +} +// entity 45 +{ +"classname" "info_pathnode" +"origin" "-88 -536 0" +} +// entity 46 +{ +"classname" "info_pathnode" +"origin" "-88 328 0" +} +// entity 47 +{ +"classname" "info_pathnode" +"origin" "-88 168 0" +} +// entity 48 +{ +"origin" "-88 -24 0" +"classname" "info_pathnode" +} +// entity 49 +{ +"origin" "-88 -184 0" +"classname" "info_pathnode" +} +// entity 50 +{ +"origin" "-248 -376 0" +"classname" "info_pathnode" +} +// entity 51 +{ +"origin" "-216 -504 0" +"classname" "info_pathnode" +} +// entity 52 +{ +"origin" "-248 264 0" +"classname" "info_pathnode" +} +// entity 53 +{ +"origin" "-248 168 0" +"classname" "info_pathnode" +} +// entity 54 +{ +"classname" "info_pathnode" +"origin" "-248 -24 0" +} +// entity 55 +{ +"classname" "info_pathnode" +"origin" "-248 -184 0" +} +// entity 56 +{ +"classname" "info_pathnode" +"origin" "-408 -312 0" +} +// entity 57 +{ +"classname" "info_pathnode" +"origin" "-408 104 0" +} +// entity 58 +{ +"origin" "-408 -24 0" +"classname" "info_pathnode" +} +// entity 59 +{ +"origin" "-408 -184 0" +"classname" "info_pathnode" +} +// entity 60 +{ +"origin" "360 8 -128" +"classname" "info_pathnode" +} +// entity 61 +{ +"classname" "info_pathnode" +"origin" "72 168 -48" +} +// entity 62 +{ +"origin" "72 256 -16" +"classname" "info_pathnode" +} +// entity 63 +{ +"origin" "-500 -96 112" +"_color" "0.710744 0.987603 1.000000" +"classname" "light" +} +// entity 64 +{ +"origin" "820 -96 200" +"_color" "0.710744 0.987603 1.000000" +"classname" "light" +} +// entity 65 +{ +"classname" "light" +"_color" "0.710744 0.987603 1.000000" +"origin" "820 -96 112" +} +// entity 66 +{ +"origin" "160 564 200" +"_color" "0.710744 0.987603 1.000000" +"classname" "light" +} +// entity 67 +{ +"classname" "light" +"_color" "0.710744 0.987603 1.000000" +"origin" "160 564 112" +} +// entity 68 +{ +"classname" "light" +"_color" "0.710744 0.987603 1.000000" +"origin" "160 -756 200" +} +// entity 69 +{ +"origin" "160 -756 112" +"_color" "0.710744 0.987603 1.000000" +"classname" "light" +} +// entity 70 +{ +"origin" "-308 112 424" +"_color" "1.000000 1.000000 1.000000" +"classname" "light" +} +// entity 71 +{ +"classname" "light" +"_color" "1.000000 1.000000 1.000000" +"origin" "-4 352 424" +} +// entity 72 +{ +"origin" "348 352 424" +"_color" "1.000000 1.000000 1.000000" +"classname" "light" +} +// entity 73 +{ +"classname" "light" +"_color" "1.000000 1.000000 1.000000" +"origin" "620 80 424" +} +// entity 74 +{ +"origin" "636 -288 424" +"_color" "1.000000 1.000000 1.000000" +"classname" "light" +} +// entity 75 +{ +"classname" "light" +"_color" "1.000000 1.000000 1.000000" +"origin" "348 -576 424" +} +// entity 76 +{ +"origin" "-20 -560 424" +"_color" "1.000000 1.000000 1.000000" +"classname" "light" +} +// entity 77 +{ +"classname" "light" +"_color" "1.000000 1.000000 1.000000" +"origin" "-276 -256 424" +} +// entity 78 +{ +"origin" "164 -96 424" +"_color" "1.000000 1.000000 1.000000" +"classname" "light" +} +// entity 79 +{ +"origin" "616 184 -128" +"classname" "info_pathnode" +} +// entity 80 +{ +"classname" "info_pathnode" +"origin" "632 -376 -128" +} +// entity 81 +{ +"classname" "info_pathnode" +"origin" "456 344 -128" +} +// entity 82 +{ +"origin" "488 -552 -128" +"classname" "info_pathnode" +} diff --git a/fakk/maps/example/gibs_and_health.prt b/fakk/maps/example/gibs_and_health.prt new file mode 100644 index 0000000..1133044 --- /dev/null +++ b/fakk/maps/example/gibs_and_health.prt @@ -0,0 +1,538 @@ +PRT1 +74 +187 +347 +4 0 59 0 (0 24 496 ) (0 576 496 ) (0 576 408 ) (0 24 408 ) +5 0 3 0 (0 576 408 ) (448 576 408 ) (832 192 408 ) (832 24 408 ) (0 24 408 ) +4 0 2 0 (208 24 408 ) (832 24 408 ) (832 24 496 ) (208 24 496 ) +4 0 1 0 (0 24 408 ) (112 24 408 ) (112 24 496 ) (0 24 496 ) +4 1 59 0 (0 0 408 ) (0 0 496 ) (0 24 496 ) (0 24 408 ) +4 1 27 0 (40 0 408 ) (88 0 408 ) (88 0 496 ) (40 0 496 ) +4 1 30 0 (0 0 496 ) (0 0 408 ) (40 0 408 ) (40 0 496 ) +4 1 3 0 (88 0 408 ) (0 0 408 ) (0 24 408 ) (112 24 408 ) +4 2 23 0 (232 0 408 ) (280 0 408 ) (280 0 496 ) (232 0 496 ) +4 2 21 0 (280 0 408 ) (832 0 408 ) (832 0 496 ) (280 0 496 ) +4 2 3 0 (832 24 408 ) (832 0 408 ) (232 0 408 ) (208 24 408 ) +4 3 59 0 (0 0 288 ) (0 0 408 ) (0 576 408 ) (0 576 288 ) +4 3 31 0 (0 0 408 ) (0 0 288 ) (832 0 288 ) (832 0 408 ) +5 3 4 0 (768 0 288 ) (0 0 288 ) (0 512 288 ) (416 512 288 ) (768 160 288 ) +4 4 60 0 (0 0 256 ) (0 0 288 ) (0 512 288 ) (0 512 256 ) +4 4 32 0 (0 0 288 ) (0 0 256 ) (768 0 256 ) (768 0 288 ) +5 4 10 0 (768 0 256 ) (0 0 256 ) (0 512 256 ) (416 512 256 ) (768 160 256 ) +4 5 61 0 (0 568 256 ) (0 576 256 ) (0 576 240 ) (0 568 240 ) +4 5 10 0 (456 568 256 ) (0 568 256 ) (0 568 240 ) (456 568 240 ) +4 5 8 0 (136 568 240 ) (0 568 240 ) (0 576 240 ) (136 576 240 ) +4 5 6 0 (456 568 240 ) (184 568 240 ) (184 576 240 ) (448 576 240 ) +4 6 10 0 (456 568 240 ) (184 568 240 ) (184 568 64 ) (456 568 64 ) +4 6 9 0 (456 568 64 ) (184 568 64 ) (184 576 64 ) (448 576 64 ) +4 7 10 0 (152 568 224 ) (152 568 80 ) (168 568 80 ) (168 568 224 ) +4 8 61 0 (0 576 240 ) (0 576 64 ) (0 568 64 ) (0 568 240 ) +4 8 10 0 (136 568 240 ) (0 568 240 ) (0 568 64 ) (136 568 64 ) +4 8 9 0 (136 568 64 ) (0 568 64 ) (0 576 64 ) (136 576 64 ) +4 9 61 0 (0 576 64 ) (0 576 8 ) (0 568 8 ) (0 568 64 ) +4 9 10 0 (0 568 8 ) (456 568 8 ) (456 568 64 ) (0 568 64 ) +4 10 61 0 (0 0 8 ) (0 0 256 ) (0 568 256 ) (0 568 8 ) +4 10 38 0 (0 0 240 ) (0 0 8 ) (824 0 8 ) (824 0 240 ) +4 10 37 0 (824 0 8 ) (832 0 8 ) (832 0 64 ) (824 0 64 ) +4 10 34 0 (832 0 64 ) (832 0 240 ) (824 0 240 ) (824 0 64 ) +4 10 33 0 (0 0 256 ) (0 0 240 ) (832 0 240 ) (832 0 256 ) +4 10 19 0 (8 328 8 ) (128 328 8 ) (128 320 8 ) (8 320 8 ) +4 10 18 0 (0 328 8 ) (0 512 8 ) (128 512 8 ) (128 328 8 ) +4 10 17 0 (128 0 8 ) (0 0 8 ) (0 320 8 ) (128 320 8 ) +4 10 16 0 (136 0 8 ) (128 0 8 ) (128 320 8 ) (136 320 8 ) +4 10 15 0 (320 0 8 ) (136 0 8 ) (136 512 8 ) (320 512 8 ) +5 10 11 0 (320 64 8 ) (320 512 8 ) (416 512 8 ) (768 160 8 ) (768 64 8 ) +4 10 14 0 (768 0 8 ) (320 0 8 ) (320 64 8 ) (768 64 8 ) +4 11 15 0 (320 512 8 ) (320 512 0 ) (320 64 0 ) (320 64 8 ) +5 11 13 0 (768 64 0 ) (448 64 0 ) (448 192 0 ) (736 192 0 ) (768 160 0 ) +4 11 12 0 (320 192 0 ) (320 512 0 ) (416 512 0 ) (736 192 0 ) +4 11 14 0 (320 64 8 ) (320 64 0 ) (768 64 0 ) (768 64 8 ) +4 12 15 0 (320 512 0 ) (320 512 -128 ) (320 192 -128 ) (320 192 0 ) +4 12 13 0 (736 192 -128 ) (736 192 0 ) (448 192 0 ) (448 192 -128 ) +4 13 14 0 (448 64 -128 ) (768 64 -128 ) (768 64 0 ) (448 64 0 ) +4 14 43 0 (320 0 -128 ) (768 0 -128 ) (768 0 8 ) (320 0 8 ) +4 14 15 0 (320 64 -128 ) (320 0 -128 ) (320 0 8 ) (320 64 8 ) +4 15 43 0 (136 0 -128 ) (320 0 -128 ) (320 0 8 ) (136 0 8 ) +3 15 16 0 (136 0 -120 ) (136 0 8 ) (136 320 8 ) +4 16 43 0 (136 0 -120 ) (136 0 8 ) (128 0 8 ) (128 0 -120 ) +3 16 17 0 (128 0 -120 ) (128 0 8 ) (128 320 8 ) +4 17 55 0 (0 0 8 ) (0 0 -120 ) (8 0 -120 ) (8 0 8 ) +4 17 43 0 (8 0 -120 ) (128 0 -120 ) (128 0 8 ) (8 0 8 ) +4 17 20 0 (128 300 0 ) (128 0 -120 ) (8 0 -120 ) (8 300 0 ) +4 17 19 0 (8 320 8 ) (128 320 8 ) (128 300 0 ) (8 300 0 ) +4 18 62 0 (0 328 8 ) (0 512 8 ) (0 512 0 ) (0 328 0 ) +4 18 19 0 (8 328 0 ) (128 328 0 ) (128 328 8 ) (8 328 8 ) +4 19 20 0 (128 300 0 ) (8 300 0 ) (8 320 0 ) (128 320 0 ) +4 20 43 0 (8 0 -128 ) (128 0 -128 ) (128 0 -120 ) (8 0 -120 ) +5 21 31 0 (280 0 408 ) (832 0 408 ) (832 -384 408 ) (448 -768 408 ) (280 -768 408 ) +4 21 23 0 (280 0 408 ) (280 -48 408 ) (280 -48 496 ) (280 0 496 ) +4 21 22 0 (280 -144 408 ) (280 -216 408 ) (280 -216 496 ) (280 -144 496 ) +4 21 29 0 (280 -216 408 ) (280 -768 408 ) (280 -768 496 ) (280 -216 496 ) +4 22 31 0 (280 -144 408 ) (280 -216 408 ) (232 -216 408 ) (232 -192 408 ) +4 22 25 0 (232 -192 408 ) (232 -216 408 ) (232 -216 496 ) (232 -192 496 ) +4 22 29 0 (232 -216 408 ) (280 -216 408 ) (280 -216 496 ) (232 -216 496 ) +3 23 31 0 (232 0 408 ) (280 0 408 ) (280 -48 408 ) +8 24 31 0 (232 -64 408 ) (232 -128 408 ) (192 -168 408 ) (128 -168 408 ) (88 -128 408 ) (88 -64 408 ) (128 -24 408 ) (192 -24 408 ) +3 25 31 0 (232 -192 408 ) (232 -216 408 ) (208 -216 408 ) +4 25 29 0 (208 -216 408 ) (232 -216 408 ) (232 -216 496 ) (208 -216 496 ) +3 26 31 0 (112 -216 408 ) (88 -216 408 ) (88 -192 408 ) +4 26 28 0 (88 -192 408 ) (88 -216 408 ) (88 -216 496 ) (88 -192 496 ) +4 26 29 0 (88 -216 408 ) (112 -216 408 ) (112 -216 496 ) (88 -216 496 ) +3 27 31 0 (40 0 408 ) (88 0 408 ) (40 -48 408 ) +4 27 30 0 (40 0 408 ) (40 -48 408 ) (40 -48 496 ) (40 0 496 ) +4 28 31 0 (88 -192 408 ) (88 -216 408 ) (40 -216 408 ) (40 -144 408 ) +4 28 29 0 (40 -216 496 ) (40 -216 408 ) (88 -216 408 ) (88 -216 496 ) +4 28 30 0 (40 -144 408 ) (40 -216 408 ) (40 -216 496 ) (40 -144 496 ) +4 29 31 0 (280 -216 408 ) (280 -768 408 ) (40 -768 408 ) (40 -216 408 ) +4 29 30 0 (40 -216 408 ) (40 -768 408 ) (40 -768 496 ) (40 -216 496 ) +4 30 64 0 (0 -768 496 ) (0 0 496 ) (0 0 408 ) (0 -768 408 ) +4 30 31 0 (0 -768 408 ) (0 0 408 ) (40 0 408 ) (40 -768 408 ) +4 31 64 0 (0 -768 408 ) (0 0 408 ) (0 0 288 ) (0 -768 288 ) +5 31 32 0 (0 -704 288 ) (0 0 288 ) (768 0 288 ) (768 -352 288 ) (416 -704 288 ) +4 32 65 0 (0 -704 288 ) (0 0 288 ) (0 0 256 ) (0 -704 256 ) +5 32 33 0 (0 -704 256 ) (0 0 256 ) (768 0 256 ) (768 -352 256 ) (416 -704 256 ) +4 33 66 0 (0 -768 256 ) (0 0 256 ) (0 0 240 ) (0 -768 240 ) +4 33 39 0 (184 -760 240 ) (456 -760 240 ) (448 -768 240 ) (184 -768 240 ) +4 33 41 0 (0 -768 240 ) (0 -760 240 ) (136 -760 240 ) (136 -768 240 ) +5 33 38 0 (0 -760 240 ) (0 0 240 ) (824 0 240 ) (824 -392 240 ) (456 -760 240 ) +4 33 36 0 (832 -120 240 ) (832 -384 240 ) (824 -392 240 ) (824 -120 240 ) +4 33 34 0 (824 0 240 ) (832 0 240 ) (832 -72 240 ) (824 -72 240 ) +4 34 38 0 (824 -72 240 ) (824 0 240 ) (824 0 64 ) (824 -72 64 ) +4 34 37 0 (824 -72 64 ) (824 0 64 ) (832 0 64 ) (832 -72 64 ) +4 35 38 0 (824 -88 224 ) (824 -88 80 ) (824 -104 80 ) (824 -104 224 ) +4 36 38 0 (824 -392 240 ) (824 -120 240 ) (824 -120 64 ) (824 -392 64 ) +4 36 37 0 (824 -392 64 ) (824 -120 64 ) (832 -120 64 ) (832 -384 64 ) +4 37 38 0 (824 0 8 ) (824 -392 8 ) (824 -392 64 ) (824 0 64 ) +4 38 66 0 (0 -760 240 ) (0 0 240 ) (0 0 8 ) (0 -760 8 ) +4 38 58 0 (0 -704 8 ) (0 -584 8 ) (8 -584 8 ) (8 -704 8 ) +4 38 56 0 (0 -576 8 ) (0 -344 8 ) (8 -344 8 ) (8 -576 8 ) +4 38 55 0 (0 -344 8 ) (0 0 8 ) (8 0 8 ) (8 -344 8 ) +4 38 53 0 (128 -704 8 ) (8 -704 8 ) (8 -576 8 ) (128 -576 8 ) +4 38 51 0 (8 -576 8 ) (8 -544 8 ) (128 -544 8 ) (128 -576 8 ) +4 38 49 0 (8 -544 8 ) (8 -512 8 ) (128 -512 8 ) (128 -544 8 ) +4 38 47 0 (8 -512 8 ) (8 -480 8 ) (128 -480 8 ) (128 -512 8 ) +4 38 46 0 (8 -480 8 ) (8 -344 8 ) (128 -344 8 ) (128 -480 8 ) +4 38 45 0 (128 -576 8 ) (128 -344 8 ) (136 -344 8 ) (136 -576 8 ) +5 38 44 0 (768 -344 8 ) (768 -352 8 ) (416 -704 8 ) (136 -704 8 ) (136 -344 8 ) +4 38 43 0 (8 0 8 ) (768 0 8 ) (768 -344 8 ) (8 -344 8 ) +4 38 42 0 (0 -760 8 ) (456 -760 8 ) (456 -760 64 ) (0 -760 64 ) +4 38 40 0 (152 -760 224 ) (152 -760 80 ) (168 -760 80 ) (168 -760 224 ) +4 38 39 0 (456 -760 64 ) (456 -760 240 ) (184 -760 240 ) (184 -760 64 ) +4 38 41 0 (136 -760 240 ) (0 -760 240 ) (0 -760 64 ) (136 -760 64 ) +4 39 42 0 (448 -768 64 ) (184 -768 64 ) (184 -760 64 ) (456 -760 64 ) +4 41 66 0 (0 -768 240 ) (0 -760 240 ) (0 -760 64 ) (0 -768 64 ) +4 41 42 0 (136 -768 64 ) (0 -768 64 ) (0 -760 64 ) (136 -760 64 ) +4 42 66 0 (0 -760 64 ) (0 -760 8 ) (0 -768 8 ) (0 -768 64 ) +4 43 55 0 (8 0 -128 ) (8 -344 -128 ) (8 -344 8 ) (8 0 8 ) +4 43 54 0 (8 -344 -112 ) (8 -344 -128 ) (128 -344 -128 ) (128 -344 -112 ) +4 43 52 0 (8 -344 -96 ) (8 -344 -112 ) (128 -344 -112 ) (128 -344 -96 ) +4 43 50 0 (8 -344 -80 ) (8 -344 -96 ) (128 -344 -96 ) (128 -344 -80 ) +4 43 48 0 (8 -344 -64 ) (8 -344 -80 ) (128 -344 -80 ) (128 -344 -64 ) +4 43 46 0 (8 -344 8 ) (8 -344 -64 ) (128 -344 -64 ) (128 -344 8 ) +4 43 45 0 (136 -344 -112 ) (136 -344 8 ) (128 -344 8 ) (128 -344 -112 ) +4 43 44 0 (136 -344 -128 ) (768 -344 -128 ) (768 -344 8 ) (136 -344 8 ) +3 44 45 0 (136 -344 8 ) (136 -344 -112 ) (136 -576 8 ) +3 45 52 0 (128 -344 -96 ) (128 -344 -112 ) (128 -374.933319 -96 ) +3 45 51 0 (128 -544 -8.551724 ) (128 -576 8 ) (128 -544 8 ) +4 45 50 0 (128 -344 -80 ) (128 -344 -96 ) (128 -374.933319 -96 ) (128 -405.866669 -80 ) +4 45 49 0 (128 -512 -25.103449 ) (128 -544 -8.551724 ) (128 -544 8 ) (128 -512 8 ) +4 45 48 0 (128 -344 -64 ) (128 -344 -80 ) (128 -405.866669 -80 ) (128 -436.799988 -64 ) +4 45 47 0 (128 -480 -41.655170 ) (128 -512 -25.103449 ) (128 -512 8 ) (128 -480 8 ) +5 45 46 0 (128 -344 8 ) (128 -344 -64 ) (128 -436.799988 -64 ) (128 -480 -41.655170 ) (128 -480 8 ) +5 46 57 0 (8 -344 0 ) (8 -344 -64 ) (8 -436.799988 -64 ) (8 -480 -41.655167 ) (8 -480 0 ) +4 46 56 0 (8 -480 8 ) (8 -344 8 ) (8 -344 0 ) (8 -480 0 ) +4 46 48 0 (8 -448 -64 ) (8 -344 -64 ) (128 -344 -64 ) (128 -448 -64 ) +4 46 47 0 (8 -480 8 ) (8 -480 -48 ) (128 -480 -48 ) (128 -480 8 ) +4 47 57 0 (8 -480 0 ) (8 -480 -41.655163 ) (8 -512 -25.103441 ) (8 -512 0 ) +4 47 56 0 (8 -512 8 ) (8 -480 8 ) (8 -480 0 ) (8 -512 0 ) +4 47 49 0 (8 -512 8 ) (8 -512 -32 ) (128 -512 -32 ) (128 -512 8 ) +4 48 57 0 (8 -344 -64 ) (8 -344 -80 ) (8 -405.866638 -80 ) (8 -436.799988 -64 ) +4 48 50 0 (8 -416 -80 ) (8 -344 -80 ) (128 -344 -80 ) (128 -416 -80 ) +4 49 57 0 (8 -512 0 ) (8 -512 -25.103439 ) (8 -544 -8.551716 ) (8 -544 0 ) +4 49 56 0 (8 -544 8 ) (8 -512 8 ) (8 -512 0 ) (8 -544 0 ) +4 49 51 0 (8 -544 8 ) (8 -544 -16 ) (128 -544 -16 ) (128 -544 8 ) +4 50 57 0 (8 -344 -80 ) (8 -344 -96 ) (8 -374.933319 -96 ) (8 -405.866638 -80 ) +4 50 52 0 (8 -384 -96 ) (8 -344 -96 ) (128 -344 -96 ) (128 -384 -96 ) +3 51 57 0 (8 -544 0 ) (8 -544 -8.551715 ) (8 -560.533325 0 ) +4 51 56 0 (8 -576 8 ) (8 -544 8 ) (8 -544 0 ) (8 -560.533325 0 ) +4 51 53 0 (8 -576 8 ) (8 -576 0 ) (128 -576 0 ) (128 -576 8 ) +3 52 57 0 (8 -344 -96 ) (8 -344 -112 ) (8 -374.933319 -96 ) +4 52 54 0 (8 -352 -112 ) (8 -344 -112 ) (128 -344 -112 ) (128 -352 -112 ) +4 53 58 0 (8 -704 0 ) (8 -704 8 ) (8 -584 8 ) (8 -584 0 ) +4 55 57 0 (8 -344 -112 ) (8 -344 0 ) (0 -344 0 ) (0 -344 -112 ) +4 55 56 0 (8 -344 0 ) (8 -344 8 ) (0 -344 8 ) (0 -344 0 ) +4 56 57 0 (0 -560.533325 0 ) (0 -344 0 ) (8 -344 0 ) (8 -560.533325 0 ) +4 58 72 0 (0 -704 8 ) (0 -584 8 ) (0 -584 0 ) (0 -704 0 ) +4 59 64 0 (-512 0 288 ) (0 0 288 ) (0 0 496 ) (-512 0 496 ) +5 59 60 0 (0 0 288 ) (-448 0 288 ) (-448 160 288 ) (-96 512 288 ) (0 512 288 ) +4 60 65 0 (-448 0 256 ) (0 0 256 ) (0 0 288 ) (-448 0 288 ) +5 60 61 0 (0 0 256 ) (-448 0 256 ) (-448 160 256 ) (-96 512 256 ) (0 512 256 ) +4 61 71 0 (-512 0 8 ) (-504 0 8 ) (-504 0 64 ) (-512 0 64 ) +4 61 68 0 (-504 0 64 ) (-504 0 240 ) (-512 0 240 ) (-512 0 64 ) +4 61 67 0 (-504 0 240 ) (-504 0 256 ) (-512 0 256 ) (-512 0 240 ) +4 61 66 0 (-504 0 8 ) (0 0 8 ) (0 0 256 ) (-504 0 256 ) +5 61 63 0 (-8 0 8 ) (-448 0 8 ) (-448 160 8 ) (-96 512 8 ) (-8 512 8 ) +4 61 62 0 (-8 328 8 ) (-8 512 8 ) (0 512 8 ) (0 328 8 ) +4 62 63 0 (-8 512 8 ) (-8 512 0 ) (-8 328 0 ) (-8 328 8 ) +4 63 73 0 (-8 0 8 ) (-448 0 8 ) (-448 0 0 ) (-8 0 0 ) +5 64 65 0 (-448 0 288 ) (0 0 288 ) (0 -704 288 ) (-96 -704 288 ) (-448 -352 288 ) +5 65 66 0 (-448 0 256 ) (0 0 256 ) (0 -704 256 ) (-96 -704 256 ) (-448 -352 256 ) +5 66 73 0 (-448 0 8 ) (-8 0 8 ) (-8 -704 8 ) (-96 -704 8 ) (-448 -352 8 ) +4 66 72 0 (0 -584 8 ) (0 -704 8 ) (-8 -704 8 ) (-8 -584 8 ) +4 66 71 0 (-504 0 8 ) (-504 -392 8 ) (-504 -392 64 ) (-504 0 64 ) +4 66 70 0 (-504 -392 64 ) (-504 -392 240 ) (-504 -120 240 ) (-504 -120 64 ) +4 66 69 0 (-504 -104 80 ) (-504 -104 224 ) (-504 -88 224 ) (-504 -88 80 ) +4 66 68 0 (-504 -72 240 ) (-504 0 240 ) (-504 0 64 ) (-504 -72 64 ) +4 66 67 0 (-504 -392 240 ) (-504 -392 256 ) (-504 0 256 ) (-504 0 240 ) +4 67 70 0 (-512 -384 240 ) (-512 -120 240 ) (-504 -120 240 ) (-504 -392 240 ) +4 67 68 0 (-512 -72 240 ) (-512 0 240 ) (-504 0 240 ) (-504 -72 240 ) +4 68 71 0 (-512 -72 64 ) (-512 0 64 ) (-504 0 64 ) (-504 -72 64 ) +4 70 71 0 (-512 -384 64 ) (-512 -120 64 ) (-504 -120 64 ) (-504 -392 64 ) +4 72 73 0 (-8 -584 0 ) (-8 -704 0 ) (-8 -704 8 ) (-8 -584 8 ) +4 0 (112 24 408 ) (208 24 408 ) (208 24 496 ) (112 24 496 ) +4 0 (448 576 408 ) (0 576 408 ) (0 576 496 ) (448 576 496 ) +5 0 (832 24 496 ) (832 192 496 ) (448 576 496 ) (0 576 496 ) (0 24 496 ) +4 0 (832 24 408 ) (832 192 408 ) (832 192 496 ) (832 24 496 ) +4 0 (832 192 496 ) (832 192 408 ) (448 576 408 ) (448 576 496 ) +4 1 (88 0 408 ) (112 24 408 ) (112 24 496 ) (88 0 496 ) +4 1 (112 24 496 ) (0 24 496 ) (0 0 496 ) (88 0 496 ) +4 2 (832 24 408 ) (832 24 496 ) (832 0 496 ) (832 0 408 ) +4 2 (832 24 496 ) (208 24 496 ) (232 0 496 ) (832 0 496 ) +4 2 (208 24 496 ) (208 24 408 ) (232 0 408 ) (232 0 496 ) +4 3 (416 512 288 ) (512 512 288 ) (768 256 288 ) (768 160 288 ) +4 3 (832 0 288 ) (768 0 288 ) (768 256 288 ) (832 192 288 ) +4 3 (0 512 288 ) (0 576 288 ) (448 576 288 ) (512 512 288 ) +4 3 (832 192 408 ) (832 0 408 ) (832 0 288 ) (832 192 288 ) +4 3 (0 576 408 ) (448 576 408 ) (448 576 288 ) (0 576 288 ) +4 3 (208 24 408 ) (112 24 408 ) (88 0 408 ) (232 0 408 ) +4 3 (448 576 288 ) (448 576 408 ) (832 192 408 ) (832 192 288 ) +4 4 (768 160 288 ) (768 0 288 ) (768 0 256 ) (768 160 256 ) +4 4 (0 512 288 ) (416 512 288 ) (416 512 256 ) (0 512 256 ) +4 4 (768 160 288 ) (768 160 256 ) (416 512 256 ) (416 512 288 ) +4 5 (152 568 240 ) (136 568 240 ) (136 576 240 ) (152 576 240 ) +4 5 (168 568 240 ) (152 568 240 ) (152 572 240 ) (168 572 240 ) +4 5 (152 572 240 ) (152 576 240 ) (168 576 240 ) (168 572 240 ) +4 5 (184 568 240 ) (168 568 240 ) (168 576 240 ) (184 576 240 ) +4 5 (456 568 256 ) (448 576 256 ) (0 576 256 ) (0 568 256 ) +4 5 (448 576 240 ) (0 576 240 ) (0 576 256 ) (448 576 256 ) +4 5 (456 568 256 ) (456 568 240 ) (448 576 240 ) (448 576 256 ) +4 6 (184 576 64 ) (184 568 64 ) (184 568 240 ) (184 576 240 ) +4 6 (448 576 64 ) (184 576 64 ) (184 576 240 ) (448 576 240 ) +4 6 (456 568 64 ) (448 576 64 ) (448 576 240 ) (456 568 240 ) +4 7 (152 568 80 ) (152 568 224 ) (152 572 224 ) (152 572 80 ) +4 7 (168 572 224 ) (168 572 80 ) (152 572 80 ) (152 572 224 ) +4 7 (168 572 80 ) (168 572 224 ) (168 568 224 ) (168 568 80 ) +4 7 (152 568 80 ) (152 572 80 ) (168 572 80 ) (168 568 80 ) +4 7 (168 568 224 ) (168 572 224 ) (152 572 224 ) (152 568 224 ) +4 8 (136 576 64 ) (0 576 64 ) (0 576 240 ) (136 576 240 ) +4 8 (136 576 240 ) (136 568 240 ) (136 568 64 ) (136 576 64 ) +4 9 (0 568 8 ) (0 576 8 ) (448 576 8 ) (456 568 8 ) +4 9 (0 576 64 ) (448 576 64 ) (448 576 8 ) (0 576 8 ) +4 9 (184 576 64 ) (168 576 64 ) (168 568 64 ) (184 568 64 ) +4 9 (168 576 64 ) (152 576 64 ) (152 568 64 ) (168 568 64 ) +4 9 (152 576 64 ) (136 576 64 ) (136 568 64 ) (152 568 64 ) +4 9 (448 576 8 ) (448 576 64 ) (456 568 64 ) (456 568 8 ) +4 10 (0 320 8 ) (0 328 8 ) (8 328 8 ) (8 320 8 ) +4 10 (128 320 8 ) (128 512 8 ) (136 512 8 ) (136 320 8 ) +4 10 (416 512 8 ) (512 512 8 ) (768 256 8 ) (768 160 8 ) +4 10 (0 512 8 ) (0 568 8 ) (456 568 8 ) (512 512 8 ) +4 10 (832 0 8 ) (768 0 8 ) (768 256 8 ) (832 192 8 ) +4 10 (832 192 256 ) (832 0 256 ) (832 0 8 ) (832 192 8 ) +4 10 (152 568 64 ) (136 568 64 ) (136 568 240 ) (152 568 240 ) +4 10 (168 568 224 ) (152 568 224 ) (152 568 240 ) (168 568 240 ) +4 10 (168 568 80 ) (168 568 64 ) (152 568 64 ) (152 568 80 ) +4 10 (184 568 64 ) (168 568 64 ) (168 568 240 ) (184 568 240 ) +4 10 (512 512 256 ) (456 568 256 ) (0 568 256 ) (0 512 256 ) +4 10 (832 192 256 ) (768 256 256 ) (768 0 256 ) (832 0 256 ) +4 10 (768 160 256 ) (768 256 256 ) (512 512 256 ) (416 512 256 ) +4 10 (832 192 256 ) (832 192 8 ) (456 568 8 ) (456 568 256 ) +4 11 (448 64 0 ) (320 64 0 ) (320 192 0 ) (448 192 0 ) +4 11 (768 64 0 ) (768 160 0 ) (768 160 8 ) (768 64 8 ) +4 11 (416 512 0 ) (320 512 0 ) (320 512 8 ) (416 512 8 ) +4 11 (768 160 8 ) (768 160 0 ) (416 512 0 ) (416 512 8 ) +4 12 (448 192 0 ) (320 192 0 ) (320 192 -128 ) (448 192 -128 ) +4 12 (416 512 -128 ) (416 512 0 ) (736 192 0 ) (736 192 -128 ) +4 12 (320 512 0 ) (416 512 0 ) (416 512 -128 ) (320 512 -128 ) +4 12 (320 192 -128 ) (320 512 -128 ) (416 512 -128 ) (736 192 -128 ) +5 13 (768 160 -128 ) (768 64 -128 ) (448 64 -128 ) (448 192 -128 ) (736 192 -128 ) +4 13 (768 160 0 ) (768 64 0 ) (768 64 -128 ) (768 160 -128 ) +4 13 (736 192 0 ) (768 160 0 ) (768 160 -128 ) (736 192 -128 ) +4 13 (448 192 0 ) (448 192 -128 ) (448 64 -128 ) (448 64 0 ) +4 14 (448 64 0 ) (448 64 -128 ) (320 64 -128 ) (320 64 0 ) +4 14 (768 64 -128 ) (768 0 -128 ) (320 0 -128 ) (320 64 -128 ) +4 14 (768 64 -128 ) (768 64 8 ) (768 0 8 ) (768 0 -128 ) +5 15 (136 512 8 ) (136 512 -128 ) (136 0 -128 ) (136 0 -120 ) (136 320 8 ) +4 15 (320 192 0 ) (320 64 0 ) (320 64 -128 ) (320 192 -128 ) +4 15 (136 512 8 ) (320 512 8 ) (320 512 -128 ) (136 512 -128 ) +4 15 (320 0 -128 ) (136 0 -128 ) (136 512 -128 ) (320 512 -128 ) +4 16 (128 0 -120 ) (128 319.998993 8 ) (136 320 8 ) (136 0 -120 ) +4 17 (0 0 0 ) (0 0 8 ) (0 320 8 ) (0 300 0 ) +3 17 (0 0 -120 ) (0 0 0 ) (0 300 0 ) +4 17 (8 0 -120 ) (0 0 -120 ) (0 300 0 ) (8 300 0 ) +4 17 (0 320 8 ) (8 320 8 ) (8 300 0 ) (0 300 0 ) +4 18 (8 512 0 ) (128 512 0 ) (128 328 0 ) (8 328 0 ) +4 18 (0 328 0 ) (0 512 0 ) (8 512 0 ) (8 328 0 ) +4 18 (0 328 0 ) (8 328 0 ) (8 328 8 ) (0 328 8 ) +4 18 (0 512 0 ) (0 512 8 ) (128 512 8 ) (128 512 0 ) +4 18 (128 328 8 ) (128 328 0 ) (128 512 0 ) (128 512 8 ) +4 19 (8 320 0 ) (8 328 0 ) (128 328 0 ) (128 320 0 ) +4 19 (128 328 8 ) (128 320 8 ) (128 300 0 ) (128 328 0 ) +4 19 (8 328 8 ) (8 328 0 ) (8 300 0 ) (8 320 8 ) +4 20 (8 0 -120 ) (8 300 0 ) (8 320 0 ) (8 0 -128 ) +4 20 (128 320 0 ) (128 300 0 ) (128 0 -120 ) (128 0 -128 ) +4 20 (8 0 -128 ) (8 319.998627 0 ) (128 319.998627 0 ) (128 0 -128 ) +4 21 (280 -48 408 ) (280 -144 408 ) (280 -144 496 ) (280 -48 496 ) +4 21 (832 0 496 ) (832 -384 496 ) (832 -384 408 ) (832 0 408 ) +5 21 (280 -768 496 ) (448 -768 496 ) (832 -384 496 ) (832 0 496 ) (280 0 496 ) +4 21 (280 -768 408 ) (448 -768 408 ) (448 -768 496 ) (280 -768 496 ) +4 21 (448 -768 496 ) (448 -768 408 ) (832 -384 408 ) (832 -384 496 ) +4 22 (280 -144 496 ) (280 -144 408 ) (232 -192 408 ) (232 -192 496 ) +4 22 (232 -192 496 ) (232 -216 496 ) (280 -216 496 ) (280 -144 496 ) +3 23 (280 -48 496 ) (280 0 496 ) (232 0 496 ) +4 23 (232 0 496 ) (232 0 408 ) (280 -48 408 ) (280 -48 496 ) +4 24 (88 -64 408 ) (88 -128 408 ) (88 -128 496 ) (88 -64 496 ) +4 24 (128 -168 408 ) (192 -168 408 ) (192 -168 496 ) (128 -168 496 ) +4 24 (192 -168 496 ) (192 -168 408 ) (232 -128 408 ) (232 -128 496 ) +4 24 (88 -128 496 ) (88 -128 408 ) (128 -168 408 ) (128 -168 496 ) +4 24 (232 -64 496 ) (232 -128 496 ) (232 -128 408 ) (232 -64 408 ) +8 24 (192 -24 496 ) (128 -24 496 ) (88 -64 496 ) (88 -128 496 ) (128 -168 496 ) (192 -168 496 ) (232 -128 496 ) (232 -64 496 ) +4 24 (128 -24 496 ) (192 -24 496 ) (192 -24 408 ) (128 -24 408 ) +4 24 (128 -24 496 ) (128 -24 408 ) (88 -64 408 ) (88 -64 496 ) +4 24 (232 -64 496 ) (232 -64 408 ) (192 -24 408 ) (192 -24 496 ) +4 25 (232 -192 496 ) (232 -192 408 ) (208 -216 408 ) (208 -216 496 ) +3 25 (208 -216 496 ) (232 -216 496 ) (232 -192 496 ) +3 26 (88 -192 496 ) (88 -216 496 ) (112 -216 496 ) +4 26 (112 -216 496 ) (112 -216 408 ) (88 -192 408 ) (88 -192 496 ) +4 27 (40 -48 496 ) (40 -48 408 ) (88 0 408 ) (88 0 496 ) +3 27 (40 -48 496 ) (88 0 496 ) (40 0 496 ) +4 28 (40 -144 496 ) (40 -216 496 ) (88 -216 496 ) (88 -192 496 ) +4 28 (88 -192 496 ) (88 -192 408 ) (40 -144 408 ) (40 -144 496 ) +4 29 (112 -216 496 ) (208 -216 496 ) (208 -216 408 ) (112 -216 408 ) +4 29 (40 -768 408 ) (280 -768 408 ) (280 -768 496 ) (40 -768 496 ) +4 29 (40 -216 496 ) (40 -768 496 ) (280 -768 496 ) (280 -216 496 ) +4 30 (40 -48 496 ) (40 -144 496 ) (40 -144 408 ) (40 -48 408 ) +4 30 (40 -768 496 ) (40 0 496 ) (0 0 496 ) (0 -768 496 ) +4 30 (0 -768 408 ) (40 -768 408 ) (40 -768 496 ) (0 -768 496 ) +4 31 (768 -352 288 ) (768 -448 288 ) (512 -704 288 ) (416 -704 288 ) +4 31 (0 -768 288 ) (0 -704 288 ) (512 -704 288 ) (448 -768 288 ) +4 31 (768 0 288 ) (832 0 288 ) (832 -384 288 ) (768 -448 288 ) +4 31 (832 0 408 ) (832 -384 408 ) (832 -384 288 ) (832 0 288 ) +4 31 (232 -192 408 ) (280 -144 408 ) (280 -48 408 ) (232 0 408 ) +4 31 (88 -24 408 ) (232 -24 408 ) (232 0 408 ) (88 0 408 ) +3 31 (88 -128 408 ) (88 -168 408 ) (128 -168 408 ) +3 31 (128 -24 408 ) (88 -24 408 ) (88 -64 408 ) +3 31 (192 -168 408 ) (232 -168 408 ) (232 -128 408 ) +3 31 (192 -24 408 ) (232 -64 408 ) (232 -24 408 ) +6 31 (88 -168 408 ) (88 -192 408 ) (112 -216 408 ) (208 -216 408 ) (232 -192 408 ) (232 -168 408 ) +4 31 (40 -48 408 ) (40 -144 408 ) (88 -192 408 ) (88 0 408 ) +4 31 (0 -768 288 ) (448 -768 288 ) (448 -768 408 ) (0 -768 408 ) +4 31 (448 -768 408 ) (448 -768 288 ) (832 -384 288 ) (832 -384 408 ) +4 32 (0 -704 256 ) (416 -704 256 ) (416 -704 288 ) (0 -704 288 ) +4 32 (768 0 288 ) (768 -352 288 ) (768 -352 256 ) (768 0 256 ) +4 32 (416 -704 288 ) (416 -704 256 ) (768 -352 256 ) (768 -352 288 ) +4 33 (152 -760 240 ) (168 -760 240 ) (168 -764 240 ) (152 -764 240 ) +4 33 (168 -760 240 ) (184 -760 240 ) (184 -764 240 ) (168 -764 240 ) +4 33 (184 -764 240 ) (184 -768 240 ) (152 -768 240 ) (152 -764 240 ) +4 33 (136 -760 240 ) (152 -760 240 ) (152 -768 240 ) (136 -768 240 ) +4 33 (832 -104 240 ) (832 -120 240 ) (824 -120 240 ) (824 -104 240 ) +4 33 (828 -104 240 ) (824 -104 240 ) (824 -88 240 ) (828 -88 240 ) +4 33 (832 -88 240 ) (832 -104 240 ) (828 -104 240 ) (828 -88 240 ) +4 33 (832 -72 240 ) (832 -88 240 ) (824 -88 240 ) (824 -72 240 ) +4 33 (832 0 256 ) (832 -384 256 ) (832 -384 240 ) (832 0 240 ) +4 33 (768 -448 256 ) (832 -384 256 ) (832 0 256 ) (768 0 256 ) +4 33 (448 -768 256 ) (512 -704 256 ) (0 -704 256 ) (0 -768 256 ) +4 33 (416 -704 256 ) (512 -704 256 ) (768 -448 256 ) (768 -352 256 ) +4 33 (0 -768 240 ) (448 -768 240 ) (448 -768 256 ) (0 -768 256 ) +4 33 (448 -768 256 ) (448 -768 240 ) (832 -384 240 ) (832 -384 256 ) +4 34 (832 0 240 ) (832 -72 240 ) (832 -72 64 ) (832 0 64 ) +4 34 (824 -72 240 ) (824 -72 64 ) (832 -72 64 ) (832 -72 240 ) +4 35 (824 -104 224 ) (824 -104 80 ) (828 -104 80 ) (828 -104 224 ) +4 35 (828 -104 224 ) (828 -104 80 ) (828 -88 80 ) (828 -88 224 ) +4 35 (828 -88 224 ) (828 -88 80 ) (824 -88 80 ) (824 -88 224 ) +4 35 (828 -104 80 ) (824 -104 80 ) (824 -88 80 ) (828 -88 80 ) +4 35 (824 -104 224 ) (828 -104 224 ) (828 -88 224 ) (824 -88 224 ) +4 36 (832 -120 240 ) (832 -120 64 ) (824 -120 64 ) (824 -120 240 ) +4 36 (832 -120 240 ) (832 -384 240 ) (832 -384 64 ) (832 -120 64 ) +4 36 (824 -392 240 ) (824 -392 64 ) (832 -384 64 ) (832 -384 240 ) +4 37 (824 0 8 ) (832 0 8 ) (832 -384 8 ) (824 -392 8 ) +4 37 (832 0 64 ) (832 -384 64 ) (832 -384 8 ) (832 0 8 ) +4 37 (832 -120 64 ) (832 -104 64 ) (824 -104 64 ) (824 -120 64 ) +4 37 (832 -104 64 ) (832 -88 64 ) (824 -88 64 ) (824 -104 64 ) +4 37 (832 -88 64 ) (832 -72 64 ) (824 -72 64 ) (824 -88 64 ) +4 37 (832 -384 8 ) (832 -384 64 ) (824 -392 64 ) (824 -392 8 ) +4 38 (0 -584 8 ) (0 -576 8 ) (8 -576 8 ) (8 -584 8 ) +4 38 (136 -704 8 ) (128 -704 8 ) (128 -576 8 ) (136 -576 8 ) +4 38 (768 -352 8 ) (768 -448 8 ) (512 -704 8 ) (416 -704 8 ) +4 38 (768 0 8 ) (824 0 8 ) (824 -392 8 ) (768 -448 8 ) +4 38 (0 -760 8 ) (0 -704 8 ) (512 -704 8 ) (456 -760 8 ) +4 38 (152 -760 80 ) (152 -760 64 ) (168 -760 64 ) (168 -760 80 ) +4 38 (168 -760 240 ) (152 -760 240 ) (152 -760 224 ) (168 -760 224 ) +4 38 (184 -760 240 ) (168 -760 240 ) (168 -760 64 ) (184 -760 64 ) +4 38 (152 -760 240 ) (136 -760 240 ) (136 -760 64 ) (152 -760 64 ) +4 38 (824 -120 64 ) (824 -104 64 ) (824 -104 240 ) (824 -120 240 ) +4 38 (824 -104 224 ) (824 -88 224 ) (824 -88 240 ) (824 -104 240 ) +4 38 (824 -104 80 ) (824 -104 64 ) (824 -88 64 ) (824 -88 80 ) +4 38 (824 -88 64 ) (824 -72 64 ) (824 -72 240 ) (824 -88 240 ) +4 38 (456 -760 240 ) (456 -760 8 ) (824 -392 8 ) (824 -392 240 ) +4 39 (184 -760 240 ) (184 -760 64 ) (184 -764 64 ) (184 -764 240 ) +4 39 (184 -764 64 ) (184 -768 64 ) (184 -768 240 ) (184 -764 240 ) +4 39 (448 -768 240 ) (184 -768 240 ) (184 -768 64 ) (448 -768 64 ) +4 39 (448 -768 240 ) (448 -768 64 ) (456 -760 64 ) (456 -760 240 ) +4 40 (152 -760 224 ) (152 -764 224 ) (168 -764 224 ) (168 -760 224 ) +4 40 (152 -764 224 ) (152 -764 80 ) (168 -764 80 ) (168 -764 224 ) +4 40 (152 -760 224 ) (152 -760 80 ) (152 -764 80 ) (152 -764 224 ) +4 40 (168 -764 224 ) (168 -764 80 ) (168 -760 80 ) (168 -760 224 ) +4 40 (168 -760 80 ) (168 -764 80 ) (152 -764 80 ) (152 -760 80 ) +4 41 (136 -768 240 ) (136 -768 64 ) (136 -760 64 ) (136 -760 240 ) +4 41 (136 -768 240 ) (0 -768 240 ) (0 -768 64 ) (136 -768 64 ) +4 42 (0 -768 8 ) (0 -760 8 ) (456 -760 8 ) (448 -768 8 ) +4 42 (0 -768 8 ) (448 -768 8 ) (448 -768 64 ) (0 -768 64 ) +4 42 (152 -760 64 ) (136 -760 64 ) (136 -768 64 ) (152 -768 64 ) +4 42 (184 -764 64 ) (152 -764 64 ) (152 -768 64 ) (184 -768 64 ) +4 42 (168 -764 64 ) (184 -764 64 ) (184 -760 64 ) (168 -760 64 ) +4 42 (168 -764 64 ) (168 -760 64 ) (152 -760 64 ) (152 -764 64 ) +4 42 (456 -760 8 ) (456 -760 64 ) (448 -768 64 ) (448 -768 8 ) +4 43 (128 -344 -128 ) (136 -344 -128 ) (136 -344 -112 ) (128 -344 -112 ) +4 43 (768 0 8 ) (768 -344 8 ) (768 -344 -128 ) (768 0 -128 ) +4 43 (128 0 -120 ) (136 0 -120 ) (136 0 -128 ) (128 0 -128 ) +4 43 (8 0 -128 ) (768 0 -128 ) (768 -344 -128 ) (8 -344 -128 ) +5 44 (136 -344 -112 ) (136 -344 -128 ) (136 -704 -128 ) (136 -704 8 ) (136 -576 8 ) +5 44 (768 -344 -128 ) (768 -352 -128 ) (416 -704 -128 ) (136 -704 -128 ) (136 -344 -128 ) +4 44 (136 -704 -128 ) (416 -704 -128 ) (416 -704 8 ) (136 -704 8 ) +4 44 (768 -344 8 ) (768 -352 8 ) (768 -352 -128 ) (768 -344 -128 ) +4 44 (416 -704 8 ) (416 -704 -128 ) (768 -352 -128 ) (768 -352 8 ) +4 45 (128 -576 8 ) (128 -344 -112 ) (136 -344 -112 ) (136 -576 8 ) +3 46 (8 -436.799988 -64 ) (8 -480 -64 ) (8 -480 -41.655167 ) +4 46 (8 -480 -64 ) (8 -448 -64 ) (128 -448 -64 ) (128 -480 -64 ) +4 46 (8 -480 -48 ) (8 -480 -64 ) (128 -480 -64 ) (128 -480 -48 ) +3 46 (128 -480 -64 ) (128 -436.799988 -64 ) (128 -480 -41.655167 ) +4 47 (8 -480 -41.655163 ) (8 -480 -48 ) (8 -512 -48 ) (8 -512 -25.103441 ) +4 47 (8 -512 -32 ) (8 -512 -48 ) (128 -512 -48 ) (128 -512 -32 ) +4 47 (128 -512 -48 ) (128 -480 -48 ) (128 -480 -41.655167 ) (128 -512 -25.103443 ) +4 47 (128 -512 -48 ) (8 -512 -48 ) (8 -480 -48 ) (128 -480 -48 ) +4 48 (8 -405.866638 -80 ) (8 -448 -80 ) (8 -448 -64 ) (8 -436.799988 -64 ) +4 48 (8 -448 -80 ) (8 -416 -80 ) (128 -416 -80 ) (128 -448 -80 ) +4 48 (128 -448 -64 ) (128 -448 -80 ) (128 -405.866638 -80 ) (128 -436.799988 -64 ) +4 48 (8 -448 -80 ) (128 -448 -80 ) (128 -448 -64 ) (8 -448 -64 ) +4 49 (8 -512 -25.103439 ) (8 -512 -32 ) (8 -544 -32 ) (8 -544 -8.551716 ) +4 49 (8 -544 -16 ) (8 -544 -32 ) (128 -544 -32 ) (128 -544 -16 ) +4 49 (128 -544 -32 ) (128 -512 -32 ) (128 -512 -25.103443 ) (128 -544 -8.551723 ) +4 49 (128 -544 -32 ) (8 -544 -32 ) (8 -512 -32 ) (128 -512 -32 ) +4 50 (8 -374.933319 -96 ) (8 -416 -96 ) (8 -416 -80 ) (8 -405.866638 -80 ) +4 50 (8 -416 -96 ) (8 -384 -96 ) (128 -384 -96 ) (128 -416 -96 ) +4 50 (128 -416 -80 ) (128 -416 -96 ) (128 -374.933319 -96 ) (128 -405.866638 -80 ) +4 50 (8 -416 -96 ) (128 -416 -96 ) (128 -416 -80 ) (8 -416 -80 ) +5 51 (8 -544 -8.551715 ) (8 -544 -16 ) (8 -576 -16 ) (8 -576 0 ) (8 -560.533325 0 ) +3 51 (8 -576 8 ) (8 -560.533325 0 ) (8 -576 0 ) +4 51 (8 -576 0 ) (8 -576 -16 ) (128 -576 -16 ) (128 -576 0 ) +4 51 (128 -544 -16 ) (128 -544 -8.551723 ) (128 -576 8 ) (128 -576 -16 ) +4 51 (128 -576 -16 ) (8 -576 -16 ) (8 -544 -16 ) (128 -544 -16 ) +4 52 (8 -344 -112 ) (8 -384 -112 ) (8 -384 -96 ) (8 -374.933319 -96 ) +4 52 (8 -384 -112 ) (8 -352 -112 ) (128 -352 -112 ) (128 -384 -112 ) +4 52 (128 -374.933319 -96 ) (128 -384 -96 ) (128 -384 -112 ) (128 -344 -112 ) +4 52 (8 -384 -112 ) (128 -384 -112 ) (128 -384 -96 ) (8 -384 -96 ) +4 53 (8 -584 8 ) (8 -576 8 ) (8 -576 0 ) (8 -584 0 ) +4 53 (128 -704 0 ) (128 -704 8 ) (8 -704 8 ) (8 -704 0 ) +4 53 (128 -576 0 ) (128 -576 8 ) (128 -704 8 ) (128 -704 0 ) +4 53 (8 -704 0 ) (8 -576 0 ) (128 -576 0 ) (128 -704 0 ) +4 54 (8 -344 -128 ) (8 -352 -128 ) (8 -352 -112 ) (8 -344 -112 ) +4 54 (128 -352 -112 ) (128 -352 -128 ) (128 -344 -128 ) (128 -344 -112 ) +4 54 (8 -352 -128 ) (8 -344 -128 ) (128 -344 -128 ) (128 -352 -128 ) +4 54 (128 -352 -128 ) (128 -352 -112 ) (8 -352 -112 ) (8 -352 -128 ) +4 55 (0 -344 8 ) (0 0 8 ) (0 0 0 ) (0 -344 0 ) +4 55 (0 0 0 ) (0 0 -128 ) (0 -344 -128 ) (0 -344 0 ) +4 55 (0 -344 -128 ) (8 -344 -128 ) (8 -344 -112 ) (0 -344 -112 ) +4 55 (0 -344 -128 ) (0 0 -128 ) (8 0 -128 ) (8 -344 -128 ) +4 55 (8 0 -120 ) (8 0 -128 ) (0 0 -128 ) (0 0 -120 ) +4 56 (0 -576 8 ) (0 -344 8 ) (0 -344 0 ) (0 -560.533325 0 ) +4 56 (0 -560.532898 0 ) (8 -560.532898 0 ) (8 -576 8 ) (0 -576 8 ) +3 57 (0 -344 0 ) (0 -344 -112 ) (0 -560.533325 0 ) +4 57 (8 -560.532898 0 ) (0 -560.532898 0 ) (0 -344 -112 ) (8 -344 -112 ) +4 58 (8 -704 0 ) (8 -704 8 ) (0 -704 8 ) (0 -704 0 ) +4 58 (0 -584 0 ) (0 -584 8 ) (8 -584 8 ) (8 -584 0 ) +4 58 (0 -584 0 ) (8 -584 0 ) (8 -704 0 ) (0 -704 0 ) +4 59 (-448 160 288 ) (-448 256 288 ) (-192 512 288 ) (-96 512 288 ) +4 59 (-448 0 288 ) (-512 0 288 ) (-512 192 288 ) (-448 256 288 ) +4 59 (-192 512 288 ) (-128 576 288 ) (0 576 288 ) (0 512 288 ) +4 59 (-128 576 496 ) (0 576 496 ) (0 576 288 ) (-128 576 288 ) +5 59 (0 576 496 ) (-128 576 496 ) (-512 192 496 ) (-512 0 496 ) (0 0 496 ) +4 59 (-512 192 288 ) (-512 0 288 ) (-512 0 496 ) (-512 192 496 ) +4 59 (-128 576 496 ) (-128 576 288 ) (-512 192 288 ) (-512 192 496 ) +4 60 (-448 160 256 ) (-448 0 256 ) (-448 0 288 ) (-448 160 288 ) +4 60 (-96 512 288 ) (0 512 288 ) (0 512 256 ) (-96 512 256 ) +4 60 (-96 512 288 ) (-96 512 256 ) (-448 160 256 ) (-448 160 288 ) +4 61 (-448 160 8 ) (-448 256 8 ) (-192 512 8 ) (-96 512 8 ) +4 61 (0 0 8 ) (-8 0 8 ) (-8 328 8 ) (0 328 8 ) +4 61 (-192 512 8 ) (-128 576 8 ) (0 576 8 ) (0 512 8 ) +4 61 (-448 0 8 ) (-512 0 8 ) (-512 192 8 ) (-448 256 8 ) +4 61 (-512 192 8 ) (-512 0 8 ) (-512 0 256 ) (-512 192 256 ) +4 61 (-192 512 256 ) (0 512 256 ) (0 576 256 ) (-128 576 256 ) +4 61 (-448 256 256 ) (-512 192 256 ) (-512 0 256 ) (-448 0 256 ) +4 61 (-96 512 256 ) (-192 512 256 ) (-448 256 256 ) (-448 160 256 ) +4 61 (-128 576 256 ) (0 576 256 ) (0 576 8 ) (-128 576 8 ) +4 61 (-128 576 256 ) (-128 576 8 ) (-512 192 8 ) (-512 192 256 ) +4 62 (-8 512 8 ) (0 512 8 ) (0 512 0 ) (-8 512 0 ) +4 62 (-8 328 0 ) (-8 512 0 ) (0 512 0 ) (0 328 0 ) +4 62 (-8 328 8 ) (-8 328 0 ) (0 328 0 ) (0 328 8 ) +4 63 (-96 512 8 ) (-8 512 8 ) (-8 512 0 ) (-96 512 0 ) +4 63 (-448 0 0 ) (-448 0 8 ) (-448 160 8 ) (-448 160 0 ) +5 63 (-8 0 0 ) (-448 0 0 ) (-448 160 0 ) (-96 512 0 ) (-8 512 0 ) +4 63 (-8 328 8 ) (-8 0 8 ) (-8 0 0 ) (-8 328 0 ) +4 63 (-96 512 8 ) (-96 512 0 ) (-448 160 0 ) (-448 160 8 ) +4 64 (-96 -704 288 ) (-192 -704 288 ) (-448 -448 288 ) (-448 -352 288 ) +4 64 (-512 0 288 ) (-448 0 288 ) (-448 -448 288 ) (-512 -384 288 ) +4 64 (0 -704 288 ) (0 -768 288 ) (-128 -768 288 ) (-192 -704 288 ) +4 64 (-128 -768 288 ) (0 -768 288 ) (0 -768 496 ) (-128 -768 496 ) +5 64 (-512 -384 496 ) (-128 -768 496 ) (0 -768 496 ) (0 0 496 ) (-512 0 496 ) +4 64 (-512 0 288 ) (-512 -384 288 ) (-512 -384 496 ) (-512 0 496 ) +4 64 (-512 -384 496 ) (-512 -384 288 ) (-128 -768 288 ) (-128 -768 496 ) +4 65 (-448 0 256 ) (-448 -352 256 ) (-448 -352 288 ) (-448 0 288 ) +4 65 (-96 -704 256 ) (0 -704 256 ) (0 -704 288 ) (-96 -704 288 ) +4 65 (-448 -352 288 ) (-448 -352 256 ) (-96 -704 256 ) (-96 -704 288 ) +4 66 (-96 -704 8 ) (-192 -704 8 ) (-448 -448 8 ) (-448 -352 8 ) +4 66 (-8 0 8 ) (0 0 8 ) (0 -584 8 ) (-8 -584 8 ) +4 66 (0 -704 8 ) (0 -768 8 ) (-128 -768 8 ) (-192 -704 8 ) +4 66 (-504 0 8 ) (-448 0 8 ) (-448 -448 8 ) (-504 -392 8 ) +4 66 (-504 -88 64 ) (-504 -104 64 ) (-504 -104 80 ) (-504 -88 80 ) +4 66 (-504 -72 224 ) (-504 -72 64 ) (-504 -88 64 ) (-504 -88 224 ) +4 66 (-504 -104 240 ) (-504 -72 240 ) (-504 -72 224 ) (-504 -104 224 ) +4 66 (-504 -120 240 ) (-504 -104 240 ) (-504 -104 64 ) (-504 -120 64 ) +4 66 (-128 -768 8 ) (0 -768 8 ) (0 -768 256 ) (-128 -768 256 ) +4 66 (-128 -768 256 ) (0 -768 256 ) (0 -704 256 ) (-192 -704 256 ) +4 66 (-504 -392 256 ) (-448 -448 256 ) (-448 0 256 ) (-504 0 256 ) +4 66 (-448 -352 256 ) (-448 -448 256 ) (-192 -704 256 ) (-96 -704 256 ) +4 66 (-504 -392 256 ) (-504 -392 8 ) (-128 -768 8 ) (-128 -768 256 ) +4 67 (-508 -72 240 ) (-504 -72 240 ) (-504 -104 240 ) (-508 -104 240 ) +4 67 (-504 -104 240 ) (-504 -120 240 ) (-508 -120 240 ) (-508 -104 240 ) +4 67 (-512 -120 240 ) (-512 -72 240 ) (-508 -72 240 ) (-508 -120 240 ) +4 67 (-512 -384 256 ) (-504 -392 256 ) (-504 0 256 ) (-512 0 256 ) +4 67 (-512 -384 256 ) (-512 0 256 ) (-512 0 240 ) (-512 -384 240 ) +4 67 (-512 -384 256 ) (-512 -384 240 ) (-504 -392 240 ) (-504 -392 256 ) +4 68 (-508 -72 64 ) (-504 -72 64 ) (-504 -72 224 ) (-508 -72 224 ) +4 68 (-504 -72 224 ) (-504 -72 240 ) (-508 -72 240 ) (-508 -72 224 ) +4 68 (-512 -72 64 ) (-508 -72 64 ) (-508 -72 240 ) (-512 -72 240 ) +4 68 (-512 -72 240 ) (-512 0 240 ) (-512 0 64 ) (-512 -72 64 ) +4 69 (-504 -88 80 ) (-508 -88 80 ) (-508 -88 224 ) (-504 -88 224 ) +4 69 (-508 -104 224 ) (-508 -104 80 ) (-504 -104 80 ) (-504 -104 224 ) +4 69 (-508 -104 80 ) (-508 -104 224 ) (-508 -88 224 ) (-508 -88 80 ) +4 69 (-504 -88 224 ) (-508 -88 224 ) (-508 -104 224 ) (-504 -104 224 ) +4 69 (-504 -104 80 ) (-508 -104 80 ) (-508 -88 80 ) (-504 -88 80 ) +4 70 (-512 -384 240 ) (-512 -120 240 ) (-512 -120 64 ) (-512 -384 64 ) +4 70 (-512 -120 240 ) (-508 -120 240 ) (-508 -120 64 ) (-512 -120 64 ) +4 70 (-508 -120 240 ) (-504 -120 240 ) (-504 -120 64 ) (-508 -120 64 ) +4 70 (-512 -384 64 ) (-504 -392 64 ) (-504 -392 240 ) (-512 -384 240 ) +4 71 (-512 0 8 ) (-504 0 8 ) (-504 -392 8 ) (-512 -384 8 ) +4 71 (-512 0 8 ) (-512 -384 8 ) (-512 -384 64 ) (-512 0 64 ) +4 71 (-508 -120 64 ) (-508 -72 64 ) (-512 -72 64 ) (-512 -120 64 ) +4 71 (-508 -104 64 ) (-508 -120 64 ) (-504 -120 64 ) (-504 -104 64 ) +4 71 (-508 -88 64 ) (-504 -88 64 ) (-504 -72 64 ) (-508 -72 64 ) +4 71 (-508 -88 64 ) (-508 -104 64 ) (-504 -104 64 ) (-504 -88 64 ) +4 71 (-504 -392 8 ) (-504 -392 64 ) (-512 -384 64 ) (-512 -384 8 ) +4 72 (-8 -704 0 ) (0 -704 0 ) (0 -704 8 ) (-8 -704 8 ) +4 72 (0 -704 0 ) (-8 -704 0 ) (-8 -584 0 ) (0 -584 0 ) +4 72 (0 -584 8 ) (0 -584 0 ) (-8 -584 0 ) (-8 -584 8 ) +4 73 (-96 -704 0 ) (-8 -704 0 ) (-8 -704 8 ) (-96 -704 8 ) +4 73 (-448 -352 8 ) (-448 0 8 ) (-448 0 0 ) (-448 -352 0 ) +5 73 (-8 -704 0 ) (-96 -704 0 ) (-448 -352 0 ) (-448 0 0 ) (-8 0 0 ) +4 73 (-8 0 8 ) (-8 -584 8 ) (-8 -584 0 ) (-8 0 0 ) +4 73 (-448 -352 8 ) (-448 -352 0 ) (-96 -704 0 ) (-96 -704 8 ) diff --git a/fakk/maps/example/gibs_and_health.pth b/fakk/maps/example/gibs_and_health.pth new file mode 100644 index 0000000..3315dea Binary files /dev/null and b/fakk/maps/example/gibs_and_health.pth differ diff --git a/fakk/maps/example/letterbox.bsp b/fakk/maps/example/letterbox.bsp new file mode 100644 index 0000000..6cbbd87 Binary files /dev/null and b/fakk/maps/example/letterbox.bsp differ diff --git a/fakk/maps/example/letterbox.map b/fakk/maps/example/letterbox.map new file mode 100644 index 0000000..54339eb --- /dev/null +++ b/fakk/maps/example/letterbox.map @@ -0,0 +1,145 @@ +{ +"classname" "worldspawn" +// brush 0 +{ +( 264 264 -8 ) ( -264 264 -8 ) ( -264 -272 -8 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 -272 264 ) ( -264 264 264 ) ( 264 264 264 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 -264 8 ) ( 264 -264 8 ) ( 264 -264 0 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( 264 264 8 ) ( -264 264 8 ) ( -264 264 0 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 264 8 ) ( -264 -272 8 ) ( -264 -272 0 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( -256 -272 8 ) ( -256 264 8 ) ( -256 -272 0 ) eden/FL_edenhouse2 0 0 0.00 1 1 0 0 0 +} +// brush 1 +{ +( 264 264 -8 ) ( -264 264 -8 ) ( -264 -272 -8 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 -272 264 ) ( -264 264 264 ) ( 264 264 264 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( 264 -272 8 ) ( 264 264 8 ) ( 264 264 0 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( 264 264 8 ) ( -264 264 8 ) ( -264 264 0 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 264 8 ) ( -264 -272 8 ) ( -264 -272 0 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 256 8 ) ( 264 256 8 ) ( -264 256 0 ) eden/FL_edenhouse2 0 0 0.00 1 1 0 0 0 +} +// brush 2 +{ +( 264 264 -8 ) ( -264 264 -8 ) ( -264 -272 -8 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 -272 264 ) ( -264 264 264 ) ( 264 264 264 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 -264 8 ) ( 264 -264 8 ) ( 264 -264 0 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( 264 -272 8 ) ( 264 264 8 ) ( 264 264 0 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( 264 264 8 ) ( -264 264 8 ) ( -264 264 0 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( 256 264 8 ) ( 256 -272 8 ) ( 256 264 0 ) eden/FL_edenhouse2 0 0 0.00 1 1 0 0 0 +} +// brush 3 +{ +( 264 264 -8 ) ( -264 264 -8 ) ( -264 -272 -8 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 -272 264 ) ( -264 264 264 ) ( 264 264 264 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 -264 8 ) ( 264 -264 8 ) ( 264 -264 0 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( 264 -272 8 ) ( 264 264 8 ) ( 264 264 0 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 264 8 ) ( -264 -272 8 ) ( -264 -272 0 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( 264 -256 8 ) ( -264 -256 8 ) ( 264 -256 0 ) eden/FL_edenhouse2 0 0 0.00 1 1 0 0 0 +} +// brush 4 +{ +( -264 -272 264 ) ( -264 264 264 ) ( 264 264 264 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 -264 8 ) ( 264 -264 8 ) ( 264 -264 0 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( 264 -272 8 ) ( 264 264 8 ) ( 264 264 0 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( 264 264 8 ) ( -264 264 8 ) ( -264 264 0 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 264 8 ) ( -264 -272 8 ) ( -264 -272 0 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 264 256 ) ( -264 -272 256 ) ( 264 264 256 ) eden/FL_edenhouse2 0 0 0.00 1 1 0 0 0 +} +// brush 5 +{ +( 264 264 -8 ) ( -264 264 -8 ) ( -264 -272 -8 ) eden/FL_edenhouse2 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 -264 8 ) ( 264 -264 8 ) ( 264 -264 0 ) eden/FL_edenhouse2 0 0 0.00 0.500000 0.500000 0 0 0 +( 264 -272 8 ) ( 264 264 8 ) ( 264 264 0 ) eden/FL_edenhouse2 0 0 0.00 0.500000 0.500000 0 0 0 +( 264 264 8 ) ( -264 264 8 ) ( -264 264 0 ) eden/FL_edenhouse2 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 264 8 ) ( -264 -272 8 ) ( -264 -272 0 ) eden/FL_edenhouse2 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 264 0 ) ( 264 264 0 ) ( -264 -272 0 ) eden/FL_edenhouse2 0 0 0.00 0.500000 0.500000 0 0 0 +} +} +// entity 1 +{ +"classname" "func_beam" +"spawnflags" "11" +"target" "t1" +"minoffset" "1" +"origin" "-164 132 100" +"maxoffset" "10" +"numsegments" "7" +"color" "1 0.2 0.2" +"alpha" "0.8" +"endalpha" "0" +"delay" "0" +"life" "0.4" +"scale" "2" +"targetname" "beam" +} +// entity 2 +{ +"targetname" "t1" +"classname" "script_object" +// brush 0 +{ +( 140 148 84 ) ( 108 148 84 ) ( 108 116 84 ) eden/LT_edenlt12w 12 20 0.00 -1 1 0 0 0 +( 108 116 116 ) ( 108 148 116 ) ( 140 148 116 ) eden/LT_edenlt12w 12 20 0.00 -1 1 0 0 0 +( 108 116 116 ) ( 140 116 116 ) ( 140 116 84 ) eden/LT_edenlt12w 12 20 0.00 -1 1 0 0 0 +( 140 116 116 ) ( 140 148 116 ) ( 140 148 84 ) eden/LT_edenlt12w 20 20 0.00 -1 1 0 0 0 +( 140 148 116 ) ( 108 148 116 ) ( 108 148 84 ) eden/LT_edenlt12w 12 20 0.00 -1 1 0 0 0 +( 108 148 116 ) ( 108 116 116 ) ( 108 116 84 ) eden/LT_edenlt12w 20 20 0.00 -1 1 0 0 0 +} +} +// entity 3 +{ +"classname" "info_pathnode" +"origin" "-192 192 0" +} +// entity 4 +{ +"origin" "0 0 128" +"light" "1000" +"classname" "light" +} +// entity 5 +{ +"origin" "0 -192 16" +"angle" "90" +"classname" "info_player_start" +} +// entity 6 +{ +"origin" "0 192 0" +"classname" "info_pathnode" +} +// entity 7 +{ +"classname" "info_pathnode" +"origin" "192 192 0" +} +// entity 8 +{ +"origin" "192 0 0" +"classname" "info_pathnode" +} +// entity 9 +{ +"classname" "info_pathnode" +"origin" "0 0 0" +} +// entity 10 +{ +"origin" "-192 0 0" +"classname" "info_pathnode" +} +// entity 11 +{ +"classname" "info_pathnode" +"origin" "-192 -192 0" +} +// entity 12 +{ +"origin" "0 -192 0" +"classname" "info_pathnode" +} +// entity 13 +{ +"classname" "info_pathnode" +"origin" "192 -192 0" +} diff --git a/fakk/maps/example/letterbox.prt b/fakk/maps/example/letterbox.prt new file mode 100644 index 0000000..b8dfdf5 --- /dev/null +++ b/fakk/maps/example/letterbox.prt @@ -0,0 +1,24 @@ +PRT1 +4 +4 +16 +4 0 2 0 (0 0 0 ) (0 0 256 ) (0 256 256 ) (0 256 0 ) +4 0 1 0 (0 0 256 ) (0 0 0 ) (256 0 0 ) (256 0 256 ) +4 1 3 0 (0 0 256 ) (0 0 0 ) (0 -256 0 ) (0 -256 256 ) +4 2 3 0 (0 0 0 ) (0 0 256 ) (-256 0 256 ) (-256 0 0 ) +4 0 (256 0 256 ) (256 0 0 ) (256 256 0 ) (256 256 256 ) +4 0 (256 256 256 ) (256 256 0 ) (0 256 0 ) (0 256 256 ) +4 0 (256 0 0 ) (0 0 0 ) (0 256 0 ) (256 256 0 ) +4 0 (0 0 256 ) (256 0 256 ) (256 256 256 ) (0 256 256 ) +4 1 (0 -256 256 ) (0 -256 0 ) (256 -256 0 ) (256 -256 256 ) +4 1 (256 -256 256 ) (256 -256 0 ) (256 0 0 ) (256 0 256 ) +4 1 (0 -256 0 ) (0 0 0 ) (256 0 0 ) (256 -256 0 ) +4 1 (256 0 256 ) (0 0 256 ) (0 -256 256 ) (256 -256 256 ) +4 2 (0 256 256 ) (0 256 0 ) (-256 256 0 ) (-256 256 256 ) +4 2 (-256 0 0 ) (-256 0 256 ) (-256 256 256 ) (-256 256 0 ) +4 2 (0 0 0 ) (-256 0 0 ) (-256 256 0 ) (0 256 0 ) +4 2 (0 256 256 ) (-256 256 256 ) (-256 0 256 ) (0 0 256 ) +4 3 (-256 -256 256 ) (-256 -256 0 ) (0 -256 0 ) (0 -256 256 ) +4 3 (-256 0 256 ) (-256 0 0 ) (-256 -256 0 ) (-256 -256 256 ) +4 3 (-256 -256 0 ) (-256 0 0 ) (0 0 0 ) (0 -256 0 ) +4 3 (0 0 256 ) (-256 0 256 ) (-256 -256 256 ) (0 -256 256 ) diff --git a/fakk/maps/example/letterbox.pth b/fakk/maps/example/letterbox.pth new file mode 100644 index 0000000..baff403 Binary files /dev/null and b/fakk/maps/example/letterbox.pth differ diff --git a/fakk/maps/example/letterbox.scr b/fakk/maps/example/letterbox.scr new file mode 100644 index 0000000..91dc144 --- /dev/null +++ b/fakk/maps/example/letterbox.scr @@ -0,0 +1,16 @@ +waitforplayer +//fadeout 3 0 0 0 1 +//wait 3 +//clearfade + +top: +wait 5 +$beam activate +//fadeout 2 1 1 1 1 +letterbox 1 +wait 8 +$beam deactivate +clearletterbox 1 +//fadein 2 1 1 1 1 +goto top +end diff --git a/fakk/maps/example/multiexploder.bsp b/fakk/maps/example/multiexploder.bsp new file mode 100644 index 0000000..af2addb Binary files /dev/null and b/fakk/maps/example/multiexploder.bsp differ diff --git a/fakk/maps/example/multiexploder.map b/fakk/maps/example/multiexploder.map new file mode 100644 index 0000000..8fe5309 --- /dev/null +++ b/fakk/maps/example/multiexploder.map @@ -0,0 +1,108 @@ +{ +"classname" "worldspawn" +// brush 0 +{ +( 64 64 0 ) ( -64 64 0 ) ( -64 -64 0 ) eden/FL_underground 0 0 0.00 1 1 0 0 0 +( -64 -64 8 ) ( -64 64 8 ) ( 64 64 8 ) eden/FL_underground 0 0 0.00 1 1 0 0 0 +( -72 -64 8 ) ( 56 -64 8 ) ( 56 -64 0 ) eden/FL_underground 0 0 0.00 1 1 0 0 0 +( 64 -64 8 ) ( 64 64 8 ) ( 64 64 0 ) eden/FL_underground 0 0 0.00 1 1 0 0 0 +( 64 64 8 ) ( -64 64 8 ) ( -64 64 0 ) eden/FL_underground 0 0 0.00 1 1 0 0 0 +( -64 64 8 ) ( -64 -64 8 ) ( -64 -64 0 ) eden/FL_underground 0 0 0.00 1 1 0 0 0 +} +// brush 1 +{ +( 264 264 -8 ) ( -264 264 -8 ) ( -264 -272 -8 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 -272 264 ) ( -264 264 264 ) ( 264 264 264 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 -264 8 ) ( 264 -264 8 ) ( 264 -264 0 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( 264 264 8 ) ( -264 264 8 ) ( -264 264 0 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 264 8 ) ( -264 -272 8 ) ( -264 -272 0 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( -256 -272 8 ) ( -256 264 8 ) ( -256 -272 0 ) eden/FL_edenhouse2 0 0 0.00 1 1 0 0 0 +} +// brush 2 +{ +( 264 264 -8 ) ( -264 264 -8 ) ( -264 -272 -8 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 -272 264 ) ( -264 264 264 ) ( 264 264 264 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( 264 -272 8 ) ( 264 264 8 ) ( 264 264 0 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( 264 264 8 ) ( -264 264 8 ) ( -264 264 0 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 264 8 ) ( -264 -272 8 ) ( -264 -272 0 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 256 8 ) ( 264 256 8 ) ( -264 256 0 ) eden/FL_edenhouse2 0 0 0.00 1 1 0 0 0 +} +// brush 3 +{ +( 264 264 -8 ) ( -264 264 -8 ) ( -264 -272 -8 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 -272 264 ) ( -264 264 264 ) ( 264 264 264 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 -264 8 ) ( 264 -264 8 ) ( 264 -264 0 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( 264 -272 8 ) ( 264 264 8 ) ( 264 264 0 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( 264 264 8 ) ( -264 264 8 ) ( -264 264 0 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( 256 264 8 ) ( 256 -272 8 ) ( 256 264 0 ) eden/FL_edenhouse2 0 0 0.00 1 1 0 0 0 +} +// brush 4 +{ +( 264 264 -8 ) ( -264 264 -8 ) ( -264 -272 -8 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 -272 264 ) ( -264 264 264 ) ( 264 264 264 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 -264 8 ) ( 264 -264 8 ) ( 264 -264 0 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( 264 -272 8 ) ( 264 264 8 ) ( 264 264 0 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 264 8 ) ( -264 -272 8 ) ( -264 -272 0 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( 264 -256 8 ) ( -264 -256 8 ) ( 264 -256 0 ) eden/FL_edenhouse2 0 0 0.00 1 1 0 0 0 +} +// brush 5 +{ +( -264 -272 264 ) ( -264 264 264 ) ( 264 264 264 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 -264 8 ) ( 264 -264 8 ) ( 264 -264 0 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( 264 -272 8 ) ( 264 264 8 ) ( 264 264 0 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( 264 264 8 ) ( -264 264 8 ) ( -264 264 0 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 264 8 ) ( -264 -272 8 ) ( -264 -272 0 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 264 256 ) ( -264 -272 256 ) ( 264 264 256 ) eden/FL_edenhouse2 0 0 0.00 1 1 0 0 0 +} +// brush 6 +{ +( 264 264 -8 ) ( -264 264 -8 ) ( -264 -272 -8 ) eden/FL_edenhouse2 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 -264 8 ) ( 264 -264 8 ) ( 264 -264 0 ) eden/FL_edenhouse2 0 0 0.00 0.500000 0.500000 0 0 0 +( 264 -272 8 ) ( 264 264 8 ) ( 264 264 0 ) eden/FL_edenhouse2 0 0 0.00 0.500000 0.500000 0 0 0 +( 264 264 8 ) ( -264 264 8 ) ( -264 264 0 ) eden/FL_edenhouse2 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 264 8 ) ( -264 -272 8 ) ( -264 -272 0 ) eden/FL_edenhouse2 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 264 0 ) ( 264 264 0 ) ( -264 -272 0 ) eden/FL_edenhouse2 0 0 0.00 0.500000 0.500000 0 0 0 +} +} +// entity 1 +{ +"classname" "func_multi_exploder" +"targetname" "t1" +"duration" "4" +// brush 0 +{ +( 16 240 48 ) ( -16 240 48 ) ( -16 208 48 ) notexture 0 -24 0.00 1 1 0 0 0 +( -16 208 192 ) ( -16 240 192 ) ( 16 240 192 ) notexture 0 -24 0.00 1 1 0 0 0 +( -16 160 192 ) ( 16 160 192 ) ( 16 160 184 ) eden/FL_underground 0 0 0.00 1 1 0 0 0 +( 128 208 192 ) ( 128 240 192 ) ( 128 240 184 ) notexture 24 -8 0.00 1 1 0 0 0 +( 16 224 192 ) ( -16 224 192 ) ( -16 224 184 ) notexture 0 -8 0.00 1 1 0 0 0 +( -128 240 192 ) ( -128 208 192 ) ( -128 208 184 ) notexture 24 -8 0.00 1 1 0 0 0 +} +} +// entity 2 +{ +"wait" "5" +"classname" "trigger_multiple" +"target" "t1" +// brush 0 +{ +( 64 64 8 ) ( -56 64 8 ) ( -56 -64 8 ) common/trigger 0 0 0.00 1 1 0 128 0 +( -56 -64 192 ) ( -56 64 192 ) ( 64 64 192 ) common/trigger 0 0 0.00 1 1 0 128 0 +( -56 -64 16 ) ( 64 -64 16 ) ( 64 -64 8 ) common/trigger 0 0 0.00 1 1 0 128 0 +( 64 -64 16 ) ( 64 64 16 ) ( 64 64 8 ) common/trigger 0 0 0.00 1 1 0 128 0 +( 64 64 16 ) ( -56 64 16 ) ( -56 64 8 ) common/trigger 0 0 0.00 1 1 0 128 0 +( -64 64 16 ) ( -64 -64 16 ) ( -64 -64 8 ) common/trigger 0 0 0.00 1 1 0 128 0 +} +} +// entity 3 +{ +"classname" "light" +"light" "1000" +"origin" "0 0 128" +} +// entity 4 +{ +"classname" "info_player_start" +"angle" "90" +"origin" "0 -192 16" +} diff --git a/fakk/maps/example/multiexploder.prt b/fakk/maps/example/multiexploder.prt new file mode 100644 index 0000000..67779b6 --- /dev/null +++ b/fakk/maps/example/multiexploder.prt @@ -0,0 +1,68 @@ +PRT1 +12 +20 +44 +4 0 6 0 (0 0 8 ) (0 0 256 ) (0 256 256 ) (0 256 8 ) +4 0 3 0 (0 0 256 ) (0 0 8 ) (256 0 8 ) (256 0 256 ) +4 0 2 0 (0 256 8 ) (64 256 8 ) (64 64 8 ) (0 64 8 ) +4 0 1 0 (64 256 8 ) (256 256 8 ) (256 0 8 ) (64 0 8 ) +4 1 4 0 (64 0 0 ) (256 0 0 ) (256 0 8 ) (64 0 8 ) +4 1 2 0 (64 256 0 ) (64 64 0 ) (64 64 8 ) (64 256 8 ) +4 2 7 0 (0 64 8 ) (0 256 8 ) (0 256 0 ) (0 64 0 ) +4 3 9 0 (0 0 256 ) (0 0 8 ) (0 -256 8 ) (0 -256 256 ) +4 3 5 0 (64 -256 8 ) (0 -256 8 ) (0 -64 8 ) (64 -64 8 ) +4 3 4 0 (256 -256 8 ) (64 -256 8 ) (64 0 8 ) (256 0 8 ) +4 4 5 0 (64 -64 0 ) (64 -256 0 ) (64 -256 8 ) (64 -64 8 ) +4 5 10 0 (0 -64 0 ) (0 -256 0 ) (0 -256 8 ) (0 -64 8 ) +4 6 9 0 (0 0 8 ) (0 0 256 ) (-256 0 256 ) (-256 0 8 ) +4 6 7 0 (-64 64 8 ) (-64 256 8 ) (0 256 8 ) (0 64 8 ) +4 6 8 0 (-64 0 8 ) (-256 0 8 ) (-256 256 8 ) (-64 256 8 ) +4 7 8 0 (-64 64 8 ) (-64 256 8 ) (-64 256 0 ) (-64 64 0 ) +4 8 11 0 (-64 0 8 ) (-256 0 8 ) (-256 0 0 ) (-64 0 0 ) +4 9 10 0 (0 -256 8 ) (-64 -256 8 ) (-64 -64 8 ) (0 -64 8 ) +4 9 11 0 (-64 -256 8 ) (-256 -256 8 ) (-256 0 8 ) (-64 0 8 ) +4 10 11 0 (-64 -64 0 ) (-64 -256 0 ) (-64 -256 8 ) (-64 -64 8 ) +4 0 (64 64 8 ) (64 0 8 ) (0 0 8 ) (0 64 8 ) +4 0 (0 0 256 ) (256 0 256 ) (256 256 256 ) (0 256 256 ) +4 0 (256 256 256 ) (256 256 8 ) (0 256 8 ) (0 256 256 ) +4 0 (256 0 256 ) (256 0 8 ) (256 256 8 ) (256 256 256 ) +4 1 (64 64 0 ) (64 0 0 ) (64 0 8 ) (64 64 8 ) +4 1 (256 0 8 ) (256 0 0 ) (256 256 0 ) (256 256 8 ) +4 1 (64 256 8 ) (256 256 8 ) (256 256 0 ) (64 256 0 ) +4 1 (256 0 0 ) (64 0 0 ) (64 256 0 ) (256 256 0 ) +4 2 (0 64 0 ) (0 256 0 ) (64 256 0 ) (64 64 0 ) +4 2 (64 256 8 ) (64 256 0 ) (0 256 0 ) (0 256 8 ) +4 2 (0 64 0 ) (64 64 0 ) (64 64 8 ) (0 64 8 ) +4 3 (0 -64 8 ) (0 0 8 ) (64 0 8 ) (64 -64 8 ) +4 3 (256 0 256 ) (0 0 256 ) (0 -256 256 ) (256 -256 256 ) +4 3 (256 -256 256 ) (256 -256 8 ) (256 0 8 ) (256 0 256 ) +4 3 (0 -256 256 ) (0 -256 8 ) (256 -256 8 ) (256 -256 256 ) +4 4 (64 0 0 ) (64 -64 0 ) (64 -64 8 ) (64 0 8 ) +4 4 (64 -256 0 ) (256 -256 0 ) (256 -256 8 ) (64 -256 8 ) +4 4 (256 -256 8 ) (256 -256 0 ) (256 0 0 ) (256 0 8 ) +4 4 (64 0 0 ) (256 0 0 ) (256 -256 0 ) (64 -256 0 ) +4 5 (0 -256 0 ) (0 -64 0 ) (64 -64 0 ) (64 -256 0 ) +4 5 (0 -256 8 ) (0 -256 0 ) (64 -256 0 ) (64 -256 8 ) +4 5 (0 -64 8 ) (64 -64 8 ) (64 -64 0 ) (0 -64 0 ) +4 6 (0 0 8 ) (-64 0 8 ) (-64 64 8 ) (0 64 8 ) +4 6 (0 256 256 ) (-256 256 256 ) (-256 0 256 ) (0 0 256 ) +4 6 (-256 0 8 ) (-256 0 256 ) (-256 256 256 ) (-256 256 8 ) +4 6 (0 256 256 ) (0 256 8 ) (-256 256 8 ) (-256 256 256 ) +4 7 (-64 64 0 ) (-64 256 0 ) (0 256 0 ) (0 64 0 ) +4 7 (-64 256 8 ) (0 256 8 ) (0 256 0 ) (-64 256 0 ) +4 7 (-64 64 8 ) (-64 64 0 ) (0 64 0 ) (0 64 8 ) +4 8 (-64 0 0 ) (-64 64 0 ) (-64 64 8 ) (-64 0 8 ) +4 8 (-64 256 8 ) (-64 256 0 ) (-256 256 0 ) (-256 256 8 ) +4 8 (-256 0 0 ) (-256 0 8 ) (-256 256 8 ) (-256 256 0 ) +4 8 (-64 0 0 ) (-256 0 0 ) (-256 256 0 ) (-64 256 0 ) +4 9 (-64 -64 8 ) (-64 0 8 ) (0 0 8 ) (0 -64 8 ) +4 9 (0 0 256 ) (-256 0 256 ) (-256 -256 256 ) (0 -256 256 ) +4 9 (-256 0 256 ) (-256 0 8 ) (-256 -256 8 ) (-256 -256 256 ) +4 9 (-256 -256 256 ) (-256 -256 8 ) (0 -256 8 ) (0 -256 256 ) +4 10 (0 -64 0 ) (0 -256 0 ) (-64 -256 0 ) (-64 -64 0 ) +4 10 (-64 -256 0 ) (0 -256 0 ) (0 -256 8 ) (-64 -256 8 ) +4 10 (0 -64 8 ) (0 -64 0 ) (-64 -64 0 ) (-64 -64 8 ) +4 11 (-64 0 8 ) (-64 -64 8 ) (-64 -64 0 ) (-64 0 0 ) +4 11 (-256 -256 8 ) (-256 -256 0 ) (-64 -256 0 ) (-64 -256 8 ) +4 11 (-256 0 8 ) (-256 0 0 ) (-256 -256 0 ) (-256 -256 8 ) +4 11 (-256 -256 0 ) (-256 0 0 ) (-64 0 0 ) (-64 -256 0 ) diff --git a/fakk/maps/example/patrol.bsp b/fakk/maps/example/patrol.bsp new file mode 100644 index 0000000..687c764 Binary files /dev/null and b/fakk/maps/example/patrol.bsp differ diff --git a/fakk/maps/example/patrol.map b/fakk/maps/example/patrol.map new file mode 100644 index 0000000..a3ae506 --- /dev/null +++ b/fakk/maps/example/patrol.map @@ -0,0 +1,1397 @@ +{ +"classname" "worldspawn" +// brush 0 +{ +( 152 560 64 ) ( 152 576 64 ) ( 136 576 64 ) eden/genmetal 0 8 0.00 1 1 0 0 0 +( 136 576 240 ) ( 152 576 240 ) ( 152 560 240 ) eden/genmetal 0 8 0.00 1 1 0 0 0 +( 136 576 256 ) ( 136 560 256 ) ( 136 560 0 ) eden/genmetal -32 0 0.00 1 1 0 0 0 +( 136 568 256 ) ( 152 568 256 ) ( 152 568 0 ) eden/genmetal 24 0 0.00 1 1 0 0 0 +( 152 568 256 ) ( 152 584 256 ) ( 152 584 0 ) eden/genmetal -32 0 0.00 1 1 0 0 0 +( 152 576 256 ) ( 136 576 256 ) ( 136 576 0 ) eden/genmetal 56 0 -180.00 1 -1 0 0 0 +} +// brush 1 +{ +( 184 560 64 ) ( 184 576 64 ) ( 168 576 64 ) eden/genmetal 0 -8 0.00 1 1 0 0 0 +( 168 576 240 ) ( 184 576 240 ) ( 184 560 240 ) eden/genmetal 0 -8 0.00 1 1 0 0 0 +( 168 584 256 ) ( 168 568 256 ) ( 168 568 0 ) eden/genmetal -32 0 0.00 1 1 0 0 0 +( 168 568 256 ) ( 184 568 256 ) ( 184 568 0 ) eden/genmetal 40 0 0.00 1 1 0 0 0 +( 184 560 256 ) ( 184 576 256 ) ( 184 576 0 ) eden/genmetal -32 0 0.00 1 1 0 0 0 +( 184 576 256 ) ( 168 576 256 ) ( 168 576 0 ) eden/genmetal 72 0 -180.00 1 -1 0 0 0 +} +// brush 2 +{ +( 176 576 272 ) ( 144 576 272 ) ( 144 576 16 ) eden/genmetal 32 16 0.00 1 1 0 0 0 +( 168 568 272 ) ( 168 584 272 ) ( 168 584 16 ) eden/genmetal -32 16 0.00 1 1 0 0 0 +( 136 568 256 ) ( 168 568 256 ) ( 168 568 0 ) eden/genmetal 32 16 0.00 1 1 0 0 0 +( 152 584 272 ) ( 152 568 272 ) ( 152 568 16 ) eden/genmetal -32 16 0.00 1 1 0 0 0 +( 144 576 80 ) ( 176 576 80 ) ( 176 560 80 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( 176 560 64 ) ( 176 576 64 ) ( 144 576 64 ) eden/genmetal 0 -64 90.00 1 1 0 0 0 +} +// brush 3 +{ +( 176 576 432 ) ( 144 576 432 ) ( 144 576 176 ) eden/genmetal 32 48 0.00 1 1 0 0 0 +( 168 568 432 ) ( 168 584 432 ) ( 168 584 176 ) eden/genmetal -32 48 0.00 1 1 0 0 0 +( 136 568 416 ) ( 168 568 416 ) ( 168 568 160 ) eden/genmetal 32 48 0.00 1 1 0 0 0 +( 152 584 432 ) ( 152 568 432 ) ( 152 568 176 ) eden/genmetal -32 48 0.00 1 1 0 0 0 +( 144 576 240 ) ( 176 576 240 ) ( 176 560 240 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( 176 560 224 ) ( 176 576 224 ) ( 144 576 224 ) eden/genmetal 0 -64 90.00 1 1 0 0 0 +} +// brush 4 +{ +( 168 576 240 ) ( 152 576 240 ) ( 152 576 64 ) otto/ottolight 35 -16 90.00 -2.250000 -0.500000 0 0 0 +( 168 568 240 ) ( 168 576 240 ) ( 168 576 64 ) otto/ottolight 35 16 90.00 -2.250000 -0.500000 0 0 0 +( 152 572 240 ) ( 168 572 240 ) ( 168 572 64 ) otto/ottolight 35 -16 90.00 -2.250000 -0.500000 0 0 0 +( 152 576 240 ) ( 152 568 240 ) ( 152 568 64 ) otto/ottolight 35 16 90.00 -2.250000 -0.500000 0 0 0 +( 152 576 224 ) ( 168 576 224 ) ( 168 568 224 ) otto/ottolight 35 -16 90.00 -2.250000 -0.500000 0 0 0 +( 168 568 80 ) ( 168 576 80 ) ( 152 576 80 ) otto/ottolight 6 16 0.00 2.250000 0.500000 0 0 0 +} +// brush 5 +{ +( 152 -768 64 ) ( 152 -768 240 ) ( 168 -768 240 ) otto/ottolight 35 -16 90.00 -2.250000 -0.500000 0 0 0 +( 168 -768 64 ) ( 168 -768 240 ) ( 168 -760 240 ) otto/ottolight 34 16 90.00 -2.250000 -0.500000 0 0 0 +( 168 -764 64 ) ( 168 -764 240 ) ( 152 -764 240 ) otto/ottolight 35 -16 90.00 -2.250000 -0.500000 0 0 0 +( 152 -760 64 ) ( 152 -760 240 ) ( 152 -768 240 ) otto/ottolight 34 16 90.00 -2.250000 -0.500000 0 0 0 +( 168 -760 224 ) ( 168 -768 224 ) ( 152 -768 224 ) otto/ottolight 34 -16 90.00 -2.250000 -0.500000 0 0 0 +( 152 -768 80 ) ( 168 -768 80 ) ( 168 -760 80 ) otto/ottolight 5 16 0.00 2.250000 0.500000 0 0 0 +} +// brush 6 +{ +( 144 -768 176 ) ( 144 -768 432 ) ( 176 -768 432 ) eden/genmetal 32 48 0.00 1 1 0 0 0 +( 168 -776 176 ) ( 168 -776 432 ) ( 168 -760 432 ) eden/genmetal -96 48 0.00 1 1 0 0 0 +( 168 -760 160 ) ( 168 -760 416 ) ( 136 -760 416 ) eden/genmetal 32 48 0.00 1 1 0 0 0 +( 152 -760 176 ) ( 152 -760 432 ) ( 152 -776 432 ) eden/genmetal -96 48 0.00 1 1 0 0 0 +( 176 -752 240 ) ( 176 -768 240 ) ( 144 -768 240 ) eden/genmetal -64 0 0.00 1 1 0 0 0 +( 144 -768 224 ) ( 176 -768 224 ) ( 176 -752 224 ) eden/genmetal 64 -63 90.00 1 1 0 0 0 +} +// brush 7 +{ +( 144 -768 16 ) ( 144 -768 272 ) ( 176 -768 272 ) eden/genmetal 32 16 0.00 1 1 0 0 0 +( 168 -776 16 ) ( 168 -776 272 ) ( 168 -760 272 ) eden/genmetal -96 16 0.00 1 1 0 0 0 +( 168 -760 0 ) ( 168 -760 256 ) ( 136 -760 256 ) eden/genmetal 32 16 0.00 1 1 0 0 0 +( 152 -760 16 ) ( 152 -760 272 ) ( 152 -776 272 ) eden/genmetal -96 16 0.00 1 1 0 0 0 +( 176 -752 80 ) ( 176 -768 80 ) ( 144 -768 80 ) eden/genmetal -64 0 0.00 1 1 0 0 0 +( 144 -768 64 ) ( 176 -768 64 ) ( 176 -752 64 ) eden/genmetal 64 -63 90.00 1 1 0 0 0 +} +// brush 8 +{ +( 168 -768 64 ) ( 184 -768 64 ) ( 184 -752 64 ) eden/genmetal -64 -8 0.00 1 1 0 0 0 +( 184 -752 240 ) ( 184 -768 240 ) ( 168 -768 240 ) eden/genmetal -64 -8 0.00 1 1 0 0 0 +( 168 -760 0 ) ( 168 -760 256 ) ( 168 -776 256 ) eden/genmetal -96 0 0.00 1 1 0 0 0 +( 184 -760 0 ) ( 184 -760 256 ) ( 168 -760 256 ) eden/genmetal 40 0 0.00 1 1 0 0 0 +( 184 -768 0 ) ( 184 -768 256 ) ( 184 -752 256 ) eden/genmetal -96 0 0.00 1 1 0 0 0 +( 168 -768 0 ) ( 168 -768 256 ) ( 184 -768 256 ) eden/genmetal 71 0 -180.00 1 -1 0 0 0 +} +// brush 9 +{ +( 136 -768 64 ) ( 152 -768 64 ) ( 152 -752 64 ) eden/genmetal -64 8 0.00 1 1 0 0 0 +( 152 -752 240 ) ( 152 -768 240 ) ( 136 -768 240 ) eden/genmetal -64 8 0.00 1 1 0 0 0 +( 136 -752 0 ) ( 136 -752 256 ) ( 136 -768 256 ) eden/genmetal -96 0 0.00 1 1 0 0 0 +( 152 -760 0 ) ( 152 -760 256 ) ( 136 -760 256 ) eden/genmetal 24 0 0.00 1 1 0 0 0 +( 152 -776 0 ) ( 152 -776 256 ) ( 152 -760 256 ) eden/genmetal -96 0 0.00 1 1 0 0 0 +( 136 -768 0 ) ( 136 -768 256 ) ( 152 -768 256 ) eden/genmetal 55 0 -180.00 1 -1 0 0 0 +} +// brush 10 +{ +( 832 -120 64 ) ( 832 -104 64 ) ( 816 -104 64 ) eden/genmetal -64 8 0.00 1 1 0 0 0 +( 816 -104 240 ) ( 832 -104 240 ) ( 832 -120 240 ) eden/genmetal -64 8 0.00 1 1 0 0 0 +( 816 -120 0 ) ( 816 -120 256 ) ( 832 -120 256 ) eden/genmetal -64 0 0.00 1 1 0 0 0 +( 824 -104 0 ) ( 824 -104 256 ) ( 824 -120 256 ) eden/genmetal -8 0 0.00 1 1 0 0 0 +( 840 -104 0 ) ( 840 -104 256 ) ( 824 -104 256 ) eden/genmetal -64 0 0.00 1 1 0 0 0 +( 832 -120 0 ) ( 832 -120 256 ) ( 832 -104 256 ) eden/genmetal -8 0 0.00 1 1 0 0 0 +} +// brush 11 +{ +( 832 -88 64 ) ( 832 -72 64 ) ( 816 -72 64 ) eden/genmetal -64 -8 0.00 1 1 0 0 0 +( 816 -72 240 ) ( 832 -72 240 ) ( 832 -88 240 ) eden/genmetal -64 -8 0.00 1 1 0 0 0 +( 824 -88 0 ) ( 824 -88 256 ) ( 840 -88 256 ) eden/genmetal -64 0 0.00 1 1 0 0 0 +( 824 -72 0 ) ( 824 -72 256 ) ( 824 -88 256 ) eden/genmetal 8 0 0.00 1 1 0 0 0 +( 832 -72 0 ) ( 832 -72 256 ) ( 816 -72 256 ) eden/genmetal -64 0 0.00 1 1 0 0 0 +( 832 -88 0 ) ( 832 -88 256 ) ( 832 -72 256 ) eden/genmetal 8 0 0.00 1 1 0 0 0 +} +// brush 12 +{ +( 832 -112 16 ) ( 832 -112 272 ) ( 832 -80 272 ) eden/genmetal 0 16 0.00 1 1 0 0 0 +( 840 -88 16 ) ( 840 -88 272 ) ( 824 -88 272 ) eden/genmetal -64 16 0.00 1 1 0 0 0 +( 824 -88 0 ) ( 824 -88 256 ) ( 824 -120 256 ) eden/genmetal 0 16 0.00 1 1 0 0 0 +( 824 -104 16 ) ( 824 -104 272 ) ( 840 -104 272 ) eden/genmetal -64 16 0.00 1 1 0 0 0 +( 816 -80 80 ) ( 832 -80 80 ) ( 832 -112 80 ) eden/genmetal -64 0 0.00 1 1 0 0 0 +( 832 -112 64 ) ( 832 -80 64 ) ( 816 -80 64 ) eden/genmetal -64 0 0.00 1 1 0 0 0 +} +// brush 13 +{ +( 832 -112 176 ) ( 832 -112 432 ) ( 832 -80 432 ) eden/genmetal 0 48 0.00 1 1 0 0 0 +( 840 -88 176 ) ( 840 -88 432 ) ( 824 -88 432 ) eden/genmetal -64 48 0.00 1 1 0 0 0 +( 824 -88 160 ) ( 824 -88 416 ) ( 824 -120 416 ) eden/genmetal 0 48 0.00 1 1 0 0 0 +( 824 -104 176 ) ( 824 -104 432 ) ( 840 -104 432 ) eden/genmetal -64 48 0.00 1 1 0 0 0 +( 816 -80 240 ) ( 832 -80 240 ) ( 832 -112 240 ) eden/genmetal -64 0 0.00 1 1 0 0 0 +( 832 -112 224 ) ( 832 -80 224 ) ( 816 -80 224 ) eden/genmetal -64 0 0.00 1 1 0 0 0 +} +// brush 14 +{ +( 832 -104 64 ) ( 832 -104 240 ) ( 832 -88 240 ) otto/ottolight 35 16 90.00 -2.250000 -0.500000 0 0 0 +( 832 -88 64 ) ( 832 -88 240 ) ( 824 -88 240 ) otto/ottolight 34 16 90.00 -2.250000 -0.500000 0 0 0 +( 828 -88 64 ) ( 828 -88 240 ) ( 828 -104 240 ) otto/ottolight 35 16 90.00 -2.250000 -0.500000 0 0 0 +( 824 -104 64 ) ( 824 -104 240 ) ( 832 -104 240 ) otto/ottolight 34 16 90.00 -2.250000 -0.500000 0 0 0 +( 824 -88 224 ) ( 832 -88 224 ) ( 832 -104 224 ) otto/ottolight 34 16 90.00 -2.250000 -0.500000 0 0 0 +( 832 -104 80 ) ( 832 -88 80 ) ( 824 -88 80 ) otto/ottolight 34 16 90.00 -2.250000 -0.500000 0 0 0 +} +// brush 15 +{ +( -512 -88 240 ) ( -512 -104 240 ) ( -512 -104 64 ) otto/ottolight 35 16 90.00 -2.250000 -0.500000 0 0 0 +( -504 -88 240 ) ( -512 -88 240 ) ( -512 -88 64 ) otto/ottolight 35 16 90.00 -2.250000 -0.500000 0 0 0 +( -508 -104 240 ) ( -508 -88 240 ) ( -508 -88 64 ) otto/ottolight 35 16 90.00 -2.250000 -0.500000 0 0 0 +( -512 -104 240 ) ( -504 -104 240 ) ( -504 -104 64 ) otto/ottolight 35 16 90.00 -2.250000 -0.500000 0 0 0 +( -512 -104 224 ) ( -512 -88 224 ) ( -504 -88 224 ) otto/ottolight 35 16 90.00 -2.250000 -0.500000 0 0 0 +( -504 -88 80 ) ( -512 -88 80 ) ( -512 -104 80 ) otto/ottolight 35 16 90.00 -2.250000 -0.500000 0 0 0 +} +// brush 16 +{ +( -512 -80 432 ) ( -512 -112 432 ) ( -512 -112 176 ) eden/genmetal 0 48 0.00 1 1 0 0 0 +( -504 -88 432 ) ( -520 -88 432 ) ( -520 -88 176 ) eden/genmetal 0 48 0.00 1 1 0 0 0 +( -504 -120 416 ) ( -504 -88 416 ) ( -504 -88 160 ) eden/genmetal 0 48 0.00 1 1 0 0 0 +( -520 -104 432 ) ( -504 -104 432 ) ( -504 -104 176 ) eden/genmetal 0 48 0.00 1 1 0 0 0 +( -512 -112 240 ) ( -512 -80 240 ) ( -496 -80 240 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( -496 -80 224 ) ( -512 -80 224 ) ( -512 -112 224 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +} +// brush 17 +{ +( -512 -80 272 ) ( -512 -112 272 ) ( -512 -112 16 ) eden/genmetal 0 16 0.00 1 1 0 0 0 +( -504 -88 272 ) ( -520 -88 272 ) ( -520 -88 16 ) eden/genmetal 0 16 0.00 1 1 0 0 0 +( -504 -120 256 ) ( -504 -88 256 ) ( -504 -88 0 ) eden/genmetal 0 16 0.00 1 1 0 0 0 +( -520 -104 272 ) ( -504 -104 272 ) ( -504 -104 16 ) eden/genmetal 0 16 0.00 1 1 0 0 0 +( -512 -112 80 ) ( -512 -80 80 ) ( -496 -80 80 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( -496 -80 64 ) ( -512 -80 64 ) ( -512 -112 64 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +} +// brush 18 +{ +( -496 -72 64 ) ( -512 -72 64 ) ( -512 -88 64 ) eden/genmetal 0 -8 0.00 1 1 0 0 0 +( -512 -88 240 ) ( -512 -72 240 ) ( -496 -72 240 ) eden/genmetal 0 -8 0.00 1 1 0 0 0 +( -520 -88 256 ) ( -504 -88 256 ) ( -504 -88 0 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( -504 -88 256 ) ( -504 -72 256 ) ( -504 -72 0 ) eden/genmetal 8 0 0.00 1 1 0 0 0 +( -496 -72 256 ) ( -512 -72 256 ) ( -512 -72 0 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( -512 -72 256 ) ( -512 -88 256 ) ( -512 -88 0 ) eden/genmetal 8 0 0.00 1 1 0 0 0 +} +// brush 19 +{ +( -496 -104 64 ) ( -512 -104 64 ) ( -512 -120 64 ) eden/genmetal 0 8 0.00 1 1 0 0 0 +( -512 -120 240 ) ( -512 -104 240 ) ( -496 -104 240 ) eden/genmetal 0 8 0.00 1 1 0 0 0 +( -512 -120 256 ) ( -496 -120 256 ) ( -496 -120 0 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( -504 -120 256 ) ( -504 -104 256 ) ( -504 -104 0 ) eden/genmetal -8 0 0.00 1 1 0 0 0 +( -504 -104 256 ) ( -520 -104 256 ) ( -520 -104 0 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( -512 -104 256 ) ( -512 -120 256 ) ( -512 -120 0 ) eden/genmetal -8 0 0.00 1 1 0 0 0 +} +// brush 20 +{ +( 128 704 -96 ) ( 128 672 -96 ) ( 128 672 -128 ) eden/edenmetalwall 0 0 0.00 1 1 0 0 0 +( 352 704 -96 ) ( 128 704 -96 ) ( 128 704 -128 ) eden/edenmetalwall 64 0 0.00 1 1 0 0 0 +( 384 672 -96 ) ( 384 704 -96 ) ( 384 704 -128 ) eden/edenmetalwall 0 0 0.00 1 1 0 0 0 +( 128 672 -96 ) ( 352 672 -96 ) ( 352 672 -128 ) eden/edenmetalwall 64 0 0.00 1 1 0 0 0 +( 128 672 -96 ) ( 128 704 -96 ) ( 352 704 -96 ) eden/edenmetalwall 64 0 0.00 1 1 0 0 0 +( 352 704 -128 ) ( 128 704 -128 ) ( 128 672 -128 ) eden/edenmetalwall 64 0 0.00 1 1 0 0 0 +} +// brush 21 + { + patchDef2 + { + eden/edenmetalwall + ( 9 3 0 536870912 0 subdivisions 90.458153 ) +( +( ( -344 -568 288 0 0 ) ( -344 -568 496 0 0.812500 ) ( 72 -184 496 0 3.437500 ) ) +( ( -312 -600 288 0.125000 0 ) ( -312 -600 496 0.125000 0.812500 ) ( 104 -216 496 0.125000 3.437500 ) ) +( ( -280 -568 288 0.250000 0 ) ( -280 -568 464 0.250000 0.812500 ) ( 104 -216 464 0.250000 3.437500 ) ) +( ( -248 -536 288 0.375000 0 ) ( -248 -536 432 0.375000 0.812500 ) ( 104 -216 432 0.375000 3.437500 ) ) +( ( -280 -504 288 0.500000 0 ) ( -280 -504 432 0.500000 0.812500 ) ( 72 -184 432 0.500000 3.437500 ) ) +( ( -312 -472 288 0.625000 0 ) ( -312 -472 432 0.625000 0.812500 ) ( 40 -152 432 0.625000 3.437500 ) ) +( ( -344 -504 288 0.750000 0 ) ( -344 -504 464 0.750000 0.812500 ) ( 40 -152 464 0.750000 3.437500 ) ) +( ( -376 -536 288 0.875000 0 ) ( -376 -536 496 0.875000 0.812500 ) ( 40 -152 496 0.875000 3.437500 ) ) +( ( -344 -568 288 1 0 ) ( -344 -568 496 1 0.812500 ) ( 72 -184 496 1 3.437500 ) ) +) + } + } +// brush 22 + { + patchDef2 + { + eden/edenmetalwall + ( 9 3 0 536870912 0 subdivisions 90.458153 ) +( +( ( 88 -8 496 0 3.437500 ) ( -328 376 496 0 0.812500 ) ( -328 376 288 0 0 ) ) +( ( 120 24 496 0.125000 3.437500 ) ( -296 408 496 0.125000 0.812500 ) ( -296 408 288 0.125000 0 ) ) +( ( 120 24 464 0.250000 3.437500 ) ( -264 376 464 0.250000 0.812500 ) ( -264 376 288 0.250000 0 ) ) +( ( 120 24 432 0.375000 3.437500 ) ( -232 344 432 0.375000 0.812500 ) ( -232 344 288 0.375000 0 ) ) +( ( 88 -8 432 0.500000 3.437500 ) ( -264 312 432 0.500000 0.812500 ) ( -264 312 288 0.500000 0 ) ) +( ( 56 -40 432 0.625000 3.437500 ) ( -296 280 432 0.625000 0.812500 ) ( -296 280 288 0.625000 0 ) ) +( ( 56 -40 464 0.750000 3.437500 ) ( -328 312 464 0.750000 0.812500 ) ( -328 312 288 0.750000 0 ) ) +( ( 56 -40 496 0.875000 3.437500 ) ( -360 344 496 0.875000 0.812500 ) ( -360 344 288 0.875000 0 ) ) +( ( 88 -8 496 1 3.437500 ) ( -328 376 496 1 0.812500 ) ( -328 376 288 1 0 ) ) +) + } + } +// brush 23 + { + patchDef2 + { + eden/edenmetalwall + ( 9 3 0 536870912 0 subdivisions 90.458153 ) +( +( ( 648 376 288 0 0 ) ( 648 376 496 0 0.812500 ) ( 232 -8 496 0 3.437500 ) ) +( ( 616 408 288 0.125000 0 ) ( 616 408 496 0.125000 0.812500 ) ( 200 24 496 0.125000 3.437500 ) ) +( ( 584 376 288 0.250000 0 ) ( 584 376 464 0.250000 0.812500 ) ( 200 24 464 0.250000 3.437500 ) ) +( ( 552 344 288 0.375000 0 ) ( 552 344 432 0.375000 0.812500 ) ( 200 24 432 0.375000 3.437500 ) ) +( ( 584 312 288 0.500000 0 ) ( 584 312 432 0.500000 0.812500 ) ( 232 -8 432 0.500000 3.437500 ) ) +( ( 616 280 288 0.625000 0 ) ( 616 280 432 0.625000 0.812500 ) ( 264 -40 432 0.625000 3.437500 ) ) +( ( 648 312 288 0.750000 0 ) ( 648 312 464 0.750000 0.812500 ) ( 264 -40 464 0.750000 3.437500 ) ) +( ( 680 344 288 0.875000 0 ) ( 680 344 496 0.875000 0.812500 ) ( 264 -40 496 0.875000 3.437500 ) ) +( ( 648 376 288 1 0 ) ( 648 376 496 1 0.812500 ) ( 232 -8 496 1 3.437500 ) ) +) + } + } +// brush 24 + { + patchDef2 + { + eden/edenmetalwall + ( 9 3 0 536870912 0 subdivisions 90.458153 ) +( +( ( 248 -184 496 0 3.437500 ) ( 664 -568 496 0 0.812500 ) ( 664 -568 288 0 0 ) ) +( ( 216 -216 496 0.125000 3.437500 ) ( 632 -600 496 0.125000 0.812500 ) ( 632 -600 288 0.125000 0 ) ) +( ( 216 -216 464 0.250000 3.437500 ) ( 600 -568 464 0.250000 0.812500 ) ( 600 -568 288 0.250000 0 ) ) +( ( 216 -216 432 0.375000 3.437500 ) ( 568 -536 432 0.375000 0.812500 ) ( 568 -536 288 0.375000 0 ) ) +( ( 248 -184 432 0.500000 3.437500 ) ( 600 -504 432 0.500000 0.812500 ) ( 600 -504 288 0.500000 0 ) ) +( ( 280 -152 432 0.625000 3.437500 ) ( 632 -472 432 0.625000 0.812500 ) ( 632 -472 288 0.625000 0 ) ) +( ( 280 -152 464 0.750000 3.437500 ) ( 664 -504 464 0.750000 0.812500 ) ( 664 -504 288 0.750000 0 ) ) +( ( 280 -152 496 0.875000 3.437500 ) ( 696 -536 496 0.875000 0.812500 ) ( 696 -536 288 0.875000 0 ) ) +( ( 248 -184 496 1 3.437500 ) ( 664 -568 496 1 0.812500 ) ( 664 -568 288 1 0 ) ) +) + } + } +// brush 25 +{ +( 280 -144 408 ) ( 280 -144 504 ) ( 280 -48 504 ) eden/edenmetalwall 8 24 0.00 1 1 0 0 0 +( 280 -48 496 ) ( 232 -64 496 ) ( 232 -64 408 ) eden/edenmetalwall -216 24 0.00 1 1 0 0 0 +( 232 -64 496 ) ( 232 -128 496 ) ( 232 -128 408 ) eden/edenmetalwall 8 24 0.00 1 1 0 0 0 +( 280 -144 408 ) ( 232 -128 408 ) ( 232 -128 496 ) eden/edenmetalwall -216 24 0.00 1 1 0 0 0 +( 224 -48 496 ) ( 288 -48 496 ) ( 288 -144 496 ) eden/edenmetalwall -200 8 0.00 1 1 0 0 0 +( 288 -144 408 ) ( 288 -48 408 ) ( 224 -48 408 ) eden/edenmetalwall 64 193 -180.00 1 1 0 0 0 +} +// brush 26 +{ +( 208 24 504 ) ( 112 24 504 ) ( 112 24 408 ) eden/edenmetalwall -72 24 0.00 1 1 0 0 0 +( 192 -24 408 ) ( 192 -24 496 ) ( 208 24 496 ) eden/edenmetalwall -120 24 0.00 1 1 0 0 0 +( 128 -24 408 ) ( 128 -24 496 ) ( 192 -24 496 ) eden/edenmetalwall -72 24 0.00 1 1 0 0 0 +( 128 -24 496 ) ( 128 -24 408 ) ( 112 24 408 ) eden/edenmetalwall -120 24 0.00 1 1 0 0 0 +( 112 32 496 ) ( 208 32 496 ) ( 208 -32 496 ) eden/edenmetalwall -88 104 0.00 1 1 0 0 0 +( 208 -32 408 ) ( 208 32 408 ) ( 112 32 408 ) eden/edenmetalwall -192 -47 90.00 1 1 0 0 0 +} +// brush 27 +{ +( 40 -48 408 ) ( 112 24 408 ) ( 112 24 496 ) eden/edenmetalwall -160 0 0.00 1 1 0 0 0 +( 40 -48 496 ) ( 88 -64 496 ) ( 88 -64 408 ) eden/edenmetalwall -16 0 0.00 1 1 0 0 0 +( 88 -64 496 ) ( 128 -24 496 ) ( 128 -24 408 ) eden/edenmetalwall -160 0 0.00 1 1 0 0 0 +( 112 24 408 ) ( 128 -24 408 ) ( 128 -24 496 ) eden/edenmetalwall -160 0 0.00 1 1 0 0 0 +( 40 -48 496 ) ( 80 0 496 ) ( 128 -16 496 ) eden/edenmetalwall -16 160 0.00 1 1 0 0 0 +( 88 -64 408 ) ( 128 -16 408 ) ( 80 0 408 ) eden/edenmetalwall -16 160 0.00 1 1 0 0 0 +} +// brush 28 +{ +( 208 24 496 ) ( 208 24 408 ) ( 280 -48 408 ) eden/edenmetalwall -160 0 0.00 1 1 0 0 0 +( 232 -64 408 ) ( 232 -64 496 ) ( 280 -48 496 ) eden/edenmetalwall -160 0 0.00 1 1 0 0 0 +( 192 -24 408 ) ( 192 -24 496 ) ( 232 -64 496 ) eden/edenmetalwall -160 0 0.00 1 1 0 0 0 +( 192 -24 496 ) ( 192 -24 408 ) ( 208 24 408 ) eden/edenmetalwall -160 0 0.00 1 1 0 0 0 +( 192 -16 496 ) ( 240 0 496 ) ( 280 -48 496 ) eden/edenmetalwall -160 160 0.00 1 1 0 0 0 +( 240 0 408 ) ( 192 -16 408 ) ( 232 -64 408 ) eden/edenmetalwall -160 160 0.00 1 1 0 0 0 +} +// brush 29 +{ +( 232 -128 408 ) ( 192 -176 408 ) ( 240 -192 408 ) eden/edenmetalwall -160 0 0.00 1 1 0 0 0 +( 280 -144 496 ) ( 240 -192 496 ) ( 192 -176 496 ) eden/edenmetalwall -160 0 0.00 1 1 0 0 0 +( 208 -216 408 ) ( 192 -168 408 ) ( 192 -168 496 ) eden/edenmetalwall 0 0 0.00 1 1 0 0 0 +( 232 -128 496 ) ( 192 -168 496 ) ( 192 -168 408 ) eden/edenmetalwall 0 0 0.00 1 1 0 0 0 +( 280 -144 496 ) ( 232 -128 496 ) ( 232 -128 408 ) eden/edenmetalwall -160 0 0.00 1 1 0 0 0 +( 280 -144 408 ) ( 208 -216 408 ) ( 208 -216 496 ) eden/edenmetalwall 0 0 0.00 1 1 0 0 0 +} +// brush 30 +{ +( 112 -224 408 ) ( 208 -224 408 ) ( 208 -160 408 ) eden/edenmetalwall 0 -47 90.00 1 1 0 0 0 +( 208 -160 496 ) ( 208 -224 496 ) ( 112 -224 496 ) eden/edenmetalwall -88 -88 0.00 1 1 0 0 0 +( 112 -216 408 ) ( 128 -168 408 ) ( 128 -168 496 ) eden/edenmetalwall 72 24 0.00 1 1 0 0 0 +( 192 -168 496 ) ( 128 -168 496 ) ( 128 -168 408 ) eden/edenmetalwall -72 24 0.00 1 1 0 0 0 +( 208 -216 496 ) ( 192 -168 496 ) ( 192 -168 408 ) eden/edenmetalwall 72 24 0.00 1 1 0 0 0 +( 112 -216 408 ) ( 112 -216 504 ) ( 208 -216 504 ) eden/edenmetalwall -72 24 0.00 1 1 0 0 0 +} +// brush 31 +{ +( 112 -216 496 ) ( 112 -216 408 ) ( 40 -144 408 ) eden/edenmetalwall 0 0 0.00 1 1 0 0 0 +( 88 -128 408 ) ( 88 -128 496 ) ( 40 -144 496 ) eden/edenmetalwall 0 0 0.00 1 1 0 0 0 +( 128 -168 408 ) ( 128 -168 496 ) ( 88 -128 496 ) eden/edenmetalwall 0 0 0.00 1 1 0 0 0 +( 128 -168 496 ) ( 128 -168 408 ) ( 112 -216 408 ) eden/edenmetalwall 0 0 0.00 1 1 0 0 0 +( 128 -176 496 ) ( 80 -192 496 ) ( 40 -143.999954 496 ) eden/edenmetalwall 0 0 0.00 1 1 0 0 0 +( 80 -192 408 ) ( 128 -176 408 ) ( 88 -127.999954 408 ) eden/edenmetalwall 0 0 0.00 1 1 0 0 0 +} +// brush 32 +{ +( 96 -48 408 ) ( 32 -48 408 ) ( 32 -144 408 ) eden/edenmetalwall 0 0 0.00 1 1 0 0 0 +( 32 -144 496 ) ( 32 -48 496 ) ( 96 -48 496 ) eden/edenmetalwall 0 0 0.00 1 1 0 0 0 +( 88 -128 496 ) ( 88 -128 408 ) ( 40 -144 408 ) eden/edenmetalwall 0 24 0.00 1 1 0 0 0 +( 88 -128 408 ) ( 88 -128 496 ) ( 88 -64 496 ) eden/edenmetalwall 0 24 0.00 1 1 0 0 0 +( 88 -64 408 ) ( 88 -64 496 ) ( 40 -48 496 ) eden/edenmetalwall 0 24 0.00 1 1 0 0 0 +( 40 -48 504 ) ( 40 -144 504 ) ( 40 -144 408 ) eden/edenmetalwall 0 24 0.00 1 1 0 0 0 +} +// brush 33 + { + patchDef2 + { + eden/edenmetalwall + ( 3 3 0 536870912 0 ) +( +( ( 32 -96 400 0 0 ) ( 16 -240 400 0 0.093750 ) ( 160 -224 400 0 0.187500 ) ) +( ( 64 -96 400 0.156250 0 ) ( 72 -184 400 0.156250 0.093750 ) ( 160 -200 400 0.156250 0.187500 ) ) +( ( 96 -96 400 0.312500 0 ) ( 96 -160 400 0.312500 0.093750 ) ( 160 -160 400 0.312500 0.187500 ) ) +) + } + } +// brush 34 + { + patchDef2 + { + eden/edenmetalwall + ( 3 3 0 536870912 0 ) +( +( ( 160 -224 400 0 0.187500 ) ( 304 -240 400 0 0.093750 ) ( 288 -96 400 0 0 ) ) +( ( 160 -200 400 0.156250 0.187500 ) ( 248 -184 400 0.156250 0.093750 ) ( 256 -96 400 0.156250 0 ) ) +( ( 160 -160 400 0.312500 0.187500 ) ( 224 -160 400 0.312500 0.093750 ) ( 224 -96 400 0.312500 0 ) ) +) + } + } +// brush 35 + { + patchDef2 + { + eden/edenmetalwall + ( 3 3 0 536870912 0 ) +( +( ( 288 -96 400 0 0 ) ( 304 48 400 0 0.093750 ) ( 160 32 400 0 0.187500 ) ) +( ( 256 -96 400 0.156250 0 ) ( 248 -8 400 0.156250 0.093750 ) ( 160 8 400 0.156250 0.187500 ) ) +( ( 224 -96 400 0.312500 0 ) ( 224 -32 400 0.312500 0.093750 ) ( 160 -32 400 0.312500 0.187500 ) ) +) + } + } +// brush 36 + { + patchDef2 + { + eden/edenmetalwall + ( 3 3 0 536870912 0 ) +( +( ( 160 32 400 0 0.187500 ) ( 16 48 400 0 0.093750 ) ( 32 -96 400 0 0 ) ) +( ( 160 8 400 0.156250 0.187500 ) ( 72 -8 400 0.156250 0.093750 ) ( 64 -96 400 0.156250 0 ) ) +( ( 160 -32 400 0.312500 0.187500 ) ( 96 -32 400 0.312500 0.093750 ) ( 96 -96 400 0.312500 0 ) ) +) + } + } +// brush 37 + { + patchDef2 + { + eden/edenmetalwall + ( 9 3 0 536870912 0 ) +( +( ( 95.999992 -96.000008 496 0 0.375000 ) ( 95.999992 -96.000008 448 0 0.187500 ) ( 95.999992 -96.000008 400 0 0 ) ) +( ( 96 -160 496 0.125000 0.375000 ) ( 96 -160 448 0.125000 0.187500 ) ( 96 -160 400 0.125000 0 ) ) +( ( 160 -159.999969 496 0.250000 0.375000 ) ( 160 -159.999969 448 0.250000 0.187500 ) ( 160 -159.999969 400 0.250000 0 ) ) +( ( 224 -160 496 0.375000 0.375000 ) ( 224 -160 448 0.375000 0.187500 ) ( 224 -160 400 0.375000 0 ) ) +( ( 223.999969 -96.000008 496 0.500000 0.375000 ) ( 223.999969 -96.000008 448 0.500000 0.187500 ) ( 223.999969 -96.000008 400 0.500000 0 ) ) +( ( 224 -31.999996 496 0.625000 0.375000 ) ( 224 -31.999996 448 0.625000 0.187500 ) ( 224 -31.999996 400 0.625000 0 ) ) +( ( 160 -32 496 0.750000 0.375000 ) ( 160 -32 448 0.750000 0.187500 ) ( 160 -32 400 0.750000 0 ) ) +( ( 96 -31.999996 496 0.875000 0.375000 ) ( 96 -31.999996 448 0.875000 0.187500 ) ( 96 -31.999996 400 0.875000 0 ) ) +( ( 95.999992 -96.000008 496 1 0.375000 ) ( 95.999992 -96.000008 448 1 0.187500 ) ( 95.999992 -96.000008 400 1 0 ) ) +) + } + } +// brush 38 + { + patchDef2 + { + eden/edenmetalwall + ( 9 3 0 536870912 0 subdivisions 90.501022 ) +( +( ( 160 576 288 0 0 ) ( 160 576 496 0 0.812500 ) ( 160 32 496 0 3.437500 ) ) +( ( 128 576 288 0.125000 0 ) ( 128 576 496 0.125000 0.812500 ) ( 128 32 496 0.125000 3.437500 ) ) +( ( 128 544 288 0.250000 0 ) ( 128 544 464 0.250000 0.812500 ) ( 128 32 464 0.250000 3.437500 ) ) +( ( 128 512 288 0.375000 0 ) ( 128 512 432 0.375000 0.812500 ) ( 128 32 432 0.375000 3.437500 ) ) +( ( 160 512 288 0.500000 0 ) ( 160 512 432 0.500000 0.812500 ) ( 160 32 432 0.500000 3.437500 ) ) +( ( 192 512 288 0.625000 0 ) ( 192 512 432 0.625000 0.812500 ) ( 192 32 432 0.625000 3.437500 ) ) +( ( 192 544 288 0.750000 0 ) ( 192 544 464 0.750000 0.812500 ) ( 192 32 464 0.750000 3.437500 ) ) +( ( 192 576 288 0.875000 0 ) ( 192 576 496 0.875000 0.812500 ) ( 192 32 496 0.875000 3.437500 ) ) +( ( 160 576 288 1 0 ) ( 160 576 496 1 0.812500 ) ( 160 32 496 1 3.437500 ) ) +) + } + } +// brush 39 + { + patchDef2 + { + eden/edenmetalwall + ( 9 3 0 536870912 0 subdivisions 91.251312 ) +( +( ( 160 -224 496 0 3.437500 ) ( 160 -768 496 0 0.812500 ) ( 160 -768 288 0 0 ) ) +( ( 128 -224 496 0.125000 3.437500 ) ( 128 -768 496 0.125000 0.812500 ) ( 128 -768 288 0.125000 0 ) ) +( ( 128 -224 464 0.250000 3.437500 ) ( 128 -736 464 0.250000 0.812500 ) ( 128 -736 288 0.250000 0 ) ) +( ( 128 -224 432 0.375000 3.437500 ) ( 128 -704 432 0.375000 0.812500 ) ( 128 -704 288 0.375000 0 ) ) +( ( 160 -224 432 0.500000 3.437500 ) ( 160 -704 432 0.500000 0.812500 ) ( 160 -704 288 0.500000 0 ) ) +( ( 192 -224 432 0.625000 3.437500 ) ( 192 -704 432 0.625000 0.812500 ) ( 192 -704 288 0.625000 0 ) ) +( ( 192 -224 464 0.750000 3.437500 ) ( 192 -736 464 0.750000 0.812500 ) ( 192 -736 288 0.750000 0 ) ) +( ( 192 -224 496 0.875000 3.437500 ) ( 192 -768 496 0.875000 0.812500 ) ( 192 -768 288 0.875000 0 ) ) +( ( 160 -224 496 1 3.437500 ) ( 160 -768 496 1 0.812500 ) ( 160 -768 288 1 0 ) ) +) + } + } +// brush 40 + { + patchDef2 + { + eden/edenmetalwall + ( 9 3 0 536870912 0 subdivisions 90.458153 ) +( +( ( 288 -96 496 0 3.437500 ) ( 832 -96 496 0 0.812500 ) ( 832 -96 288 0 0 ) ) +( ( 288 -128 496 0.125000 3.437500 ) ( 832 -128 496 0.125000 0.812500 ) ( 832 -128 288 0.125000 0 ) ) +( ( 288 -128 464 0.250000 3.437500 ) ( 800 -128 464 0.250000 0.812500 ) ( 800 -128 288 0.250000 0 ) ) +( ( 288 -128 432 0.375000 3.437500 ) ( 768 -128 432 0.375000 0.812500 ) ( 768 -128 288 0.375000 0 ) ) +( ( 288 -96 432 0.500000 3.437500 ) ( 768 -96 432 0.500000 0.812500 ) ( 768 -96 288 0.500000 0 ) ) +( ( 288 -64 432 0.625000 3.437500 ) ( 768 -64 432 0.625000 0.812500 ) ( 768 -64 288 0.625000 0 ) ) +( ( 288 -64 464 0.750000 3.437500 ) ( 800 -64 464 0.750000 0.812500 ) ( 800 -64 288 0.750000 0 ) ) +( ( 288 -64 496 0.875000 3.437500 ) ( 832 -64 496 0.875000 0.812500 ) ( 832 -64 288 0.875000 0 ) ) +( ( 288 -96 496 1 3.437500 ) ( 832 -96 496 1 0.812500 ) ( 832 -96 288 1 0 ) ) +) + } + } +// brush 41 + { + patchDef2 + { + eden/edenmetalwall + ( 9 3 0 536870912 0 subdivisions 91.251312 ) +( +( ( -512 -96 288 0 0 ) ( -512 -96 496 0 0.812500 ) ( 32 -96 496 0 3.437500 ) ) +( ( -512 -128 288 0.125000 0 ) ( -512 -128 496 0.125000 0.812500 ) ( 32 -128 496 0.125000 3.437500 ) ) +( ( -480 -128 288 0.250000 0 ) ( -480 -128 464 0.250000 0.812500 ) ( 32 -128 464 0.250000 3.437500 ) ) +( ( -448 -128 288 0.375000 0 ) ( -448 -128 432 0.375000 0.812500 ) ( 32 -128 432 0.375000 3.437500 ) ) +( ( -448 -96 288 0.500000 0 ) ( -448 -96 432 0.500000 0.812500 ) ( 32 -96 432 0.500000 3.437500 ) ) +( ( -448 -64 288 0.625000 0 ) ( -448 -64 432 0.625000 0.812500 ) ( 32 -64 432 0.625000 3.437500 ) ) +( ( -480 -64 288 0.750000 0 ) ( -480 -64 464 0.750000 0.812500 ) ( 32 -64 464 0.750000 3.437500 ) ) +( ( -512 -64 288 0.875000 0 ) ( -512 -64 496 0.875000 0.812500 ) ( 32 -64 496 0.875000 3.437500 ) ) +( ( -512 -96 288 1 0 ) ( -512 -96 496 1 0.812500 ) ( 32 -96 496 1 3.437500 ) ) +) + } + } +// brush 42 +{ +( 8 -576 -128 ) ( -8 -576 -128 ) ( -8 -584 -128 ) eden/genmetal 24 0 0.00 1 1 0 0 0 +( -8 -584 8 ) ( -8 -576 8 ) ( 8 -576 8 ) eden/genmetal 24 0 0.00 1 1 0 0 0 +( -8 -584 8 ) ( 8 -584 8 ) ( 8 -584 -128 ) eden/genmetal 24 0 0.00 1 1 0 0 0 +( 8 -584 8 ) ( 8 -576 8 ) ( 8 -576 -128 ) eden/genmetal 24 0 0.00 1 1 0 0 0 +( 8 -576 8 ) ( -8 -576 8 ) ( -8 -576 -128 ) eden/genmetal 24 0 0.00 1 1 0 0 0 +( -8 -576 8 ) ( -8 -584 8 ) ( -8 -584 -128 ) eden/genmetal 24 0 0.00 1 1 0 0 0 +} +// brush 43 +{ +( 0 -352 8 ) ( 0 -776 8 ) ( 0 -776 -128 ) eden/genmetal 32 0 0.00 1 1 0 0 0 +( 8 -344 8 ) ( -120 -344 8 ) ( -120 -344 -128 ) eden/genmetal 32 0 0.00 1 1 0 0 0 +( 8 -768 8 ) ( 8 -344 8 ) ( 8 -344 -128 ) eden/genmetal 32 0 0.00 1 1 0 0 0 +( 8 -344 -128 ) ( -120 -344 -128 ) ( -120 -768 -128 ) eden/genmetal 32 0 0.00 1 1 0 0 0 +( -120 -576 8 ) ( -120 -344 -112 ) ( 8 -460 -52 ) eden/genmetal 32 0 0.00 1 1 0 0 0 +( 8 -576 -128 ) ( 0 -576 -128 ) ( 4 -576 8 ) eden/genmetal 32 0 0.00 1 1 0 0 0 +} +// brush 44 +{ +( 0 328 0 ) ( -8 328 0 ) ( -8 224 0 ) eden/genmetal 24 0 0.00 1 1 0 0 0 +( -8 224 8 ) ( -8 328 8 ) ( 0 328 8 ) eden/genmetal 24 0 0.00 1 1 0 0 0 +( -16 -576 8 ) ( -8 -576 8 ) ( -8 -576 -128 ) eden/genmetal 24 0 0.00 1 1 0 0 0 +( 0 224 8 ) ( 0 328 8 ) ( 0 328 -128 ) eden/genmetal 24 0 0.00 1 1 0 0 0 +( 0 328 8 ) ( -8 328 8 ) ( -8 328 -128 ) eden/genmetal 24 0 0.00 1 1 0 0 0 +( -8 120 8 ) ( -8 16 8 ) ( -8 16 -128 ) eden/genmetal 24 0 0.00 1 1 0 0 0 +} +// brush 45 +{ +( 8 0 -120 ) ( 0 0 -120 ) ( 0 320 8 ) eden/genmetal 24 0 0.00 1 1 0 0 0 +( 0 0 -128 ) ( 8 0 -128 ) ( 8 512 -128 ) eden/genmetal 24 0 0.00 1 1 0 0 0 +( 8 320 8 ) ( 0 320 8 ) ( 0 512 8 ) eden/genmetal 24 0 0.00 1 1 0 0 0 +( 0 -8 -112 ) ( 0 -8 -128 ) ( 0 512 -128 ) eden/genmetal 32 0 0.00 1 1 0 0 0 +( 8 0 -128 ) ( 0 0 -128 ) ( 0 0 -120 ) eden/genmetal 24 0 0.00 1 1 0 0 0 +( 8 -8 -128 ) ( 8 -8 -112 ) ( 8 312 8 ) eden/genmetal 32 0 0.00 1 1 0 0 0 +( 0 328 -128 ) ( 8 328 -128 ) ( 4 328 8 ) eden/genmetal 32 0 0.00 1 1 0 0 0 +} +// brush 46 +{ +( -544 192 496 ) ( -544 -352 496 ) ( -544 -352 240 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( -512 192 496 ) ( -544 192 496 ) ( -544 192 240 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( -512 -384 496 ) ( -512 160 496 ) ( -512 160 240 ) eden/TR_church2_fx 0 0 0.00 1 1 0 0 0 +( -544 -384 496 ) ( -512 -384 496 ) ( -512 -384 240 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( -544 -352 496 ) ( -544 192 496 ) ( -512 192 496 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( -512 192 288 ) ( -544 192 288 ) ( -544 -352 288 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +} +// brush 47 +{ +( 832 192 544 ) ( 832 -352 544 ) ( 832 -352 288 ) eden/TR_church2_fx 0 0 0.00 1 1 0 0 0 +( 864 192 496 ) ( 832 192 496 ) ( 832 192 240 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( 864 -384 496 ) ( 864 160 496 ) ( 864 160 240 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( 832 -384 496 ) ( 864 -384 496 ) ( 864 -384 240 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( 832 -352 496 ) ( 832 192 496 ) ( 864 192 496 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( 864 192 288 ) ( 832 192 288 ) ( 832 -352 288 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +} +// brush 48 +{ +( 448 -800 288 ) ( 448 -768 288 ) ( -96 -768 288 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( -96 -768 496 ) ( 448 -768 496 ) ( 448 -800 496 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( -128 -768 544 ) ( -128 -800 544 ) ( -128 -800 288 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( -128 -800 496 ) ( 416 -800 496 ) ( 416 -800 240 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( 448 -800 544 ) ( 448 -768 544 ) ( 448 -768 288 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( 448 -768 496 ) ( -96 -768 496 ) ( -96 -768 240 ) eden/TR_church2_fx 0 0 0.00 1 1 0 0 0 +} +// brush 49 +{ +( 448 576 288 ) ( 448 608 288 ) ( -96 608 288 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( -96 608 496 ) ( 448 608 496 ) ( 448 576 496 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( -128 608 544 ) ( -128 576 544 ) ( -128 576 288 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( -128 576 496 ) ( 416 576 496 ) ( 416 576 240 ) eden/TR_church2_fx 0 0 0.00 1 1 0 0 0 +( 448 576 544 ) ( 448 608 544 ) ( 448 608 288 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( 448 608 496 ) ( -96 608 496 ) ( -96 608 240 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +} +// brush 50 +{ +( 448 -768 544 ) ( 448 -800 544 ) ( 448 -800 288 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( 832 -384 240 ) ( 832 -384 496 ) ( 448 -768 496 ) eden/TR_church2_fx 0 0 0.00 1 1 0 0 0 +( 864 -384 240 ) ( 864 -384 496 ) ( 832 -384 496 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( 864 -384 496 ) ( 864 -384 240 ) ( 448 -800 240 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( 832 -384 496 ) ( 832 -416 496 ) ( 448 -800 496 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( 832 -416 288 ) ( 832 -384 288 ) ( 448 -768 288 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +} +// brush 51 +{ +( -128 -800 288 ) ( -128 -800 544 ) ( -128 -768 544 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( -128 -768 496 ) ( -512 -384 496 ) ( -512 -384 240 ) eden/TR_church2_fx 0 0 0.00 1 1 0 0 0 +( -512 -384 496 ) ( -544 -384 496 ) ( -544 -384 240 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( -128 -800 240 ) ( -544 -384 240 ) ( -544 -384 496 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( -128 -800 496 ) ( -512 -416 496 ) ( -512 -384 496 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( -128 -768 288 ) ( -512 -384 288 ) ( -512 -416 288 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +} +// brush 52 +{ +( -512 224 288 ) ( -512 192 288 ) ( -128 576 288 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( -512 192 496 ) ( -512 224 496 ) ( -128 608 496 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( -544 192 496 ) ( -544 192 240 ) ( -128 608 240 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( -544 192 240 ) ( -544 192 496 ) ( -512 192 496 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( -512 192 240 ) ( -512 192 496 ) ( -128 576 496 ) eden/TR_church2_fx 0 0 0.00 1 1 0 0 0 +( -128 576 544 ) ( -128 608 544 ) ( -128 608 288 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +} +// brush 53 +{ +( 448 576 288 ) ( 832 192 288 ) ( 832 224 288 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( 448 608 496 ) ( 832 224 496 ) ( 832 192 496 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( 448 608 240 ) ( 864 192 240 ) ( 864 192 496 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( 832 192 496 ) ( 864 192 496 ) ( 864 192 240 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( 448 576 496 ) ( 832 192 496 ) ( 832 192 240 ) eden/TR_church2_fx 0 0 0.00 1 1 0 0 0 +( 448 608 288 ) ( 448 608 544 ) ( 448 576 544 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +} +// brush 54 +{ +( -512 192 496 ) ( -496 208 496 ) ( -504 200 512 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( 832 -384 480 ) ( 800 -416 480 ) ( 816 -400 736 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( 832 576 736 ) ( -544 576 736 ) ( -544 576 480 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( 832 -768 736 ) ( 832 640 736 ) ( 832 640 480 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( -544 -768 736 ) ( 832 -768 736 ) ( 832 -768 480 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( -544 -768 512 ) ( -544 640 512 ) ( 832 640 512 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( 832 640 496 ) ( -544 640 496 ) ( -544 -768 496 ) eden/TR_church2_fx 0 0 0.00 1 1 0 0 0 +( 448 576 480 ) ( 480 544 480 ) ( 464 560 736 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( -512 352 480 ) ( -512 432 480 ) ( -512 392 512 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +( -128 -768 496 ) ( -144 -752 496 ) ( -136 -760 512 ) sky/cliffsky 0 0 0.00 1 1 0 0 0 +} +// brush 55 +{ +( 624 -384.000244 256 ) ( 600 192.000046 256 ) ( 576 -384.000244 256 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( -448 -352 400 ) ( -448 -352 384 ) ( -512 -384 384 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( -448 -352 384 ) ( -448 -352 400 ) ( -448 160 400 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( -448 160 384 ) ( -448 160 400 ) ( -512 192 400 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( -512 192 384 ) ( -512 -384 384 ) ( -512 -384 352 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( 544 -384.000244 288 ) ( 576 192.000046 288 ) ( 608 -384.000244 288 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +} +// brush 56 +{ +( 624 -767.999939 256 ) ( 600 -351.999878 256 ) ( 576 -767.999939 256 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( -128 -768 400 ) ( -128 -768 384 ) ( -512 -384.000427 384 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( -448 -352 384 ) ( -448 -352 400 ) ( -512 -384 400 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( -448 -352 400 ) ( -448 -352 384 ) ( -96 -704 384 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( -96 -704 224 ) ( -96 -704 208 ) ( -128 -768 208 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( 544 -767.999939 288 ) ( 576 -351.999878 288 ) ( 608 -767.999939 288 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +} +// brush 57 +{ +( -128 -768 352 ) ( -128 -768 384 ) ( 448 -768 384 ) eden/genmetal 32 0 0.00 1 1 0 0 0 +( 416 -704 96 ) ( 416 -704 80 ) ( 448 -768 80 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( -96 -704 400 ) ( -96 -704 384 ) ( 416 -704 384 ) eden/genmetal 32 0 0.00 1 1 0 0 0 +( -96 -704 208 ) ( -96 -704 224 ) ( -128 -768 224 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( -128 -768 256 ) ( 448 -768 256 ) ( 448 -704 256 ) eden/genmetal 0 -64 90.00 1 1 0 0 0 +( 544 -768 288 ) ( 576 -704 288 ) ( 608 -768 288 ) eden/genmetal 0 -64 90.00 1 1 0 0 0 +} +// brush 58 +{ +( 768 -320 256 ) ( 384 -704 256 ) ( 448 -768 256 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( 416 -704 80 ) ( 416 -704 96 ) ( 448 -768 96 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( 416 -704 96 ) ( 416 -704 80 ) ( 768 -352 80 ) eden/genmetal -32 0 0.00 1 1 0 0 0 +( 768 -352 224 ) ( 768 -352 208 ) ( 832 -384 208 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( 832 -384 384 ) ( 448 -768 384 ) ( 448 -768 400 ) eden/genmetal -32 0 0.00 1 1 0 0 0 +( 544 -768.000061 288 ) ( 576 -352 288 ) ( 608 -768.000061 288 ) eden/genmetal -32 0 0.00 1 1 0 0 0 +} +// brush 59 +{ +( 832 -384 352 ) ( 832 -384 384 ) ( 832 192 384 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( 768 160 96 ) ( 768 160 80 ) ( 832 192 80 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( 768 -352 272 ) ( 768 -352 256 ) ( 768 160 256 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( 768 -352 208 ) ( 768 -352 224 ) ( 832 -384 224 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( 832 -384 256 ) ( 832 192 256 ) ( 768 192 256 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( 544 -384 288 ) ( 576 192.000504 288 ) ( 608 -384 288 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +} +// brush 60 +{ +( 448 576 400 ) ( 448 576 384 ) ( 832 192 384 ) eden/genmetal -64 0 0.00 1 1 0 0 0 +( 768 160 80 ) ( 768 160 96 ) ( 832 192 96 ) eden/genmetal -32 0 0.00 1 1 0 0 0 +( 768 160 272 ) ( 768 160 256 ) ( 416 512 256 ) eden/genmetal -64 0 0.00 1 1 0 0 0 +( 416 512 96 ) ( 416 512 80 ) ( 448 576 80 ) eden/genmetal -32 0 0.00 1 1 0 0 0 +( 448 576 256 ) ( 384 512 256 ) ( 768 128 256 ) eden/genmetal 0 32 0.00 1 1 0 0 0 +( 544 159.999893 288 ) ( 576 576 288 ) ( 608 159.999893 288 ) eden/genmetal 0 32 0.00 1 1 0 0 0 +} +// brush 61 +{ +( 448 576 208 ) ( -128 576 208 ) ( -128 576 176 ) eden/genmetal 32 0 0.00 1 1 0 0 0 +( 416 512 80 ) ( 416 512 96 ) ( 448 576 96 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( 416 512 400 ) ( 416 512 384 ) ( -96 512 384 ) eden/genmetal 32 0 0.00 1 1 0 0 0 +( -96 512 224 ) ( -96 512 208 ) ( -128 576 208 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( 448 512 256 ) ( 448 576 256 ) ( -128 576 256 ) eden/genmetal 0 -64 90.00 1 1 0 0 0 +( 544 512 288 ) ( 576 576 288 ) ( 608 512 288 ) eden/genmetal 0 -64 90.00 1 1 0 0 0 +} +// brush 62 +{ +( 624 159.999817 256 ) ( 600 576 256 ) ( 576 159.999817 256 ) eden/genmetal 0 32 0.00 1 1 0 0 0 +( -96 512 208 ) ( -96 512 224 ) ( -128 576 224 ) eden/genmetal -32 0 0.00 1 1 0 0 0 +( -448 160 384 ) ( -448 160 400 ) ( -96 512 400 ) eden/genmetal -64 0 0.00 1 1 0 0 0 +( -448 160 400 ) ( -448 160 384 ) ( -512 192 384 ) eden/genmetal -32 0 0.00 1 1 0 0 0 +( -512 192 384 ) ( -128 576 384 ) ( -128 576 400 ) eden/genmetal -64 0 0.00 1 1 0 0 0 +( 544 159.999817 288 ) ( 576 576 288 ) ( 608 159.999817 288 ) eden/genmetal -64 0 0.00 1 1 0 0 0 +} +// brush 63 +{ +( 320 192 0 ) ( 320 64 0 ) ( 320 64 -128 ) eden/edentable 64 0 0.00 -1 1 0 0 0 +( 448 192 0 ) ( 320 192 0 ) ( 320 192 -128 ) eden/edentable 64 0 0.00 -1 1 0 0 0 +( 448 64 0 ) ( 448 192 0 ) ( 448 192 -128 ) eden/edentable 64 0 0.00 -1 1 0 0 0 +( 320 64 0 ) ( 448 64 0 ) ( 448 64 -128 ) eden/edentable 64 0 0.00 -1 1 0 0 0 +( 320 64 0 ) ( 320 192 0 ) ( 448 192 0 ) eden/edentable 64 64 0.00 -1 1 0 0 0 +( 448 192 -128 ) ( 320 192 -128 ) ( 320 64 -128 ) eden/edentable 64 64 0.00 -1 1 0 0 0 +} +// brush 64 +{ +( 136 -8 -128 ) ( 136 -8 -112 ) ( 136 312 8 ) eden/genmetal 32 0 0.00 1 1 0 0 0 +( 136 0 -128 ) ( 128 0 -128 ) ( 128 0 -120 ) eden/genmetal 24 0 0.00 1 1 0 0 0 +( 128 -8 -112 ) ( 128 -8 -128 ) ( 128 512 -128 ) eden/genmetal 32 0 0.00 1 1 0 0 0 +( 256 512 8 ) ( 128 512 8 ) ( 128 512 -128 ) eden/genmetal 24 0 0.00 1 1 0 0 0 +( 136 320 8 ) ( 128 320 8 ) ( 128 512 8 ) eden/genmetal 24 0 0.00 1 1 0 0 0 +( 128 0 -128 ) ( 136 0 -128 ) ( 136 512 -128 ) eden/genmetal 24 0 0.00 1 1 0 0 0 +( 136 0 -120 ) ( 128 0 -120 ) ( 128 320 8 ) eden/genmetal 24 0 0.00 1 1 0 0 0 +} +// brush 65 +{ +( 128 -352 8 ) ( 128 -776 8 ) ( 128 -776 -128 ) eden/genmetal 32 0 0.00 1 1 0 0 0 +( 136 -344 8 ) ( 8 -344 8 ) ( 8 -344 -128 ) eden/genmetal 32 0 0.00 1 1 0 0 0 +( 136 -768 8 ) ( 136 -344 8 ) ( 136 -344 -128 ) eden/genmetal 32 0 0.00 1 1 0 0 0 +( 8 -768 8 ) ( 136 -768 8 ) ( 136 -768 -128 ) eden/genmetal 32 0 0.00 1 1 0 0 0 +( 8 -768 8 ) ( 8 -344 8 ) ( 136 -344 8 ) eden/genmetal 32 0 0.00 1 1 0 0 0 +( 136 -344 -128 ) ( 8 -344 -128 ) ( 8 -768 -128 ) eden/genmetal 32 0 0.00 1 1 0 0 0 +( 8 -576 8 ) ( 8 -344 -112 ) ( 136 -460 -52 ) eden/genmetal 32 0 0.00 1 1 0 0 0 +} +// brush 66 +{ +( 0 -352 -96 ) ( 0 -384 -96 ) ( 0 -384 -224 ) eden/FL_edenhouse3 -64 -96 0.00 1 1 0 0 0 +( 128 -352 -96 ) ( 0 -352 -96 ) ( 0 -352 -224 ) eden/FL_edenhouse2 0 -96 0.00 1 1 0 0 0 +( 128 -384 -96 ) ( 128 -352 -96 ) ( 128 -352 -224 ) eden/FL_edenhouse2 0 0 0.00 1 1 0 0 0 +( 0 -384 -96 ) ( 128 -384 -96 ) ( 128 -384 -224 ) eden/FL_edenhouse3 0 -96 0.00 1 1 0 0 0 +( 0 -384 -112 ) ( 0 -352 -112 ) ( 128 -352 -112 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 0 -304 -128 ) ( 0 -384 -128 ) ( 128 -344 -128 ) eden/FL_edenhouse3 0 64 0.00 1 1 0 0 0 +} +// brush 67 +{ +( 0 -416 -96 ) ( 0 -384 -96 ) ( 128 -384 -96 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 0 -416 -48 ) ( 128 -416 -48 ) ( 128 -416 -176 ) eden/FL_edenhouse3 0 -48 0.00 1 1 0 0 0 +( 128 -416 -48 ) ( 128 -384 -48 ) ( 128 -384 -176 ) eden/FL_edenhouse2 0 0 0.00 1 1 0 0 0 +( 128 -384 -48 ) ( 0 -384 -48 ) ( 0 -384 -176 ) eden/FL_edenhouse2 0 -48 0.00 1 1 0 0 0 +( 0 -384 -48 ) ( 0 -416 -48 ) ( 0 -416 -176 ) eden/FL_edenhouse3 -32 -48 0.00 1 1 0 0 0 +( 112 -416 -128 ) ( 80 -384 -128 ) ( 48 -416 -128 ) eden/FL_edenhouse3 -32 -48 0.00 1 1 0 0 0 +} +// brush 68 +{ +( 112 -448 -128 ) ( 80 -416 -128 ) ( 48 -448 -128 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 0 -448 -80 ) ( 0 -416 -80 ) ( 128 -416 -80 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 0 -448 -48 ) ( 128 -448 -48 ) ( 128 -448 -176 ) eden/FL_edenhouse3 0 -48 0.00 1 1 0 0 0 +( 128 -448 -48 ) ( 128 -416 -48 ) ( 128 -416 -176 ) eden/FL_edenhouse2 0 0 0.00 1 1 0 0 0 +( 128 -416 -48 ) ( 0 -416 -48 ) ( 0 -416 -176 ) eden/FL_edenhouse2 0 -48 0.00 1 1 0 0 0 +( 0 -416 -48 ) ( 0 -448 -48 ) ( 0 -448 -176 ) eden/FL_edenhouse3 0 -48 0.00 1 1 0 0 0 +} +// brush 69 +{ +( 0 -480 -64 ) ( 0 -448 -64 ) ( 128 -448 -64 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 0 -480 -48 ) ( 128 -480 -48 ) ( 128 -480 -176 ) eden/FL_edenhouse3 0 -48 0.00 1 1 0 0 0 +( 128 -480 -48 ) ( 128 -448 -48 ) ( 128 -448 -176 ) eden/FL_edenhouse2 0 0 0.00 1 1 0 0 0 +( 128 -448 -48 ) ( 0 -448 -48 ) ( 0 -448 -176 ) eden/FL_edenhouse2 0 -48 0.00 1 1 0 0 0 +( 0 -448 -48 ) ( 0 -480 -48 ) ( 0 -480 -176 ) eden/FL_edenhouse3 -96 -48 0.00 1 1 0 0 0 +( 112 -480 -128 ) ( 80 -448 -128 ) ( 48 -480 -128 ) eden/FL_edenhouse3 -96 -48 0.00 1 1 0 0 0 +} +// brush 70 +{ +( 0 -480 0 ) ( 0 -512 0 ) ( 0 -512 -128 ) eden/FL_edenhouse3 -64 0 0.00 1 1 0 0 0 +( 128 -480 0 ) ( 0 -480 0 ) ( 0 -480 -128 ) eden/FL_edenhouse2 0 0 0.00 1 1 0 0 0 +( 128 -512 0 ) ( 128 -480 0 ) ( 128 -480 -128 ) eden/FL_edenhouse2 -64 0 0.00 1 1 0 0 0 +( 0 -512 0 ) ( 128 -512 0 ) ( 128 -512 -128 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 0 -512 -48 ) ( 0 -480 -48 ) ( 128 -480 -48 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 128 -480 -128 ) ( 0 -480 -128 ) ( 0 -512 -128 ) eden/FL_edenhouse3 0 64 0.00 1 1 0 0 0 +} +// brush 71 +{ +( 128 -512 -128 ) ( 0 -512 -128 ) ( 0 -544 -128 ) eden/FL_edenhouse3 0 32 0.00 1 1 0 0 0 +( 0 -544 -32 ) ( 0 -512 -32 ) ( 128 -512 -32 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 0 -544 0 ) ( 128 -544 0 ) ( 128 -544 -128 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 128 -544 0 ) ( 128 -512 0 ) ( 128 -512 -128 ) eden/FL_edenhouse2 -32 0 0.00 1 1 0 0 0 +( 128 -512 0 ) ( 0 -512 0 ) ( 0 -512 -128 ) eden/FL_edenhouse2 0 0 0.00 1 1 0 0 0 +( 0 -512 0 ) ( 0 -544 0 ) ( 0 -544 -128 ) eden/FL_edenhouse3 -32 0 0.00 1 1 0 0 0 +} +// brush 72 +{ +( 0 -544 0 ) ( 0 -576 0 ) ( 0 -576 -128 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 128 -544 0 ) ( 0 -544 0 ) ( 0 -544 -128 ) eden/FL_edenhouse2 0 0 0.00 1 1 0 0 0 +( 128 -576 0 ) ( 128 -544 0 ) ( 128 -544 -128 ) eden/FL_edenhouse2 0 0 0.00 1 1 0 0 0 +( 0 -576 0 ) ( 128 -576 0 ) ( 128 -576 -128 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 0 -576 -16 ) ( 0 -544 -16 ) ( 128 -544 -16 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 128 -544 -128 ) ( 0 -544 -128 ) ( 0 -576 -128 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +} +// brush 73 +{ +( 128 -512 -128 ) ( 0 -512 -128 ) ( 0 -704 -128 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 0 -704 0 ) ( 0 -512 0 ) ( 128 -512 0 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 0 -704 0 ) ( 128 -704 0 ) ( 128 -704 -128 ) eden/FL_edenhouse2 0 0 0.00 1 1 0 0 0 +( 128 -704 0 ) ( 128 -512 0 ) ( 128 -512 -128 ) eden/FL_edenhouse2 0 0 0.00 1 1 0 0 0 +( 144 -576 0 ) ( 16 -576 0 ) ( 16 -576 -128 ) eden/FL_edenhouse2 0 0 0.00 1 1 0 0 0 +( 0 -512 0 ) ( 0 -704 0 ) ( 0 -704 -128 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +} +// brush 74 +{ +( 144 0 -128 ) ( 96 320 -128 ) ( 48 0 -128 ) eden/FL_edenhouse2 0 0 0.00 1 1 0 0 0 +( 128 0 -128 ) ( 0 0 -128 ) ( 0 320 0 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 128 0 -256 ) ( 128 0 -128 ) ( 128 320 0 ) eden/FL_edenhouse2 0 0 0.00 1 1 0 0 0 +( 128 320 0 ) ( 0 320 0 ) ( 0 320 -128 ) eden/FL_edenhouse2 0 0 0.00 1 1 0 0 0 +( 0 0 -128 ) ( 0 0 -256 ) ( 0 320 -128 ) eden/FL_edenhouse2 0 0 0.00 1 1 0 0 0 +} +// brush 75 +{ +( 0 512 0 ) ( 0 320 0 ) ( 0 320 -128 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 128 512 0 ) ( 0 512 0 ) ( 0 512 -128 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 128 320 0 ) ( 128 512 0 ) ( 128 512 -128 ) eden/FL_edenhouse2 0 0 0.00 1 1 0 0 0 +( 0 320 0 ) ( 128 320 0 ) ( 128 320 -128 ) eden/FL_edenhouse2 0 0 0.00 1 1 0 0 0 +( 0 320 0 ) ( 0 512 0 ) ( 128 512 0 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 128 512 -128 ) ( 0 512 -128 ) ( 0 320 -128 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +} +// brush 76 +{ +( 832 -384 -160 ) ( 800 -416 -160 ) ( 816 -400 96 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 832 576 96 ) ( -544 576 96 ) ( -544 576 -160 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 832 -768 96 ) ( 832 640 96 ) ( 832 640 -160 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( -544 -768 96 ) ( 832 -768 96 ) ( 832 -768 -160 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( -544 -768 -128 ) ( -544 640 -128 ) ( 832 640 -128 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 832 640 -160 ) ( -544 640 -160 ) ( -544 -768 -160 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 448 576 -160 ) ( 480 544 -160 ) ( 464 560 96 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 0 336 -160 ) ( 0 416 -160 ) ( 0 376 -128 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +} +// brush 77 +{ +( -512 192 -32 ) ( -480 224 -32 ) ( -496 208 224 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( -512 640 224 ) ( -512 -768 224 ) ( -512 -768 -32 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 832 576 224 ) ( -544 576 224 ) ( -544 576 -32 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( -544 -768 224 ) ( 832 -768 224 ) ( 832 -768 -32 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( -544 -768 0 ) ( -544 640 0 ) ( 832 640 0 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 832 640 -128 ) ( -544 640 -128 ) ( -544 -768 -128 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( -128 -768 -32 ) ( -160 -736 -32 ) ( -144 -752 224 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 0 416 -32 ) ( 0 336 -32 ) ( 0 376 0 ) eden/FL_edenhouse2 0 0 0.00 1 1 0 0 0 +} +// brush 78 +{ +( -512 192 0 ) ( -128 576 0 ) ( -128 576 16 ) eden/genmetal -64 0 0.00 1 1 0 0 0 +( -448 160 16 ) ( -448 160 0 ) ( -512 192 0 ) eden/genmetal -32 0 0.00 1 1 0 0 0 +( -448 160 0 ) ( -448 160 16 ) ( -96 512 16 ) eden/genmetal -64 0 0.00 1 1 0 0 0 +( -96 512 0 ) ( -96 512 16 ) ( -128 576 16 ) eden/genmetal -32 0 0.00 1 1 0 0 0 +( -448 128 0 ) ( -64 512 0 ) ( -128 576 0 ) eden/genmetal 0 32 0.00 1 1 0 0 0 +( -432 159.999817 8 ) ( -420 576 8 ) ( -408 159.999817 8 ) eden/genmetal 0 32 0.00 1 1 0 0 0 +} +// brush 79 +{ +( 448 512 -128 ) ( 448 576 -128 ) ( -128 576 -128 ) eden/genmetal 0 -64 90.00 1 1 0 0 0 +( -128 576 8 ) ( 448 576 8 ) ( 448 512 8 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( -96 512 16 ) ( -96 512 0 ) ( -128 576 0 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( 416 512 16 ) ( 416 512 0 ) ( -96 512 0 ) eden/genmetal 32 0 0.00 1 1 0 0 0 +( 416 512 -128 ) ( 416 512 -112 ) ( 448 576 -112 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( 448 576 0 ) ( -128 576 0 ) ( -128 576 -32 ) eden/genmetal 32 0 0.00 1 1 0 0 0 +} +// brush 80 +{ +( -432 159.999832 8 ) ( -420 576.000183 8 ) ( -408 159.999832 8 ) eden/genmetal 0 32 0.00 1 1 0 0 0 +( 448 576 -128 ) ( 384 512 -128 ) ( 768 128 -128 ) eden/genmetal 0 32 0.00 1 1 0 0 0 +( 416 512 -112 ) ( 416 512 -128 ) ( 448 576 -128 ) eden/genmetal -32 0 0.00 1 1 0 0 0 +( 768 160 -112 ) ( 768 160 -128 ) ( 416 512 -128 ) eden/genmetal -64 0 0.00 1 1 0 0 0 +( 768 160 -128 ) ( 768 160 -112 ) ( 832 192 -112 ) eden/genmetal -32 0 0.00 1 1 0 0 0 +( 448 576 16 ) ( 448 576 0 ) ( 832 192 0 ) eden/genmetal -64 0 0.00 1 1 0 0 0 +} +// brush 81 +{ +( 832 -384 -128 ) ( 832 192 -128 ) ( 768 192 -128 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( 768 192 8 ) ( 832 192 8 ) ( 832 -384 8 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( 768 -352 0 ) ( 768 -352 16 ) ( 832 -384 16 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( 768 -352 -112 ) ( 768 -352 -128 ) ( 768 160 -128 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( 768 160 -112 ) ( 768 160 -128 ) ( 832 192 -128 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( 832 -384 -32 ) ( 832 -384 0 ) ( 832 192 0 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +} +// brush 82 +{ +( -432 -768.000244 8 ) ( -420 -351.999817 8 ) ( -408 -768.000244 8 ) eden/genmetal -32 0 0.00 1 1 0 0 0 +( 832 -384 0 ) ( 448 -768 0 ) ( 448 -768 16 ) eden/genmetal -32 0 0.00 1 1 0 0 0 +( 768 -352 16 ) ( 768 -352 0 ) ( 832 -384 0 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( 416 -704 -112 ) ( 416 -704 -128 ) ( 768 -352 -128 ) eden/genmetal -32 0 0.00 1 1 0 0 0 +( 416 -704 -128 ) ( 416 -704 -112 ) ( 448 -768 -112 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( 768 -320 -128 ) ( 384 -704 -128 ) ( 448 -768 -128 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +} +// brush 83 +{ +( -128 -768 -128 ) ( 448 -768 -128 ) ( 448 -704 -128 ) eden/genmetal 0 -64 90.00 1 1 0 0 0 +( 448 -704 8 ) ( 448 -768 8 ) ( -128 -768 8 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( -96 -704 0 ) ( -96 -704 16 ) ( -128 -768 16 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( -96 -704 16 ) ( -96 -704 0 ) ( 416 -704 0 ) eden/genmetal 32 0 0.00 1 1 0 0 0 +( 416 -704 -112 ) ( 416 -704 -128 ) ( 448 -768 -128 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( -128 -768 -32 ) ( -128 -768 0 ) ( 448 -768 0 ) eden/genmetal 32 0 0.00 1 1 0 0 0 +} +// brush 84 +{ +( -128 -768 0 ) ( -64 -704 0 ) ( -448 -320.000427 0 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( -96 -704 16 ) ( -96 -704 0 ) ( -128 -768 0 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( -448 -352 16 ) ( -448 -352 0 ) ( -96 -704 0 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( -448 -352 0 ) ( -448 -352 16 ) ( -512 -384 16 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( -128 -768 16 ) ( -128 -768 0 ) ( -512 -384.000427 0 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( -432 -767.999939 8 ) ( -420 -351.999878 8 ) ( -408 -767.999939 8 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +} +// brush 85 +{ +( -512 192 0 ) ( -512 -384 0 ) ( -512 -384 -32 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( -448 160 0 ) ( -448 160 16 ) ( -512 192 16 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( -448 -352 0 ) ( -448 -352 16 ) ( -448 160 16 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( -448 -352 16 ) ( -448 -352 0 ) ( -512 -384 0 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( -512 -384 8 ) ( -512 192 8 ) ( -448 192 8 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +( -448 192 0 ) ( -512 192 0 ) ( -512 -384 0 ) eden/genmetal 0 0 0.00 1 1 0 0 0 +} +// brush 86 +{ +( 448 576 0 ) ( 832 192 0 ) ( 832 224 0 ) eden/WL_edentown2 0 0 0.00 1 1 0 0 0 +( 448 608 256 ) ( 832 224 256 ) ( 832 192 256 ) eden/WL_edentown2 0 0 0.00 1 1 0 0 0 +( 448 608 0 ) ( 864 192 0 ) ( 864 192 256 ) eden/WL_edentown2 0 0 0.00 1 1 0 0 0 +( 832 192 256 ) ( 864 192 256 ) ( 864 192 0 ) eden/WL_edentown2 0 0 0.00 1 1 0 0 0 +( 448 576 256 ) ( 832 192 256 ) ( 832 192 0 ) eden/WL_edentown2 0 0 0.00 1 1 0 0 0 +( 448 608 0 ) ( 448 608 256 ) ( 448 576 256 ) eden/WL_edentown2 0 0 0.00 1 1 0 0 0 +} +// brush 87 +{ +( -512 224 0 ) ( -512 192 0 ) ( -128 576 0 ) eden/WL_edentown2 -64 0 0.00 1 1 0 0 0 +( -512 192 256 ) ( -512 224 256 ) ( -128 608 256 ) eden/WL_edentown2 -64 0 0.00 1 1 0 0 0 +( -544 192 256 ) ( -544 192 0 ) ( -128 608 0 ) eden/WL_edentown2 0 0 0.00 1 1 0 0 0 +( -544 192 0 ) ( -544 192 256 ) ( -512 192 256 ) eden/WL_edentown2 -64 0 0.00 1 1 0 0 0 +( -512 192 0 ) ( -512 192 256 ) ( -128 576 256 ) eden/WL_edentown2 0 0 0.00 1 1 0 0 0 +( -128 576 256 ) ( -128 608 256 ) ( -128 608 0 ) eden/WL_edentown2 0 0 0.00 1 1 0 0 0 +} +// brush 88 +{ +( -128 -800 0 ) ( -128 -800 256 ) ( -128 -768 256 ) eden/WL_edentown2 0 0 0.00 1 1 0 0 0 +( -128 -768 256 ) ( -512 -384 256 ) ( -512 -384 0 ) eden/WL_edentown2 0 0 0.00 1 1 0 0 0 +( -512 -384 256 ) ( -544 -384 256 ) ( -544 -384 0 ) eden/WL_edentown2 -64 0 0.00 1 1 0 0 0 +( -128 -800 0 ) ( -544 -384 0 ) ( -544 -384 256 ) eden/WL_edentown2 0 0 0.00 1 1 0 0 0 +( -128 -800 256 ) ( -512 -416 256 ) ( -512 -384 256 ) eden/WL_edentown2 -64 0 0.00 1 1 0 0 0 +( -128 -768 0 ) ( -512 -384 0 ) ( -512 -416 0 ) eden/WL_edentown2 -64 0 0.00 1 1 0 0 0 +} +// brush 89 +{ +( 448 -768 256 ) ( 448 -800 256 ) ( 448 -800 0 ) eden/WL_edentown2 0 0 0.00 1 1 0 0 0 +( 832 -384 0 ) ( 832 -384 256 ) ( 448 -768 256 ) eden/WL_edentown2 0 0 0.00 1 1 0 0 0 +( 864 -384 0 ) ( 864 -384 256 ) ( 832 -384 256 ) eden/WL_edentown2 0 0 0.00 1 1 0 0 0 +( 864 -384 256 ) ( 864 -384 0 ) ( 448 -800 0 ) eden/WL_edentown2 0 0 0.00 1 1 0 0 0 +( 832 -384 256 ) ( 832 -416 256 ) ( 448 -800 256 ) eden/WL_edentown2 0 0 0.00 1 1 0 0 0 +( 832 -416 0 ) ( 832 -384 0 ) ( 448 -768 0 ) eden/WL_edentown2 0 0 0.00 1 1 0 0 0 +} +// brush 90 +{ +( 448 576 0 ) ( 448 608 0 ) ( -96 608 0 ) eden/WL_edentown2 0 0 0.00 1 1 0 0 0 +( -96 608 256 ) ( 448 608 256 ) ( 448 576 256 ) eden/WL_edentown2 0 0 0.00 1 1 0 0 0 +( -128 608 256 ) ( -128 576 256 ) ( -128 576 0 ) eden/WL_edentown2 -64 0 0.00 1 1 0 0 0 +( -128 576 256 ) ( 416 576 256 ) ( 416 576 0 ) eden/WL_edentown2 64 0 0.00 1 1 0 0 0 +( 448 576 256 ) ( 448 608 256 ) ( 448 608 0 ) eden/WL_edentown2 -64 0 0.00 1 1 0 0 0 +( 448 608 256 ) ( -96 608 256 ) ( -96 608 0 ) eden/WL_edentown2 64 0 -180.00 1 -1 0 0 0 +} +// brush 91 +{ +( 448 -800 0 ) ( 448 -768 0 ) ( -96 -768 0 ) eden/WL_edentown2 32 0 0.00 1 1 0 0 0 +( -96 -768 256 ) ( 448 -768 256 ) ( 448 -800 256 ) eden/WL_edentown2 32 0 0.00 1 1 0 0 0 +( -128 -768 256 ) ( -128 -800 256 ) ( -128 -800 0 ) eden/WL_edentown2 -32 0 0.00 1 1 0 0 0 +( -128 -800 256 ) ( 416 -800 256 ) ( 416 -800 0 ) eden/WL_edentown2 64 0 0.00 1 1 0 0 0 +( 448 -800 256 ) ( 448 -768 256 ) ( 448 -768 0 ) eden/WL_edentown2 -32 0 0.00 1 1 0 0 0 +( 448 -768 256 ) ( -96 -768 256 ) ( -96 -768 0 ) eden/WL_edentown2 63 0 -180.00 1 -1 0 0 0 +} +// brush 92 +{ +( 832 192 256 ) ( 832 -352 256 ) ( 832 -352 0 ) eden/WL_edentown2 0 0 0.00 1 1 0 0 0 +( 864 192 256 ) ( 832 192 256 ) ( 832 192 0 ) eden/WL_edentown2 -96 0 0.00 1 1 0 0 0 +( 864 -384 256 ) ( 864 160 256 ) ( 864 160 0 ) eden/WL_edentown2 0 0 0.00 1 1 0 0 0 +( 832 -384 256 ) ( 864 -384 256 ) ( 864 -384 0 ) eden/WL_edentown2 -96 0 0.00 1 1 0 0 0 +( 832 -352 256 ) ( 832 192 256 ) ( 864 192 256 ) eden/WL_edentown2 -96 0 0.00 1 1 0 0 0 +( 864 192 0 ) ( 832 192 0 ) ( 832 -352 0 ) eden/WL_edentown2 -96 0 0.00 1 1 0 0 0 +} +// brush 93 +{ +( -544 192 256 ) ( -544 -352 256 ) ( -544 -352 0 ) eden/WL_edentown2 0 0 0.00 1 1 0 0 0 +( -512 192 256 ) ( -544 192 256 ) ( -544 192 0 ) eden/WL_edentown2 0 0 0.00 1 1 0 0 0 +( -512 -384 256 ) ( -512 160 256 ) ( -512 160 0 ) eden/WL_edentown2 0 0 0.00 1 1 0 0 0 +( -544 -384 256 ) ( -512 -384 256 ) ( -512 -384 0 ) eden/WL_edentown2 0 0 0.00 1 1 0 0 0 +( -544 -352 256 ) ( -544 192 256 ) ( -512 192 256 ) eden/WL_edentown2 0 0 0.00 1 1 0 0 0 +( -512 192 0 ) ( -544 192 0 ) ( -544 -352 0 ) eden/WL_edentown2 0 0 0.00 1 1 0 0 0 +} +} +// entity 1 +{ +"classname" "Enemies_DarkCreeper" +"scale" "1.0" +"model" "creeper.tik" +"targetname" "creeper1" +"origin" "-312.00 -80.00 0.00" +} +// entity 2 +{ +"origin" "-500 -96 200" +"_color" "0.710744 0.987603 1.000000" +"classname" "light" +} +// entity 3 +{ +"classname" "info_pathnode" +"origin" "184 424 -128" +} +// entity 4 +{ +"classname" "info_player_start" +"angle" "135" +"origin" "496 128 -128" +} +// entity 5 +{ +"classname" "func_group" +"type" "patchCapped" +// brush 0 + { + patchDef2 + { + eden/edenmetalwall + ( 9 3 0 536870912 0 ) +( +( ( 32 -96 400 0 0 ) ( 32 -96 448 0 0.406250 ) ( 32 -96 496 0 0.812500 ) ) +( ( 16 -240 400 0.500000 0 ) ( 16 -240 448 0.500000 0.406250 ) ( 16 -240 496 0.500000 0.812500 ) ) +( ( 160 -224 400 1 0 ) ( 160 -224 448 1 0.406250 ) ( 160 -224 496 1 0.812500 ) ) +( ( 304 -240 400 1.500000 0 ) ( 304 -240 448 1.500000 0.406250 ) ( 304 -240 496 1.500000 0.812500 ) ) +( ( 288 -96 400 2 0 ) ( 288 -96 448 2 0.406250 ) ( 288 -96 496 2 0.812500 ) ) +( ( 304 48 400 2.500000 0 ) ( 304 48 448 2.500000 0.406250 ) ( 304 48 496 2.500000 0.812500 ) ) +( ( 160 32 400 3 0 ) ( 160 32 448 3 0.406250 ) ( 160 32 496 3 0.812500 ) ) +( ( 16 48 400 3.500000 0 ) ( 16 48 448 3.500000 0.406250 ) ( 16 48 496 3.500000 0.812500 ) ) +( ( 32 -96 400 4 0 ) ( 32 -96 448 4 0.406250 ) ( 32 -96 496 4 0.812500 ) ) +) + } + } +} +// entity 6 +{ +"origin" "360 424 -128" +"classname" "info_pathnode" +} +// entity 7 +{ +"origin" "184 232 -128" +"classname" "info_pathnode" +} +// entity 8 +{ +"classname" "info_pathnode" +"origin" "360 232 -128" +} +// entity 9 +{ +"origin" "184 72 -128" +"classname" "info_pathnode" +} +// entity 10 +{ +"classname" "info_pathnode" +"origin" "184 -120 -128" +} +// entity 11 +{ +"origin" "360 -120 -128" +"classname" "info_pathnode" +} +// entity 12 +{ +"classname" "info_pathnode" +"origin" "184 -280 -128" +} +// entity 13 +{ +"origin" "360 -280 -128" +"classname" "info_pathnode" +} +// entity 14 +{ +"origin" "184 -472 -128" +"classname" "info_pathnode" +} +// entity 15 +{ +"classname" "info_pathnode" +"origin" "360 -472 -128" +} +// entity 16 +{ +"origin" "184 -632 -128" +"classname" "info_pathnode" +} +// entity 17 +{ +"classname" "info_pathnode" +"origin" "360 -632 -128" +} +// entity 18 +{ +"classname" "info_pathnode" +"origin" "536 -120 -128" +} +// entity 19 +{ +"origin" "536 -312 -128" +"classname" "info_pathnode" +} +// entity 20 +{ +"origin" "536 -472 -128" +"classname" "info_pathnode" +} +// entity 21 +{ +"origin" "696 88 -128" +"classname" "info_pathnode" +} +// entity 22 +{ +"origin" "696 -72 -128" +"classname" "info_pathnode" +} +// entity 23 +{ +"classname" "info_pathnode" +"origin" "696 -264 -128" +} +// entity 24 +{ +"origin" "536 232 -128" +"classname" "info_pathnode" +} +// entity 25 +{ +"origin" "536 40 -128" +"classname" "info_pathnode" +} +// entity 26 +{ +"origin" "72 -280 -128" +"classname" "info_pathnode" +} +// entity 27 +{ +"classname" "info_pathnode" +"origin" "72 -56 -128" +} +// entity 28 +{ +"classname" "info_pathnode" +"origin" "72 -344 -112" +} +// entity 29 +{ +"origin" "72 -408 -80" +"classname" "info_pathnode" +} +// entity 30 +{ +"classname" "info_pathnode" +"origin" "72 -472 -48" +} +// entity 31 +{ +"origin" "72 -536 -16" +"classname" "info_pathnode" +} +// entity 32 +{ +"classname" "info_pathnode" +"origin" "72 -568 0" +} +// entity 33 +{ +"origin" "72 -696 0" +"classname" "info_pathnode" +} +// entity 34 +{ +"classname" "info_pathnode" +"origin" "-56 -664 0" +} +// entity 35 +{ +"origin" "72 -24 -128" +"classname" "info_pathnode" +} +// entity 36 +{ +"classname" "info_pathnode" +"origin" "72 72 -80" +} +// entity 37 +{ +"origin" "72 312 0" +"classname" "info_pathnode" +} +// entity 38 +{ +"classname" "info_pathnode" +"origin" "72 440 0" +} +// entity 39 +{ +"origin" "-88 440 0" +"classname" "info_pathnode" +} +// entity 40 +{ +"origin" "-88 -376 0" +"classname" "info_pathnode" +} +// entity 41 +{ +"origin" "-88 -536 0" +"classname" "info_pathnode" +"targetname" "patrol1" +} +// entity 42 +{ +"origin" "-88 328 0" +"classname" "info_pathnode" +"targetname" "patrol2" +} +// entity 43 +{ +"origin" "-88 168 0" +"classname" "info_pathnode" +} +// entity 44 +{ +"classname" "info_pathnode" +"origin" "-88 -24 0" +} +// entity 45 +{ +"classname" "info_pathnode" +"origin" "-88 -184 0" +} +// entity 46 +{ +"classname" "info_pathnode" +"origin" "-248 -376 0" +} +// entity 47 +{ +"classname" "info_pathnode" +"origin" "-216 -504 0" +} +// entity 48 +{ +"classname" "info_pathnode" +"origin" "-248 264 0" +} +// entity 49 +{ +"classname" "info_pathnode" +"origin" "-248 168 0" +} +// entity 50 +{ +"origin" "-248 -24 0" +"classname" "info_pathnode" +} +// entity 51 +{ +"origin" "-248 -184 0" +"classname" "info_pathnode" +} +// entity 52 +{ +"origin" "-408 -312 0" +"classname" "info_pathnode" +} +// entity 53 +{ +"origin" "-408 104 0" +"classname" "info_pathnode" +} +// entity 54 +{ +"classname" "info_pathnode" +"origin" "-408 -24 0" +} +// entity 55 +{ +"classname" "info_pathnode" +"origin" "-408 -184 0" +} +// entity 56 +{ +"classname" "info_pathnode" +"origin" "360 8 -128" +} +// entity 57 +{ +"origin" "72 168 -48" +"classname" "info_pathnode" +} +// entity 58 +{ +"classname" "info_pathnode" +"origin" "72 256 -16" +} +// entity 59 +{ +"classname" "light" +"_color" "0.710744 0.987603 1.000000" +"origin" "-500 -96 112" +} +// entity 60 +{ +"classname" "light" +"_color" "0.710744 0.987603 1.000000" +"origin" "820 -96 200" +} +// entity 61 +{ +"origin" "820 -96 112" +"_color" "0.710744 0.987603 1.000000" +"classname" "light" +} +// entity 62 +{ +"classname" "light" +"_color" "0.710744 0.987603 1.000000" +"origin" "160 564 200" +} +// entity 63 +{ +"origin" "160 564 112" +"_color" "0.710744 0.987603 1.000000" +"classname" "light" +} +// entity 64 +{ +"origin" "160 -756 200" +"_color" "0.710744 0.987603 1.000000" +"classname" "light" +} +// entity 65 +{ +"classname" "light" +"_color" "0.710744 0.987603 1.000000" +"origin" "160 -756 112" +} +// entity 66 +{ +"classname" "light" +"_color" "1.000000 1.000000 1.000000" +"origin" "-308 112 424" +} +// entity 67 +{ +"origin" "-4 352 424" +"_color" "1.000000 1.000000 1.000000" +"classname" "light" +} +// entity 68 +{ +"classname" "light" +"_color" "1.000000 1.000000 1.000000" +"origin" "348 352 424" +} +// entity 69 +{ +"origin" "620 80 424" +"_color" "1.000000 1.000000 1.000000" +"classname" "light" +} +// entity 70 +{ +"classname" "light" +"_color" "1.000000 1.000000 1.000000" +"origin" "636 -288 424" +} +// entity 71 +{ +"origin" "348 -576 424" +"_color" "1.000000 1.000000 1.000000" +"classname" "light" +} +// entity 72 +{ +"classname" "light" +"_color" "1.000000 1.000000 1.000000" +"origin" "-20 -560 424" +} +// entity 73 +{ +"origin" "-276 -256 424" +"_color" "1.000000 1.000000 1.000000" +"classname" "light" +} +// entity 74 +{ +"classname" "light" +"_color" "1.000000 1.000000 1.000000" +"origin" "164 -96 424" +} +// entity 75 +{ +"classname" "info_pathnode" +"origin" "616 184 -128" +} +// entity 76 +{ +"origin" "632 -376 -128" +"classname" "info_pathnode" +} +// entity 77 +{ +"origin" "456 344 -128" +"classname" "info_pathnode" +} +// entity 78 +{ +"classname" "info_pathnode" +"origin" "488 -552 -128" +} diff --git a/fakk/maps/example/patrol.prt b/fakk/maps/example/patrol.prt new file mode 100644 index 0000000..1133044 --- /dev/null +++ b/fakk/maps/example/patrol.prt @@ -0,0 +1,538 @@ +PRT1 +74 +187 +347 +4 0 59 0 (0 24 496 ) (0 576 496 ) (0 576 408 ) (0 24 408 ) +5 0 3 0 (0 576 408 ) (448 576 408 ) (832 192 408 ) (832 24 408 ) (0 24 408 ) +4 0 2 0 (208 24 408 ) (832 24 408 ) (832 24 496 ) (208 24 496 ) +4 0 1 0 (0 24 408 ) (112 24 408 ) (112 24 496 ) (0 24 496 ) +4 1 59 0 (0 0 408 ) (0 0 496 ) (0 24 496 ) (0 24 408 ) +4 1 27 0 (40 0 408 ) (88 0 408 ) (88 0 496 ) (40 0 496 ) +4 1 30 0 (0 0 496 ) (0 0 408 ) (40 0 408 ) (40 0 496 ) +4 1 3 0 (88 0 408 ) (0 0 408 ) (0 24 408 ) (112 24 408 ) +4 2 23 0 (232 0 408 ) (280 0 408 ) (280 0 496 ) (232 0 496 ) +4 2 21 0 (280 0 408 ) (832 0 408 ) (832 0 496 ) (280 0 496 ) +4 2 3 0 (832 24 408 ) (832 0 408 ) (232 0 408 ) (208 24 408 ) +4 3 59 0 (0 0 288 ) (0 0 408 ) (0 576 408 ) (0 576 288 ) +4 3 31 0 (0 0 408 ) (0 0 288 ) (832 0 288 ) (832 0 408 ) +5 3 4 0 (768 0 288 ) (0 0 288 ) (0 512 288 ) (416 512 288 ) (768 160 288 ) +4 4 60 0 (0 0 256 ) (0 0 288 ) (0 512 288 ) (0 512 256 ) +4 4 32 0 (0 0 288 ) (0 0 256 ) (768 0 256 ) (768 0 288 ) +5 4 10 0 (768 0 256 ) (0 0 256 ) (0 512 256 ) (416 512 256 ) (768 160 256 ) +4 5 61 0 (0 568 256 ) (0 576 256 ) (0 576 240 ) (0 568 240 ) +4 5 10 0 (456 568 256 ) (0 568 256 ) (0 568 240 ) (456 568 240 ) +4 5 8 0 (136 568 240 ) (0 568 240 ) (0 576 240 ) (136 576 240 ) +4 5 6 0 (456 568 240 ) (184 568 240 ) (184 576 240 ) (448 576 240 ) +4 6 10 0 (456 568 240 ) (184 568 240 ) (184 568 64 ) (456 568 64 ) +4 6 9 0 (456 568 64 ) (184 568 64 ) (184 576 64 ) (448 576 64 ) +4 7 10 0 (152 568 224 ) (152 568 80 ) (168 568 80 ) (168 568 224 ) +4 8 61 0 (0 576 240 ) (0 576 64 ) (0 568 64 ) (0 568 240 ) +4 8 10 0 (136 568 240 ) (0 568 240 ) (0 568 64 ) (136 568 64 ) +4 8 9 0 (136 568 64 ) (0 568 64 ) (0 576 64 ) (136 576 64 ) +4 9 61 0 (0 576 64 ) (0 576 8 ) (0 568 8 ) (0 568 64 ) +4 9 10 0 (0 568 8 ) (456 568 8 ) (456 568 64 ) (0 568 64 ) +4 10 61 0 (0 0 8 ) (0 0 256 ) (0 568 256 ) (0 568 8 ) +4 10 38 0 (0 0 240 ) (0 0 8 ) (824 0 8 ) (824 0 240 ) +4 10 37 0 (824 0 8 ) (832 0 8 ) (832 0 64 ) (824 0 64 ) +4 10 34 0 (832 0 64 ) (832 0 240 ) (824 0 240 ) (824 0 64 ) +4 10 33 0 (0 0 256 ) (0 0 240 ) (832 0 240 ) (832 0 256 ) +4 10 19 0 (8 328 8 ) (128 328 8 ) (128 320 8 ) (8 320 8 ) +4 10 18 0 (0 328 8 ) (0 512 8 ) (128 512 8 ) (128 328 8 ) +4 10 17 0 (128 0 8 ) (0 0 8 ) (0 320 8 ) (128 320 8 ) +4 10 16 0 (136 0 8 ) (128 0 8 ) (128 320 8 ) (136 320 8 ) +4 10 15 0 (320 0 8 ) (136 0 8 ) (136 512 8 ) (320 512 8 ) +5 10 11 0 (320 64 8 ) (320 512 8 ) (416 512 8 ) (768 160 8 ) (768 64 8 ) +4 10 14 0 (768 0 8 ) (320 0 8 ) (320 64 8 ) (768 64 8 ) +4 11 15 0 (320 512 8 ) (320 512 0 ) (320 64 0 ) (320 64 8 ) +5 11 13 0 (768 64 0 ) (448 64 0 ) (448 192 0 ) (736 192 0 ) (768 160 0 ) +4 11 12 0 (320 192 0 ) (320 512 0 ) (416 512 0 ) (736 192 0 ) +4 11 14 0 (320 64 8 ) (320 64 0 ) (768 64 0 ) (768 64 8 ) +4 12 15 0 (320 512 0 ) (320 512 -128 ) (320 192 -128 ) (320 192 0 ) +4 12 13 0 (736 192 -128 ) (736 192 0 ) (448 192 0 ) (448 192 -128 ) +4 13 14 0 (448 64 -128 ) (768 64 -128 ) (768 64 0 ) (448 64 0 ) +4 14 43 0 (320 0 -128 ) (768 0 -128 ) (768 0 8 ) (320 0 8 ) +4 14 15 0 (320 64 -128 ) (320 0 -128 ) (320 0 8 ) (320 64 8 ) +4 15 43 0 (136 0 -128 ) (320 0 -128 ) (320 0 8 ) (136 0 8 ) +3 15 16 0 (136 0 -120 ) (136 0 8 ) (136 320 8 ) +4 16 43 0 (136 0 -120 ) (136 0 8 ) (128 0 8 ) (128 0 -120 ) +3 16 17 0 (128 0 -120 ) (128 0 8 ) (128 320 8 ) +4 17 55 0 (0 0 8 ) (0 0 -120 ) (8 0 -120 ) (8 0 8 ) +4 17 43 0 (8 0 -120 ) (128 0 -120 ) (128 0 8 ) (8 0 8 ) +4 17 20 0 (128 300 0 ) (128 0 -120 ) (8 0 -120 ) (8 300 0 ) +4 17 19 0 (8 320 8 ) (128 320 8 ) (128 300 0 ) (8 300 0 ) +4 18 62 0 (0 328 8 ) (0 512 8 ) (0 512 0 ) (0 328 0 ) +4 18 19 0 (8 328 0 ) (128 328 0 ) (128 328 8 ) (8 328 8 ) +4 19 20 0 (128 300 0 ) (8 300 0 ) (8 320 0 ) (128 320 0 ) +4 20 43 0 (8 0 -128 ) (128 0 -128 ) (128 0 -120 ) (8 0 -120 ) +5 21 31 0 (280 0 408 ) (832 0 408 ) (832 -384 408 ) (448 -768 408 ) (280 -768 408 ) +4 21 23 0 (280 0 408 ) (280 -48 408 ) (280 -48 496 ) (280 0 496 ) +4 21 22 0 (280 -144 408 ) (280 -216 408 ) (280 -216 496 ) (280 -144 496 ) +4 21 29 0 (280 -216 408 ) (280 -768 408 ) (280 -768 496 ) (280 -216 496 ) +4 22 31 0 (280 -144 408 ) (280 -216 408 ) (232 -216 408 ) (232 -192 408 ) +4 22 25 0 (232 -192 408 ) (232 -216 408 ) (232 -216 496 ) (232 -192 496 ) +4 22 29 0 (232 -216 408 ) (280 -216 408 ) (280 -216 496 ) (232 -216 496 ) +3 23 31 0 (232 0 408 ) (280 0 408 ) (280 -48 408 ) +8 24 31 0 (232 -64 408 ) (232 -128 408 ) (192 -168 408 ) (128 -168 408 ) (88 -128 408 ) (88 -64 408 ) (128 -24 408 ) (192 -24 408 ) +3 25 31 0 (232 -192 408 ) (232 -216 408 ) (208 -216 408 ) +4 25 29 0 (208 -216 408 ) (232 -216 408 ) (232 -216 496 ) (208 -216 496 ) +3 26 31 0 (112 -216 408 ) (88 -216 408 ) (88 -192 408 ) +4 26 28 0 (88 -192 408 ) (88 -216 408 ) (88 -216 496 ) (88 -192 496 ) +4 26 29 0 (88 -216 408 ) (112 -216 408 ) (112 -216 496 ) (88 -216 496 ) +3 27 31 0 (40 0 408 ) (88 0 408 ) (40 -48 408 ) +4 27 30 0 (40 0 408 ) (40 -48 408 ) (40 -48 496 ) (40 0 496 ) +4 28 31 0 (88 -192 408 ) (88 -216 408 ) (40 -216 408 ) (40 -144 408 ) +4 28 29 0 (40 -216 496 ) (40 -216 408 ) (88 -216 408 ) (88 -216 496 ) +4 28 30 0 (40 -144 408 ) (40 -216 408 ) (40 -216 496 ) (40 -144 496 ) +4 29 31 0 (280 -216 408 ) (280 -768 408 ) (40 -768 408 ) (40 -216 408 ) +4 29 30 0 (40 -216 408 ) (40 -768 408 ) (40 -768 496 ) (40 -216 496 ) +4 30 64 0 (0 -768 496 ) (0 0 496 ) (0 0 408 ) (0 -768 408 ) +4 30 31 0 (0 -768 408 ) (0 0 408 ) (40 0 408 ) (40 -768 408 ) +4 31 64 0 (0 -768 408 ) (0 0 408 ) (0 0 288 ) (0 -768 288 ) +5 31 32 0 (0 -704 288 ) (0 0 288 ) (768 0 288 ) (768 -352 288 ) (416 -704 288 ) +4 32 65 0 (0 -704 288 ) (0 0 288 ) (0 0 256 ) (0 -704 256 ) +5 32 33 0 (0 -704 256 ) (0 0 256 ) (768 0 256 ) (768 -352 256 ) (416 -704 256 ) +4 33 66 0 (0 -768 256 ) (0 0 256 ) (0 0 240 ) (0 -768 240 ) +4 33 39 0 (184 -760 240 ) (456 -760 240 ) (448 -768 240 ) (184 -768 240 ) +4 33 41 0 (0 -768 240 ) (0 -760 240 ) (136 -760 240 ) (136 -768 240 ) +5 33 38 0 (0 -760 240 ) (0 0 240 ) (824 0 240 ) (824 -392 240 ) (456 -760 240 ) +4 33 36 0 (832 -120 240 ) (832 -384 240 ) (824 -392 240 ) (824 -120 240 ) +4 33 34 0 (824 0 240 ) (832 0 240 ) (832 -72 240 ) (824 -72 240 ) +4 34 38 0 (824 -72 240 ) (824 0 240 ) (824 0 64 ) (824 -72 64 ) +4 34 37 0 (824 -72 64 ) (824 0 64 ) (832 0 64 ) (832 -72 64 ) +4 35 38 0 (824 -88 224 ) (824 -88 80 ) (824 -104 80 ) (824 -104 224 ) +4 36 38 0 (824 -392 240 ) (824 -120 240 ) (824 -120 64 ) (824 -392 64 ) +4 36 37 0 (824 -392 64 ) (824 -120 64 ) (832 -120 64 ) (832 -384 64 ) +4 37 38 0 (824 0 8 ) (824 -392 8 ) (824 -392 64 ) (824 0 64 ) +4 38 66 0 (0 -760 240 ) (0 0 240 ) (0 0 8 ) (0 -760 8 ) +4 38 58 0 (0 -704 8 ) (0 -584 8 ) (8 -584 8 ) (8 -704 8 ) +4 38 56 0 (0 -576 8 ) (0 -344 8 ) (8 -344 8 ) (8 -576 8 ) +4 38 55 0 (0 -344 8 ) (0 0 8 ) (8 0 8 ) (8 -344 8 ) +4 38 53 0 (128 -704 8 ) (8 -704 8 ) (8 -576 8 ) (128 -576 8 ) +4 38 51 0 (8 -576 8 ) (8 -544 8 ) (128 -544 8 ) (128 -576 8 ) +4 38 49 0 (8 -544 8 ) (8 -512 8 ) (128 -512 8 ) (128 -544 8 ) +4 38 47 0 (8 -512 8 ) (8 -480 8 ) (128 -480 8 ) (128 -512 8 ) +4 38 46 0 (8 -480 8 ) (8 -344 8 ) (128 -344 8 ) (128 -480 8 ) +4 38 45 0 (128 -576 8 ) (128 -344 8 ) (136 -344 8 ) (136 -576 8 ) +5 38 44 0 (768 -344 8 ) (768 -352 8 ) (416 -704 8 ) (136 -704 8 ) (136 -344 8 ) +4 38 43 0 (8 0 8 ) (768 0 8 ) (768 -344 8 ) (8 -344 8 ) +4 38 42 0 (0 -760 8 ) (456 -760 8 ) (456 -760 64 ) (0 -760 64 ) +4 38 40 0 (152 -760 224 ) (152 -760 80 ) (168 -760 80 ) (168 -760 224 ) +4 38 39 0 (456 -760 64 ) (456 -760 240 ) (184 -760 240 ) (184 -760 64 ) +4 38 41 0 (136 -760 240 ) (0 -760 240 ) (0 -760 64 ) (136 -760 64 ) +4 39 42 0 (448 -768 64 ) (184 -768 64 ) (184 -760 64 ) (456 -760 64 ) +4 41 66 0 (0 -768 240 ) (0 -760 240 ) (0 -760 64 ) (0 -768 64 ) +4 41 42 0 (136 -768 64 ) (0 -768 64 ) (0 -760 64 ) (136 -760 64 ) +4 42 66 0 (0 -760 64 ) (0 -760 8 ) (0 -768 8 ) (0 -768 64 ) +4 43 55 0 (8 0 -128 ) (8 -344 -128 ) (8 -344 8 ) (8 0 8 ) +4 43 54 0 (8 -344 -112 ) (8 -344 -128 ) (128 -344 -128 ) (128 -344 -112 ) +4 43 52 0 (8 -344 -96 ) (8 -344 -112 ) (128 -344 -112 ) (128 -344 -96 ) +4 43 50 0 (8 -344 -80 ) (8 -344 -96 ) (128 -344 -96 ) (128 -344 -80 ) +4 43 48 0 (8 -344 -64 ) (8 -344 -80 ) (128 -344 -80 ) (128 -344 -64 ) +4 43 46 0 (8 -344 8 ) (8 -344 -64 ) (128 -344 -64 ) (128 -344 8 ) +4 43 45 0 (136 -344 -112 ) (136 -344 8 ) (128 -344 8 ) (128 -344 -112 ) +4 43 44 0 (136 -344 -128 ) (768 -344 -128 ) (768 -344 8 ) (136 -344 8 ) +3 44 45 0 (136 -344 8 ) (136 -344 -112 ) (136 -576 8 ) +3 45 52 0 (128 -344 -96 ) (128 -344 -112 ) (128 -374.933319 -96 ) +3 45 51 0 (128 -544 -8.551724 ) (128 -576 8 ) (128 -544 8 ) +4 45 50 0 (128 -344 -80 ) (128 -344 -96 ) (128 -374.933319 -96 ) (128 -405.866669 -80 ) +4 45 49 0 (128 -512 -25.103449 ) (128 -544 -8.551724 ) (128 -544 8 ) (128 -512 8 ) +4 45 48 0 (128 -344 -64 ) (128 -344 -80 ) (128 -405.866669 -80 ) (128 -436.799988 -64 ) +4 45 47 0 (128 -480 -41.655170 ) (128 -512 -25.103449 ) (128 -512 8 ) (128 -480 8 ) +5 45 46 0 (128 -344 8 ) (128 -344 -64 ) (128 -436.799988 -64 ) (128 -480 -41.655170 ) (128 -480 8 ) +5 46 57 0 (8 -344 0 ) (8 -344 -64 ) (8 -436.799988 -64 ) (8 -480 -41.655167 ) (8 -480 0 ) +4 46 56 0 (8 -480 8 ) (8 -344 8 ) (8 -344 0 ) (8 -480 0 ) +4 46 48 0 (8 -448 -64 ) (8 -344 -64 ) (128 -344 -64 ) (128 -448 -64 ) +4 46 47 0 (8 -480 8 ) (8 -480 -48 ) (128 -480 -48 ) (128 -480 8 ) +4 47 57 0 (8 -480 0 ) (8 -480 -41.655163 ) (8 -512 -25.103441 ) (8 -512 0 ) +4 47 56 0 (8 -512 8 ) (8 -480 8 ) (8 -480 0 ) (8 -512 0 ) +4 47 49 0 (8 -512 8 ) (8 -512 -32 ) (128 -512 -32 ) (128 -512 8 ) +4 48 57 0 (8 -344 -64 ) (8 -344 -80 ) (8 -405.866638 -80 ) (8 -436.799988 -64 ) +4 48 50 0 (8 -416 -80 ) (8 -344 -80 ) (128 -344 -80 ) (128 -416 -80 ) +4 49 57 0 (8 -512 0 ) (8 -512 -25.103439 ) (8 -544 -8.551716 ) (8 -544 0 ) +4 49 56 0 (8 -544 8 ) (8 -512 8 ) (8 -512 0 ) (8 -544 0 ) +4 49 51 0 (8 -544 8 ) (8 -544 -16 ) (128 -544 -16 ) (128 -544 8 ) +4 50 57 0 (8 -344 -80 ) (8 -344 -96 ) (8 -374.933319 -96 ) (8 -405.866638 -80 ) +4 50 52 0 (8 -384 -96 ) (8 -344 -96 ) (128 -344 -96 ) (128 -384 -96 ) +3 51 57 0 (8 -544 0 ) (8 -544 -8.551715 ) (8 -560.533325 0 ) +4 51 56 0 (8 -576 8 ) (8 -544 8 ) (8 -544 0 ) (8 -560.533325 0 ) +4 51 53 0 (8 -576 8 ) (8 -576 0 ) (128 -576 0 ) (128 -576 8 ) +3 52 57 0 (8 -344 -96 ) (8 -344 -112 ) (8 -374.933319 -96 ) +4 52 54 0 (8 -352 -112 ) (8 -344 -112 ) (128 -344 -112 ) (128 -352 -112 ) +4 53 58 0 (8 -704 0 ) (8 -704 8 ) (8 -584 8 ) (8 -584 0 ) +4 55 57 0 (8 -344 -112 ) (8 -344 0 ) (0 -344 0 ) (0 -344 -112 ) +4 55 56 0 (8 -344 0 ) (8 -344 8 ) (0 -344 8 ) (0 -344 0 ) +4 56 57 0 (0 -560.533325 0 ) (0 -344 0 ) (8 -344 0 ) (8 -560.533325 0 ) +4 58 72 0 (0 -704 8 ) (0 -584 8 ) (0 -584 0 ) (0 -704 0 ) +4 59 64 0 (-512 0 288 ) (0 0 288 ) (0 0 496 ) (-512 0 496 ) +5 59 60 0 (0 0 288 ) (-448 0 288 ) (-448 160 288 ) (-96 512 288 ) (0 512 288 ) +4 60 65 0 (-448 0 256 ) (0 0 256 ) (0 0 288 ) (-448 0 288 ) +5 60 61 0 (0 0 256 ) (-448 0 256 ) (-448 160 256 ) (-96 512 256 ) (0 512 256 ) +4 61 71 0 (-512 0 8 ) (-504 0 8 ) (-504 0 64 ) (-512 0 64 ) +4 61 68 0 (-504 0 64 ) (-504 0 240 ) (-512 0 240 ) (-512 0 64 ) +4 61 67 0 (-504 0 240 ) (-504 0 256 ) (-512 0 256 ) (-512 0 240 ) +4 61 66 0 (-504 0 8 ) (0 0 8 ) (0 0 256 ) (-504 0 256 ) +5 61 63 0 (-8 0 8 ) (-448 0 8 ) (-448 160 8 ) (-96 512 8 ) (-8 512 8 ) +4 61 62 0 (-8 328 8 ) (-8 512 8 ) (0 512 8 ) (0 328 8 ) +4 62 63 0 (-8 512 8 ) (-8 512 0 ) (-8 328 0 ) (-8 328 8 ) +4 63 73 0 (-8 0 8 ) (-448 0 8 ) (-448 0 0 ) (-8 0 0 ) +5 64 65 0 (-448 0 288 ) (0 0 288 ) (0 -704 288 ) (-96 -704 288 ) (-448 -352 288 ) +5 65 66 0 (-448 0 256 ) (0 0 256 ) (0 -704 256 ) (-96 -704 256 ) (-448 -352 256 ) +5 66 73 0 (-448 0 8 ) (-8 0 8 ) (-8 -704 8 ) (-96 -704 8 ) (-448 -352 8 ) +4 66 72 0 (0 -584 8 ) (0 -704 8 ) (-8 -704 8 ) (-8 -584 8 ) +4 66 71 0 (-504 0 8 ) (-504 -392 8 ) (-504 -392 64 ) (-504 0 64 ) +4 66 70 0 (-504 -392 64 ) (-504 -392 240 ) (-504 -120 240 ) (-504 -120 64 ) +4 66 69 0 (-504 -104 80 ) (-504 -104 224 ) (-504 -88 224 ) (-504 -88 80 ) +4 66 68 0 (-504 -72 240 ) (-504 0 240 ) (-504 0 64 ) (-504 -72 64 ) +4 66 67 0 (-504 -392 240 ) (-504 -392 256 ) (-504 0 256 ) (-504 0 240 ) +4 67 70 0 (-512 -384 240 ) (-512 -120 240 ) (-504 -120 240 ) (-504 -392 240 ) +4 67 68 0 (-512 -72 240 ) (-512 0 240 ) (-504 0 240 ) (-504 -72 240 ) +4 68 71 0 (-512 -72 64 ) (-512 0 64 ) (-504 0 64 ) (-504 -72 64 ) +4 70 71 0 (-512 -384 64 ) (-512 -120 64 ) (-504 -120 64 ) (-504 -392 64 ) +4 72 73 0 (-8 -584 0 ) (-8 -704 0 ) (-8 -704 8 ) (-8 -584 8 ) +4 0 (112 24 408 ) (208 24 408 ) (208 24 496 ) (112 24 496 ) +4 0 (448 576 408 ) (0 576 408 ) (0 576 496 ) (448 576 496 ) +5 0 (832 24 496 ) (832 192 496 ) (448 576 496 ) (0 576 496 ) (0 24 496 ) +4 0 (832 24 408 ) (832 192 408 ) (832 192 496 ) (832 24 496 ) +4 0 (832 192 496 ) (832 192 408 ) (448 576 408 ) (448 576 496 ) +4 1 (88 0 408 ) (112 24 408 ) (112 24 496 ) (88 0 496 ) +4 1 (112 24 496 ) (0 24 496 ) (0 0 496 ) (88 0 496 ) +4 2 (832 24 408 ) (832 24 496 ) (832 0 496 ) (832 0 408 ) +4 2 (832 24 496 ) (208 24 496 ) (232 0 496 ) (832 0 496 ) +4 2 (208 24 496 ) (208 24 408 ) (232 0 408 ) (232 0 496 ) +4 3 (416 512 288 ) (512 512 288 ) (768 256 288 ) (768 160 288 ) +4 3 (832 0 288 ) (768 0 288 ) (768 256 288 ) (832 192 288 ) +4 3 (0 512 288 ) (0 576 288 ) (448 576 288 ) (512 512 288 ) +4 3 (832 192 408 ) (832 0 408 ) (832 0 288 ) (832 192 288 ) +4 3 (0 576 408 ) (448 576 408 ) (448 576 288 ) (0 576 288 ) +4 3 (208 24 408 ) (112 24 408 ) (88 0 408 ) (232 0 408 ) +4 3 (448 576 288 ) (448 576 408 ) (832 192 408 ) (832 192 288 ) +4 4 (768 160 288 ) (768 0 288 ) (768 0 256 ) (768 160 256 ) +4 4 (0 512 288 ) (416 512 288 ) (416 512 256 ) (0 512 256 ) +4 4 (768 160 288 ) (768 160 256 ) (416 512 256 ) (416 512 288 ) +4 5 (152 568 240 ) (136 568 240 ) (136 576 240 ) (152 576 240 ) +4 5 (168 568 240 ) (152 568 240 ) (152 572 240 ) (168 572 240 ) +4 5 (152 572 240 ) (152 576 240 ) (168 576 240 ) (168 572 240 ) +4 5 (184 568 240 ) (168 568 240 ) (168 576 240 ) (184 576 240 ) +4 5 (456 568 256 ) (448 576 256 ) (0 576 256 ) (0 568 256 ) +4 5 (448 576 240 ) (0 576 240 ) (0 576 256 ) (448 576 256 ) +4 5 (456 568 256 ) (456 568 240 ) (448 576 240 ) (448 576 256 ) +4 6 (184 576 64 ) (184 568 64 ) (184 568 240 ) (184 576 240 ) +4 6 (448 576 64 ) (184 576 64 ) (184 576 240 ) (448 576 240 ) +4 6 (456 568 64 ) (448 576 64 ) (448 576 240 ) (456 568 240 ) +4 7 (152 568 80 ) (152 568 224 ) (152 572 224 ) (152 572 80 ) +4 7 (168 572 224 ) (168 572 80 ) (152 572 80 ) (152 572 224 ) +4 7 (168 572 80 ) (168 572 224 ) (168 568 224 ) (168 568 80 ) +4 7 (152 568 80 ) (152 572 80 ) (168 572 80 ) (168 568 80 ) +4 7 (168 568 224 ) (168 572 224 ) (152 572 224 ) (152 568 224 ) +4 8 (136 576 64 ) (0 576 64 ) (0 576 240 ) (136 576 240 ) +4 8 (136 576 240 ) (136 568 240 ) (136 568 64 ) (136 576 64 ) +4 9 (0 568 8 ) (0 576 8 ) (448 576 8 ) (456 568 8 ) +4 9 (0 576 64 ) (448 576 64 ) (448 576 8 ) (0 576 8 ) +4 9 (184 576 64 ) (168 576 64 ) (168 568 64 ) (184 568 64 ) +4 9 (168 576 64 ) (152 576 64 ) (152 568 64 ) (168 568 64 ) +4 9 (152 576 64 ) (136 576 64 ) (136 568 64 ) (152 568 64 ) +4 9 (448 576 8 ) (448 576 64 ) (456 568 64 ) (456 568 8 ) +4 10 (0 320 8 ) (0 328 8 ) (8 328 8 ) (8 320 8 ) +4 10 (128 320 8 ) (128 512 8 ) (136 512 8 ) (136 320 8 ) +4 10 (416 512 8 ) (512 512 8 ) (768 256 8 ) (768 160 8 ) +4 10 (0 512 8 ) (0 568 8 ) (456 568 8 ) (512 512 8 ) +4 10 (832 0 8 ) (768 0 8 ) (768 256 8 ) (832 192 8 ) +4 10 (832 192 256 ) (832 0 256 ) (832 0 8 ) (832 192 8 ) +4 10 (152 568 64 ) (136 568 64 ) (136 568 240 ) (152 568 240 ) +4 10 (168 568 224 ) (152 568 224 ) (152 568 240 ) (168 568 240 ) +4 10 (168 568 80 ) (168 568 64 ) (152 568 64 ) (152 568 80 ) +4 10 (184 568 64 ) (168 568 64 ) (168 568 240 ) (184 568 240 ) +4 10 (512 512 256 ) (456 568 256 ) (0 568 256 ) (0 512 256 ) +4 10 (832 192 256 ) (768 256 256 ) (768 0 256 ) (832 0 256 ) +4 10 (768 160 256 ) (768 256 256 ) (512 512 256 ) (416 512 256 ) +4 10 (832 192 256 ) (832 192 8 ) (456 568 8 ) (456 568 256 ) +4 11 (448 64 0 ) (320 64 0 ) (320 192 0 ) (448 192 0 ) +4 11 (768 64 0 ) (768 160 0 ) (768 160 8 ) (768 64 8 ) +4 11 (416 512 0 ) (320 512 0 ) (320 512 8 ) (416 512 8 ) +4 11 (768 160 8 ) (768 160 0 ) (416 512 0 ) (416 512 8 ) +4 12 (448 192 0 ) (320 192 0 ) (320 192 -128 ) (448 192 -128 ) +4 12 (416 512 -128 ) (416 512 0 ) (736 192 0 ) (736 192 -128 ) +4 12 (320 512 0 ) (416 512 0 ) (416 512 -128 ) (320 512 -128 ) +4 12 (320 192 -128 ) (320 512 -128 ) (416 512 -128 ) (736 192 -128 ) +5 13 (768 160 -128 ) (768 64 -128 ) (448 64 -128 ) (448 192 -128 ) (736 192 -128 ) +4 13 (768 160 0 ) (768 64 0 ) (768 64 -128 ) (768 160 -128 ) +4 13 (736 192 0 ) (768 160 0 ) (768 160 -128 ) (736 192 -128 ) +4 13 (448 192 0 ) (448 192 -128 ) (448 64 -128 ) (448 64 0 ) +4 14 (448 64 0 ) (448 64 -128 ) (320 64 -128 ) (320 64 0 ) +4 14 (768 64 -128 ) (768 0 -128 ) (320 0 -128 ) (320 64 -128 ) +4 14 (768 64 -128 ) (768 64 8 ) (768 0 8 ) (768 0 -128 ) +5 15 (136 512 8 ) (136 512 -128 ) (136 0 -128 ) (136 0 -120 ) (136 320 8 ) +4 15 (320 192 0 ) (320 64 0 ) (320 64 -128 ) (320 192 -128 ) +4 15 (136 512 8 ) (320 512 8 ) (320 512 -128 ) (136 512 -128 ) +4 15 (320 0 -128 ) (136 0 -128 ) (136 512 -128 ) (320 512 -128 ) +4 16 (128 0 -120 ) (128 319.998993 8 ) (136 320 8 ) (136 0 -120 ) +4 17 (0 0 0 ) (0 0 8 ) (0 320 8 ) (0 300 0 ) +3 17 (0 0 -120 ) (0 0 0 ) (0 300 0 ) +4 17 (8 0 -120 ) (0 0 -120 ) (0 300 0 ) (8 300 0 ) +4 17 (0 320 8 ) (8 320 8 ) (8 300 0 ) (0 300 0 ) +4 18 (8 512 0 ) (128 512 0 ) (128 328 0 ) (8 328 0 ) +4 18 (0 328 0 ) (0 512 0 ) (8 512 0 ) (8 328 0 ) +4 18 (0 328 0 ) (8 328 0 ) (8 328 8 ) (0 328 8 ) +4 18 (0 512 0 ) (0 512 8 ) (128 512 8 ) (128 512 0 ) +4 18 (128 328 8 ) (128 328 0 ) (128 512 0 ) (128 512 8 ) +4 19 (8 320 0 ) (8 328 0 ) (128 328 0 ) (128 320 0 ) +4 19 (128 328 8 ) (128 320 8 ) (128 300 0 ) (128 328 0 ) +4 19 (8 328 8 ) (8 328 0 ) (8 300 0 ) (8 320 8 ) +4 20 (8 0 -120 ) (8 300 0 ) (8 320 0 ) (8 0 -128 ) +4 20 (128 320 0 ) (128 300 0 ) (128 0 -120 ) (128 0 -128 ) +4 20 (8 0 -128 ) (8 319.998627 0 ) (128 319.998627 0 ) (128 0 -128 ) +4 21 (280 -48 408 ) (280 -144 408 ) (280 -144 496 ) (280 -48 496 ) +4 21 (832 0 496 ) (832 -384 496 ) (832 -384 408 ) (832 0 408 ) +5 21 (280 -768 496 ) (448 -768 496 ) (832 -384 496 ) (832 0 496 ) (280 0 496 ) +4 21 (280 -768 408 ) (448 -768 408 ) (448 -768 496 ) (280 -768 496 ) +4 21 (448 -768 496 ) (448 -768 408 ) (832 -384 408 ) (832 -384 496 ) +4 22 (280 -144 496 ) (280 -144 408 ) (232 -192 408 ) (232 -192 496 ) +4 22 (232 -192 496 ) (232 -216 496 ) (280 -216 496 ) (280 -144 496 ) +3 23 (280 -48 496 ) (280 0 496 ) (232 0 496 ) +4 23 (232 0 496 ) (232 0 408 ) (280 -48 408 ) (280 -48 496 ) +4 24 (88 -64 408 ) (88 -128 408 ) (88 -128 496 ) (88 -64 496 ) +4 24 (128 -168 408 ) (192 -168 408 ) (192 -168 496 ) (128 -168 496 ) +4 24 (192 -168 496 ) (192 -168 408 ) (232 -128 408 ) (232 -128 496 ) +4 24 (88 -128 496 ) (88 -128 408 ) (128 -168 408 ) (128 -168 496 ) +4 24 (232 -64 496 ) (232 -128 496 ) (232 -128 408 ) (232 -64 408 ) +8 24 (192 -24 496 ) (128 -24 496 ) (88 -64 496 ) (88 -128 496 ) (128 -168 496 ) (192 -168 496 ) (232 -128 496 ) (232 -64 496 ) +4 24 (128 -24 496 ) (192 -24 496 ) (192 -24 408 ) (128 -24 408 ) +4 24 (128 -24 496 ) (128 -24 408 ) (88 -64 408 ) (88 -64 496 ) +4 24 (232 -64 496 ) (232 -64 408 ) (192 -24 408 ) (192 -24 496 ) +4 25 (232 -192 496 ) (232 -192 408 ) (208 -216 408 ) (208 -216 496 ) +3 25 (208 -216 496 ) (232 -216 496 ) (232 -192 496 ) +3 26 (88 -192 496 ) (88 -216 496 ) (112 -216 496 ) +4 26 (112 -216 496 ) (112 -216 408 ) (88 -192 408 ) (88 -192 496 ) +4 27 (40 -48 496 ) (40 -48 408 ) (88 0 408 ) (88 0 496 ) +3 27 (40 -48 496 ) (88 0 496 ) (40 0 496 ) +4 28 (40 -144 496 ) (40 -216 496 ) (88 -216 496 ) (88 -192 496 ) +4 28 (88 -192 496 ) (88 -192 408 ) (40 -144 408 ) (40 -144 496 ) +4 29 (112 -216 496 ) (208 -216 496 ) (208 -216 408 ) (112 -216 408 ) +4 29 (40 -768 408 ) (280 -768 408 ) (280 -768 496 ) (40 -768 496 ) +4 29 (40 -216 496 ) (40 -768 496 ) (280 -768 496 ) (280 -216 496 ) +4 30 (40 -48 496 ) (40 -144 496 ) (40 -144 408 ) (40 -48 408 ) +4 30 (40 -768 496 ) (40 0 496 ) (0 0 496 ) (0 -768 496 ) +4 30 (0 -768 408 ) (40 -768 408 ) (40 -768 496 ) (0 -768 496 ) +4 31 (768 -352 288 ) (768 -448 288 ) (512 -704 288 ) (416 -704 288 ) +4 31 (0 -768 288 ) (0 -704 288 ) (512 -704 288 ) (448 -768 288 ) +4 31 (768 0 288 ) (832 0 288 ) (832 -384 288 ) (768 -448 288 ) +4 31 (832 0 408 ) (832 -384 408 ) (832 -384 288 ) (832 0 288 ) +4 31 (232 -192 408 ) (280 -144 408 ) (280 -48 408 ) (232 0 408 ) +4 31 (88 -24 408 ) (232 -24 408 ) (232 0 408 ) (88 0 408 ) +3 31 (88 -128 408 ) (88 -168 408 ) (128 -168 408 ) +3 31 (128 -24 408 ) (88 -24 408 ) (88 -64 408 ) +3 31 (192 -168 408 ) (232 -168 408 ) (232 -128 408 ) +3 31 (192 -24 408 ) (232 -64 408 ) (232 -24 408 ) +6 31 (88 -168 408 ) (88 -192 408 ) (112 -216 408 ) (208 -216 408 ) (232 -192 408 ) (232 -168 408 ) +4 31 (40 -48 408 ) (40 -144 408 ) (88 -192 408 ) (88 0 408 ) +4 31 (0 -768 288 ) (448 -768 288 ) (448 -768 408 ) (0 -768 408 ) +4 31 (448 -768 408 ) (448 -768 288 ) (832 -384 288 ) (832 -384 408 ) +4 32 (0 -704 256 ) (416 -704 256 ) (416 -704 288 ) (0 -704 288 ) +4 32 (768 0 288 ) (768 -352 288 ) (768 -352 256 ) (768 0 256 ) +4 32 (416 -704 288 ) (416 -704 256 ) (768 -352 256 ) (768 -352 288 ) +4 33 (152 -760 240 ) (168 -760 240 ) (168 -764 240 ) (152 -764 240 ) +4 33 (168 -760 240 ) (184 -760 240 ) (184 -764 240 ) (168 -764 240 ) +4 33 (184 -764 240 ) (184 -768 240 ) (152 -768 240 ) (152 -764 240 ) +4 33 (136 -760 240 ) (152 -760 240 ) (152 -768 240 ) (136 -768 240 ) +4 33 (832 -104 240 ) (832 -120 240 ) (824 -120 240 ) (824 -104 240 ) +4 33 (828 -104 240 ) (824 -104 240 ) (824 -88 240 ) (828 -88 240 ) +4 33 (832 -88 240 ) (832 -104 240 ) (828 -104 240 ) (828 -88 240 ) +4 33 (832 -72 240 ) (832 -88 240 ) (824 -88 240 ) (824 -72 240 ) +4 33 (832 0 256 ) (832 -384 256 ) (832 -384 240 ) (832 0 240 ) +4 33 (768 -448 256 ) (832 -384 256 ) (832 0 256 ) (768 0 256 ) +4 33 (448 -768 256 ) (512 -704 256 ) (0 -704 256 ) (0 -768 256 ) +4 33 (416 -704 256 ) (512 -704 256 ) (768 -448 256 ) (768 -352 256 ) +4 33 (0 -768 240 ) (448 -768 240 ) (448 -768 256 ) (0 -768 256 ) +4 33 (448 -768 256 ) (448 -768 240 ) (832 -384 240 ) (832 -384 256 ) +4 34 (832 0 240 ) (832 -72 240 ) (832 -72 64 ) (832 0 64 ) +4 34 (824 -72 240 ) (824 -72 64 ) (832 -72 64 ) (832 -72 240 ) +4 35 (824 -104 224 ) (824 -104 80 ) (828 -104 80 ) (828 -104 224 ) +4 35 (828 -104 224 ) (828 -104 80 ) (828 -88 80 ) (828 -88 224 ) +4 35 (828 -88 224 ) (828 -88 80 ) (824 -88 80 ) (824 -88 224 ) +4 35 (828 -104 80 ) (824 -104 80 ) (824 -88 80 ) (828 -88 80 ) +4 35 (824 -104 224 ) (828 -104 224 ) (828 -88 224 ) (824 -88 224 ) +4 36 (832 -120 240 ) (832 -120 64 ) (824 -120 64 ) (824 -120 240 ) +4 36 (832 -120 240 ) (832 -384 240 ) (832 -384 64 ) (832 -120 64 ) +4 36 (824 -392 240 ) (824 -392 64 ) (832 -384 64 ) (832 -384 240 ) +4 37 (824 0 8 ) (832 0 8 ) (832 -384 8 ) (824 -392 8 ) +4 37 (832 0 64 ) (832 -384 64 ) (832 -384 8 ) (832 0 8 ) +4 37 (832 -120 64 ) (832 -104 64 ) (824 -104 64 ) (824 -120 64 ) +4 37 (832 -104 64 ) (832 -88 64 ) (824 -88 64 ) (824 -104 64 ) +4 37 (832 -88 64 ) (832 -72 64 ) (824 -72 64 ) (824 -88 64 ) +4 37 (832 -384 8 ) (832 -384 64 ) (824 -392 64 ) (824 -392 8 ) +4 38 (0 -584 8 ) (0 -576 8 ) (8 -576 8 ) (8 -584 8 ) +4 38 (136 -704 8 ) (128 -704 8 ) (128 -576 8 ) (136 -576 8 ) +4 38 (768 -352 8 ) (768 -448 8 ) (512 -704 8 ) (416 -704 8 ) +4 38 (768 0 8 ) (824 0 8 ) (824 -392 8 ) (768 -448 8 ) +4 38 (0 -760 8 ) (0 -704 8 ) (512 -704 8 ) (456 -760 8 ) +4 38 (152 -760 80 ) (152 -760 64 ) (168 -760 64 ) (168 -760 80 ) +4 38 (168 -760 240 ) (152 -760 240 ) (152 -760 224 ) (168 -760 224 ) +4 38 (184 -760 240 ) (168 -760 240 ) (168 -760 64 ) (184 -760 64 ) +4 38 (152 -760 240 ) (136 -760 240 ) (136 -760 64 ) (152 -760 64 ) +4 38 (824 -120 64 ) (824 -104 64 ) (824 -104 240 ) (824 -120 240 ) +4 38 (824 -104 224 ) (824 -88 224 ) (824 -88 240 ) (824 -104 240 ) +4 38 (824 -104 80 ) (824 -104 64 ) (824 -88 64 ) (824 -88 80 ) +4 38 (824 -88 64 ) (824 -72 64 ) (824 -72 240 ) (824 -88 240 ) +4 38 (456 -760 240 ) (456 -760 8 ) (824 -392 8 ) (824 -392 240 ) +4 39 (184 -760 240 ) (184 -760 64 ) (184 -764 64 ) (184 -764 240 ) +4 39 (184 -764 64 ) (184 -768 64 ) (184 -768 240 ) (184 -764 240 ) +4 39 (448 -768 240 ) (184 -768 240 ) (184 -768 64 ) (448 -768 64 ) +4 39 (448 -768 240 ) (448 -768 64 ) (456 -760 64 ) (456 -760 240 ) +4 40 (152 -760 224 ) (152 -764 224 ) (168 -764 224 ) (168 -760 224 ) +4 40 (152 -764 224 ) (152 -764 80 ) (168 -764 80 ) (168 -764 224 ) +4 40 (152 -760 224 ) (152 -760 80 ) (152 -764 80 ) (152 -764 224 ) +4 40 (168 -764 224 ) (168 -764 80 ) (168 -760 80 ) (168 -760 224 ) +4 40 (168 -760 80 ) (168 -764 80 ) (152 -764 80 ) (152 -760 80 ) +4 41 (136 -768 240 ) (136 -768 64 ) (136 -760 64 ) (136 -760 240 ) +4 41 (136 -768 240 ) (0 -768 240 ) (0 -768 64 ) (136 -768 64 ) +4 42 (0 -768 8 ) (0 -760 8 ) (456 -760 8 ) (448 -768 8 ) +4 42 (0 -768 8 ) (448 -768 8 ) (448 -768 64 ) (0 -768 64 ) +4 42 (152 -760 64 ) (136 -760 64 ) (136 -768 64 ) (152 -768 64 ) +4 42 (184 -764 64 ) (152 -764 64 ) (152 -768 64 ) (184 -768 64 ) +4 42 (168 -764 64 ) (184 -764 64 ) (184 -760 64 ) (168 -760 64 ) +4 42 (168 -764 64 ) (168 -760 64 ) (152 -760 64 ) (152 -764 64 ) +4 42 (456 -760 8 ) (456 -760 64 ) (448 -768 64 ) (448 -768 8 ) +4 43 (128 -344 -128 ) (136 -344 -128 ) (136 -344 -112 ) (128 -344 -112 ) +4 43 (768 0 8 ) (768 -344 8 ) (768 -344 -128 ) (768 0 -128 ) +4 43 (128 0 -120 ) (136 0 -120 ) (136 0 -128 ) (128 0 -128 ) +4 43 (8 0 -128 ) (768 0 -128 ) (768 -344 -128 ) (8 -344 -128 ) +5 44 (136 -344 -112 ) (136 -344 -128 ) (136 -704 -128 ) (136 -704 8 ) (136 -576 8 ) +5 44 (768 -344 -128 ) (768 -352 -128 ) (416 -704 -128 ) (136 -704 -128 ) (136 -344 -128 ) +4 44 (136 -704 -128 ) (416 -704 -128 ) (416 -704 8 ) (136 -704 8 ) +4 44 (768 -344 8 ) (768 -352 8 ) (768 -352 -128 ) (768 -344 -128 ) +4 44 (416 -704 8 ) (416 -704 -128 ) (768 -352 -128 ) (768 -352 8 ) +4 45 (128 -576 8 ) (128 -344 -112 ) (136 -344 -112 ) (136 -576 8 ) +3 46 (8 -436.799988 -64 ) (8 -480 -64 ) (8 -480 -41.655167 ) +4 46 (8 -480 -64 ) (8 -448 -64 ) (128 -448 -64 ) (128 -480 -64 ) +4 46 (8 -480 -48 ) (8 -480 -64 ) (128 -480 -64 ) (128 -480 -48 ) +3 46 (128 -480 -64 ) (128 -436.799988 -64 ) (128 -480 -41.655167 ) +4 47 (8 -480 -41.655163 ) (8 -480 -48 ) (8 -512 -48 ) (8 -512 -25.103441 ) +4 47 (8 -512 -32 ) (8 -512 -48 ) (128 -512 -48 ) (128 -512 -32 ) +4 47 (128 -512 -48 ) (128 -480 -48 ) (128 -480 -41.655167 ) (128 -512 -25.103443 ) +4 47 (128 -512 -48 ) (8 -512 -48 ) (8 -480 -48 ) (128 -480 -48 ) +4 48 (8 -405.866638 -80 ) (8 -448 -80 ) (8 -448 -64 ) (8 -436.799988 -64 ) +4 48 (8 -448 -80 ) (8 -416 -80 ) (128 -416 -80 ) (128 -448 -80 ) +4 48 (128 -448 -64 ) (128 -448 -80 ) (128 -405.866638 -80 ) (128 -436.799988 -64 ) +4 48 (8 -448 -80 ) (128 -448 -80 ) (128 -448 -64 ) (8 -448 -64 ) +4 49 (8 -512 -25.103439 ) (8 -512 -32 ) (8 -544 -32 ) (8 -544 -8.551716 ) +4 49 (8 -544 -16 ) (8 -544 -32 ) (128 -544 -32 ) (128 -544 -16 ) +4 49 (128 -544 -32 ) (128 -512 -32 ) (128 -512 -25.103443 ) (128 -544 -8.551723 ) +4 49 (128 -544 -32 ) (8 -544 -32 ) (8 -512 -32 ) (128 -512 -32 ) +4 50 (8 -374.933319 -96 ) (8 -416 -96 ) (8 -416 -80 ) (8 -405.866638 -80 ) +4 50 (8 -416 -96 ) (8 -384 -96 ) (128 -384 -96 ) (128 -416 -96 ) +4 50 (128 -416 -80 ) (128 -416 -96 ) (128 -374.933319 -96 ) (128 -405.866638 -80 ) +4 50 (8 -416 -96 ) (128 -416 -96 ) (128 -416 -80 ) (8 -416 -80 ) +5 51 (8 -544 -8.551715 ) (8 -544 -16 ) (8 -576 -16 ) (8 -576 0 ) (8 -560.533325 0 ) +3 51 (8 -576 8 ) (8 -560.533325 0 ) (8 -576 0 ) +4 51 (8 -576 0 ) (8 -576 -16 ) (128 -576 -16 ) (128 -576 0 ) +4 51 (128 -544 -16 ) (128 -544 -8.551723 ) (128 -576 8 ) (128 -576 -16 ) +4 51 (128 -576 -16 ) (8 -576 -16 ) (8 -544 -16 ) (128 -544 -16 ) +4 52 (8 -344 -112 ) (8 -384 -112 ) (8 -384 -96 ) (8 -374.933319 -96 ) +4 52 (8 -384 -112 ) (8 -352 -112 ) (128 -352 -112 ) (128 -384 -112 ) +4 52 (128 -374.933319 -96 ) (128 -384 -96 ) (128 -384 -112 ) (128 -344 -112 ) +4 52 (8 -384 -112 ) (128 -384 -112 ) (128 -384 -96 ) (8 -384 -96 ) +4 53 (8 -584 8 ) (8 -576 8 ) (8 -576 0 ) (8 -584 0 ) +4 53 (128 -704 0 ) (128 -704 8 ) (8 -704 8 ) (8 -704 0 ) +4 53 (128 -576 0 ) (128 -576 8 ) (128 -704 8 ) (128 -704 0 ) +4 53 (8 -704 0 ) (8 -576 0 ) (128 -576 0 ) (128 -704 0 ) +4 54 (8 -344 -128 ) (8 -352 -128 ) (8 -352 -112 ) (8 -344 -112 ) +4 54 (128 -352 -112 ) (128 -352 -128 ) (128 -344 -128 ) (128 -344 -112 ) +4 54 (8 -352 -128 ) (8 -344 -128 ) (128 -344 -128 ) (128 -352 -128 ) +4 54 (128 -352 -128 ) (128 -352 -112 ) (8 -352 -112 ) (8 -352 -128 ) +4 55 (0 -344 8 ) (0 0 8 ) (0 0 0 ) (0 -344 0 ) +4 55 (0 0 0 ) (0 0 -128 ) (0 -344 -128 ) (0 -344 0 ) +4 55 (0 -344 -128 ) (8 -344 -128 ) (8 -344 -112 ) (0 -344 -112 ) +4 55 (0 -344 -128 ) (0 0 -128 ) (8 0 -128 ) (8 -344 -128 ) +4 55 (8 0 -120 ) (8 0 -128 ) (0 0 -128 ) (0 0 -120 ) +4 56 (0 -576 8 ) (0 -344 8 ) (0 -344 0 ) (0 -560.533325 0 ) +4 56 (0 -560.532898 0 ) (8 -560.532898 0 ) (8 -576 8 ) (0 -576 8 ) +3 57 (0 -344 0 ) (0 -344 -112 ) (0 -560.533325 0 ) +4 57 (8 -560.532898 0 ) (0 -560.532898 0 ) (0 -344 -112 ) (8 -344 -112 ) +4 58 (8 -704 0 ) (8 -704 8 ) (0 -704 8 ) (0 -704 0 ) +4 58 (0 -584 0 ) (0 -584 8 ) (8 -584 8 ) (8 -584 0 ) +4 58 (0 -584 0 ) (8 -584 0 ) (8 -704 0 ) (0 -704 0 ) +4 59 (-448 160 288 ) (-448 256 288 ) (-192 512 288 ) (-96 512 288 ) +4 59 (-448 0 288 ) (-512 0 288 ) (-512 192 288 ) (-448 256 288 ) +4 59 (-192 512 288 ) (-128 576 288 ) (0 576 288 ) (0 512 288 ) +4 59 (-128 576 496 ) (0 576 496 ) (0 576 288 ) (-128 576 288 ) +5 59 (0 576 496 ) (-128 576 496 ) (-512 192 496 ) (-512 0 496 ) (0 0 496 ) +4 59 (-512 192 288 ) (-512 0 288 ) (-512 0 496 ) (-512 192 496 ) +4 59 (-128 576 496 ) (-128 576 288 ) (-512 192 288 ) (-512 192 496 ) +4 60 (-448 160 256 ) (-448 0 256 ) (-448 0 288 ) (-448 160 288 ) +4 60 (-96 512 288 ) (0 512 288 ) (0 512 256 ) (-96 512 256 ) +4 60 (-96 512 288 ) (-96 512 256 ) (-448 160 256 ) (-448 160 288 ) +4 61 (-448 160 8 ) (-448 256 8 ) (-192 512 8 ) (-96 512 8 ) +4 61 (0 0 8 ) (-8 0 8 ) (-8 328 8 ) (0 328 8 ) +4 61 (-192 512 8 ) (-128 576 8 ) (0 576 8 ) (0 512 8 ) +4 61 (-448 0 8 ) (-512 0 8 ) (-512 192 8 ) (-448 256 8 ) +4 61 (-512 192 8 ) (-512 0 8 ) (-512 0 256 ) (-512 192 256 ) +4 61 (-192 512 256 ) (0 512 256 ) (0 576 256 ) (-128 576 256 ) +4 61 (-448 256 256 ) (-512 192 256 ) (-512 0 256 ) (-448 0 256 ) +4 61 (-96 512 256 ) (-192 512 256 ) (-448 256 256 ) (-448 160 256 ) +4 61 (-128 576 256 ) (0 576 256 ) (0 576 8 ) (-128 576 8 ) +4 61 (-128 576 256 ) (-128 576 8 ) (-512 192 8 ) (-512 192 256 ) +4 62 (-8 512 8 ) (0 512 8 ) (0 512 0 ) (-8 512 0 ) +4 62 (-8 328 0 ) (-8 512 0 ) (0 512 0 ) (0 328 0 ) +4 62 (-8 328 8 ) (-8 328 0 ) (0 328 0 ) (0 328 8 ) +4 63 (-96 512 8 ) (-8 512 8 ) (-8 512 0 ) (-96 512 0 ) +4 63 (-448 0 0 ) (-448 0 8 ) (-448 160 8 ) (-448 160 0 ) +5 63 (-8 0 0 ) (-448 0 0 ) (-448 160 0 ) (-96 512 0 ) (-8 512 0 ) +4 63 (-8 328 8 ) (-8 0 8 ) (-8 0 0 ) (-8 328 0 ) +4 63 (-96 512 8 ) (-96 512 0 ) (-448 160 0 ) (-448 160 8 ) +4 64 (-96 -704 288 ) (-192 -704 288 ) (-448 -448 288 ) (-448 -352 288 ) +4 64 (-512 0 288 ) (-448 0 288 ) (-448 -448 288 ) (-512 -384 288 ) +4 64 (0 -704 288 ) (0 -768 288 ) (-128 -768 288 ) (-192 -704 288 ) +4 64 (-128 -768 288 ) (0 -768 288 ) (0 -768 496 ) (-128 -768 496 ) +5 64 (-512 -384 496 ) (-128 -768 496 ) (0 -768 496 ) (0 0 496 ) (-512 0 496 ) +4 64 (-512 0 288 ) (-512 -384 288 ) (-512 -384 496 ) (-512 0 496 ) +4 64 (-512 -384 496 ) (-512 -384 288 ) (-128 -768 288 ) (-128 -768 496 ) +4 65 (-448 0 256 ) (-448 -352 256 ) (-448 -352 288 ) (-448 0 288 ) +4 65 (-96 -704 256 ) (0 -704 256 ) (0 -704 288 ) (-96 -704 288 ) +4 65 (-448 -352 288 ) (-448 -352 256 ) (-96 -704 256 ) (-96 -704 288 ) +4 66 (-96 -704 8 ) (-192 -704 8 ) (-448 -448 8 ) (-448 -352 8 ) +4 66 (-8 0 8 ) (0 0 8 ) (0 -584 8 ) (-8 -584 8 ) +4 66 (0 -704 8 ) (0 -768 8 ) (-128 -768 8 ) (-192 -704 8 ) +4 66 (-504 0 8 ) (-448 0 8 ) (-448 -448 8 ) (-504 -392 8 ) +4 66 (-504 -88 64 ) (-504 -104 64 ) (-504 -104 80 ) (-504 -88 80 ) +4 66 (-504 -72 224 ) (-504 -72 64 ) (-504 -88 64 ) (-504 -88 224 ) +4 66 (-504 -104 240 ) (-504 -72 240 ) (-504 -72 224 ) (-504 -104 224 ) +4 66 (-504 -120 240 ) (-504 -104 240 ) (-504 -104 64 ) (-504 -120 64 ) +4 66 (-128 -768 8 ) (0 -768 8 ) (0 -768 256 ) (-128 -768 256 ) +4 66 (-128 -768 256 ) (0 -768 256 ) (0 -704 256 ) (-192 -704 256 ) +4 66 (-504 -392 256 ) (-448 -448 256 ) (-448 0 256 ) (-504 0 256 ) +4 66 (-448 -352 256 ) (-448 -448 256 ) (-192 -704 256 ) (-96 -704 256 ) +4 66 (-504 -392 256 ) (-504 -392 8 ) (-128 -768 8 ) (-128 -768 256 ) +4 67 (-508 -72 240 ) (-504 -72 240 ) (-504 -104 240 ) (-508 -104 240 ) +4 67 (-504 -104 240 ) (-504 -120 240 ) (-508 -120 240 ) (-508 -104 240 ) +4 67 (-512 -120 240 ) (-512 -72 240 ) (-508 -72 240 ) (-508 -120 240 ) +4 67 (-512 -384 256 ) (-504 -392 256 ) (-504 0 256 ) (-512 0 256 ) +4 67 (-512 -384 256 ) (-512 0 256 ) (-512 0 240 ) (-512 -384 240 ) +4 67 (-512 -384 256 ) (-512 -384 240 ) (-504 -392 240 ) (-504 -392 256 ) +4 68 (-508 -72 64 ) (-504 -72 64 ) (-504 -72 224 ) (-508 -72 224 ) +4 68 (-504 -72 224 ) (-504 -72 240 ) (-508 -72 240 ) (-508 -72 224 ) +4 68 (-512 -72 64 ) (-508 -72 64 ) (-508 -72 240 ) (-512 -72 240 ) +4 68 (-512 -72 240 ) (-512 0 240 ) (-512 0 64 ) (-512 -72 64 ) +4 69 (-504 -88 80 ) (-508 -88 80 ) (-508 -88 224 ) (-504 -88 224 ) +4 69 (-508 -104 224 ) (-508 -104 80 ) (-504 -104 80 ) (-504 -104 224 ) +4 69 (-508 -104 80 ) (-508 -104 224 ) (-508 -88 224 ) (-508 -88 80 ) +4 69 (-504 -88 224 ) (-508 -88 224 ) (-508 -104 224 ) (-504 -104 224 ) +4 69 (-504 -104 80 ) (-508 -104 80 ) (-508 -88 80 ) (-504 -88 80 ) +4 70 (-512 -384 240 ) (-512 -120 240 ) (-512 -120 64 ) (-512 -384 64 ) +4 70 (-512 -120 240 ) (-508 -120 240 ) (-508 -120 64 ) (-512 -120 64 ) +4 70 (-508 -120 240 ) (-504 -120 240 ) (-504 -120 64 ) (-508 -120 64 ) +4 70 (-512 -384 64 ) (-504 -392 64 ) (-504 -392 240 ) (-512 -384 240 ) +4 71 (-512 0 8 ) (-504 0 8 ) (-504 -392 8 ) (-512 -384 8 ) +4 71 (-512 0 8 ) (-512 -384 8 ) (-512 -384 64 ) (-512 0 64 ) +4 71 (-508 -120 64 ) (-508 -72 64 ) (-512 -72 64 ) (-512 -120 64 ) +4 71 (-508 -104 64 ) (-508 -120 64 ) (-504 -120 64 ) (-504 -104 64 ) +4 71 (-508 -88 64 ) (-504 -88 64 ) (-504 -72 64 ) (-508 -72 64 ) +4 71 (-508 -88 64 ) (-508 -104 64 ) (-504 -104 64 ) (-504 -88 64 ) +4 71 (-504 -392 8 ) (-504 -392 64 ) (-512 -384 64 ) (-512 -384 8 ) +4 72 (-8 -704 0 ) (0 -704 0 ) (0 -704 8 ) (-8 -704 8 ) +4 72 (0 -704 0 ) (-8 -704 0 ) (-8 -584 0 ) (0 -584 0 ) +4 72 (0 -584 8 ) (0 -584 0 ) (-8 -584 0 ) (-8 -584 8 ) +4 73 (-96 -704 0 ) (-8 -704 0 ) (-8 -704 8 ) (-96 -704 8 ) +4 73 (-448 -352 8 ) (-448 0 8 ) (-448 0 0 ) (-448 -352 0 ) +5 73 (-8 -704 0 ) (-96 -704 0 ) (-448 -352 0 ) (-448 0 0 ) (-8 0 0 ) +4 73 (-8 0 8 ) (-8 -584 8 ) (-8 -584 0 ) (-8 0 0 ) +4 73 (-448 -352 8 ) (-448 -352 0 ) (-96 -704 0 ) (-96 -704 8 ) diff --git a/fakk/maps/example/patrol.pth b/fakk/maps/example/patrol.pth new file mode 100644 index 0000000..2189731 Binary files /dev/null and b/fakk/maps/example/patrol.pth differ diff --git a/fakk/maps/example/patrol.scr b/fakk/maps/example/patrol.scr new file mode 100644 index 0000000..59a30d8 --- /dev/null +++ b/fakk/maps/example/patrol.scr @@ -0,0 +1,18 @@ +waitforplayer +start: + +$creeper1 thread creeper_thread +$creeper1 setidlethread creeper_thread + +end + +creeper_thread: + +local.self walkto $patrol1 +waitFor local.self +local.self walkto $patrol2 +waitFor local.self +goto creeper_thread + +end + diff --git a/fakk/maps/example/pickup.bsp b/fakk/maps/example/pickup.bsp new file mode 100644 index 0000000..a2f8625 Binary files /dev/null and b/fakk/maps/example/pickup.bsp differ diff --git a/fakk/maps/example/pickup.map b/fakk/maps/example/pickup.map new file mode 100644 index 0000000..9a427b8 --- /dev/null +++ b/fakk/maps/example/pickup.map @@ -0,0 +1,335 @@ +{ +"classname" "worldspawn" +// brush 0 +{ +( -256 448 64 ) ( 640 448 64 ) ( 640 512 64 ) eden/lt_edenlt22b 16 0 0.00 -1 0.125000 0 0 0 +( 640 512 192 ) ( 640 448 192 ) ( -256 448 192 ) eden/lt_edenlt22b 16 0 0.00 -1 0.125000 0 0 0 +( -192 512 0 ) ( -176 512 0 ) ( -184 512 256 ) eden/lt_edenlt22b 16 64 0.00 -1 1 0 0 0 +( -208 496 0 ) ( -208 512 0 ) ( -208 504 256 ) eden/lt_edenlt22b 0 64 0.00 -0.500000 1 0 0 0 +( -176 512 0 ) ( -176 496 0 ) ( -176 504 256 ) eden/lt_edenlt22b 0 64 0.00 -0.500000 1 0 0 0 +( -176 496 0 ) ( -192 496 0 ) ( -184 496 256 ) eden/lt_edenlt22b 16 64 0.00 -1 1 0 0 0 +} +// brush 1 +{ +( -192 448 64 ) ( 704 448 64 ) ( 704 512 64 ) eden/lt_edenlt22b 16 0 0.00 -1 0.125000 0 0 0 +( 704 512 192 ) ( 704 448 192 ) ( -192 448 192 ) eden/lt_edenlt22b 16 0 0.00 -1 0.125000 0 0 0 +( -128 512 0 ) ( -112 512 0 ) ( -120 512 256 ) eden/lt_edenlt22b 16 64 0.00 -1 1 0 0 0 +( -144 496 0 ) ( -144 512 0 ) ( -144 504 256 ) eden/lt_edenlt22b 0 64 0.00 -0.500000 1 0 0 0 +( -112 512 0 ) ( -112 496 0 ) ( -112 504 256 ) eden/lt_edenlt22b 0 64 0.00 -0.500000 1 0 0 0 +( -112 496 0 ) ( -128 496 0 ) ( -120 496 256 ) eden/lt_edenlt22b 16 64 0.00 -1 1 0 0 0 +} +// brush 2 +{ +( -64 448 64 ) ( 832 448 64 ) ( 832 512 64 ) eden/lt_edenlt24 16 0 0.00 -1 0.125000 0 0 0 +( 832 512 192 ) ( 832 448 192 ) ( -64 448 192 ) eden/lt_edenlt24 16 0 0.00 -1 0.125000 0 0 0 +( 0 512 0 ) ( 16 512 0 ) ( 8 512 256 ) eden/lt_edenlt24 16 64 0.00 -1 1 0 0 0 +( -16 496 0 ) ( -16 512 0 ) ( -16 504 256 ) eden/lt_edenlt24 0 64 0.00 -0.500000 1 0 0 0 +( 16 512 0 ) ( 16 496 0 ) ( 16 504 256 ) eden/lt_edenlt24 0 64 0.00 -0.500000 1 0 0 0 +( 16 496 0 ) ( 0 496 0 ) ( 8 496 256 ) eden/lt_edenlt24 16 64 0.00 -1 1 0 0 0 +} +// brush 3 +{ +( -128 448 64 ) ( 768 448 64 ) ( 768 512 64 ) eden/lt_edenlt18v 16 0 0.00 -1 0.125000 0 0 0 +( 768 512 192 ) ( 768 448 192 ) ( -128 448 192 ) eden/lt_edenlt18v 16 0 0.00 -1 0.125000 0 0 0 +( -64 512 0 ) ( -48 512 0 ) ( -56 512 256 ) eden/lt_edenlt18v 16 64 0.00 -1 1 0 0 0 +( -80 496 0 ) ( -80 512 0 ) ( -80 504 256 ) eden/lt_edenlt18v 0 64 0.00 -0.500000 1 0 0 0 +( -48 512 0 ) ( -48 496 0 ) ( -48 504 256 ) eden/lt_edenlt18v 0 64 0.00 -0.500000 1 0 0 0 +( -48 496 0 ) ( -64 496 0 ) ( -56 496 256 ) eden/lt_edenlt18v 16 64 0.00 -1 1 0 0 0 +} +// brush 4 +{ +( 0 448 64 ) ( 896 448 64 ) ( 896 512 64 ) eden/lt_edenlt22w 16 0 0.00 -1 0.125000 0 0 0 +( 896 512 192 ) ( 896 448 192 ) ( 0 448 192 ) eden/lt_edenlt22w 16 0 0.00 -1 0.125000 0 0 0 +( 64 512 0 ) ( 80 512 0 ) ( 72 512 256 ) eden/lt_edenlt22w 16 64 0.00 -1 1 0 0 0 +( 48 496 0 ) ( 48 512 0 ) ( 48 504 256 ) eden/lt_edenlt22w 0 64 0.00 -0.500000 1 0 0 0 +( 80 512 0 ) ( 80 496 0 ) ( 80 504 256 ) eden/lt_edenlt22w 0 64 0.00 -0.500000 1 0 0 0 +( 80 496 0 ) ( 64 496 0 ) ( 72 496 256 ) eden/lt_edenlt22w 16 64 0.00 -1 1 0 0 0 +} +// brush 5 +{ +( 0 -304 64 ) ( 896 -304 64 ) ( 896 -240 64 ) eden/lt_edenlt23w 16 0 0.00 -1 0.125000 0 0 0 +( 896 -240 192 ) ( 896 -304 192 ) ( 0 -304 192 ) eden/lt_edenlt23w 16 0 0.00 -1 0.125000 0 0 0 +( 64 -240 0 ) ( 80 -240 0 ) ( 72 -240 256 ) eden/lt_edenlt23w 16 64 0.00 -1 1 0 0 0 +( 48 -256 0 ) ( 48 -240 0 ) ( 48 -248 256 ) eden/lt_edenlt23w 0 64 0.00 -0.500000 1 0 0 0 +( 80 -240 0 ) ( 80 -256 0 ) ( 80 -248 256 ) eden/lt_edenlt23w 0 64 0.00 -0.500000 1 0 0 0 +( 80 -256 0 ) ( 64 -256 0 ) ( 72 -256 256 ) eden/lt_edenlt23w 16 64 0.00 -1 1 0 0 0 +} +// brush 6 +{ +( -128 -304 64 ) ( 768 -304 64 ) ( 768 -240 64 ) eden/lt_edenlt21w 16 0 0.00 -1 0.125000 0 0 0 +( 768 -240 192 ) ( 768 -304 192 ) ( -128 -304 192 ) eden/lt_edenlt21w 16 0 0.00 -1 0.125000 0 0 0 +( -64 -240 0 ) ( -48 -240 0 ) ( -56 -240 256 ) eden/lt_edenlt21w 16 64 0.00 -1 1 0 0 0 +( -80 -256 0 ) ( -80 -240 0 ) ( -80 -248 256 ) eden/lt_edenlt21w 0 64 0.00 -0.500000 1 0 0 0 +( -48 -240 0 ) ( -48 -256 0 ) ( -48 -248 256 ) eden/lt_edenlt21w 0 64 0.00 -0.500000 1 0 0 0 +( -48 -256 0 ) ( -64 -256 0 ) ( -56 -256 256 ) eden/lt_edenlt21w 16 64 0.00 -1 1 0 0 0 +} +// brush 7 +{ +( -64 -304 64 ) ( 832 -304 64 ) ( 832 -240 64 ) eden/lt_edenlt20 16 0 0.00 -1 0.125000 0 0 0 +( 832 -240 192 ) ( 832 -304 192 ) ( -64 -304 192 ) eden/lt_edenlt20 16 0 0.00 -1 0.125000 0 0 0 +( 0 -240 0 ) ( 16 -240 0 ) ( 8 -240 256 ) eden/lt_edenlt20 16 64 0.00 -1 1 0 0 0 +( -16 -256 0 ) ( -16 -240 0 ) ( -16 -248 256 ) eden/lt_edenlt20 0 64 0.00 -0.500000 1 0 0 0 +( 16 -240 0 ) ( 16 -256 0 ) ( 16 -248 256 ) eden/lt_edenlt20 0 64 0.00 -0.500000 1 0 0 0 +( 16 -256 0 ) ( 0 -256 0 ) ( 8 -256 256 ) eden/lt_edenlt20 16 64 0.00 -1 1 0 0 0 +} +// brush 8 +{ +( -192 -304 64 ) ( 704 -304 64 ) ( 704 -240 64 ) eden/lt_edenlt17b 16 0 0.00 -1 0.125000 0 0 0 +( 704 -240 192 ) ( 704 -304 192 ) ( -192 -304 192 ) eden/lt_edenlt17b 16 0 0.00 -1 0.125000 0 0 0 +( -128 -240 0 ) ( -112 -240 0 ) ( -120 -240 256 ) eden/lt_edenlt17b 16 64 0.00 -1 1 0 0 0 +( -144 -256 0 ) ( -144 -240 0 ) ( -144 -248 256 ) eden/lt_edenlt17b 0 64 0.00 -0.500000 1 0 0 0 +( -112 -240 0 ) ( -112 -256 0 ) ( -112 -248 256 ) eden/lt_edenlt17b 0 64 0.00 -0.500000 1 0 0 0 +( -112 -256 0 ) ( -128 -256 0 ) ( -120 -256 256 ) eden/lt_edenlt17b 16 64 0.00 -1 1 0 0 0 +} +// brush 9 +{ +( -256 -304 64 ) ( 640 -304 64 ) ( 640 -240 64 ) eden/lt_edenlt17w 16 0 0.00 -1 0.125000 0 0 0 +( 640 -240 192 ) ( 640 -304 192 ) ( -256 -304 192 ) eden/lt_edenlt17w 16 0 0.00 -1 0.125000 0 0 0 +( -192 -240 0 ) ( -176 -240 0 ) ( -184 -240 256 ) eden/lt_edenlt17w 16 64 0.00 -1 1 0 0 0 +( -208 -256 0 ) ( -208 -240 0 ) ( -208 -248 256 ) eden/lt_edenlt17w 0 64 0.00 -0.500000 1 0 0 0 +( -176 -240 0 ) ( -176 -256 0 ) ( -176 -248 256 ) eden/lt_edenlt17w 0 64 0.00 -0.500000 1 0 0 0 +( -176 -256 0 ) ( -192 -256 0 ) ( -184 -256 256 ) eden/lt_edenlt17w 16 64 0.00 -1 1 0 0 0 +} +// brush 10 +{ +( 192 0 0 ) ( 176 0 0 ) ( 176 -64 0 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 176 -64 128 ) ( 176 0 128 ) ( 192 0 128 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 176 -64 32 ) ( 192 -64 32 ) ( 192 -64 0 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 192 -64 32 ) ( 192 0 32 ) ( 192 0 0 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 192 0 32 ) ( 176 0 32 ) ( 176 0 0 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 176 0 96 ) ( 176 -64 96 ) ( 176 -64 64 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +} +// brush 11 +{ +( 640 512 256 ) ( -256 512 256 ) ( -256 -256 256 ) eden/genmetal_2 0 0 0.00 1 1 0 0 0 +( -256 -256 320 ) ( -256 512 320 ) ( 640 512 320 ) eden/genmetal_2 0 0 0.00 1 1 0 0 0 +( -256 -256 320 ) ( 640 -256 320 ) ( 640 -256 256 ) eden/genmetal_2 0 0 0.00 1 1 0 0 0 +( 640 -256 320 ) ( 640 512 320 ) ( 640 512 256 ) eden/genmetal_2 0 0 0.00 1 1 0 0 0 +( 640 512 320 ) ( -256 512 320 ) ( -256 512 256 ) eden/genmetal_2 0 0 0.00 1 1 0 0 0 +( -256 512 320 ) ( -256 -256 320 ) ( -256 -256 256 ) eden/genmetal_2 0 0 0.00 1 1 0 0 0 +} +// brush 12 +{ +( 2432 -1664 0 ) ( 2432 -512 0 ) ( 3712 -512 0 ) eden/fl_grass 0 0 0.00 1 1 0 0 0 +( -256 256 -64 ) ( -256 320 -64 ) ( -256 288 0 ) eden/fl_grass 0 0 0.00 1 1 0 0 0 +( 64 512 -64 ) ( 256 512 -64 ) ( 160 512 0 ) eden/fl_grass 0 0 0.00 1 1 0 0 0 +( 192 -384 -64 ) ( 192 -448 -64 ) ( 192 -416 0 ) eden/fl_grass 0 0 0.00 1 1 0 0 0 +( -208 -256 -64 ) ( -256 -256 -64 ) ( -232 -256 0 ) eden/fl_grass 0 0 0.00 1 1 0 0 0 +( 192 -256 -64 ) ( 32 512 -64 ) ( -128 -256 -64 ) eden/fl_grass 0 0 0.00 1 1 0 0 0 +} +// brush 13 +{ +( 304 3008 0 ) ( 304 1728 0 ) ( -848 1728 0 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 224 -640 -96 ) ( 224 -576 -80 ) ( 224 -640 -64 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 624 512 -32 ) ( 640 512 -32 ) ( 632 512 0 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 288 -256 -32 ) ( 208 -256 -32 ) ( 248 -256 0 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 640 512 -32 ) ( 640 480 -32 ) ( 640 496 0 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 192 -256 -64 ) ( 32 512 -64 ) ( -128 -256 -64 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +} +// brush 14 +{ +( -256 -320 0 ) ( 640 -320 0 ) ( 640 -256 0 ) eden/WL_neweden_4 0 0 0.00 1 1 0 0 0 +( 640 -256 256 ) ( 640 -320 256 ) ( -256 -320 256 ) eden/WL_neweden_4 0 0 0.00 1 1 0 0 0 +( 640 -256 64 ) ( -256 -256 64 ) ( -256 -256 0 ) eden/WL_neweden_4 0 0 0.00 1 1 0 0 0 +( -256 -256 64 ) ( -256 -320 64 ) ( -256 -320 0 ) eden/WL_neweden_4 0 0 0.00 1 1 0 0 0 +( -256 -320 64 ) ( 640 -320 64 ) ( 640 -320 0 ) eden/WL_neweden_4 0 0 0.00 1 1 0 0 0 +( 640 -320 64 ) ( 640 -256 64 ) ( 640 -256 0 ) eden/WL_neweden_4 0 0 0.00 1 1 0 0 0 +} +// brush 15 +{ +( -320 640 0 ) ( -320 -256 0 ) ( -256 -256 0 ) eden/WL_neweden_4 0 0 0.00 1 1 0 0 0 +( -256 -256 256 ) ( -320 -256 256 ) ( -320 640 256 ) eden/WL_neweden_4 0 0 0.00 1 1 0 0 0 +( -256 -256 64 ) ( -256 640 64 ) ( -256 640 0 ) eden/WL_neweden_4 0 0 0.00 1 1 0 0 0 +( -320 640 64 ) ( -320 -256 64 ) ( -320 -256 0 ) eden/WL_neweden_4 0 0 0.00 1 1 0 0 0 +( -320 -256 64 ) ( -256 -256 64 ) ( -256 -256 0 ) eden/WL_neweden_4 0 0 0.00 1 1 0 0 0 +( -384 512 0 ) ( -64 512 0 ) ( -224 512 256 ) eden/WL_neweden_4 0 0 0.00 1 1 0 0 0 +} +// brush 16 +{ +( 704 -384 0 ) ( 704 512 0 ) ( 640 512 0 ) eden/WL_neweden_4 0 0 0.00 1 1 0 0 0 +( 640 512 256 ) ( 704 512 256 ) ( 704 -384 256 ) eden/WL_neweden_4 0 0 0.00 1 1 0 0 0 +( 640 512 64 ) ( 640 -384 64 ) ( 640 -384 0 ) eden/WL_neweden_4 0 0 0.00 1 1 0 0 0 +( 704 -384 64 ) ( 704 512 64 ) ( 704 512 0 ) eden/WL_neweden_4 0 0 0.00 1 1 0 0 0 +( 704 512 64 ) ( 640 512 64 ) ( 640 512 0 ) eden/WL_neweden_4 0 0 0.00 1 1 0 0 0 +( 768 -256 0 ) ( 448 -256 0 ) ( 608 -256 256 ) eden/WL_neweden_4 0 0 0.00 1 1 0 0 0 +} +// brush 17 +{ +( 640 576 0 ) ( -256 576 0 ) ( -256 512 0 ) eden/WL_neweden_4 0 0 0.00 1 1 0 0 0 +( -256 512 256 ) ( -256 576 256 ) ( 640 576 256 ) eden/WL_neweden_4 0 0 0.00 1 1 0 0 0 +( -256 512 64 ) ( 640 512 64 ) ( 640 512 0 ) eden/WL_neweden_4 0 0 0.00 1 1 0 0 0 +( 640 512 64 ) ( 640 576 64 ) ( 640 576 0 ) eden/WL_neweden_4 0 0 0.00 1 1 0 0 0 +( 640 576 64 ) ( -256 576 64 ) ( -256 576 0 ) eden/WL_neweden_4 0 0 0.00 1 1 0 0 0 +( -256 576 64 ) ( -256 512 64 ) ( -256 512 0 ) eden/WL_neweden_4 0 0 0.00 1 1 0 0 0 +} +// brush 18 +{ +( 672 240 256 ) ( 672 448 256 ) ( 960 448 256 ) eden/WL_neweden_1 0 0 0.00 1 1 0 0 0 +( 192 336 0 ) ( 192 384 0 ) ( 192 360 256 ) eden/WL_neweden_1 0 0 0.00 1 1 0 0 0 +( 224 448 0 ) ( 224 400 0 ) ( 224 424 256 ) eden/WL_edenhouse 0 0 0.00 1 1 0 0 0 +( 192 -480 0 ) ( 192 -544 0 ) ( 208 -512 0 ) eden/WL_neweden_1 0 0 0.00 1 1 0 0 0 +( 160 64 0 ) ( 256 64 0 ) ( 208 64 256 ) eden/genmetal_3 0 0 0.00 1 1 0 0 0 +( 320 -256 0 ) ( 64 -256 0 ) ( 192 -256 256 ) eden/genmetal_3 0 0 0.00 1 1 0 0 0 +} +// brush 19 +{ +( 672 176 256 ) ( 672 384 256 ) ( 960 384 256 ) eden/WL_neweden_1 0 0 0.00 1 1 0 0 0 +( 192 272 0 ) ( 192 320 0 ) ( 192 296 256 ) eden/WL_neweden_1 0 0 0.00 1 1 0 0 0 +( 224 640 0 ) ( 224 592 0 ) ( 224 616 256 ) eden/WL_edenhouse 0 0 0.00 1 1 0 0 0 +( 192 -576 0 ) ( 192 -640 0 ) ( 208 -608 0 ) eden/WL_neweden_1 0 0 0.00 1 1 0 0 0 +( 256 192 0 ) ( 160 192 0 ) ( 208 192 256 ) eden/genmetal_3 0 0 0.00 1 1 0 0 0 +( 128 512 0 ) ( 384 512 0 ) ( 256 512 256 ) eden/genmetal_3 0 0 0.00 1 1 0 0 0 +} +// brush 20 +{ +( 304 3552 0 ) ( 304 2272 0 ) ( -848 2272 0 ) eden/genmetal_3 0 0 0.00 1 1 0 0 0 +( 368 -64 -32 ) ( 328 -32 -32 ) ( 288 -64 -32 ) eden/genmetal_3 0 0 0.00 1 1 0 0 0 +( 192 -64 -32 ) ( 192 0 -16 ) ( 192 -64 0 ) eden/genmetal_3 0 0 0.00 1 1 0 0 0 +( 224 192 -32 ) ( 224 160 -32 ) ( 224 176 0 ) eden/genmetal_3 0 0 0.00 1 1 0 0 0 +( 192 64 -32 ) ( 192 64 16 ) ( 224 64 -8 ) eden/genmetal_3 0 0 0.00 1 1 0 0 0 +( 192 192 0 ) ( 192 192 -32 ) ( 224 192 -16 ) eden/genmetal_3 0 0 0.00 1 1 0 0 0 +} +// brush 21 +{ +( 672 240 256 ) ( 672 448 256 ) ( 960 448 256 ) eden/WL_neweden_1 0 0 0.00 1 1 0 0 0 +( 192 336 0 ) ( 192 384 0 ) ( 192 360 256 ) eden/WL_neweden_1 0 0 0.00 1 1 0 0 0 +( 224 448 0 ) ( 224 400 0 ) ( 224 424 256 ) eden/WL_edenhouse 0 0 0.00 1 1 0 0 0 +( 176 192 0 ) ( 240 192 0 ) ( 208 192 256 ) eden/WL_neweden_1 0 0 0.00 1 1 0 0 0 +( 256 64 0 ) ( 192 64 0 ) ( 224 64 256 ) eden/WL_neweden_1 0 0 0.00 1 1 0 0 0 +( 192 176 128 ) ( 192 96 128 ) ( 224 136 128 ) eden/genmetal_3 0 0 0.00 1 1 0 0 0 +} +// brush 22 +{ +( 192 240 0 ) ( 192 288 0 ) ( 192 264 256 ) eden/WL_edendoor 64 0 0.00 1 1 0 0 0 +( 192 192 0 ) ( 272 192 0 ) ( 232 192 256 ) eden/genmetal_3 0 0 0.00 1 1 0 0 0 +( 204 192 0 ) ( 204 168 0 ) ( 204 180 256 ) eden/genmetal_3 0 0 0.00 1 1 0 0 0 +( 192 192 0 ) ( 192 160 128 ) ( 200 176 64 ) eden/genmetal_3 0 0 0.00 1 1 0 0 0 +( 192 160 128 ) ( 192 224 128 ) ( 200 192 128 ) eden/genmetal_3 0 0 0.00 1 1 0 0 0 +} +// brush 23 +{ +( 224 352 0 ) ( 224 304 0 ) ( 224 328 256 ) eden/WL_edendoor 64 0 0.00 1 1 0 0 0 +( 192 192 0 ) ( 272 192 0 ) ( 232 192 256 ) eden/genmetal_3 0 0 0.00 1 1 0 0 0 +( 212 176 0 ) ( 212 192 0 ) ( 212 184 256 ) eden/genmetal_3 0 0 0.00 1 1 0 0 0 +( 216 192 0 ) ( 216 160 128 ) ( 224 176 64 ) eden/genmetal_3 0 0 0.00 1 1 0 0 0 +( 216 160 128 ) ( 216 224 128 ) ( 224 192 128 ) eden/genmetal_3 0 0 0.00 1 1 0 0 0 +} +// brush 24 +{ +( 224 -72 256 ) ( 224 -48 0 ) ( 224 -96 0 ) eden/WL_edendoor 64 0 0.00 1 1 0 0 0 +( 232 64 256 ) ( 272 64 0 ) ( 192 64 0 ) eden/genmetal_3 0 0 0.00 1 1 0 0 0 +( 212 72 256 ) ( 212 64 0 ) ( 212 80 0 ) eden/genmetal_3 0 0 0.00 1 1 0 0 0 +( 220 80 64 ) ( 212 96 128 ) ( 212 64 0 ) eden/genmetal_3 0 0 0.00 1 1 0 0 0 +( 224 64 128 ) ( 216 32 128 ) ( 216 96 128 ) eden/genmetal_3 0 0 0.00 1 1 0 0 0 +} +// brush 25 +{ +( 192 -8 256 ) ( 192 -32 0 ) ( 192 16 0 ) eden/WL_edendoor 64 0 0.00 1 1 0 0 0 +( 232 64 256 ) ( 272 64 0 ) ( 192 64 0 ) eden/genmetal_3 0 0 0.00 1 1 0 0 0 +( 204 76 256 ) ( 204 88 0 ) ( 204 64 0 ) eden/genmetal_3 0 0 0.00 1 1 0 0 0 +( 204 80 64 ) ( 196 96 128 ) ( 196 64 0 ) eden/genmetal_3 0 0 0.00 1 1 0 0 0 +( 200 64 128 ) ( 192 32 128 ) ( 192 96 128 ) eden/genmetal_3 0 0 0.00 1 1 0 0 0 +} +} +// entity 1 +{ +"classname" "Animal_Shgliek" +"scale" "1.0" +"model" "shgliek.tik" +"targetname" "shgliek1" +"origin" "-8.00 312.00 0.00" +} +// entity 2 +{ +"classname" "light" +"origin" "-64 320 128" +} +// entity 3 +{ +"origin" "-192.00 128.00 0.00" +"targetname" "dude" +"model" "edenmale_balthazar.tik" +"scale" "1.0" +"classname" "Characters_EdenMale_Balthazar" +} +// entity 4 +{ +"origin" "-192 0 0" +"classname" "info_player_start" +} +// entity 5 +{ +"spawnflags" "8" +"origin" "168 128 0" +"classname" "info_pathnode" +} +// entity 6 +{ +"classname" "func_door" +"angle" "-1" +// brush 0 +{ +( 292 192 0 ) ( 260 192 0 ) ( 260 32 0 ) eden/genmetal_3 0 0 0.00 1 1 0 0 0 +( 212 32 320 ) ( 212 192 320 ) ( 212 192 64 ) eden/WL_edendoor 64 0 0.00 1 1 0 0 0 +( 204 192 320 ) ( 204 32 320 ) ( 204 32 64 ) eden/WL_edendoor 64 0 0.00 1 1 0 0 0 +( 260 64 128 ) ( 260 96 128 ) ( 276 80 128 ) eden/genmetal_3 0 0 0.00 1 1 0 0 0 +( 260 64 0 ) ( 260 96 128 ) ( 276 80 64 ) eden/genmetal_3 0 0 0.00 1 1 0 0 0 +( 260 160 128 ) ( 260 192 0 ) ( 276 176 64 ) eden/genmetal_3 0 0 0.00 1 1 0 0 0 +} +} +// entity 7 +{ +"spawnflags" "8" +"classname" "info_pathnode" +"origin" "248 128 0" +} +// entity 8 +{ +"origin" "384 128 0" +"classname" "info_pathnode" +} +// entity 9 +{ +"targetname" "dude_dest" +"classname" "info_pathnode" +"origin" "576 128 0" +} +// entity 10 +{ +"origin" "0 128 0" +"classname" "info_pathnode" +} +// entity 11 +{ +"classname" "info_pathnode" +"origin" "-192 128 0" +} +// entity 12 +{ +"origin" "-64 -64 128" +"classname" "light" +} +// entity 13 +{ +"origin" "448 320 128" +"classname" "light" +} +// entity 14 +{ +"classname" "light" +"origin" "448 -64 128" +} +// entity 15 +{ +"classname" "trigger_useonce" +"thread" "dude_go_thread" +// brush 0 +{ +( 176 0 0 ) ( 160 0 0 ) ( 160 -64 0 ) common/trigger 0 0 0.00 1 1 0 128 0 +( 160 -64 128 ) ( 160 0 128 ) ( 176 0 128 ) common/trigger 0 0 0.00 1 1 0 128 0 +( 160 -64 32 ) ( 176 -64 32 ) ( 176 -64 0 ) common/trigger 0 0 0.00 1 1 0 128 0 +( 176 -64 32 ) ( 176 0 32 ) ( 176 0 0 ) common/trigger 0 0 0.00 1 1 0 128 0 +( 176 0 32 ) ( 160 0 32 ) ( 160 0 0 ) common/trigger 0 0 0.00 1 1 0 128 0 +( 160 0 96 ) ( 160 -64 96 ) ( 160 -64 64 ) common/trigger 0 0 0.00 1 1 0 128 0 +} +} diff --git a/fakk/maps/example/pickup.prt b/fakk/maps/example/pickup.prt new file mode 100644 index 0000000..d6b5b64 --- /dev/null +++ b/fakk/maps/example/pickup.prt @@ -0,0 +1,216 @@ +PRT1 +31 +67 +145 +4 0 9 0 (224 0 0 ) (640 0 0 ) (640 0 256 ) (224 0 256 ) +4 0 1 0 (224 192 0 ) (224 64 0 ) (224 96 128 ) (224 160 128 ) +4 1 2 0 (212 64 0 ) (212 96 128 ) (212 160 128 ) (212 192 0 ) +4 2 3 0 (204 192 0 ) (204 64 0 ) (204 96 128 ) (204 160 128 ) +4 3 8 0 (192 192 0 ) (192 64 0 ) (192 96 128 ) (192 160 128 ) +4 4 17 0 (0 0 192 ) (0 0 256 ) (0 512 256 ) (0 512 192 ) +4 4 13 0 (0 0 256 ) (0 0 192 ) (80 0 192 ) (80 0 256 ) +4 4 10 0 (80 0 192 ) (192 0 192 ) (192 0 256 ) (80 0 256 ) +4 4 5 0 (192 512 192 ) (192 496 192 ) (80 496 192 ) (80 512 192 ) +4 4 6 0 (48 496 192 ) (16 496 192 ) (16 512 192 ) (48 512 192 ) +4 4 8 0 (192 496 192 ) (192 0 192 ) (0 0 192 ) (0 496 192 ) +4 5 7 0 (192 496 64 ) (80 496 64 ) (80 512 64 ) (192 512 64 ) +4 5 8 0 (192 496 64 ) (192 496 192 ) (80 496 192 ) (80 496 64 ) +4 6 7 0 (48 496 64 ) (16 496 64 ) (16 512 64 ) (48 512 64 ) +4 6 8 0 (48 496 192 ) (16 496 192 ) (16 496 64 ) (48 496 64 ) +4 7 22 0 (0 512 0 ) (0 496 0 ) (0 496 64 ) (0 512 64 ) +4 7 8 0 (0 496 0 ) (192 496 0 ) (192 496 64 ) (0 496 64 ) +4 8 23 0 (0 0 0 ) (0 0 192 ) (0 496 192 ) (0 496 0 ) +4 8 13 0 (0 0 192 ) (0 0 0 ) (80 0 0 ) (80 0 192 ) +4 8 12 0 (80 0 0 ) (176 0 0 ) (176 0 128 ) (80 0 128 ) +4 8 10 0 (192 0 128 ) (192 0 192 ) (80 0 192 ) (80 0 128 ) +4 10 14 0 (80 -256 192 ) (80 -256 256 ) (80 -240 256 ) (80 -240 192 ) +4 10 13 0 (80 -240 256 ) (80 0 256 ) (80 0 128 ) (80 -240 128 ) +4 10 11 0 (192 -64 128 ) (192 -256 128 ) (176 -256 128 ) (176 -64 128 ) +4 10 12 0 (80 -256 128 ) (80 0 128 ) (176 0 128 ) (176 -256 128 ) +4 11 12 0 (176 -64 0 ) (176 -256 0 ) (176 -256 128 ) (176 -64 128 ) +4 12 16 0 (80 -240 0 ) (80 -256 0 ) (80 -256 64 ) (80 -240 64 ) +4 12 13 0 (80 0 0 ) (80 -240 0 ) (80 -240 128 ) (80 0 128 ) +4 13 25 0 (0 0 192 ) (0 0 0 ) (0 -240 0 ) (0 -240 192 ) +4 13 24 0 (0 -240 256 ) (0 0 256 ) (0 0 192 ) (0 -240 192 ) +4 13 15 0 (48 -240 192 ) (16 -240 192 ) (16 -240 64 ) (48 -240 64 ) +4 13 16 0 (0 -240 0 ) (80 -240 0 ) (80 -240 64 ) (0 -240 64 ) +4 13 14 0 (80 -240 192 ) (80 -240 256 ) (0 -240 256 ) (0 -240 192 ) +4 14 24 0 (0 -256 256 ) (0 -240 256 ) (0 -240 192 ) (0 -256 192 ) +4 14 15 0 (16 -240 192 ) (48 -240 192 ) (48 -256 192 ) (16 -256 192 ) +4 15 16 0 (16 -240 64 ) (48 -240 64 ) (48 -256 64 ) (16 -256 64 ) +4 16 30 0 (0 -240 64 ) (0 -240 0 ) (0 -256 0 ) (0 -256 64 ) +4 17 24 0 (-256 0 192 ) (0 0 192 ) (0 0 256 ) (-256 0 256 ) +4 17 23 0 (0 0 192 ) (-256 0 192 ) (-256 496 192 ) (0 496 192 ) +4 17 21 0 (-256 496 192 ) (-256 512 192 ) (-208 512 192 ) (-208 496 192 ) +4 17 20 0 (-176 512 192 ) (-144 512 192 ) (-144 496 192 ) (-176 496 192 ) +4 17 19 0 (-112 512 192 ) (-80 512 192 ) (-80 496 192 ) (-112 496 192 ) +4 17 18 0 (-48 512 192 ) (-16 512 192 ) (-16 496 192 ) (-48 496 192 ) +4 18 23 0 (-16 496 192 ) (-48 496 192 ) (-48 496 64 ) (-16 496 64 ) +4 18 22 0 (-16 496 64 ) (-48 496 64 ) (-48 512 64 ) (-16 512 64 ) +4 19 23 0 (-80 496 192 ) (-112 496 192 ) (-112 496 64 ) (-80 496 64 ) +4 19 22 0 (-80 496 64 ) (-112 496 64 ) (-112 512 64 ) (-80 512 64 ) +4 20 23 0 (-144 496 192 ) (-176 496 192 ) (-176 496 64 ) (-144 496 64 ) +4 20 22 0 (-144 496 64 ) (-176 496 64 ) (-176 512 64 ) (-144 512 64 ) +4 21 23 0 (-208 496 192 ) (-256 496 192 ) (-256 496 64 ) (-208 496 64 ) +4 21 22 0 (-208 496 64 ) (-256 496 64 ) (-256 512 64 ) (-208 512 64 ) +4 22 23 0 (0 496 0 ) (0 496 64 ) (-256 496 64 ) (-256 496 0 ) +4 23 25 0 (-256 0 0 ) (0 0 0 ) (0 0 192 ) (-256 0 192 ) +4 24 27 0 (-80 -256 192 ) (-112 -256 192 ) (-112 -240 192 ) (-80 -240 192 ) +4 24 28 0 (-144 -256 192 ) (-176 -256 192 ) (-176 -240 192 ) (-144 -240 192 ) +4 24 26 0 (-16 -256 192 ) (-48 -256 192 ) (-48 -240 192 ) (-16 -240 192 ) +4 24 29 0 (-208 -256 192 ) (-256 -256 192 ) (-256 -240 192 ) (-208 -240 192 ) +4 24 25 0 (-256 0 192 ) (0 0 192 ) (0 -240 192 ) (-256 -240 192 ) +4 25 30 0 (0 -240 0 ) (0 -240 64 ) (-256 -240 64 ) (-256 -240 0 ) +4 25 27 0 (-80 -240 192 ) (-112 -240 192 ) (-112 -240 64 ) (-80 -240 64 ) +4 25 28 0 (-144 -240 192 ) (-176 -240 192 ) (-176 -240 64 ) (-144 -240 64 ) +4 25 26 0 (-16 -240 192 ) (-48 -240 192 ) (-48 -240 64 ) (-16 -240 64 ) +4 25 29 0 (-208 -240 192 ) (-256 -240 192 ) (-256 -240 64 ) (-208 -240 64 ) +4 26 30 0 (-48 -240 64 ) (-16 -240 64 ) (-16 -256 64 ) (-48 -256 64 ) +4 27 30 0 (-112 -240 64 ) (-80 -240 64 ) (-80 -256 64 ) (-112 -256 64 ) +4 28 30 0 (-176 -240 64 ) (-144 -240 64 ) (-144 -256 64 ) (-176 -256 64 ) +4 29 30 0 (-256 -240 64 ) (-208 -240 64 ) (-208 -256 64 ) (-256 -256 64 ) +4 0 (224 512 0 ) (224 192 0 ) (224 160 128 ) (224 512 128 ) +3 0 (224 64 0 ) (224 64 128 ) (224 96 128 ) +4 0 (224 64 128 ) (224 64 256 ) (224 512 256 ) (224 512 128 ) +4 0 (224 64 0 ) (224 0 0 ) (224 0 256 ) (224 64 256 ) +4 0 (640 512 256 ) (224 512 256 ) (224 0 256 ) (640 0 256 ) +4 0 (640 0 0 ) (224 0 0 ) (224 512 0 ) (640 512 0 ) +4 0 (640 512 256 ) (640 512 0 ) (224 512 0 ) (224 512 256 ) +4 0 (640 0 0 ) (640 512 0 ) (640 512 256 ) (640 0 256 ) +4 1 (224 96 128 ) (212 96 128 ) (212 64 0 ) (224 64 0 ) +4 1 (224 192 0 ) (224 64 0 ) (212 64 0 ) (212 192 0 ) +4 1 (224 96 128 ) (224 160 128 ) (212 160 128 ) (212 96 128 ) +4 1 (212 192 0 ) (212 160 128 ) (224 160 128 ) (224 192 0 ) +3 2 (204 192 128 ) (204 192 0 ) (204 160 128 ) +3 2 (204 64 0 ) (204 64 128 ) (204 96 128 ) +4 2 (212 192 128 ) (212 192 0 ) (204 192 0 ) (204 192 128 ) +3 2 (212 192 0 ) (212 192 128 ) (212 160 128 ) +3 2 (212 96 128 ) (212 64 128 ) (212 64 0 ) +4 2 (204 64 128 ) (204 64 0 ) (212 64 0 ) (212 64 128 ) +4 2 (204 64 0 ) (204 192 0 ) (212 192 0 ) (212 64 0 ) +4 2 (204 64 128 ) (212 64 128 ) (212 192 128 ) (204 192 128 ) +4 3 (204 64 0 ) (204 96 128 ) (192 96 128 ) (192 64 0 ) +4 3 (192 64 0 ) (192 192 0 ) (204 192 0 ) (204 64 0 ) +4 3 (204 96 128 ) (204 160 128 ) (192 160 128 ) (192 96 128 ) +4 3 (192 160 128 ) (204 160 128 ) (204 192 0 ) (192 192 0 ) +4 4 (80 496 192 ) (48 496 192 ) (48 512 192 ) (80 512 192 ) +4 4 (16 496 192 ) (0 496 192 ) (0 512 192 ) (16 512 192 ) +4 4 (192 512 256 ) (192 512 192 ) (0 512 192 ) (0 512 256 ) +4 4 (192 512 192 ) (192 512 256 ) (192 0 256 ) (192 0 192 ) +4 4 (0 0 256 ) (192 0 256 ) (192 512 256 ) (0 512 256 ) +4 5 (80 512 192 ) (192 512 192 ) (192 512 64 ) (80 512 64 ) +4 5 (192 496 128 ) (192 512 128 ) (192 512 192 ) (192 496 192 ) +4 5 (192 512 64 ) (192 512 128 ) (192 496 128 ) (192 496 64 ) +4 5 (80 512 192 ) (80 512 64 ) (80 496 64 ) (80 496 192 ) +4 6 (48 496 192 ) (48 496 64 ) (48 512 64 ) (48 512 192 ) +4 6 (16 512 192 ) (16 512 64 ) (16 496 64 ) (16 496 192 ) +4 6 (16 512 192 ) (48 512 192 ) (48 512 64 ) (16 512 64 ) +4 7 (192 512 64 ) (192 496 64 ) (192 496 0 ) (192 512 0 ) +4 7 (0 496 0 ) (0 512 0 ) (192 512 0 ) (192 496 0 ) +4 7 (16 512 64 ) (0 512 64 ) (0 496 64 ) (16 496 64 ) +4 7 (80 512 64 ) (48 512 64 ) (48 496 64 ) (80 496 64 ) +4 7 (0 512 64 ) (192 512 64 ) (192 512 0 ) (0 512 0 ) +4 8 (176 0 0 ) (192 0 0 ) (192 0 128 ) (176 0 128 ) +4 8 (80 496 64 ) (48 496 64 ) (48 496 192 ) (80 496 192 ) +4 8 (16 496 64 ) (0 496 64 ) (0 496 192 ) (16 496 192 ) +4 8 (192 496 128 ) (192 160 128 ) (192 192 0 ) (192 496 0 ) +4 8 (192 96 128 ) (192 0 128 ) (192 0 0 ) (192 64 0 ) +4 8 (192 496 128 ) (192 496 192 ) (192 0 192 ) (192 0 128 ) +4 8 (192 0 0 ) (0 0 0 ) (0 496 0 ) (192 496 0 ) +4 9 (224 -256 0 ) (640 -256 0 ) (640 -256 256 ) (224 -256 256 ) +4 9 (640 -256 256 ) (640 -256 0 ) (640 0 0 ) (640 0 256 ) +4 9 (224 0 0 ) (640 0 0 ) (640 -256 0 ) (224 -256 0 ) +4 9 (224 -256 256 ) (640 -256 256 ) (640 0 256 ) (224 0 256 ) +4 9 (224 0 0 ) (224 -256 0 ) (224 -256 256 ) (224 0 256 ) +4 10 (80 -256 128 ) (80 -256 192 ) (80 -240 192 ) (80 -240 128 ) +4 10 (176 0 128 ) (192 0 128 ) (192 -64 128 ) (176 -64 128 ) +4 10 (192 -256 128 ) (192 -256 256 ) (80 -256 256 ) (80 -256 128 ) +4 10 (80 -256 256 ) (192 -256 256 ) (192 0 256 ) (80 0 256 ) +4 10 (192 0 128 ) (192 0 256 ) (192 -256 256 ) (192 -256 128 ) +4 11 (176 -256 0 ) (192 -256 0 ) (192 -256 128 ) (176 -256 128 ) +4 11 (192 -64 0 ) (192 -256 0 ) (176 -256 0 ) (176 -64 0 ) +4 11 (192 -64 128 ) (192 -256 128 ) (192 -256 0 ) (192 -64 0 ) +4 11 (192 -64 128 ) (192 -64 0 ) (176 -64 0 ) (176 -64 128 ) +4 12 (80 -256 64 ) (80 -256 128 ) (80 -240 128 ) (80 -240 64 ) +4 12 (176 0 128 ) (176 -64 128 ) (176 -64 0 ) (176 0 0 ) +4 12 (80 0 0 ) (176 0 0 ) (176 -256 0 ) (80 -256 0 ) +4 12 (80 -256 0 ) (176 -256 0 ) (176 -256 128 ) (80 -256 128 ) +4 13 (16 -240 192 ) (0 -240 192 ) (0 -240 64 ) (16 -240 64 ) +4 13 (80 -240 64 ) (80 -240 192 ) (48 -240 192 ) (48 -240 64 ) +4 13 (80 -240 256 ) (80 0 256 ) (0 0 256 ) (0 -240 256 ) +4 13 (0 -240 0 ) (0 0 0 ) (80 0 0 ) (80 -240 0 ) +4 14 (0 -240 192 ) (16 -240 192 ) (16 -256 192 ) (0 -256 192 ) +4 14 (48 -240 192 ) (80 -240 192 ) (80 -256 192 ) (48 -256 192 ) +4 14 (80 -256 192 ) (80 -256 256 ) (0 -256 256 ) (0 -256 192 ) +4 14 (80 -256 256 ) (80 -240 256 ) (0 -240 256 ) (0 -256 256 ) +4 15 (48 -240 192 ) (48 -256 192 ) (48 -256 64 ) (48 -240 64 ) +4 15 (48 -256 192 ) (16 -256 192 ) (16 -256 64 ) (48 -256 64 ) +4 15 (16 -240 64 ) (16 -256 64 ) (16 -256 192 ) (16 -240 192 ) +4 16 (0 -256 64 ) (16 -256 64 ) (16 -240 64 ) (0 -240 64 ) +4 16 (48 -256 64 ) (80 -256 64 ) (80 -240 64 ) (48 -240 64 ) +4 16 (0 -256 0 ) (0 -240 0 ) (80 -240 0 ) (80 -256 0 ) +4 16 (0 -256 0 ) (80 -256 0 ) (80 -256 64 ) (0 -256 64 ) +4 17 (-208 512 192 ) (-176 512 192 ) (-176 496 192 ) (-208 496 192 ) +4 17 (-144 512 192 ) (-112 512 192 ) (-112 496 192 ) (-144 496 192 ) +4 17 (-80 512 192 ) (-48 512 192 ) (-48 496 192 ) (-80 496 192 ) +4 17 (-16 512 192 ) (0 512 192 ) (0 496 192 ) (-16 496 192 ) +4 17 (0 512 256 ) (-256 512 256 ) (-256 0 256 ) (0 0 256 ) +4 17 (-256 512 256 ) (0 512 256 ) (0 512 192 ) (-256 512 192 ) +4 17 (-256 0 256 ) (-256 512 256 ) (-256 512 192 ) (-256 0 192 ) +4 18 (-16 496 192 ) (-16 496 64 ) (-16 512 64 ) (-16 512 192 ) +4 18 (-48 512 192 ) (-16 512 192 ) (-16 512 64 ) (-48 512 64 ) +4 18 (-48 512 192 ) (-48 512 64 ) (-48 496 64 ) (-48 496 192 ) +4 19 (-112 512 192 ) (-112 512 64 ) (-112 496 64 ) (-112 496 192 ) +4 19 (-112 512 192 ) (-80 512 192 ) (-80 512 64 ) (-112 512 64 ) +4 19 (-80 496 192 ) (-80 496 64 ) (-80 512 64 ) (-80 512 192 ) +4 20 (-176 512 192 ) (-176 512 64 ) (-176 496 64 ) (-176 496 192 ) +4 20 (-176 512 192 ) (-144 512 192 ) (-144 512 64 ) (-176 512 64 ) +4 20 (-144 496 192 ) (-144 496 64 ) (-144 512 64 ) (-144 512 192 ) +4 21 (-256 512 192 ) (-256 512 64 ) (-256 496 64 ) (-256 496 192 ) +4 21 (-256 512 192 ) (-208 512 192 ) (-208 512 64 ) (-256 512 64 ) +4 21 (-208 496 192 ) (-208 496 64 ) (-208 512 64 ) (-208 512 192 ) +4 22 (0 496 0 ) (-256 496 0 ) (-256 512 0 ) (0 512 0 ) +4 22 (0 512 64 ) (-16 512 64 ) (-16 496 64 ) (0 496 64 ) +4 22 (-48 512 64 ) (-80 512 64 ) (-80 496 64 ) (-48 496 64 ) +4 22 (-112 512 64 ) (-144 512 64 ) (-144 496 64 ) (-112 496 64 ) +4 22 (-176 512 64 ) (-208 512 64 ) (-208 496 64 ) (-176 496 64 ) +4 22 (-256 512 0 ) (-256 512 64 ) (0 512 64 ) (0 512 0 ) +4 22 (-256 512 64 ) (-256 512 0 ) (-256 496 0 ) (-256 496 64 ) +4 23 (0 0 0 ) (-256 0 0 ) (-256 496 0 ) (0 496 0 ) +4 23 (-176 496 64 ) (-208 496 64 ) (-208 496 192 ) (-176 496 192 ) +4 23 (-112 496 64 ) (-144 496 64 ) (-144 496 192 ) (-112 496 192 ) +4 23 (-48 496 64 ) (-80 496 64 ) (-80 496 192 ) (-48 496 192 ) +4 23 (-16 496 64 ) (-16 496 192 ) (0 496 192 ) (0 496 64 ) +4 23 (-256 496 192 ) (-256 496 0 ) (-256 0 0 ) (-256 0 192 ) +4 24 (-112 -256 192 ) (-144 -256 192 ) (-144 -240 192 ) (-112 -240 192 ) +4 24 (-48 -256 192 ) (-80 -256 192 ) (-80 -240 192 ) (-48 -240 192 ) +4 24 (-176 -256 192 ) (-208 -256 192 ) (-208 -240 192 ) (-176 -240 192 ) +4 24 (0 -240 192 ) (0 -256 192 ) (-16 -256 192 ) (-16 -240 192 ) +4 24 (0 -256 256 ) (0 0 256 ) (-256 0 256 ) (-256 -256 256 ) +4 24 (-256 0 256 ) (-256 0 192 ) (-256 -256 192 ) (-256 -256 256 ) +4 24 (0 -256 256 ) (-256 -256 256 ) (-256 -256 192 ) (0 -256 192 ) +4 25 (-112 -240 192 ) (-144 -240 192 ) (-144 -240 64 ) (-112 -240 64 ) +4 25 (-48 -240 192 ) (-80 -240 192 ) (-80 -240 64 ) (-48 -240 64 ) +4 25 (-176 -240 192 ) (-208 -240 192 ) (-208 -240 64 ) (-176 -240 64 ) +4 25 (0 -240 64 ) (0 -240 192 ) (-16 -240 192 ) (-16 -240 64 ) +4 25 (0 -240 0 ) (-256 -240 0 ) (-256 0 0 ) (0 0 0 ) +4 25 (-256 0 0 ) (-256 -240 0 ) (-256 -240 192 ) (-256 0 192 ) +4 26 (-48 -240 192 ) (-48 -240 64 ) (-48 -256 64 ) (-48 -256 192 ) +4 26 (-48 -256 64 ) (-16 -256 64 ) (-16 -256 192 ) (-48 -256 192 ) +4 26 (-16 -256 192 ) (-16 -256 64 ) (-16 -240 64 ) (-16 -240 192 ) +4 27 (-112 -256 64 ) (-80 -256 64 ) (-80 -256 192 ) (-112 -256 192 ) +4 27 (-80 -256 192 ) (-80 -256 64 ) (-80 -240 64 ) (-80 -240 192 ) +4 27 (-112 -240 192 ) (-112 -240 64 ) (-112 -256 64 ) (-112 -256 192 ) +4 28 (-144 -256 192 ) (-144 -256 64 ) (-144 -240 64 ) (-144 -240 192 ) +4 28 (-176 -256 64 ) (-144 -256 64 ) (-144 -256 192 ) (-176 -256 192 ) +4 28 (-176 -240 192 ) (-176 -240 64 ) (-176 -256 64 ) (-176 -256 192 ) +4 29 (-208 -256 192 ) (-208 -256 64 ) (-208 -240 64 ) (-208 -240 192 ) +4 29 (-256 -256 192 ) (-256 -256 64 ) (-208 -256 64 ) (-208 -256 192 ) +4 29 (-256 -240 192 ) (-256 -240 64 ) (-256 -256 64 ) (-256 -256 192 ) +4 30 (-256 -256 0 ) (-256 -240 0 ) (0 -240 0 ) (0 -256 0 ) +4 30 (-16 -256 64 ) (0 -256 64 ) (0 -240 64 ) (-16 -240 64 ) +4 30 (-208 -256 64 ) (-176 -256 64 ) (-176 -240 64 ) (-208 -240 64 ) +4 30 (-80 -256 64 ) (-48 -256 64 ) (-48 -240 64 ) (-80 -240 64 ) +4 30 (-144 -256 64 ) (-112 -256 64 ) (-112 -240 64 ) (-144 -240 64 ) +4 30 (-256 -256 64 ) (-256 -240 64 ) (-256 -240 0 ) (-256 -256 0 ) +4 30 (-256 -256 64 ) (-256 -256 0 ) (0 -256 0 ) (0 -256 64 ) diff --git a/fakk/maps/example/pickup.pth b/fakk/maps/example/pickup.pth new file mode 100644 index 0000000..c95d6e3 Binary files /dev/null and b/fakk/maps/example/pickup.pth differ diff --git a/fakk/maps/example/pickup.scr b/fakk/maps/example/pickup.scr new file mode 100644 index 0000000..2c4dfe3 --- /dev/null +++ b/fakk/maps/example/pickup.scr @@ -0,0 +1,25 @@ +waitforplayer +start: + +$shgliek1 idle STILL + +end + +dude_go_thread: + +$dude thread dude_AIthread + +end + +dude_AIthread: +local.self pickupent $shgliek1 shgliek_pickup +waitFor local.self +local.self walkto $dude_dest walk_shgliek +waitFor local.self +local.self throwent shgliek_toss +waitFor local.self +local.self idle STAND_IDLE + +end + + diff --git a/fakk/maps/example/pushobject.bsp b/fakk/maps/example/pushobject.bsp new file mode 100644 index 0000000..8ea5013 Binary files /dev/null and b/fakk/maps/example/pushobject.bsp differ diff --git a/fakk/maps/example/pushobject.map b/fakk/maps/example/pushobject.map new file mode 100644 index 0000000..9a02b14 --- /dev/null +++ b/fakk/maps/example/pushobject.map @@ -0,0 +1,454 @@ +{ +"classname" "worldspawn" +// brush 0 +{ +( -480 -512 64 ) ( -480 -544 64 ) ( 224 -544 64 ) eden/edenmetalwall -31 31 -90.00 1 1 0 0 0 +( 224 -512 96 ) ( -480 -512 96 ) ( -480 -512 64 ) eden/edenmetalwall -32 62 0.00 1.000008 1 0 0 0 +( -480 -512 96 ) ( -480 -544 96 ) ( -480 -544 64 ) eden/edenmetalwall -33 63 -180.00 1 -1 0 0 0 +( -480 -544 96 ) ( 224 -544 96 ) ( 224 -544 64 ) eden/edenmetalwall -32 62 0.00 1.000008 1 0 0 0 +( -56 -544 128 ) ( -56 -512 128 ) ( 72 -512 128 ) eden/edenmetalwall -32 62 0.00 1.000008 1 0 0 0 +( -64 -544 256 ) ( -64 -512 256 ) ( -64 -544 0 ) eden/edenmetalwall -32 62 0.00 1.000008 1 0 0 0 +} +// brush 1 +{ +( -480 -512 64 ) ( -480 -544 64 ) ( 224 -544 64 ) eden/edenmetalwall -31 31 -90.00 1 1 0 0 0 +( 224 -544 96 ) ( 224 -512 96 ) ( 224 -512 64 ) eden/edenmetalwall -32 63 -180.00 1 -1 0 0 0 +( 224 -512 96 ) ( -480 -512 96 ) ( -480 -512 64 ) eden/edenmetalwall -32 62 0.00 1.000008 1 0 0 0 +( -480 -544 96 ) ( 224 -544 96 ) ( 224 -544 64 ) eden/edenmetalwall -32 62 0.00 1.000008 1 0 0 0 +( -56 -544 128 ) ( -56 -512 128 ) ( 72 -512 128 ) eden/edenmetalwall -32 62 0.00 1.000008 1 0 0 0 +( 64 -512 256 ) ( 64 -544 256 ) ( 64 -512 0 ) eden/edenmetalwall -32 62 0.00 1.000008 1 0 0 0 +} +// brush 2 +{ +( 224 -544 320 ) ( -480 -544 320 ) ( -480 -512 320 ) eden/edenmetalwall -32 62 0.00 1.000008 1 0 0 0 +( 224 -544 96 ) ( 224 -512 96 ) ( 224 -512 64 ) eden/edenmetalwall -32 62 0.00 1.000008 1 0 0 0 +( 224 -512 96 ) ( -480 -512 96 ) ( -480 -512 64 ) eden/edenmetalwall -32 62 0.00 1.000008 1 0 0 0 +( -480 -512 96 ) ( -480 -544 96 ) ( -480 -544 64 ) eden/edenmetalwall -32 62 0.00 1.000008 1 0 0 0 +( -480 -544 96 ) ( 224 -544 96 ) ( 224 -544 64 ) eden/edenmetalwall -32 62 0.00 1.000008 1 0 0 0 +( -56 -512 128 ) ( -56 -544 128 ) ( 72 -512 128 ) eden/edenmetalwall -32 62 0.00 1.000008 1 0 0 0 +} +// brush 3 +{ +( -480 -512 0 ) ( -480 -544 0 ) ( 224 -544 0 ) eden/bedtrim -32 0 0.00 1 1 0 0 0 +( 224 -544 64 ) ( -480 -544 64 ) ( -480 -512 64 ) eden/bedtrim -32 0 0.00 1 1 0 0 0 +( 224 -512 256 ) ( -480 -512 256 ) ( -480 -512 0 ) eden/bedtrim -32 0 0.00 1 1 0 0 0 +( -480 -512 256 ) ( -480 -544 256 ) ( -480 -544 0 ) eden/bedtrim -32 0 0.00 1 1 0 0 0 +( -480 -544 256 ) ( 224 -544 256 ) ( 224 -544 0 ) eden/bedtrim -32 0 0.00 1 1 0 0 0 +( -64 -544 256 ) ( -64 -512 256 ) ( -64 -544 0 ) eden/bedtrim -32 0 0.00 1 1 0 0 0 +} +// brush 4 +{ +( -480 -512 0 ) ( -480 -544 0 ) ( 224 -544 0 ) eden/bedtrim -31 32 -90.00 1 1 0 0 0 +( 224 -544 64 ) ( -480 -544 64 ) ( -480 -512 64 ) eden/bedtrim -31 32 -90.00 1 1 0 0 0 +( 224 -544 256 ) ( 224 -512 256 ) ( 224 -512 0 ) eden/bedtrim -32 0 -180.00 1 -1 0 0 0 +( 224 -512 256 ) ( -480 -512 256 ) ( -480 -512 0 ) eden/bedtrim -32 0 0.00 1 1 0 0 0 +( -480 -544 256 ) ( 224 -544 256 ) ( 224 -544 0 ) eden/bedtrim -32 0 0.00 1 1 0 0 0 +( 64 -512 256 ) ( 64 -544 256 ) ( 64 -512 0 ) eden/bedtrim -32 0 0.00 1 1 0 0 0 +} +// brush 5 +{ +( -480 -768 0 ) ( -480 -800 0 ) ( 224 -800 0 ) eden/bedtrim -31 32 -90.00 1 1 0 0 0 +( 224 -800 64 ) ( -480 -800 64 ) ( -480 -768 64 ) eden/bedtrim -31 32 -90.00 1 1 0 0 0 +( 224 -800 256 ) ( 224 -768 256 ) ( 224 -768 0 ) eden/bedtrim -32 0 -180.00 1 -1 0 0 0 +( 224 -768 256 ) ( -480 -768 256 ) ( -480 -768 0 ) eden/bedtrim -32 0 0.00 1 1 0 0 0 +( -480 -768 256 ) ( -480 -800 256 ) ( -480 -800 0 ) eden/bedtrim -33 0 -180.00 1 -1 0 0 0 +( -480 -800 256 ) ( 224 -800 256 ) ( 224 -800 0 ) eden/bedtrim -32 0 0.00 1 1 0 0 0 +} +// brush 6 +{ +( -480 -768 64 ) ( -480 -800 64 ) ( 224 -800 64 ) eden/edenmetalwall -31 31 -90.00 1 1 0 0 0 +( 224 -800 320 ) ( -480 -800 320 ) ( -480 -768 320 ) eden/edenmetalwall -31 31 -90.00 1 1 0 0 0 +( 224 -800 96 ) ( 224 -768 96 ) ( 224 -768 64 ) eden/edenmetalwall -32 62 -180.00 1 -1 0 0 0 +( 224 -768 96 ) ( -480 -768 96 ) ( -480 -768 64 ) eden/edenmetalwall -31 62 0.00 1.000008 1 0 0 0 +( -480 -768 96 ) ( -480 -800 96 ) ( -480 -800 64 ) eden/edenmetalwall -33 62 -180.00 1 -1 0 0 0 +( -480 -800 96 ) ( 224 -800 96 ) ( 224 -800 64 ) eden/edenmetalwall -31 62 0.00 1.000008 1 0 0 0 +} +// brush 7 +{ +( 64 -96 0 ) ( 0 -96 0 ) ( 0 -224 0 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +( 0 -224 96 ) ( 0 -96 96 ) ( 64 -96 96 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +( 8 -256 96 ) ( 72 -256 96 ) ( 72 -256 0 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +( 64 -224 96 ) ( 64 -96 96 ) ( 64 -96 0 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +( 72 -64 96 ) ( 8 -64 96 ) ( 8 -64 0 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +( 0 -96 96 ) ( 0 -224 96 ) ( 0 -224 0 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +} +// brush 8 +{ +( 224 192 0 ) ( 224 224 0 ) ( -480 224 0 ) eden/bedtrim -224 -32 90.00 1 1 0 0 0 +( -480 224 64 ) ( 224 224 64 ) ( 224 192 64 ) eden/bedtrim -224 -32 90.00 1 1 0 0 0 +( -480 224 256 ) ( -480 192 256 ) ( -480 192 0 ) eden/bedtrim -224 0 0.00 1 1 0 0 0 +( -480 192 256 ) ( 224 192 256 ) ( 224 192 0 ) common/skip 0 0 0.00 1 1 805306368 16512 0 +( 224 224 256 ) ( -480 224 256 ) ( -480 224 0 ) eden/bedtrim 224 0 -180.00 1 -1 0 0 0 +( -416 224 0 ) ( -416 192 0 ) ( -416 208 64 ) eden/bedtrim 224 0 -180.00 1 -1 0 0 0 +} +// brush 9 +{ +( 224 192 0 ) ( 224 224 0 ) ( -480 224 0 ) eden/bedtrim -224 -32 90.00 1 1 0 0 0 +( -480 224 64 ) ( 224 224 64 ) ( 224 192 64 ) eden/bedtrim -224 -32 90.00 1 1 0 0 0 +( -480 192 256 ) ( 224 192 256 ) ( 224 192 0 ) eden/bedtrim 224 0 -180.00 1 -1 0 0 0 +( 224 192 256 ) ( 224 224 256 ) ( 224 224 0 ) eden/bedtrim -224 0 0.00 1 1 0 0 0 +( 224 224 256 ) ( -480 224 256 ) ( -480 224 0 ) eden/bedtrim 224 0 -180.00 1 -1 0 0 0 +( -480 192 0 ) ( -480 224 0 ) ( -480 208 64 ) eden/bedtrim 224 0 -180.00 1 -1 0 0 0 +} +// brush 10 +{ +( 224 192 64 ) ( 224 224 64 ) ( -480 224 64 ) eden/edenmetalwall -224 -224 90.00 1 1 0 0 0 +( -480 224 320 ) ( 224 224 320 ) ( 224 192 320 ) eden/edenmetalwall -224 -224 90.00 1 1 0 0 0 +( -480 224 96 ) ( -480 192 96 ) ( -480 192 64 ) eden/edenmetalwall -224 64 0.00 1 1 0 0 0 +( -480 192 96 ) ( 224 192 96 ) ( 224 192 64 ) common/skip 0 0 0.00 1 1 805306368 16512 0 +( 224 224 96 ) ( -480 224 96 ) ( -480 224 64 ) eden/edenmetalwall 224 63 -180.00 1 -1 0 0 0 +( -416 224 64 ) ( -416 192 64 ) ( -416 208 320 ) eden/edenmetalwall 224 63 -180.00 1 -1 0 0 0 +} +// brush 11 +{ +( 224 192 64 ) ( 224 224 64 ) ( -480 224 64 ) eden/edenmetalwall -224 -224 90.00 1 1 0 0 0 +( -480 224 320 ) ( 224 224 320 ) ( 224 192 320 ) eden/edenmetalwall -224 -224 90.00 1 1 0 0 0 +( -480 192 96 ) ( 224 192 96 ) ( 224 192 64 ) eden/edenmetalwall 224 63 -180.00 1 -1 0 0 0 +( 224 192 96 ) ( 224 224 96 ) ( 224 224 64 ) eden/edenmetalwall -224 64 0.00 1 1 0 0 0 +( 224 224 96 ) ( -480 224 96 ) ( -480 224 64 ) eden/edenmetalwall 224 63 -180.00 1 -1 0 0 0 +( -480 192 64 ) ( -480 224 64 ) ( -480 208 320 ) eden/edenmetalwall 224 63 -180.00 1 -1 0 0 0 +} +// brush 12 + { + patchDef2 + { + eden/edenmetalwall + ( 3 3 0 536870912 0 ) +( +( ( -480 96 63.999992 0 0 ) ( -480 96 192 0 0.500000 ) ( -480 96 320 0 1 ) ) +( ( -384 96 63.999992 0.500000 0 ) ( -384 96 192 0.500000 0.500000 ) ( -384 96 320 0.500000 1 ) ) +( ( -384 192 63.999992 1 0 ) ( -384 192 192 1 0.500000 ) ( -384 192 320 1 1 ) ) +) + } + } +// brush 13 +{ +( -480 192 0 ) ( -512 192 0 ) ( -512 -512 0 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +( -512 -512 64 ) ( -512 192 64 ) ( -480 192 64 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +( -480 -512 256 ) ( -480 192 256 ) ( -480 192 0 ) common/skip 0 0 0.00 1 1 805306368 16512 0 +( -480 192 256 ) ( -512 192 256 ) ( -512 192 0 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +( -512 192 256 ) ( -512 -512 256 ) ( -512 -512 0 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +( -480 128 0 ) ( -512 128 0 ) ( -496 128 64 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +} +// brush 14 +{ +( -480 192 0 ) ( -512 192 0 ) ( -512 -512 0 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +( -512 -512 64 ) ( -512 192 64 ) ( -480 192 64 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +( -504 -800 256 ) ( -472 -800 256 ) ( -472 -800 0 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +( -480 -512 256 ) ( -480 192 256 ) ( -480 192 0 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +( -512 192 256 ) ( -512 -512 256 ) ( -512 -512 0 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +( -512 192 0 ) ( -480 192 0 ) ( -496 192 64 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +} +// brush 15 +{ +( -480 192 64 ) ( -512 192 64 ) ( -512 -512 64 ) eden/edenmetalwall 0 0 0.00 1 1 0 0 0 +( -512 -512 320 ) ( -512 192 320 ) ( -480 192 320 ) eden/edenmetalwall 0 0 0.00 1 1 0 0 0 +( -480 -512 96 ) ( -480 192 96 ) ( -480 192 64 ) common/skip 0 0 0.00 1 1 805306368 16512 0 +( -480 192 96 ) ( -512 192 96 ) ( -512 192 64 ) eden/edenmetalwall 0 64 0.00 1 1 0 0 0 +( -512 192 96 ) ( -512 -512 96 ) ( -512 -512 64 ) eden/edenmetalwall 0 64 0.00 1 1 0 0 0 +( -480 128 64 ) ( -512 128 64 ) ( -496 128 320 ) eden/edenmetalwall 0 64 0.00 1 1 0 0 0 +} +// brush 16 +{ +( -480 192 64 ) ( -512 192 64 ) ( -512 -512 64 ) eden/edenmetalwall 0 0 0.00 1 1 0 0 0 +( -512 -512 320 ) ( -512 192 320 ) ( -480 192 320 ) eden/edenmetalwall 0 0 0.00 1 1 0 0 0 +( -512 -800 96 ) ( -480 -800 96 ) ( -480 -800 64 ) eden/edenmetalwall 0 64 0.00 1 1 0 0 0 +( -480 -512 96 ) ( -480 192 96 ) ( -480 192 64 ) eden/edenmetalwall 0 64 0.00 1 1 0 0 0 +( -512 192 96 ) ( -512 -512 96 ) ( -512 -512 64 ) eden/edenmetalwall 0 64 0.00 1 1 0 0 0 +( -512 192 64 ) ( -480 192 64 ) ( -496 192 320 ) eden/edenmetalwall 0 64 0.00 1 1 0 0 0 +} +// brush 17 + { + patchDef2 + { + eden/bedtrim + ( 3 3 0 536870912 0 ) +( +( ( -480 96 0 0 0 ) ( -480 96 32 0 0.500000 ) ( -480 96 64 0 1 ) ) +( ( -384 96 0 0.500000 0 ) ( -384 96 32 0.500000 0.500000 ) ( -384 96 64 0.500000 1 ) ) +( ( -384 192 0 1 0 ) ( -384 192 32 1 0.500000 ) ( -384 192 64 1 1 ) ) +) + } + } +// brush 18 +{ +( 96 96 352 ) ( -32 96 352 ) ( -32 -416 352 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( -32 -416 416 ) ( -32 96 416 ) ( 96 96 416 ) we_cemetary_test/levelord_sky 0 0 0.00 1 1 0 0 0 +( -32 -416 416 ) ( 96 -416 416 ) ( 96 -416 352 ) we_cemetary_test/levelord_sky 0 0 0.00 1 1 0 0 0 +( 96 -416 416 ) ( 96 96 416 ) ( 96 96 352 ) we_cemetary_test/levelord_sky 0 0 0.00 1 1 0 0 0 +( 96 96 416 ) ( -32 96 416 ) ( -32 96 352 ) we_cemetary_test/levelord_sky 0 0 0.00 1 1 0 0 0 +( -32 96 416 ) ( -32 -416 416 ) ( -32 -416 352 ) we_cemetary_test/levelord_sky 0 0 0.00 1 1 0 0 0 +} +// brush 19 +{ +( -64 -416 304 ) ( -64 -448 304 ) ( 128 -448 304 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( 128 -448 352 ) ( -64 -448 352 ) ( -64 -416 352 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( 96 -416 352 ) ( -32 -416 352 ) ( -32 -416 320 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( 128 -448 352 ) ( 96 -416 352 ) ( 96 -416 320 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( -64 -448 320 ) ( -64 -448 352 ) ( 128 -448 352 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( -64 -448 320 ) ( -32 -416 320 ) ( -32 -416 352 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +} +// brush 20 +{ +( -32 128 304 ) ( -64 128 304 ) ( -64 -64 304 ) eden/FL_edenhouse 0 32 90.00 1 1 0 0 0 +( -64 -64 352 ) ( -64 128 352 ) ( -32 128 352 ) eden/FL_edenhouse 0 32 90.00 1 1 0 0 0 +( -32 -32 352 ) ( -32 96 352 ) ( -32 96 320 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( -64 -448 352 ) ( -32 -416 352 ) ( -32 -416 320 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( -64 128 320 ) ( -64 128 352 ) ( -64 -64 352 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( -64 128 320 ) ( -32 96 320 ) ( -32 96 352 ) eden/FL_edenhouse -64 0 -180.00 1 -1 0 0 0 +} +// brush 21 +{ +( 128 -64 304 ) ( 128 128 304 ) ( 96 128 304 ) eden/FL_edenhouse 0 -96 90.00 1 1 0 0 0 +( 96 128 352 ) ( 128 128 352 ) ( 128 -64 352 ) eden/FL_edenhouse 0 -96 90.00 1 1 0 0 0 +( 96 96 320 ) ( 96 96 352 ) ( 96 -32 352 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( 96 -416 320 ) ( 96 -416 352 ) ( 128 -448 352 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( 128 -64 352 ) ( 128 128 352 ) ( 128 128 320 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( 96 96 352 ) ( 96 96 320 ) ( 128 128 320 ) eden/FL_edenhouse -64 0 -180.00 1 -1 0 0 0 +} +// brush 22 +{ +( 128 128 304 ) ( -64 128 304 ) ( -64 96 304 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( -64 96 352 ) ( -64 128 352 ) ( 128 128 352 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( -32 96 320 ) ( -32 96 352 ) ( 96 96 352 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( 96 96 320 ) ( 96 96 352 ) ( 128 128 352 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( 128 128 352 ) ( -64 128 352 ) ( -64 128 320 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( -32 96 352 ) ( -32 96 320 ) ( -64 128 320 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +} +// brush 23 +{ +( 128 192 320 ) ( -64 192 320 ) ( -64 128 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( -64 128 352 ) ( -64 192 352 ) ( 128 192 352 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( -64 128 352 ) ( 128 128 352 ) ( 128 128 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( 128 128 352 ) ( 128 192 352 ) ( 128 192 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( 128 192 352 ) ( -64 192 352 ) ( -64 192 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( -64 192 352 ) ( -64 128 352 ) ( -64 128 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +} +// brush 24 +{ +( 192 192 320 ) ( 128 192 320 ) ( 128 -448 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( 128 -448 352 ) ( 128 192 352 ) ( 192 192 352 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( 128 -448 352 ) ( 192 -448 352 ) ( 192 -448 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( 192 -448 352 ) ( 192 192 352 ) ( 192 192 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( 192 192 352 ) ( 128 192 352 ) ( 128 192 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( 128 192 352 ) ( 128 -448 352 ) ( 128 -448 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +} +// brush 25 +{ +( 192 192 320 ) ( -480 192 320 ) ( -480 -512 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( -480 -512 352 ) ( -480 192 352 ) ( 192 192 352 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( -480 -768 352 ) ( 192 -768 352 ) ( 192 -768 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( 192 -512 352 ) ( 192 192 352 ) ( 192 192 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( 224 -448 352 ) ( -448 -448 352 ) ( -448 -448 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( -64 -512 320 ) ( -64 -384 320 ) ( -64 -448 352 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +} +// brush 26 +{ +( 192 192 320 ) ( -480 192 320 ) ( -480 -512 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( -480 -512 352 ) ( -480 192 352 ) ( 192 192 352 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( -480 -768 352 ) ( 192 -768 352 ) ( 192 -768 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( 192 192 352 ) ( -480 192 352 ) ( -480 192 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( -480 192 352 ) ( -480 -512 352 ) ( -480 -512 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( -64 -384 320 ) ( -64 -512 320 ) ( -64 -448 352 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +} +// brush 27 +{ +( 192 192 -32 ) ( -480 192 -32 ) ( -480 -512 -32 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( -480 -512 0 ) ( -480 192 0 ) ( 192 192 0 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( -464 -768 224 ) ( 208 -768 224 ) ( 208 -768 -32 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 192 -512 224 ) ( 192 192 224 ) ( 192 192 -32 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 192 192 224 ) ( -480 192 224 ) ( -480 192 -32 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( -480 192 224 ) ( -480 -512 224 ) ( -480 -512 -32 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +} +// brush 28 +{ +( 192 -512 0 ) ( 224 -512 0 ) ( 224 192 0 ) eden/bedtrim 160 0 -180.00 1 1 0 0 0 +( 224 192 64 ) ( 224 -512 64 ) ( 192 -512 64 ) eden/bedtrim 160 0 -180.00 1 1 0 0 0 +( 224 192 256 ) ( 192 192 256 ) ( 192 192 0 ) eden/bedtrim 160 0 -180.00 1 -1 0 0 0 +( 192 192 256 ) ( 192 -512 256 ) ( 192 -512 0 ) eden/bedtrim -64 0 -180.00 1 -1 0 0 0 +( 208 -768 256 ) ( 240 -768 256 ) ( 240 -768 0 ) eden/bedtrim 159 0 -180.00 1 -1 0 0 0 +( 224 -512 256 ) ( 224 192 256 ) ( 224 192 0 ) eden/bedtrim -64 0 -180.00 1 -1 0 0 0 +} +// brush 29 +{ +( 192 -512 64 ) ( 224 -512 64 ) ( 224 192 64 ) eden/edenmetalwall 160 63 -180.00 1 1 0 0 0 +( 224 192 320 ) ( 224 -512 320 ) ( 192 -512 320 ) eden/edenmetalwall 160 63 -180.00 1 1 0 0 0 +( 224 192 96 ) ( 192 192 96 ) ( 192 192 64 ) eden/edenmetalwall 160 64 -180.00 1 -1 0 0 0 +( 192 -96 96 ) ( 192 -800 96 ) ( 192 -800 64 ) eden/edenmetalwall -64 62 -180.00 1 -1 0 0 0 +( 192 -768 96 ) ( 224 -768 96 ) ( 224 -768 64 ) eden/edenmetalwall 159 64 -180.00 1 -1 0 0 0 +( 224 -512 96 ) ( 224 192 96 ) ( 224 192 64 ) eden/edenmetalwall -64 62 -180.00 1 -1 0 0 0 +} +} +// entity 1 +{ +"classname" "func_door" +"angle" "0" +"targetname" "t1" +// brush 0 +{ +( 72 -512 0 ) ( -56 -512 0 ) ( -56 -544 0 ) eden/WL_edendoor2 -64 0 0.00 1 1 0 0 0 +( -56 -544 128 ) ( -56 -512 128 ) ( 72 -512 128 ) eden/WL_edendoor2 -64 0 0.00 1 1 0 0 0 +( -64 -536 256 ) ( 64 -536 256 ) ( 64 -536 0 ) eden/WL_edendoor2 -64 0 0.00 1 1 0 0 0 +( 64 -536 256 ) ( 64 -504 256 ) ( 64 -504 0 ) eden/WL_edendoor2 0 0 0.00 1 1 0 0 0 +( 72 -520 256 ) ( -56 -520 256 ) ( -56 -520 0 ) eden/WL_edendoor2 -64 0 0.00 1 1 0 0 0 +( 0 -528 256 ) ( 0 -560 256 ) ( 0 -560 0 ) eden/WL_edendoor2 0 0 0.00 1 1 0 0 0 +} +} +// entity 2 +{ +"classname" "func_door" +"angle" "180" +"targetname" "t1" +// brush 0 +{ +( 72 -520 0 ) ( -56 -520 0 ) ( -56 -552 0 ) eden/WL_edendoor2 -64 -8 0.00 1 1 0 0 0 +( -56 -552 128 ) ( -56 -520 128 ) ( 72 -520 128 ) eden/WL_edendoor2 -64 -8 0.00 1 1 0 0 0 +( -56 -536 256 ) ( 72 -536 256 ) ( 72 -536 0 ) eden/WL_edendoor2 -64 0 0.00 1 1 0 0 0 +( 0 -544 256 ) ( 0 -512 256 ) ( 0 -512 0 ) eden/WL_edendoor2 8 0 0.00 1 1 0 0 0 +( 64 -520 256 ) ( -64 -520 256 ) ( -64 -520 0 ) eden/WL_edendoor2 -64 0 0.00 1 1 0 0 0 +( -64 -520 256 ) ( -64 -552 256 ) ( -64 -552 0 ) eden/WL_edendoor2 8 0 0.00 1 1 0 0 0 +} +} +// entity 3 +{ +"classname" "trigger_pushobject" +"message" "Got me!" +// brush 0 +{ +( 184 184 0 ) ( 168 184 0 ) ( 168 160 0 ) common/trigger 0 0 0.00 1 1 0 128 0 +( 168 160 192 ) ( 168 184 192 ) ( 184 184 192 ) common/trigger 0 0 0.00 1 1 0 128 0 +( 176 176 8 ) ( 192 176 8 ) ( 192 176 0 ) common/trigger 0 0 0.00 1 1 0 128 0 +( 192 168 8 ) ( 192 192 8 ) ( 192 192 0 ) common/trigger 0 0 0.00 1 1 0 128 0 +( 192 192 8 ) ( 176 192 8 ) ( 176 192 0 ) common/trigger 0 0 0.00 1 1 0 128 0 +( 176 200 8 ) ( 176 176 8 ) ( 176 176 0 ) common/trigger 0 0 0.00 1 1 0 128 0 +} +} +// entity 4 +{ +"classname" "func_pushobject" +// brush 0 +{ +( -176 16 96 ) ( -176 -16 96 ) ( -208 -16 96 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +( -256 -64 0 ) ( -128 -64 0 ) ( -128 64 0 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +( -208 -16 96 ) ( -176 -16 96 ) ( -128 -64 0 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +( -176 -16 96 ) ( -176 16 96 ) ( -128 64 0 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +( -176 16 96 ) ( -208 16 96 ) ( -256 64 0 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +( -208 16 96 ) ( -208 -16 96 ) ( -256 -64 0 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +} +} +// entity 5 +{ +"targetname" "box1" +"classname" "func_pushobject" +// brush 0 +{ +( -72 -128 0 ) ( -256 -128 0 ) ( -256 -272 0 ) otto/ottocrate 0 0 0.00 1 1 0 0 0 +( -256 -272 128 ) ( -256 -128 128 ) ( -72 -128 128 ) otto/ottocrate 0 0 0.00 1 1 0 0 0 +( -312 -256 8 ) ( -128 -256 8 ) ( -128 -256 0 ) otto/ottocrate 0 0 0.00 1 1 0 0 0 +( -128 -256 8 ) ( -128 -112 8 ) ( -128 -112 0 ) otto/ottocrate 0 0 0.00 1 1 0 0 0 +( -72 -128 8 ) ( -256 -128 8 ) ( -256 -128 0 ) otto/ottocrate 0 0 0.00 1 1 0 0 0 +( -256 -128 8 ) ( -256 -272 8 ) ( -256 -272 0 ) otto/ottocrate 0 0 0.00 1 1 0 0 0 +} +} +// entity 6 +{ +"classname" "script_object" +"targetname" "movinlight2" +// brush 0 +{ +( 16 -368 144 ) ( 0 -368 144 ) ( 0 -384 144 ) common/skip 32 16 0.00 1 1 805306368 16512 0 +( 0 -384 160 ) ( 0 -368 160 ) ( 16 -368 160 ) common/skip 32 16 0.00 1 1 805306368 16512 0 +( 0 -384 240 ) ( 16 -384 240 ) ( 16 -384 144 ) common/skip 32 -48 0.00 1 1 805306368 16512 0 +( 16 -384 240 ) ( 16 -368 240 ) ( 16 -368 144 ) common/skip -16 -48 0.00 1 1 805306368 16512 0 +( 16 -368 240 ) ( 0 -368 240 ) ( 0 -368 144 ) common/skip 32 -48 0.00 1 1 805306368 16512 0 +( 0 -368 240 ) ( 0 -384 240 ) ( 0 -384 144 ) common/skip -16 -48 0.00 1 1 805306368 16512 0 +} +} +// entity 7 +{ +"classname" "script_object" +"targetname" "movinlight1" +// brush 0 +{ +( -344 64 144 ) ( -360 64 144 ) ( -360 48 144 ) common/skip 0 0 0.00 1 1 805306368 16512 0 +( -360 48 160 ) ( -360 64 160 ) ( -344 64 160 ) common/skip 0 0 0.00 1 1 805306368 16512 0 +( -360 48 240 ) ( -344 48 240 ) ( -344 48 144 ) common/skip 0 -48 0.00 1 1 805306368 16512 0 +( -344 48 240 ) ( -344 64 240 ) ( -344 64 144 ) common/skip 0 -48 0.00 1 1 805306368 16512 0 +( -344 64 240 ) ( -360 64 240 ) ( -360 64 144 ) common/skip 0 -48 0.00 1 1 805306368 16512 0 +( -360 64 240 ) ( -360 48 240 ) ( -360 48 144 ) common/skip 0 -48 0.00 1 1 805306368 16512 0 +} +} +// entity 8 +{ +"_color" "1.000000 0.724409 0.523622" +"light" "200" +"origin" "-352 56 168" +"spawnflags" "0" +"classname" "light" +} +// entity 9 +{ +"origin" "-432 -464 24" +"angle" "45" +"classname" "info_player_start" +} +// entity 10 +{ +"_color" "0.629921 0.846457 1.000000" +"light" "200" +"classname" "light" +"spawnflags" "0" +"origin" "8 56 168" +} +// entity 11 +{ +"light" "200" +"classname" "light" +"spawnflags" "0" +"origin" "-344 -376 168" +} +// entity 12 +{ +"light" "200" +"origin" "8 -376 168" +"spawnflags" "0" +"classname" "light" +} +// entity 13 +{ +"origin" "-168 -160 168" +"spawnflags" "0" +"classname" "light" +"light" "200" +} +// entity 14 +{ +"triggername" "box1" +"classname" "trigger_pushobject" +"cnt" "-1" +"message" "Got me!" +"target" "t1" +// brush 0 +{ +( 184 -504 0 ) ( 168 -504 0 ) ( 168 -528 0 ) common/trigger 0 -48 0.00 1 1 0 128 0 +( 168 -528 192 ) ( 168 -504 192 ) ( 184 -504 192 ) common/trigger 0 -48 0.00 1 1 0 128 0 +( 176 -512 8 ) ( 192 -512 8 ) ( 192 -512 0 ) common/trigger 0 0 0.00 1 1 0 128 0 +( 192 -520 8 ) ( 192 -496 8 ) ( 192 -496 0 ) common/trigger 48 0 0.00 1 1 0 128 0 +( 192 -496 8 ) ( 176 -496 8 ) ( 176 -496 0 ) common/trigger 0 0 0.00 1 1 0 128 0 +( 176 -488 8 ) ( 176 -512 8 ) ( 176 -512 0 ) common/trigger 48 0 0.00 1 1 0 128 0 +} +} +// entity 15 +{ +"origin" "-312 -648 168" +"spawnflags" "0" +"classname" "light" +"light" "200" +} +// entity 16 +{ +"light" "200" +"classname" "light" +"spawnflags" "0" +"origin" "-8 -648 168" +} diff --git a/fakk/maps/example/pushobject.prt b/fakk/maps/example/pushobject.prt new file mode 100644 index 0000000..1ef1d69 --- /dev/null +++ b/fakk/maps/example/pushobject.prt @@ -0,0 +1,163 @@ +PRT1 +27 +54 +105 +4 0 4 0 (128 0 304 ) (192 0 304 ) (192 0 320 ) (128 0 320 ) +4 0 3 0 (128 192 304 ) (192 192 304 ) (192 0 304 ) (128 0 304 ) +4 0 1 0 (128 192 320 ) (128 192 304 ) (128 128 304 ) (128 128 320 ) +4 1 13 0 (0 192 320 ) (0 192 304 ) (0 128 304 ) (0 128 320 ) +4 1 3 0 (0 192 304 ) (128 192 304 ) (128 128 304 ) (0 128 304 ) +4 2 14 0 (0 0 304 ) (0 0 352 ) (0 96 352 ) (0 96 304 ) +4 2 5 0 (0 0 352 ) (0 0 304 ) (96 0 304 ) (96 0 352 ) +4 2 3 0 (96 0 304 ) (0 0 304 ) (0 96 304 ) (96 96 304 ) +4 3 16 0 (0 0 0 ) (0 0 304 ) (0 192 304 ) (0 192 0 ) +4 3 8 0 (0 0 96 ) (0 0 0 ) (192 0 0 ) (192 0 96 ) +4 3 7 0 (0 0 304 ) (0 0 96 ) (192 0 96 ) (192 0 304 ) +4 4 7 0 (128 0 304 ) (192 0 304 ) (192 -448 304 ) (128 -448 304 ) +4 4 6 0 (128 -448 304 ) (192 -448 304 ) (192 -448 320 ) (128 -448 320 ) +4 5 18 0 (0 0 320 ) (0 0 304 ) (0 -416 304 ) (0 -416 320 ) +4 5 17 0 (0 -416 352 ) (0 0 352 ) (0 0 320 ) (0 -416 320 ) +4 5 7 0 (0 -416 304 ) (0 0 304 ) (96 0 304 ) (96 -416 304 ) +4 6 19 0 (0 -512 304 ) (0 -512 320 ) (0 -448 320 ) (0 -448 304 ) +4 6 7 0 (192 -512 304 ) (0 -512 304 ) (0 -448 304 ) (192 -448 304 ) +4 7 24 0 (0 -512 96 ) (0 -512 128 ) (0 0 128 ) (0 0 96 ) +4 7 22 0 (0 -512 128 ) (0 -512 304 ) (0 0 304 ) (0 0 128 ) +4 7 11 0 (0 -512 128 ) (0 -512 96 ) (64 -512 96 ) (64 -512 128 ) +4 7 10 0 (64 -512 96 ) (0 -512 96 ) (0 -256 96 ) (64 -256 96 ) +4 7 9 0 (192 -512 96 ) (64 -512 96 ) (64 -64 96 ) (192 -64 96 ) +4 7 8 0 (0 -64 96 ) (0 0 96 ) (192 0 96 ) (192 -64 96 ) +4 8 24 0 (0 -64 96 ) (0 0 96 ) (0 0 0 ) (0 -64 0 ) +4 8 9 0 (64 -64 0 ) (192 -64 0 ) (192 -64 96 ) (64 -64 96 ) +4 9 10 0 (64 -256 0 ) (64 -512 0 ) (64 -512 96 ) (64 -256 96 ) +4 10 24 0 (0 -512 0 ) (0 -512 96 ) (0 -256 96 ) (0 -256 0 ) +4 10 11 0 (0 -512 96 ) (0 -512 0 ) (64 -512 0 ) (64 -512 96 ) +4 11 25 0 (0 -512 128 ) (0 -512 0 ) (0 -544 0 ) (0 -544 128 ) +4 11 12 0 (0 -544 128 ) (0 -544 0 ) (64 -544 0 ) (64 -544 128 ) +4 12 25 0 (0 -768 0 ) (0 -768 128 ) (0 -544 128 ) (0 -544 0 ) +4 12 23 0 (0 -768 128 ) (0 -768 304 ) (0 -544 304 ) (0 -544 128 ) +4 12 21 0 (0 -768 304 ) (0 -768 320 ) (0 -544 320 ) (0 -544 304 ) +4 13 16 0 (-64 128 304 ) (-64 192 304 ) (0 192 304 ) (0 128 304 ) +4 13 15 0 (-64 192 320 ) (-64 192 304 ) (-64 128 304 ) (-64 128 320 ) +4 14 18 0 (0 0 304 ) (0 0 320 ) (-32 0 320 ) (-32 0 304 ) +4 14 17 0 (0 0 320 ) (0 0 352 ) (-32 0 352 ) (-32 0 320 ) +4 14 16 0 (0 0 304 ) (-32 0 304 ) (-32 96 304 ) (0 96 304 ) +4 15 20 0 (-480 0 320 ) (-480 0 304 ) (-64 0 304 ) (-64 0 320 ) +4 15 16 0 (-64 0 304 ) (-480 0 304 ) (-480 192 304 ) (-64 192 304 ) +4 16 24 0 (0 0 0 ) (0 0 128 ) (-480 0 128 ) (-480 0 0 ) +4 16 22 0 (0 0 128 ) (0 0 304 ) (-480 0 304 ) (-480 0 128 ) +4 17 18 0 (-32 0 320 ) (0 0 320 ) (0 -416 320 ) (-32 -416 320 ) +4 18 22 0 (-32 0 304 ) (0 0 304 ) (0 -416 304 ) (-32 -416 304 ) +4 19 22 0 (0 -448 304 ) (0 -512 304 ) (-64 -512 304 ) (-64 -448 304 ) +4 19 20 0 (-64 -448 304 ) (-64 -512 304 ) (-64 -512 320 ) (-64 -448 320 ) +4 20 22 0 (-480 -512 304 ) (-480 0 304 ) (-64 0 304 ) (-64 -512 304 ) +4 21 23 0 (0 -768 304 ) (-480 -768 304 ) (-480 -544 304 ) (0 -544 304 ) +4 22 24 0 (-480 -512 128 ) (-480 0 128 ) (0 0 128 ) (0 -512 128 ) +4 23 26 0 (-64 -768 128 ) (-480 -768 128 ) (-480 -544 128 ) (-64 -544 128 ) +4 23 25 0 (0 -768 128 ) (-64 -768 128 ) (-64 -544 128 ) (0 -544 128 ) +4 24 25 0 (-64 -512 0 ) (0 -512 0 ) (0 -512 128 ) (-64 -512 128 ) +4 25 26 0 (-64 -544 0 ) (-64 -768 0 ) (-64 -768 128 ) (-64 -544 128 ) +4 0 (128 96 304 ) (128 0 304 ) (128 0 320 ) (128 96 320 ) +4 0 (128 128 304 ) (128 96 304 ) (128 96 320 ) (128 128 320 ) +4 0 (192 0 320 ) (192 0 304 ) (192 192 304 ) (192 192 320 ) +4 0 (128 192 320 ) (192 192 320 ) (192 192 304 ) (128 192 304 ) +4 0 (192 0 320 ) (192 192 320 ) (128 192 320 ) (128 0 320 ) +4 1 (0 128 304 ) (128 128 304 ) (128 128 320 ) (0 128 320 ) +4 1 (128 192 320 ) (128 192 304 ) (0 192 304 ) (0 192 320 ) +4 1 (128 192 320 ) (0 192 320 ) (0 128 320 ) (128 128 320 ) +4 2 (96 96 352 ) (0 96 352 ) (0 0 352 ) (96 0 352 ) +4 2 (0 96 352 ) (96 96 352 ) (96 96 304 ) (0 96 304 ) +4 2 (96 0 352 ) (96 0 304 ) (96 96 304 ) (96 96 352 ) +4 3 (192 192 304 ) (192 192 0 ) (0 192 0 ) (0 192 304 ) +4 3 (192 0 304 ) (192 0 0 ) (192 192 0 ) (192 192 304 ) +4 3 (0 128 304 ) (0 96 304 ) (128 96 304 ) (128 128 304 ) +4 3 (96 96 304 ) (96 0 304 ) (128 0 304 ) (128 96 304 ) +4 3 (0 192 0 ) (192 192 0 ) (192 0 0 ) (0 0 0 ) +4 4 (128 0 304 ) (128 -448 304 ) (128 -448 320 ) (128 0 320 ) +4 4 (192 -448 320 ) (192 -448 304 ) (192 0 304 ) (192 0 320 ) +4 4 (192 0 320 ) (128 0 320 ) (128 -448 320 ) (192 -448 320 ) +4 5 (96 0 352 ) (96 -416 352 ) (96 -416 304 ) (96 0 304 ) +4 5 (96 -416 352 ) (96 0 352 ) (0 0 352 ) (0 -416 352 ) +4 5 (0 -416 304 ) (96 -416 304 ) (96 -416 352 ) (0 -416 352 ) +4 6 (0 -512 320 ) (0 -512 304 ) (64 -512 304 ) (64 -512 320 ) +4 6 (64 -512 304 ) (192 -512 304 ) (192 -512 320 ) (64 -512 320 ) +4 6 (192 -448 320 ) (192 -512 320 ) (192 -512 304 ) (192 -448 304 ) +4 6 (96 -448 320 ) (128 -448 320 ) (128 -448 304 ) (96 -448 304 ) +4 6 (0 -448 320 ) (96 -448 320 ) (96 -448 304 ) (0 -448 304 ) +4 6 (192 -448 320 ) (0 -448 320 ) (0 -512 320 ) (192 -512 320 ) +4 7 (0 -512 304 ) (0 -512 128 ) (64 -512 128 ) (64 -512 304 ) +4 7 (64 -512 96 ) (192 -512 96 ) (192 -512 304 ) (64 -512 304 ) +4 7 (0 -256 96 ) (0 -64 96 ) (64 -64 96 ) (64 -256 96 ) +4 7 (192 -512 304 ) (192 -512 96 ) (192 0 96 ) (192 0 304 ) +4 7 (96 -448 304 ) (128 -448 304 ) (128 0 304 ) (96 0 304 ) +4 7 (96 -448 304 ) (96 -416 304 ) (0 -416 304 ) (0 -448 304 ) +4 8 (0 -64 0 ) (64 -64 0 ) (64 -64 96 ) (0 -64 96 ) +4 8 (0 -64 0 ) (0 0 0 ) (192 0 0 ) (192 -64 0 ) +4 8 (192 -64 96 ) (192 -64 0 ) (192 0 0 ) (192 0 96 ) +4 9 (64 -512 0 ) (192 -512 0 ) (192 -512 96 ) (64 -512 96 ) +4 9 (64 -64 96 ) (64 -64 0 ) (64 -256 0 ) (64 -256 96 ) +4 9 (192 -64 96 ) (192 -512 96 ) (192 -512 0 ) (192 -64 0 ) +4 9 (192 -512 0 ) (64 -512 0 ) (64 -64 0 ) (192 -64 0 ) +4 10 (64 -512 0 ) (0 -512 0 ) (0 -256 0 ) (64 -256 0 ) +4 10 (0 -256 96 ) (64 -256 96 ) (64 -256 0 ) (0 -256 0 ) +4 11 (64 -512 128 ) (64 -544 128 ) (64 -544 0 ) (64 -512 0 ) +4 11 (0 -512 0 ) (64 -512 0 ) (64 -544 0 ) (0 -544 0 ) +4 11 (0 -544 128 ) (64 -544 128 ) (64 -512 128 ) (0 -512 128 ) +4 12 (0 -768 320 ) (0 -768 0 ) (192 -768 0 ) (192 -768 320 ) +4 12 (192 -544 0 ) (192 -544 320 ) (192 -768 320 ) (192 -768 0 ) +4 12 (192 -544 0 ) (192 -768 0 ) (0 -768 0 ) (0 -544 0 ) +4 12 (64 -544 320 ) (192 -544 320 ) (192 -544 0 ) (64 -544 0 ) +4 12 (64 -544 320 ) (64 -544 128 ) (0 -544 128 ) (0 -544 320 ) +4 12 (0 -768 320 ) (192 -768 320 ) (192 -544 320 ) (0 -544 320 ) +4 13 (-64 128 320 ) (-64 128 304 ) (0 128 304 ) (0 128 320 ) +4 13 (-64 192 304 ) (-64 192 320 ) (0 192 320 ) (0 192 304 ) +4 13 (0 192 320 ) (-64 192 320 ) (-64 128 320 ) (0 128 320 ) +4 14 (0 96 352 ) (-32 96 352 ) (-32 0 352 ) (0 0 352 ) +4 14 (0 96 304 ) (-32 96 304 ) (-32 96 352 ) (0 96 352 ) +4 14 (-32 96 352 ) (-32 96 304 ) (-32 0 304 ) (-32 0 352 ) +4 15 (-480 192 320 ) (-480 192 304 ) (-480 0 304 ) (-480 0 320 ) +4 15 (-64 192 320 ) (-64 192 304 ) (-480 192 304 ) (-480 192 320 ) +4 15 (-64 128 320 ) (-64 96 320 ) (-64 96 304 ) (-64 128 304 ) +4 15 (-64 96 320 ) (-64 0 320 ) (-64 0 304 ) (-64 96 304 ) +4 15 (-64 0 320 ) (-64 192 320 ) (-480 192 320 ) (-480 0 320 ) +4 16 (-480 192 0 ) (-480 192 304 ) (0 192 304 ) (0 192 0 ) +4 16 (-480 192 304 ) (-480 192 0 ) (-480 0 0 ) (-480 0 304 ) +4 16 (0 96 304 ) (0 128 304 ) (-64 128 304 ) (-64 96 304 ) +4 16 (-32 96 304 ) (-64 96 304 ) (-64 0 304 ) (-32 0 304 ) +4 16 (0 0 0 ) (-480 0 0 ) (-480 192 0 ) (0 192 0 ) +4 17 (-32 -416 320 ) (0 -416 320 ) (0 -416 352 ) (-32 -416 352 ) +4 17 (-32 -416 352 ) (0 -416 352 ) (0 0 352 ) (-32 0 352 ) +4 17 (-32 0 320 ) (-32 -416 320 ) (-32 -416 352 ) (-32 0 352 ) +4 18 (-32 -416 304 ) (0 -416 304 ) (0 -416 320 ) (-32 -416 320 ) +4 18 (-32 0 304 ) (-32 -416 304 ) (-32 -416 320 ) (-32 0 320 ) +4 19 (-64 -512 304 ) (0 -512 304 ) (0 -512 320 ) (-64 -512 320 ) +4 19 (-64 -448 320 ) (-64 -512 320 ) (0 -512 320 ) (0 -448 320 ) +4 19 (0 -448 320 ) (0 -448 304 ) (-64 -448 304 ) (-64 -448 320 ) +4 20 (-480 -512 304 ) (-64 -512 304 ) (-64 -512 320 ) (-480 -512 320 ) +4 20 (-64 -416 320 ) (-64 -448 320 ) (-64 -448 304 ) (-64 -416 304 ) +4 20 (-64 0 320 ) (-64 -416 320 ) (-64 -416 304 ) (-64 0 304 ) +4 20 (-64 -416 320 ) (-64 0 320 ) (-480 0 320 ) (-480 -416 320 ) +4 20 (-64 -512 320 ) (-64 -416 320 ) (-480 -416 320 ) (-480 -512 320 ) +4 20 (-480 0 320 ) (-480 0 304 ) (-480 -512 304 ) (-480 -512 320 ) +4 21 (0 -544 320 ) (-480 -544 320 ) (-480 -768 320 ) (0 -768 320 ) +4 21 (0 -768 304 ) (0 -768 320 ) (-480 -768 320 ) (-480 -768 304 ) +4 21 (-480 -544 304 ) (-480 -768 304 ) (-480 -768 320 ) (-480 -544 320 ) +4 21 (-480 -544 320 ) (0 -544 320 ) (0 -544 304 ) (-480 -544 304 ) +4 22 (-64 -416 304 ) (-64 -448 304 ) (0 -448 304 ) (0 -416 304 ) +4 22 (-64 -416 304 ) (-32 -416 304 ) (-32 0 304 ) (-64 0 304 ) +4 22 (-480 0 304 ) (-480 0 128 ) (-480 -512 128 ) (-480 -512 304 ) +4 22 (-480 -512 128 ) (0 -512 128 ) (0 -512 304 ) (-480 -512 304 ) +4 23 (-480 -544 304 ) (0 -544 304 ) (0 -544 128 ) (-480 -544 128 ) +4 23 (0 -768 128 ) (0 -768 304 ) (-480 -768 304 ) (-480 -768 128 ) +4 23 (-480 -544 128 ) (-480 -768 128 ) (-480 -768 304 ) (-480 -544 304 ) +4 24 (-480 -512 0 ) (-64 -512 0 ) (-64 -512 128 ) (-480 -512 128 ) +4 24 (-480 -512 0 ) (-480 0 0 ) (0 0 0 ) (0 -512 0 ) +4 24 (-480 0 128 ) (-480 0 0 ) (-480 -512 0 ) (-480 -512 128 ) +4 24 (0 -256 0 ) (0 -64 0 ) (0 -64 96 ) (0 -256 96 ) +4 25 (-64 -512 128 ) (-64 -512 0 ) (-64 -544 0 ) (-64 -544 128 ) +4 25 (0 -768 0 ) (0 -768 128 ) (-64 -768 128 ) (-64 -768 0 ) +4 25 (-64 -544 128 ) (0 -544 128 ) (0 -512 128 ) (-64 -512 128 ) +4 25 (0 -768 0 ) (-64 -768 0 ) (-64 -512 0 ) (0 -512 0 ) +4 26 (-64 -768 0 ) (-480 -768 0 ) (-480 -544 0 ) (-64 -544 0 ) +4 26 (-480 -544 0 ) (-480 -768 0 ) (-480 -768 128 ) (-480 -544 128 ) +4 26 (-64 -768 128 ) (-480 -768 128 ) (-480 -768 0 ) (-64 -768 0 ) +4 26 (-480 -544 128 ) (-64 -544 128 ) (-64 -544 0 ) (-480 -544 0 ) diff --git a/fakk/maps/example/rain.bsp b/fakk/maps/example/rain.bsp new file mode 100644 index 0000000..67f53f0 Binary files /dev/null and b/fakk/maps/example/rain.bsp differ diff --git a/fakk/maps/example/rain.map b/fakk/maps/example/rain.map new file mode 100644 index 0000000..6dae0c1 --- /dev/null +++ b/fakk/maps/example/rain.map @@ -0,0 +1,114 @@ +{ +"classname" "worldspawn" +// brush 0 +{ +( 320 192 -16 ) ( -192 192 -16 ) ( -192 -320 -16 ) eden/WL_inside_3 0 0 0.00 1 1 0 0 0 +( -192 -320 272 ) ( -192 192 272 ) ( 320 192 272 ) eden/WL_inside_3 0 0 0.00 1 1 0 0 0 +( -192 -336 16 ) ( 320 -336 16 ) ( 320 -336 0 ) eden/WL_inside_3 0 0 0.00 1 1 0 0 0 +( 320 208 16 ) ( -192 208 16 ) ( -192 208 0 ) eden/WL_inside_3 0 0 0.00 1 1 0 0 0 +( -208 192 16 ) ( -208 -320 16 ) ( -208 -320 0 ) eden/WL_inside_3 0 0 0.00 1 1 0 0 0 +( -192 -320 16 ) ( -192 192 16 ) ( -192 -320 0 ) eden/WL_inside_3 0 0 0.00 1 1 0 0 0 +} +// brush 1 +{ +( 320 192 -16 ) ( -192 192 -16 ) ( -192 -320 -16 ) eden/WL_inside_3 0 0 0.00 1 1 0 0 0 +( -192 -320 272 ) ( -192 192 272 ) ( 320 192 272 ) eden/WL_inside_3 0 0 0.00 1 1 0 0 0 +( 336 -320 16 ) ( 336 192 16 ) ( 336 192 0 ) eden/WL_inside_3 0 0 0.00 1 1 0 0 0 +( 320 208 16 ) ( -192 208 16 ) ( -192 208 0 ) eden/WL_inside_3 0 0 0.00 1 1 0 0 0 +( -208 192 16 ) ( -208 -320 16 ) ( -208 -320 0 ) eden/WL_inside_3 0 0 0.00 1 1 0 0 0 +( -192 192 16 ) ( 320 192 16 ) ( -192 192 0 ) eden/WL_inside_3 0 0 0.00 1 1 0 0 0 +} +// brush 2 +{ +( 320 192 -16 ) ( -192 192 -16 ) ( -192 -320 -16 ) eden/WL_inside_3 0 0 0.00 1 1 0 0 0 +( -192 -320 272 ) ( -192 192 272 ) ( 320 192 272 ) eden/WL_inside_3 0 0 0.00 1 1 0 0 0 +( -192 -336 16 ) ( 320 -336 16 ) ( 320 -336 0 ) eden/WL_inside_3 0 0 0.00 1 1 0 0 0 +( 336 -320 16 ) ( 336 192 16 ) ( 336 192 0 ) eden/WL_inside_3 0 0 0.00 1 1 0 0 0 +( 320 208 16 ) ( -192 208 16 ) ( -192 208 0 ) eden/WL_inside_3 0 0 0.00 1 1 0 0 0 +( 320 192 16 ) ( 320 -320 16 ) ( 320 192 0 ) eden/WL_inside_3 0 0 0.00 1 1 0 0 0 +} +// brush 3 +{ +( 320 192 -16 ) ( -192 192 -16 ) ( -192 -320 -16 ) eden/WL_inside_3 0 0 0.00 1 1 0 0 0 +( -192 -320 272 ) ( -192 192 272 ) ( 320 192 272 ) eden/WL_inside_3 0 0 0.00 1 1 0 0 0 +( -192 -336 16 ) ( 320 -336 16 ) ( 320 -336 0 ) eden/WL_inside_3 0 0 0.00 1 1 0 0 0 +( 336 -320 16 ) ( 336 192 16 ) ( 336 192 0 ) eden/WL_inside_3 0 0 0.00 1 1 0 0 0 +( -208 192 16 ) ( -208 -320 16 ) ( -208 -320 0 ) eden/WL_inside_3 0 0 0.00 1 1 0 0 0 +( 320 -320 16 ) ( -192 -320 16 ) ( 320 -320 0 ) eden/WL_inside_3 0 0 0.00 1 1 0 0 0 +} +// brush 4 +{ +( -192 -320 272 ) ( -192 192 272 ) ( 320 192 272 ) eden/WL_market_sides 0 0 0.00 1 1 0 0 0 +( -192 -336 16 ) ( 320 -336 16 ) ( 320 -336 0 ) eden/WL_market_sides 0 0 0.00 1 1 0 0 0 +( 336 -320 16 ) ( 336 192 16 ) ( 336 192 0 ) eden/WL_market_sides 0 0 0.00 1 1 0 0 0 +( 320 208 16 ) ( -192 208 16 ) ( -192 208 0 ) eden/WL_market_sides 0 0 0.00 1 1 0 0 0 +( -208 192 16 ) ( -208 -320 16 ) ( -208 -320 0 ) eden/WL_market_sides 0 0 0.00 1 1 0 0 0 +( -192 192 256 ) ( -192 -320 256 ) ( 320 192 256 ) eden/WL_market_sides 0 0 0.00 1 1 0 0 0 +} +// brush 5 +{ +( 320 192 -16 ) ( -192 192 -16 ) ( -192 -320 -16 ) eden/WL_neweden_2 0 0 0.00 1 1 0 0 0 +( -192 -336 16 ) ( 320 -336 16 ) ( 320 -336 0 ) eden/WL_neweden_2 0 0 0.00 1 1 0 0 0 +( 336 -320 16 ) ( 336 192 16 ) ( 336 192 0 ) eden/WL_neweden_2 0 0 0.00 1 1 0 0 0 +( 320 208 16 ) ( -192 208 16 ) ( -192 208 0 ) eden/WL_neweden_2 0 0 0.00 1 1 0 0 0 +( -208 192 16 ) ( -208 -320 16 ) ( -208 -320 0 ) eden/WL_neweden_2 0 0 0.00 1 1 0 0 0 +( -192 192 0 ) ( 320 192 0 ) ( -192 -320 0 ) eden/WL_neweden_2 0 0 0.00 1 1 0 0 0 +} +} +// entity 1 +{ +"light" "200" +"classname" "light" +"origin" "-56 -136 104" +} +// entity 2 +{ +"classname" "info_player_start" +"angle" "45" +"origin" "-128 -240 0" +} +// entity 3 +{ +"classname" "func_rain" +// brush 0 +{ +( 304 176 224 ) ( -176 176 224 ) ( -176 -304 224 ) common/trigger 0 0 0.00 1 1 0 128 0 +( -176 -304 240 ) ( -176 176 240 ) ( 304 176 240 ) common/trigger 0 0 0.00 1 1 0 128 0 +( -176 -304 240 ) ( 304 -304 240 ) ( 304 -304 224 ) common/trigger 0 0 0.00 1 1 0 128 0 +( 64 -320 240 ) ( 64 160 240 ) ( 64 160 224 ) common/trigger 0 0 0.00 1 1 0 128 0 +( 304 176 240 ) ( -176 176 240 ) ( -176 176 224 ) common/trigger 0 0 0.00 1 1 0 128 0 +( -176 176 240 ) ( -176 -304 240 ) ( -176 -304 224 ) common/trigger 0 0 0.00 1 1 0 128 0 +} +} +// entity 4 +{ +"light" "200" +"origin" "-56 88 104" +"classname" "light" +} +// entity 5 +{ +"light" "200" +"classname" "light" +"origin" "200 72 104" +} +// entity 6 +{ +"light" "200" +"origin" "216 -184 104" +"classname" "light" +} +// entity 7 +{ +"emitter" "defaultleaf" +"classname" "func_emitter" +// brush 0 +{ +( 544 176 224 ) ( 64 176 224 ) ( 64 -304 224 ) common/trigger -48 0 0.00 1 1 0 128 0 +( 64 -304 240 ) ( 64 176 240 ) ( 544 176 240 ) common/trigger -48 0 0.00 1 1 0 128 0 +( 64 -304 240 ) ( 544 -304 240 ) ( 544 -304 224 ) common/trigger -48 0 0.00 1 1 0 128 0 +( 304 -320 240 ) ( 304 160 240 ) ( 304 160 224 ) common/trigger 0 0 0.00 1 1 0 128 0 +( 544 176 240 ) ( 64 176 240 ) ( 64 176 224 ) common/trigger -48 0 0.00 1 1 0 128 0 +( 64 176 240 ) ( 64 -304 240 ) ( 64 -304 224 ) common/trigger 0 0 0.00 1 1 0 128 0 +} +} diff --git a/fakk/maps/example/rain.prt b/fakk/maps/example/rain.prt new file mode 100644 index 0000000..dd2ecc7 --- /dev/null +++ b/fakk/maps/example/rain.prt @@ -0,0 +1,24 @@ +PRT1 +4 +4 +16 +4 0 2 0 (0 0 0 ) (0 0 256 ) (0 192 256 ) (0 192 0 ) +4 0 1 0 (0 0 256 ) (0 0 0 ) (320 0 0 ) (320 0 256 ) +4 1 3 0 (0 0 256 ) (0 0 0 ) (0 -320 0 ) (0 -320 256 ) +4 2 3 0 (0 0 0 ) (0 0 256 ) (-192 0 256 ) (-192 0 0 ) +4 0 (320 0 256 ) (320 0 0 ) (320 192 0 ) (320 192 256 ) +4 0 (320 192 256 ) (320 192 0 ) (0 192 0 ) (0 192 256 ) +4 0 (320 0 0 ) (0 0 0 ) (0 192 0 ) (320 192 0 ) +4 0 (0 0 256 ) (320 0 256 ) (320 192 256 ) (0 192 256 ) +4 1 (0 -320 256 ) (0 -320 0 ) (320 -320 0 ) (320 -320 256 ) +4 1 (320 -320 256 ) (320 -320 0 ) (320 0 0 ) (320 0 256 ) +4 1 (0 -320 0 ) (0 0 0 ) (320 0 0 ) (320 -320 0 ) +4 1 (320 0 256 ) (0 0 256 ) (0 -320 256 ) (320 -320 256 ) +4 2 (0 192 256 ) (0 192 0 ) (-192 192 0 ) (-192 192 256 ) +4 2 (-192 0 0 ) (-192 0 256 ) (-192 192 256 ) (-192 192 0 ) +4 2 (0 0 0 ) (-192 0 0 ) (-192 192 0 ) (0 192 0 ) +4 2 (0 192 256 ) (-192 192 256 ) (-192 0 256 ) (0 0 256 ) +4 3 (-192 -320 256 ) (-192 -320 0 ) (0 -320 0 ) (0 -320 256 ) +4 3 (-192 0 256 ) (-192 0 0 ) (-192 -320 0 ) (-192 -320 256 ) +4 3 (-192 -320 0 ) (-192 0 0 ) (0 0 0 ) (0 -320 0 ) +4 3 (0 0 256 ) (-192 0 256 ) (-192 -320 256 ) (0 -320 256 ) diff --git a/fakk/maps/example/rain.pth b/fakk/maps/example/rain.pth new file mode 100644 index 0000000..d95140e Binary files /dev/null and b/fakk/maps/example/rain.pth differ diff --git a/fakk/maps/example/runthrough.bsp b/fakk/maps/example/runthrough.bsp new file mode 100644 index 0000000..07afbb2 Binary files /dev/null and b/fakk/maps/example/runthrough.bsp differ diff --git a/fakk/maps/example/runthrough.map b/fakk/maps/example/runthrough.map new file mode 100644 index 0000000..b25e89b --- /dev/null +++ b/fakk/maps/example/runthrough.map @@ -0,0 +1,293 @@ +{ +"classname" "worldspawn" +// brush 0 +{ +( 24 -48 0 ) ( -288 -48 0 ) ( -288 -240 0 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( -288 -240 8 ) ( -288 -48 8 ) ( 24 -48 8 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( -304 -320 8 ) ( 8 -320 8 ) ( 8 -320 0 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( 72 -240 8 ) ( 72 -48 8 ) ( 72 -48 0 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( 24 40 8 ) ( -288 40 8 ) ( -288 40 0 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( -328 -88 8 ) ( -328 -280 8 ) ( -328 -280 0 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +} +// brush 1 +{ +( 224 192 0 ) ( 224 224 0 ) ( -480 224 0 ) eden/bedtrim -224 -32 90.00 1 1 0 0 0 +( -480 224 64 ) ( 224 224 64 ) ( 224 192 64 ) eden/bedtrim -224 -32 90.00 1 1 0 0 0 +( -480 224 256 ) ( -480 192 256 ) ( -480 192 0 ) eden/bedtrim -224 0 0.00 1 1 0 0 0 +( -480 192 256 ) ( 224 192 256 ) ( 224 192 0 ) common/skip 0 0 0.00 1 1 805306368 16512 0 +( 224 224 256 ) ( -480 224 256 ) ( -480 224 0 ) eden/bedtrim 224 0 -180.00 1 -1 0 0 0 +( -416 224 0 ) ( -416 192 0 ) ( -416 208 64 ) eden/bedtrim 224 0 -180.00 1 -1 0 0 0 +} +// brush 2 +{ +( 224 192 0 ) ( 224 224 0 ) ( -480 224 0 ) eden/bedtrim -224 -32 90.00 1 1 0 0 0 +( -480 224 64 ) ( 224 224 64 ) ( 224 192 64 ) eden/bedtrim -224 -32 90.00 1 1 0 0 0 +( -480 192 256 ) ( 224 192 256 ) ( 224 192 0 ) eden/bedtrim 224 0 -180.00 1 -1 0 0 0 +( 224 192 256 ) ( 224 224 256 ) ( 224 224 0 ) eden/bedtrim -224 0 0.00 1 1 0 0 0 +( 224 224 256 ) ( -480 224 256 ) ( -480 224 0 ) eden/bedtrim 224 0 -180.00 1 -1 0 0 0 +( -480 192 0 ) ( -480 224 0 ) ( -480 208 64 ) eden/bedtrim 224 0 -180.00 1 -1 0 0 0 +} +// brush 3 +{ +( 224 192 64 ) ( 224 224 64 ) ( -480 224 64 ) eden/edenmetalwall -224 -224 90.00 1 1 0 0 0 +( -480 224 320 ) ( 224 224 320 ) ( 224 192 320 ) eden/edenmetalwall -224 -224 90.00 1 1 0 0 0 +( -480 224 96 ) ( -480 192 96 ) ( -480 192 64 ) eden/edenmetalwall -224 64 0.00 1 1 0 0 0 +( -480 192 96 ) ( 224 192 96 ) ( 224 192 64 ) common/skip 0 0 0.00 1 1 805306368 16512 0 +( 224 224 96 ) ( -480 224 96 ) ( -480 224 64 ) eden/edenmetalwall 224 63 -180.00 1 -1 0 0 0 +( -416 224 64 ) ( -416 192 64 ) ( -416 208 320 ) eden/edenmetalwall 224 63 -180.00 1 -1 0 0 0 +} +// brush 4 +{ +( 224 192 64 ) ( 224 224 64 ) ( -480 224 64 ) eden/edenmetalwall -224 -224 90.00 1 1 0 0 0 +( -480 224 320 ) ( 224 224 320 ) ( 224 192 320 ) eden/edenmetalwall -224 -224 90.00 1 1 0 0 0 +( -480 192 96 ) ( 224 192 96 ) ( 224 192 64 ) eden/edenmetalwall 224 63 -180.00 1 -1 0 0 0 +( 224 192 96 ) ( 224 224 96 ) ( 224 224 64 ) eden/edenmetalwall -224 64 0.00 1 1 0 0 0 +( 224 224 96 ) ( -480 224 96 ) ( -480 224 64 ) eden/edenmetalwall 224 63 -180.00 1 -1 0 0 0 +( -480 192 64 ) ( -480 224 64 ) ( -480 208 320 ) eden/edenmetalwall 224 63 -180.00 1 -1 0 0 0 +} +// brush 5 + { + patchDef2 + { + eden/edenmetalwall + ( 3 3 0 536870912 0 ) +( +( ( -480 96 63.999992 0 0 ) ( -480 96 192 0 0.500000 ) ( -480 96 320 0 1 ) ) +( ( -384 96 63.999992 0.500000 0 ) ( -384 96 192 0.500000 0.500000 ) ( -384 96 320 0.500000 1 ) ) +( ( -384 192 63.999992 1 0 ) ( -384 192 192 1 0.500000 ) ( -384 192 320 1 1 ) ) +) + } + } +// brush 6 +{ +( -480 192 0 ) ( -512 192 0 ) ( -512 -512 0 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +( -512 -512 64 ) ( -512 192 64 ) ( -480 192 64 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +( -480 -512 256 ) ( -480 192 256 ) ( -480 192 0 ) common/skip 0 0 0.00 1 1 805306368 16512 0 +( -480 192 256 ) ( -512 192 256 ) ( -512 192 0 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +( -512 192 256 ) ( -512 -512 256 ) ( -512 -512 0 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +( -480 128 0 ) ( -512 128 0 ) ( -496 128 64 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +} +// brush 7 +{ +( -480 192 0 ) ( -512 192 0 ) ( -512 -512 0 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +( -512 -512 64 ) ( -512 192 64 ) ( -480 192 64 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +( -512 -512 256 ) ( -480 -512 256 ) ( -480 -512 0 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +( -480 -512 256 ) ( -480 192 256 ) ( -480 192 0 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +( -512 192 256 ) ( -512 -512 256 ) ( -512 -512 0 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +( -512 192 0 ) ( -480 192 0 ) ( -496 192 64 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +} +// brush 8 +{ +( -480 192 64 ) ( -512 192 64 ) ( -512 -512 64 ) eden/edenmetalwall 0 0 0.00 1 1 0 0 0 +( -512 -512 320 ) ( -512 192 320 ) ( -480 192 320 ) eden/edenmetalwall 0 0 0.00 1 1 0 0 0 +( -480 -512 96 ) ( -480 192 96 ) ( -480 192 64 ) common/skip 0 0 0.00 1 1 805306368 16512 0 +( -480 192 96 ) ( -512 192 96 ) ( -512 192 64 ) eden/edenmetalwall 0 64 0.00 1 1 0 0 0 +( -512 192 96 ) ( -512 -512 96 ) ( -512 -512 64 ) eden/edenmetalwall 0 64 0.00 1 1 0 0 0 +( -480 128 64 ) ( -512 128 64 ) ( -496 128 320 ) eden/edenmetalwall 0 64 0.00 1 1 0 0 0 +} +// brush 9 +{ +( -480 192 64 ) ( -512 192 64 ) ( -512 -512 64 ) eden/edenmetalwall 0 0 0.00 1 1 0 0 0 +( -512 -512 320 ) ( -512 192 320 ) ( -480 192 320 ) eden/edenmetalwall 0 0 0.00 1 1 0 0 0 +( -512 -512 96 ) ( -480 -512 96 ) ( -480 -512 64 ) eden/edenmetalwall 0 64 0.00 1 1 0 0 0 +( -480 -512 96 ) ( -480 192 96 ) ( -480 192 64 ) eden/edenmetalwall 0 64 0.00 1 1 0 0 0 +( -512 192 96 ) ( -512 -512 96 ) ( -512 -512 64 ) eden/edenmetalwall 0 64 0.00 1 1 0 0 0 +( -512 192 64 ) ( -480 192 64 ) ( -496 192 320 ) eden/edenmetalwall 0 64 0.00 1 1 0 0 0 +} +// brush 10 + { + patchDef2 + { + eden/bedtrim + ( 3 3 0 536870912 0 ) +( +( ( -480 96 0 0 0 ) ( -480 96 32 0 0.500000 ) ( -480 96 64 0 1 ) ) +( ( -384 96 0 0.500000 0 ) ( -384 96 32 0.500000 0.500000 ) ( -384 96 64 0.500000 1 ) ) +( ( -384 192 0 1 0 ) ( -384 192 32 1 0.500000 ) ( -384 192 64 1 1 ) ) +) + } + } +// brush 11 +{ +( 96 96 352 ) ( -32 96 352 ) ( -32 -416 352 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( -32 -416 416 ) ( -32 96 416 ) ( 96 96 416 ) we_cemetary_test/levelord_sky 0 0 0.00 1 1 0 0 0 +( -32 -416 416 ) ( 96 -416 416 ) ( 96 -416 352 ) we_cemetary_test/levelord_sky 0 0 0.00 1 1 0 0 0 +( 96 -416 416 ) ( 96 96 416 ) ( 96 96 352 ) we_cemetary_test/levelord_sky 0 0 0.00 1 1 0 0 0 +( 96 96 416 ) ( -32 96 416 ) ( -32 96 352 ) we_cemetary_test/levelord_sky 0 0 0.00 1 1 0 0 0 +( -32 96 416 ) ( -32 -416 416 ) ( -32 -416 352 ) we_cemetary_test/levelord_sky 0 0 0.00 1 1 0 0 0 +} +// brush 12 +{ +( -64 -416 304 ) ( -64 -448 304 ) ( 128 -448 304 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( 128 -448 352 ) ( -64 -448 352 ) ( -64 -416 352 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( 96 -416 352 ) ( -32 -416 352 ) ( -32 -416 320 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( 128 -448 352 ) ( 96 -416 352 ) ( 96 -416 320 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( -64 -448 320 ) ( -64 -448 352 ) ( 128 -448 352 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( -64 -448 320 ) ( -32 -416 320 ) ( -32 -416 352 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +} +// brush 13 +{ +( -32 128 304 ) ( -64 128 304 ) ( -64 -64 304 ) eden/FL_edenhouse 0 32 90.00 1 1 0 0 0 +( -64 -64 352 ) ( -64 128 352 ) ( -32 128 352 ) eden/FL_edenhouse 0 32 90.00 1 1 0 0 0 +( -32 -32 352 ) ( -32 96 352 ) ( -32 96 320 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( -64 -448 352 ) ( -32 -416 352 ) ( -32 -416 320 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( -64 128 320 ) ( -64 128 352 ) ( -64 -64 352 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( -64 128 320 ) ( -32 96 320 ) ( -32 96 352 ) eden/FL_edenhouse -64 0 -180.00 1 -1 0 0 0 +} +// brush 14 +{ +( 128 -64 304 ) ( 128 128 304 ) ( 96 128 304 ) eden/FL_edenhouse 0 -96 90.00 1 1 0 0 0 +( 96 128 352 ) ( 128 128 352 ) ( 128 -64 352 ) eden/FL_edenhouse 0 -96 90.00 1 1 0 0 0 +( 96 96 320 ) ( 96 96 352 ) ( 96 -32 352 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( 96 -416 320 ) ( 96 -416 352 ) ( 128 -448 352 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( 128 -64 352 ) ( 128 128 352 ) ( 128 128 320 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( 96 96 352 ) ( 96 96 320 ) ( 128 128 320 ) eden/FL_edenhouse -64 0 -180.00 1 -1 0 0 0 +} +// brush 15 +{ +( 128 128 304 ) ( -64 128 304 ) ( -64 96 304 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( -64 96 352 ) ( -64 128 352 ) ( 128 128 352 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( -32 96 320 ) ( -32 96 352 ) ( 96 96 352 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( 96 96 320 ) ( 96 96 352 ) ( 128 128 352 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( 128 128 352 ) ( -64 128 352 ) ( -64 128 320 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( -32 96 352 ) ( -32 96 320 ) ( -64 128 320 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +} +// brush 16 +{ +( 128 192 320 ) ( -64 192 320 ) ( -64 128 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( -64 128 352 ) ( -64 192 352 ) ( 128 192 352 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( -64 128 352 ) ( 128 128 352 ) ( 128 128 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( 128 128 352 ) ( 128 192 352 ) ( 128 192 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( 128 192 352 ) ( -64 192 352 ) ( -64 192 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( -64 192 352 ) ( -64 128 352 ) ( -64 128 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +} +// brush 17 +{ +( 192 192 320 ) ( 128 192 320 ) ( 128 -448 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( 128 -448 352 ) ( 128 192 352 ) ( 192 192 352 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( 128 -448 352 ) ( 192 -448 352 ) ( 192 -448 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( 192 -448 352 ) ( 192 192 352 ) ( 192 192 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( 192 192 352 ) ( 128 192 352 ) ( 128 192 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( 128 192 352 ) ( 128 -448 352 ) ( 128 -448 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +} +// brush 18 +{ +( 192 192 320 ) ( -480 192 320 ) ( -480 -512 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( -480 -512 352 ) ( -480 192 352 ) ( 192 192 352 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( -480 -512 352 ) ( 192 -512 352 ) ( 192 -512 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( 192 -512 352 ) ( 192 192 352 ) ( 192 192 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( 224 -448 352 ) ( -448 -448 352 ) ( -448 -448 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( -64 -256 320 ) ( -64 -128 320 ) ( -64 -192 352 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +} +// brush 19 +{ +( 192 192 320 ) ( -480 192 320 ) ( -480 -512 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( -480 -512 352 ) ( -480 192 352 ) ( 192 192 352 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( -480 -512 352 ) ( 192 -512 352 ) ( 192 -512 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( 192 192 352 ) ( -480 192 352 ) ( -480 192 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( -480 192 352 ) ( -480 -512 352 ) ( -480 -512 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( -64 -128 320 ) ( -64 -256 320 ) ( -64 -192 352 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +} +// brush 20 +{ +( 192 192 -32 ) ( -480 192 -32 ) ( -480 -512 -32 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( -480 -512 0 ) ( -480 192 0 ) ( 192 192 0 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( -480 -512 224 ) ( 192 -512 224 ) ( 192 -512 -32 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 192 -512 224 ) ( 192 192 224 ) ( 192 192 -32 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 192 192 224 ) ( -480 192 224 ) ( -480 192 -32 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( -480 192 224 ) ( -480 -512 224 ) ( -480 -512 -32 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +} +// brush 21 +{ +( -480 -512 64 ) ( -480 -544 64 ) ( 224 -544 64 ) eden/edenmetalwall -31 31 -90.00 1 1 0 0 0 +( 224 -544 320 ) ( -480 -544 320 ) ( -480 -512 320 ) eden/edenmetalwall -31 31 -90.00 1 1 0 0 0 +( 224 -544 96 ) ( 224 -512 96 ) ( 224 -512 64 ) eden/edenmetalwall -32 63 -180.00 1 -1 0 0 0 +( 224 -512 96 ) ( -480 -512 96 ) ( -480 -512 64 ) eden/edenmetalwall -32 62 0.00 1.000008 1 0 0 0 +( -480 -512 96 ) ( -480 -544 96 ) ( -480 -544 64 ) eden/edenmetalwall -33 63 -180.00 1 -1 0 0 0 +( -480 -544 96 ) ( 224 -544 96 ) ( 224 -544 64 ) eden/edenmetalwall -32 62 0.00 1.000008 1 0 0 0 +} +// brush 22 +{ +( -480 -512 0 ) ( -480 -544 0 ) ( 224 -544 0 ) eden/bedtrim -31 32 -90.00 1 1 0 0 0 +( 224 -544 64 ) ( -480 -544 64 ) ( -480 -512 64 ) eden/bedtrim -31 32 -90.00 1 1 0 0 0 +( 224 -544 256 ) ( 224 -512 256 ) ( 224 -512 0 ) eden/bedtrim -32 0 -180.00 1 -1 0 0 0 +( 224 -512 256 ) ( -480 -512 256 ) ( -480 -512 0 ) eden/bedtrim -32 0 0.00 1 1 0 0 0 +( -480 -512 256 ) ( -480 -544 256 ) ( -480 -544 0 ) eden/bedtrim -33 0 -180.00 1 -1 0 0 0 +( -480 -544 256 ) ( 224 -544 256 ) ( 224 -544 0 ) eden/bedtrim -32 0 0.00 1 1 0 0 0 +} +// brush 23 +{ +( 192 -512 0 ) ( 224 -512 0 ) ( 224 192 0 ) eden/bedtrim 160 0 -180.00 1 1 0 0 0 +( 224 192 64 ) ( 224 -512 64 ) ( 192 -512 64 ) eden/bedtrim 160 0 -180.00 1 1 0 0 0 +( 224 192 256 ) ( 192 192 256 ) ( 192 192 0 ) eden/bedtrim 160 0 -180.00 1 -1 0 0 0 +( 192 192 256 ) ( 192 -512 256 ) ( 192 -512 0 ) eden/bedtrim -64 0 -180.00 1 -1 0 0 0 +( 192 -512 256 ) ( 224 -512 256 ) ( 224 -512 0 ) eden/bedtrim 159 0 -180.00 1 -1 0 0 0 +( 224 -512 256 ) ( 224 192 256 ) ( 224 192 0 ) eden/bedtrim -64 0 -180.00 1 -1 0 0 0 +} +// brush 24 +{ +( 192 -512 64 ) ( 224 -512 64 ) ( 224 192 64 ) eden/edenmetalwall 160 63 -180.00 1 1 0 0 0 +( 224 192 320 ) ( 224 -512 320 ) ( 192 -512 320 ) eden/edenmetalwall 160 63 -180.00 1 1 0 0 0 +( 224 192 96 ) ( 192 192 96 ) ( 192 192 64 ) eden/edenmetalwall 160 64 -180.00 1 -1 0 0 0 +( 192 192 96 ) ( 192 -512 96 ) ( 192 -512 64 ) eden/edenmetalwall -64 62 -180.00 1 -1 0 0 0 +( 192 -512 96 ) ( 224 -512 96 ) ( 224 -512 64 ) eden/edenmetalwall 159 64 -180.00 1 -1 0 0 0 +( 224 -512 96 ) ( 224 192 96 ) ( 224 192 64 ) eden/edenmetalwall -64 62 -180.00 1 -1 0 0 0 +} +} +// entity 1 +{ +"classname" "func_runthrough" +"spawnmodel" "fx_plantseeds.tik" +// brush 0 +{ +( 72 40 8 ) ( -328 40 8 ) ( -328 -320 8 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( -328 -320 40 ) ( -328 40 40 ) ( 72 40 40 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( -328 -320 16 ) ( 72 -320 16 ) ( 72 -320 8 ) eden/FL_edenhouse 0 8 0.00 1 1 0 0 0 +( 72 -320 16 ) ( 72 40 16 ) ( 72 40 8 ) eden/FL_edenhouse 0 8 0.00 1 1 0 0 0 +( 72 40 16 ) ( -328 40 16 ) ( -328 40 8 ) eden/FL_edenhouse 0 8 0.00 1 1 0 0 0 +( -328 40 16 ) ( -328 -320 16 ) ( -328 -320 8 ) eden/FL_edenhouse 0 8 0.00 1 1 0 0 0 +} +} +// entity 2 +{ +"classname" "light" +"spawnflags" "0" +"origin" "-352 56 168" +"light" "200" +"_color" "1.000000 0.724409 0.523622" +} +// entity 3 +{ +"classname" "info_player_start" +"angle" "45" +"origin" "-432 -464 24" +} +// entity 4 +{ +"origin" "8 56 168" +"spawnflags" "0" +"classname" "light" +"light" "200" +"_color" "0.629921 0.846457 1.000000" +} +// entity 5 +{ +"origin" "-344 -376 168" +"spawnflags" "0" +"classname" "light" +"light" "200" +} +// entity 6 +{ +"classname" "light" +"spawnflags" "0" +"origin" "8 -376 168" +"light" "200" +} +// entity 7 +{ +"light" "200" +"classname" "light" +"spawnflags" "0" +"origin" "-168 -160 168" +} diff --git a/fakk/maps/example/runthrough.prt b/fakk/maps/example/runthrough.prt new file mode 100644 index 0000000..573a4c6 --- /dev/null +++ b/fakk/maps/example/runthrough.prt @@ -0,0 +1,140 @@ +PRT1 +24 +44 +92 +4 0 6 0 (128 0 304 ) (192 0 304 ) (192 0 320 ) (128 0 320 ) +4 0 3 0 (128 192 304 ) (192 192 304 ) (192 0 304 ) (128 0 304 ) +4 0 1 0 (128 192 320 ) (128 192 304 ) (128 128 304 ) (128 128 320 ) +4 1 12 0 (0 192 320 ) (0 192 304 ) (0 128 304 ) (0 128 320 ) +4 1 3 0 (0 192 304 ) (128 192 304 ) (128 128 304 ) (0 128 304 ) +4 2 13 0 (0 0 304 ) (0 0 352 ) (0 96 352 ) (0 96 304 ) +4 2 7 0 (0 0 352 ) (0 0 304 ) (96 0 304 ) (96 0 352 ) +4 2 3 0 (96 0 304 ) (0 0 304 ) (0 96 304 ) (96 96 304 ) +4 3 15 0 (0 0 8 ) (0 0 304 ) (0 192 304 ) (0 192 8 ) +4 3 9 0 (0 0 304 ) (0 0 8 ) (192 0 8 ) (192 0 304 ) +4 3 5 0 (0 192 8 ) (72 192 8 ) (72 40 8 ) (0 40 8 ) +4 3 4 0 (72 192 8 ) (192 192 8 ) (192 0 8 ) (72 0 8 ) +4 4 10 0 (72 0 0 ) (192 0 0 ) (192 0 8 ) (72 0 8 ) +4 4 5 0 (72 192 0 ) (72 40 0 ) (72 40 8 ) (72 192 8 ) +4 5 16 0 (0 40 8 ) (0 192 8 ) (0 192 0 ) (0 40 0 ) +4 6 9 0 (128 0 304 ) (192 0 304 ) (192 -448 304 ) (128 -448 304 ) +4 6 8 0 (128 -448 304 ) (192 -448 304 ) (192 -448 320 ) (128 -448 320 ) +4 7 18 0 (0 0 352 ) (0 0 304 ) (0 -416 304 ) (0 -416 352 ) +4 7 9 0 (0 0 304 ) (96 0 304 ) (96 -416 304 ) (0 -416 304 ) +4 8 19 0 (0 -512 304 ) (0 -512 320 ) (0 -448 320 ) (0 -448 304 ) +4 8 9 0 (192 -448 304 ) (192 -512 304 ) (0 -512 304 ) (0 -448 304 ) +4 9 21 0 (0 -512 8 ) (0 -512 304 ) (0 0 304 ) (0 0 8 ) +4 9 11 0 (72 -320 8 ) (72 -512 8 ) (0 -512 8 ) (0 -320 8 ) +4 9 10 0 (72 0 8 ) (192 0 8 ) (192 -512 8 ) (72 -512 8 ) +4 10 11 0 (72 -320 0 ) (72 -512 0 ) (72 -512 8 ) (72 -320 8 ) +4 11 22 0 (0 -512 0 ) (0 -512 8 ) (0 -320 8 ) (0 -320 0 ) +4 12 15 0 (-64 128 304 ) (-64 192 304 ) (0 192 304 ) (0 128 304 ) +4 12 14 0 (-64 192 320 ) (-64 192 304 ) (-64 128 304 ) (-64 128 320 ) +4 13 18 0 (0 0 304 ) (0 0 352 ) (-32 0 352 ) (-32 0 304 ) +4 13 15 0 (0 0 304 ) (-32 0 304 ) (-32 96 304 ) (0 96 304 ) +4 14 20 0 (-480 0 320 ) (-480 0 304 ) (-64 0 304 ) (-64 0 320 ) +4 14 15 0 (-64 0 304 ) (-480 0 304 ) (-480 192 304 ) (-64 192 304 ) +4 15 21 0 (0 0 8 ) (0 0 304 ) (-480 0 304 ) (-480 0 8 ) +4 15 16 0 (-328 40 8 ) (-328 192 8 ) (0 192 8 ) (0 40 8 ) +4 15 17 0 (-328 0 8 ) (-480 0 8 ) (-480 192 8 ) (-328 192 8 ) +4 16 17 0 (-328 192 0 ) (-328 40 0 ) (-328 40 8 ) (-328 192 8 ) +4 17 23 0 (-328 0 8 ) (-480 0 8 ) (-480 0 0 ) (-328 0 0 ) +4 18 21 0 (-32 0 304 ) (0 0 304 ) (0 -416 304 ) (-32 -416 304 ) +4 19 21 0 (0 -512 304 ) (-64 -512 304 ) (-64 -448 304 ) (0 -448 304 ) +4 19 20 0 (-64 -448 304 ) (-64 -512 304 ) (-64 -512 320 ) (-64 -448 320 ) +4 20 21 0 (-64 -512 304 ) (-480 -512 304 ) (-480 0 304 ) (-64 0 304 ) +4 21 22 0 (0 -512 8 ) (-328 -512 8 ) (-328 -320 8 ) (0 -320 8 ) +4 21 23 0 (-328 -512 8 ) (-480 -512 8 ) (-480 0 8 ) (-328 0 8 ) +4 22 23 0 (-328 -320 0 ) (-328 -512 0 ) (-328 -512 8 ) (-328 -320 8 ) +4 0 (128 96 304 ) (128 0 304 ) (128 0 320 ) (128 96 320 ) +4 0 (128 128 304 ) (128 96 304 ) (128 96 320 ) (128 128 320 ) +4 0 (192 0 320 ) (192 0 304 ) (192 192 304 ) (192 192 320 ) +4 0 (128 192 320 ) (192 192 320 ) (192 192 304 ) (128 192 304 ) +4 0 (192 0 320 ) (192 192 320 ) (128 192 320 ) (128 0 320 ) +4 1 (0 128 304 ) (128 128 304 ) (128 128 320 ) (0 128 320 ) +4 1 (128 192 320 ) (128 192 304 ) (0 192 304 ) (0 192 320 ) +4 1 (128 192 320 ) (0 192 320 ) (0 128 320 ) (128 128 320 ) +4 2 (96 96 352 ) (0 96 352 ) (0 0 352 ) (96 0 352 ) +4 2 (0 96 352 ) (96 96 352 ) (96 96 304 ) (0 96 304 ) +4 2 (96 0 352 ) (96 0 304 ) (96 96 304 ) (96 96 352 ) +4 3 (72 40 8 ) (72 0 8 ) (0 0 8 ) (0 40 8 ) +4 3 (96 96 304 ) (96 0 304 ) (128 0 304 ) (128 96 304 ) +4 3 (0 128 304 ) (0 96 304 ) (128 96 304 ) (128 128 304 ) +4 3 (192 0 304 ) (192 0 8 ) (192 192 8 ) (192 192 304 ) +4 3 (192 192 304 ) (192 192 8 ) (0 192 8 ) (0 192 304 ) +4 4 (72 40 0 ) (72 0 0 ) (72 0 8 ) (72 40 8 ) +4 4 (72 192 8 ) (192 192 8 ) (192 192 0 ) (72 192 0 ) +4 4 (192 0 8 ) (192 0 0 ) (192 192 0 ) (192 192 8 ) +4 4 (72 192 0 ) (192 192 0 ) (192 0 0 ) (72 0 0 ) +4 5 (0 192 0 ) (72 192 0 ) (72 40 0 ) (0 40 0 ) +4 5 (72 192 8 ) (72 192 0 ) (0 192 0 ) (0 192 8 ) +4 5 (0 40 0 ) (72 40 0 ) (72 40 8 ) (0 40 8 ) +4 6 (128 0 304 ) (128 -448 304 ) (128 -448 320 ) (128 0 320 ) +4 6 (192 -448 320 ) (192 -448 304 ) (192 0 304 ) (192 0 320 ) +4 6 (192 0 320 ) (128 0 320 ) (128 -448 320 ) (192 -448 320 ) +4 7 (96 -416 352 ) (96 0 352 ) (0 0 352 ) (0 -416 352 ) +4 7 (96 0 352 ) (96 -416 352 ) (96 -416 304 ) (96 0 304 ) +4 7 (0 -416 304 ) (96 -416 304 ) (96 -416 352 ) (0 -416 352 ) +4 8 (192 -448 320 ) (192 -512 320 ) (192 -512 304 ) (192 -448 304 ) +4 8 (0 -512 320 ) (0 -512 304 ) (192 -512 304 ) (192 -512 320 ) +4 8 (96 -448 320 ) (128 -448 320 ) (128 -448 304 ) (96 -448 304 ) +4 8 (96 -448 320 ) (96 -448 304 ) (0 -448 304 ) (0 -448 320 ) +4 8 (0 -512 320 ) (192 -512 320 ) (192 -448 320 ) (0 -448 320 ) +4 9 (0 0 8 ) (72 0 8 ) (72 -320 8 ) (0 -320 8 ) +4 9 (0 -416 304 ) (0 -448 304 ) (96 -448 304 ) (96 -416 304 ) +4 9 (96 -448 304 ) (128 -448 304 ) (128 0 304 ) (96 0 304 ) +4 9 (192 -512 304 ) (192 -512 8 ) (192 0 8 ) (192 0 304 ) +4 9 (0 -512 304 ) (0 -512 8 ) (192 -512 8 ) (192 -512 304 ) +4 10 (72 0 0 ) (72 -320 0 ) (72 -320 8 ) (72 0 8 ) +4 10 (72 -512 0 ) (192 -512 0 ) (192 -512 8 ) (72 -512 8 ) +4 10 (192 -512 8 ) (192 -512 0 ) (192 0 0 ) (192 0 8 ) +4 10 (72 0 0 ) (192 0 0 ) (192 -512 0 ) (72 -512 0 ) +4 11 (72 -320 0 ) (72 -512 0 ) (0 -512 0 ) (0 -320 0 ) +4 11 (0 -512 8 ) (0 -512 0 ) (72 -512 0 ) (72 -512 8 ) +4 11 (0 -320 8 ) (72 -320 8 ) (72 -320 0 ) (0 -320 0 ) +4 12 (-64 128 320 ) (-64 128 304 ) (0 128 304 ) (0 128 320 ) +4 12 (-64 192 304 ) (-64 192 320 ) (0 192 320 ) (0 192 304 ) +4 12 (0 192 320 ) (-64 192 320 ) (-64 128 320 ) (0 128 320 ) +4 13 (0 96 352 ) (-32 96 352 ) (-32 0 352 ) (0 0 352 ) +4 13 (0 96 304 ) (-32 96 304 ) (-32 96 352 ) (0 96 352 ) +4 13 (-32 96 352 ) (-32 96 304 ) (-32 0 304 ) (-32 0 352 ) +4 14 (-480 192 320 ) (-480 192 304 ) (-480 0 304 ) (-480 0 320 ) +4 14 (-64 192 320 ) (-64 192 304 ) (-480 192 304 ) (-480 192 320 ) +4 14 (-64 128 320 ) (-64 96 320 ) (-64 96 304 ) (-64 128 304 ) +4 14 (-64 96 320 ) (-64 0 320 ) (-64 0 304 ) (-64 96 304 ) +4 14 (-64 0 320 ) (-64 192 320 ) (-480 192 320 ) (-480 0 320 ) +4 15 (0 0 8 ) (-328 0 8 ) (-328 40 8 ) (0 40 8 ) +4 15 (-32 96 304 ) (-64 96 304 ) (-64 0 304 ) (-32 0 304 ) +4 15 (0 96 304 ) (0 128 304 ) (-64 128 304 ) (-64 96 304 ) +4 15 (-480 192 304 ) (-480 192 8 ) (-480 0 8 ) (-480 0 304 ) +4 15 (-480 192 8 ) (-480 192 304 ) (0 192 304 ) (0 192 8 ) +4 16 (-328 40 0 ) (-328 192 0 ) (0 192 0 ) (0 40 0 ) +4 16 (-328 192 0 ) (-328 192 8 ) (0 192 8 ) (0 192 0 ) +4 16 (-328 40 8 ) (-328 40 0 ) (0 40 0 ) (0 40 8 ) +4 17 (-328 40 8 ) (-328 0 8 ) (-328 0 0 ) (-328 40 0 ) +4 17 (-328 192 0 ) (-480 192 0 ) (-480 192 8 ) (-328 192 8 ) +4 17 (-480 192 8 ) (-480 192 0 ) (-480 0 0 ) (-480 0 8 ) +4 17 (-328 0 0 ) (-480 0 0 ) (-480 192 0 ) (-328 192 0 ) +4 18 (0 -416 352 ) (-32 -416 352 ) (-32 -416 304 ) (0 -416 304 ) +4 18 (-32 -416 352 ) (0 -416 352 ) (0 0 352 ) (-32 0 352 ) +4 18 (-32 0 304 ) (-32 -416 304 ) (-32 -416 352 ) (-32 0 352 ) +4 19 (-64 -512 304 ) (0 -512 304 ) (0 -512 320 ) (-64 -512 320 ) +4 19 (0 -448 320 ) (0 -448 304 ) (-64 -448 304 ) (-64 -448 320 ) +4 19 (0 -448 320 ) (-64 -448 320 ) (-64 -512 320 ) (0 -512 320 ) +4 20 (-480 -512 320 ) (-480 -512 304 ) (-64 -512 304 ) (-64 -512 320 ) +4 20 (-480 0 320 ) (-480 0 304 ) (-480 -512 304 ) (-480 -512 320 ) +4 20 (-64 -416 320 ) (-64 -448 320 ) (-64 -448 304 ) (-64 -416 304 ) +4 20 (-64 -416 320 ) (-64 -416 304 ) (-64 0 304 ) (-64 0 320 ) +4 20 (-480 0 320 ) (-480 -512 320 ) (-64 -512 320 ) (-64 0 320 ) +4 21 (-328 -320 8 ) (-328 0 8 ) (0 0 8 ) (0 -320 8 ) +4 21 (-32 -416 304 ) (-32 0 304 ) (-64 0 304 ) (-64 -416 304 ) +4 21 (0 -448 304 ) (0 -416 304 ) (-64 -416 304 ) (-64 -448 304 ) +4 21 (-480 -512 304 ) (-480 -512 8 ) (0 -512 8 ) (0 -512 304 ) +4 21 (-480 0 304 ) (-480 0 8 ) (-480 -512 8 ) (-480 -512 304 ) +4 22 (0 -512 0 ) (-328 -512 0 ) (-328 -320 0 ) (0 -320 0 ) +4 22 (-328 -512 0 ) (0 -512 0 ) (0 -512 8 ) (-328 -512 8 ) +4 22 (0 -320 8 ) (0 -320 0 ) (-328 -320 0 ) (-328 -320 8 ) +4 23 (-328 0 8 ) (-328 -320 8 ) (-328 -320 0 ) (-328 0 0 ) +4 23 (-480 0 8 ) (-480 0 0 ) (-480 -512 0 ) (-480 -512 8 ) +4 23 (-480 -512 8 ) (-480 -512 0 ) (-328 -512 0 ) (-328 -512 8 ) +4 23 (-328 -512 0 ) (-480 -512 0 ) (-480 0 0 ) (-328 0 0 ) diff --git a/fakk/maps/example/scriptgravity.bsp b/fakk/maps/example/scriptgravity.bsp new file mode 100644 index 0000000..7175054 Binary files /dev/null and b/fakk/maps/example/scriptgravity.bsp differ diff --git a/fakk/maps/example/scriptgravity.map b/fakk/maps/example/scriptgravity.map new file mode 100644 index 0000000..753c845 --- /dev/null +++ b/fakk/maps/example/scriptgravity.map @@ -0,0 +1,198 @@ +{ +"classname" "worldspawn" +// brush 0 +{ +( 224 192 0 ) ( 224 224 0 ) ( -480 224 0 ) eden/FL_sheiekpens 0 0 0.00 1 1 0 0 0 +( -480 224 64 ) ( 224 224 64 ) ( 224 192 64 ) eden/FL_sheiekpens 0 0 0.00 1 1 0 0 0 +( -480 192 256 ) ( 224 192 256 ) ( 224 192 0 ) eden/FL_sheiekpens 0 0 0.00 1 1 0 0 0 +( 224 192 256 ) ( 224 224 256 ) ( 224 224 0 ) eden/FL_sheiekpens 0 0 0.00 1 1 0 0 0 +( 224 224 256 ) ( -480 224 256 ) ( -480 224 0 ) eden/FL_sheiekpens 0 0 0.00 1 1 0 0 0 +( -480 192 0 ) ( -480 224 0 ) ( -480 208 64 ) eden/FL_sheiekpens 0 0 0.00 1 1 0 0 0 +} +// brush 1 +{ +( 224 192 64 ) ( 224 224 64 ) ( -480 224 64 ) eden/CL_church 0 0 0.00 1 1 0 0 0 +( -480 224 320 ) ( 224 224 320 ) ( 224 192 320 ) eden/CL_church 0 0 0.00 1 1 0 0 0 +( -480 192 96 ) ( 224 192 96 ) ( 224 192 64 ) eden/CL_church 0 0 0.00 1 1 0 0 0 +( 224 192 96 ) ( 224 224 96 ) ( 224 224 64 ) eden/CL_church 0 0 0.00 1 1 0 0 0 +( 224 224 96 ) ( -480 224 96 ) ( -480 224 64 ) eden/CL_church 0 0 0.00 1 1 0 0 0 +( -480 192 64 ) ( -480 224 64 ) ( -480 208 320 ) eden/CL_church 0 0 0.00 1 1 0 0 0 +} +// brush 2 +{ +( -480 192 0 ) ( -512 192 0 ) ( -512 -512 0 ) eden/FL_edenhouse2 0 0 0.00 1 1 0 0 0 +( -512 -512 64 ) ( -512 192 64 ) ( -480 192 64 ) eden/FL_edenhouse2 0 0 0.00 1 1 0 0 0 +( -512 -512 256 ) ( -480 -512 256 ) ( -480 -512 0 ) eden/FL_edenhouse2 0 0 0.00 1 1 0 0 0 +( -480 -512 256 ) ( -480 192 256 ) ( -480 192 0 ) eden/FL_edenhouse2 0 0 0.00 1 1 0 0 0 +( -512 192 256 ) ( -512 -512 256 ) ( -512 -512 0 ) eden/FL_edenhouse2 0 0 0.00 1 1 0 0 0 +( -512 192 0 ) ( -480 192 0 ) ( -496 192 64 ) eden/FL_edenhouse2 0 0 0.00 1 1 0 0 0 +} +// brush 3 +{ +( -480 192 64 ) ( -512 192 64 ) ( -512 -512 64 ) eden/FL_basement2 0 0 0.00 1 1 0 0 0 +( -512 -512 320 ) ( -512 192 320 ) ( -480 192 320 ) eden/FL_basement2 0 0 0.00 1 1 0 0 0 +( -512 -512 96 ) ( -480 -512 96 ) ( -480 -512 64 ) eden/FL_basement2 0 0 0.00 1 1 0 0 0 +( -480 -512 96 ) ( -480 192 96 ) ( -480 192 64 ) eden/FL_basement2 0 0 0.00 1 1 0 0 0 +( -512 192 96 ) ( -512 -512 96 ) ( -512 -512 64 ) eden/FL_basement2 0 0 0.00 1 1 0 0 0 +( -512 192 64 ) ( -480 192 64 ) ( -496 192 320 ) eden/FL_basement2 0 0 0.00 1 1 0 0 0 +} +// brush 4 +{ +( 192 192 320 ) ( -480 192 320 ) ( -480 -512 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( -480 -512 352 ) ( -480 192 352 ) ( 192 192 352 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( -480 -512 352 ) ( 192 -512 352 ) ( 192 -512 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( 192 192 352 ) ( -480 192 352 ) ( -480 192 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( -480 192 352 ) ( -480 -512 352 ) ( -480 -512 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( 224 -96 320 ) ( 224 -224 320 ) ( 224 -160 352 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +} +// brush 5 +{ +( 192 192 -32 ) ( -480 192 -32 ) ( -480 -512 -32 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( -480 -512 0 ) ( -480 192 0 ) ( 192 192 0 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( -480 -512 224 ) ( 192 -512 224 ) ( 192 -512 -32 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 192 -512 224 ) ( 192 192 224 ) ( 192 192 -32 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 192 192 224 ) ( -480 192 224 ) ( -480 192 -32 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( -480 192 224 ) ( -480 -512 224 ) ( -480 -512 -32 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +} +// brush 6 +{ +( -480 -512 64 ) ( -480 -544 64 ) ( 224 -544 64 ) eden/edenmetalwall -31 31 -90.00 1 1 0 0 0 +( 224 -544 320 ) ( -480 -544 320 ) ( -480 -512 320 ) eden/edenmetalwall -31 31 -90.00 1 1 0 0 0 +( 224 -544 96 ) ( 224 -512 96 ) ( 224 -512 64 ) eden/edenmetalwall -32 63 -180.00 1 -1 0 0 0 +( 224 -512 96 ) ( -480 -512 96 ) ( -480 -512 64 ) eden/edenmetalwall -32 62 0.00 1.000008 1 0 0 0 +( -480 -512 96 ) ( -480 -544 96 ) ( -480 -544 64 ) eden/edenmetalwall -33 63 -180.00 1 -1 0 0 0 +( -480 -544 96 ) ( 224 -544 96 ) ( 224 -544 64 ) eden/edenmetalwall -32 62 0.00 1.000008 1 0 0 0 +} +// brush 7 +{ +( -480 -512 0 ) ( -480 -544 0 ) ( 224 -544 0 ) eden/FL_woodchips 0 0 0.00 1 1 0 0 0 +( 224 -544 64 ) ( -480 -544 64 ) ( -480 -512 64 ) eden/FL_woodchips 0 0 0.00 1 1 0 0 0 +( 224 -544 256 ) ( 224 -512 256 ) ( 224 -512 0 ) eden/FL_woodchips 0 0 0.00 1 1 0 0 0 +( 224 -512 256 ) ( -480 -512 256 ) ( -480 -512 0 ) eden/FL_woodchips 0 0 0.00 1 1 0 0 0 +( -480 -512 256 ) ( -480 -544 256 ) ( -480 -544 0 ) eden/FL_woodchips 0 0 0.00 1 1 0 0 0 +( -480 -544 256 ) ( 224 -544 256 ) ( 224 -544 0 ) eden/FL_woodchips 0 0 0.00 1 1 0 0 0 +} +// brush 8 +{ +( 192 -512 0 ) ( 224 -512 0 ) ( 224 192 0 ) eden/FL_underground 0 0 0.00 1 1 0 0 0 +( 224 192 64 ) ( 224 -512 64 ) ( 192 -512 64 ) eden/FL_underground 0 0 0.00 1 1 0 0 0 +( 224 192 256 ) ( 192 192 256 ) ( 192 192 0 ) eden/FL_underground 0 0 0.00 1 1 0 0 0 +( 192 192 256 ) ( 192 -512 256 ) ( 192 -512 0 ) eden/FL_underground 0 0 0.00 1 1 0 0 0 +( 192 -512 256 ) ( 224 -512 256 ) ( 224 -512 0 ) eden/FL_underground 0 0 0.00 1 1 0 0 0 +( 224 -512 256 ) ( 224 192 256 ) ( 224 192 0 ) eden/FL_underground 0 0 0.00 1 1 0 0 0 +} +// brush 9 +{ +( 192 -512 64 ) ( 224 -512 64 ) ( 224 192 64 ) eden/CL_edenroof 0 0 0.00 1 1 0 0 0 +( 224 192 320 ) ( 224 -512 320 ) ( 192 -512 320 ) eden/CL_edenroof 0 0 0.00 1 1 0 0 0 +( 224 192 96 ) ( 192 192 96 ) ( 192 192 64 ) eden/CL_edenroof 0 0 0.00 1 1 0 0 0 +( 192 192 96 ) ( 192 -512 96 ) ( 192 -512 64 ) eden/CL_edenroof 0 0 0.00 1 1 0 0 0 +( 192 -512 96 ) ( 224 -512 96 ) ( 224 -512 64 ) eden/CL_edenroof 0 0 0.00 1 1 0 0 0 +( 224 -512 96 ) ( 224 192 96 ) ( 224 192 64 ) eden/CL_edenroof 0 0 0.00 1 1 0 0 0 +} +} +// entity 1 +{ +"origin" "-240 -80 200" +"targetname" "guss_start" +"classname" "info_waypoint" +} +// entity 2 +{ +"classname" "script_object" +"targetname" "guss" +// brush 0 +{ +( -184 -16 192 ) ( -304 -16 192 ) ( -304 -144 192 ) eden/FL_basement2 0 0 0.00 1 1 0 0 0 +( -304 -144 200 ) ( -304 -16 200 ) ( -184 -16 200 ) eden/FL_basement2 0 0 0.00 1 1 0 0 0 +( -304 -144 200 ) ( -184 -144 200 ) ( -184 -144 192 ) eden/FL_basement2 0 64 0.00 1 1 0 0 0 +( -184 -144 200 ) ( -184 -16 200 ) ( -184 -16 192 ) eden/FL_basement2 0 64 0.00 1 1 0 0 0 +( -184 -16 200 ) ( -304 -16 200 ) ( -304 -16 192 ) eden/FL_basement2 0 64 0.00 1 1 0 0 0 +( -304 -16 200 ) ( -304 -144 200 ) ( -304 -144 192 ) eden/FL_basement2 0 64 0.00 1 1 0 0 0 +} +} +// entity 3 +{ +"_color" "1.000000 0.724409 0.523622" +"light" "200" +"origin" "-352 56 168" +"spawnflags" "0" +"classname" "light" +} +// entity 4 +{ +"origin" "-432 -464 24" +"angle" "45" +"classname" "info_player_start" +} +// entity 5 +{ +"_color" "0.629921 0.846457 1.000000" +"light" "200" +"classname" "light" +"spawnflags" "0" +"origin" "8 56 168" +} +// entity 6 +{ +"light" "200" +"classname" "light" +"spawnflags" "0" +"origin" "-344 -376 168" +} +// entity 7 +{ +"light" "200" +"origin" "8 -376 168" +"spawnflags" "0" +"classname" "light" +} +// entity 8 +{ +"origin" "-168 -160 168" +"spawnflags" "0" +"classname" "light" +"light" "200" +} +// entity 9 +{ +"targetname" "sam" +"classname" "script_object" +// brush 0 +{ +( 56 -16 192 ) ( -64 -16 192 ) ( -64 -144 192 ) eden/FL_basement2 16 0 0.00 1 1 0 0 0 +( -64 -144 200 ) ( -64 -16 200 ) ( 56 -16 200 ) eden/FL_basement2 16 0 0.00 1 1 0 0 0 +( -64 -144 200 ) ( 56 -144 200 ) ( 56 -144 192 ) eden/FL_basement2 16 64 0.00 1 1 0 0 0 +( 56 -144 200 ) ( 56 -16 200 ) ( 56 -16 192 ) eden/FL_basement2 0 64 0.00 1 1 0 0 0 +( 56 -16 200 ) ( -64 -16 200 ) ( -64 -16 192 ) eden/FL_basement2 16 64 0.00 1 1 0 0 0 +( -64 -16 200 ) ( -64 -144 200 ) ( -64 -144 192 ) eden/FL_basement2 0 64 0.00 1 1 0 0 0 +} +} +// entity 10 +{ +"classname" "script_object" +"targetname" "larry" +// brush 0 +{ +( -184 -192 192 ) ( -304 -192 192 ) ( -304 -320 192 ) eden/FL_basement2 0 -48 0.00 1 1 0 0 0 +( -304 -320 200 ) ( -304 -192 200 ) ( -184 -192 200 ) eden/FL_basement2 0 -48 0.00 1 1 0 0 0 +( -304 -320 200 ) ( -184 -320 200 ) ( -184 -320 192 ) eden/FL_basement2 0 64 0.00 1 1 0 0 0 +( -184 -320 200 ) ( -184 -192 200 ) ( -184 -192 192 ) eden/FL_basement2 48 64 0.00 1 1 0 0 0 +( -184 -192 200 ) ( -304 -192 200 ) ( -304 -192 192 ) eden/FL_basement2 0 64 0.00 1 1 0 0 0 +( -304 -192 200 ) ( -304 -320 200 ) ( -304 -320 192 ) eden/FL_basement2 48 64 0.00 1 1 0 0 0 +} +} +// entity 11 +{ +"targetname" "tom" +"classname" "script_object" +// brush 0 +{ +( 56 -184 192 ) ( -64 -184 192 ) ( -64 -312 192 ) eden/FL_basement2 -112 -40 0.00 1 1 0 0 0 +( -64 -312 200 ) ( -64 -184 200 ) ( 56 -184 200 ) eden/FL_basement2 -112 -40 0.00 1 1 0 0 0 +( -64 -312 200 ) ( 56 -312 200 ) ( 56 -312 192 ) eden/FL_basement2 -112 64 0.00 1 1 0 0 0 +( 56 -312 200 ) ( 56 -184 200 ) ( 56 -184 192 ) eden/FL_basement2 40 64 0.00 1 1 0 0 0 +( 56 -184 200 ) ( -64 -184 200 ) ( -64 -184 192 ) eden/FL_basement2 -112 64 0.00 1 1 0 0 0 +( -64 -184 200 ) ( -64 -312 200 ) ( -64 -312 192 ) eden/FL_basement2 40 64 0.00 1 1 0 0 0 +} +} diff --git a/fakk/maps/example/scriptgravity.prt b/fakk/maps/example/scriptgravity.prt new file mode 100644 index 0000000..d9675c1 --- /dev/null +++ b/fakk/maps/example/scriptgravity.prt @@ -0,0 +1,24 @@ +PRT1 +4 +4 +16 +4 0 2 0 (0 0 0 ) (0 0 320 ) (0 192 320 ) (0 192 0 ) +4 0 1 0 (0 0 320 ) (0 0 0 ) (192 0 0 ) (192 0 320 ) +4 1 3 0 (0 -512 0 ) (0 -512 320 ) (0 0 320 ) (0 0 0 ) +4 2 3 0 (0 0 0 ) (0 0 320 ) (-480 0 320 ) (-480 0 0 ) +4 0 (0 0 320 ) (192 0 320 ) (192 192 320 ) (0 192 320 ) +4 0 (192 192 320 ) (192 192 0 ) (0 192 0 ) (0 192 320 ) +4 0 (192 0 320 ) (192 0 0 ) (192 192 0 ) (192 192 320 ) +4 0 (0 192 0 ) (192 192 0 ) (192 0 0 ) (0 0 0 ) +4 1 (0 -512 320 ) (192 -512 320 ) (192 0 320 ) (0 0 320 ) +4 1 (0 -512 320 ) (0 -512 0 ) (192 -512 0 ) (192 -512 320 ) +4 1 (192 -512 320 ) (192 -512 0 ) (192 0 0 ) (192 0 320 ) +4 1 (0 0 0 ) (192 0 0 ) (192 -512 0 ) (0 -512 0 ) +4 2 (0 192 320 ) (-480 192 320 ) (-480 0 320 ) (0 0 320 ) +4 2 (-480 192 0 ) (-480 192 320 ) (0 192 320 ) (0 192 0 ) +4 2 (-480 192 320 ) (-480 192 0 ) (-480 0 0 ) (-480 0 320 ) +4 2 (0 0 0 ) (-480 0 0 ) (-480 192 0 ) (0 192 0 ) +4 3 (0 0 320 ) (-480 0 320 ) (-480 -512 320 ) (0 -512 320 ) +4 3 (-480 0 320 ) (-480 0 0 ) (-480 -512 0 ) (-480 -512 320 ) +4 3 (-480 -512 320 ) (-480 -512 0 ) (0 -512 0 ) (0 -512 320 ) +4 3 (0 -512 0 ) (-480 -512 0 ) (-480 0 0 ) (0 0 0 ) diff --git a/fakk/maps/example/scriptgravity.scr b/fakk/maps/example/scriptgravity.scr new file mode 100644 index 0000000..8eb0560 --- /dev/null +++ b/fakk/maps/example/scriptgravity.scr @@ -0,0 +1,59 @@ +waitforplayer + +wait 3 + +thread larry_touch_setup + +loop: + +wait 1 + +print "dropping larry\n" +wait 0.2 +$larry physics_on +$larry physics_velocity "0 0 300" +wait 0.2 + +print "dropping guss\n" +$guss physics_on +$guss rotatex 100 +$guss rotatey 200 +$guss physics_velocity "200 -80 300" +wait 0.2 + +print "dropping sam\n" +$sam physics_on +wait 0.2 + +print "dropping tom\n" +$tom physics_on + +wait 3 +print "resetting everyone\n" +$larry physics_off +$guss physics_off +$guss angles "0 0 0" +$tom physics_off +$sam physics_off + +$larry time 2 +$larry moveup 192 +$guss time 2 +$guss moveto $guss_start +$tom time 2 +$tom moveup 192 +$sam time 2 +$sam moveup 192 + +waitfor $tom +goto loop + +larry_touch: +print "larry touched\n" +pause + +larry_touch_setup: +$larry ontouch larry_touch +pause + +end \ No newline at end of file diff --git a/fakk/maps/example/sinkobject.bsp b/fakk/maps/example/sinkobject.bsp new file mode 100644 index 0000000..d8ffd97 Binary files /dev/null and b/fakk/maps/example/sinkobject.bsp differ diff --git a/fakk/maps/example/sinkobject.map b/fakk/maps/example/sinkobject.map new file mode 100644 index 0000000..bb597a8 --- /dev/null +++ b/fakk/maps/example/sinkobject.map @@ -0,0 +1,723 @@ +{ +"classname" "worldspawn" +// brush 0 +{ +( -64 -896 0 ) ( -320 -896 0 ) ( -320 -1016 0 ) eden/woodfloor 0 0 0.00 1 1 0 0 0 +( -320 -1016 16 ) ( -320 -896 16 ) ( -64 -896 16 ) eden/woodfloor 0 0 0.00 1 1 0 0 0 +( -320 -1016 96 ) ( -64 -1016 96 ) ( -64 -1016 0 ) eden/woodfloor 0 -24 0.00 1 1 0 0 0 +( -64 -1016 96 ) ( -64 -896 96 ) ( -64 -896 0 ) eden/woodfloor 64 -24 0.00 1 1 0 0 0 +( -64 -896 96 ) ( -320 -896 96 ) ( -320 -896 0 ) eden/woodfloor 0 -24 0.00 1 1 0 0 0 +( -320 -896 96 ) ( -320 -1016 96 ) ( -320 -1016 0 ) eden/woodfloor 64 -24 0.00 1 1 0 0 0 +} +// brush 1 +{ +( -48 -896 16 ) ( -304 -896 16 ) ( -304 -1016 16 ) eden/woodfloor -16 0 0.00 1 1 0 0 0 +( -304 -1016 32 ) ( -304 -896 32 ) ( -48 -896 32 ) eden/woodfloor -16 0 0.00 1 1 0 0 0 +( -304 -1016 112 ) ( -48 -1016 112 ) ( -48 -1016 16 ) eden/woodfloor -16 -8 0.00 1 1 0 0 0 +( -64 -1016 112 ) ( -64 -896 112 ) ( -64 -896 16 ) eden/woodfloor 64 -8 0.00 1 1 0 0 0 +( -48 -896 112 ) ( -304 -896 112 ) ( -304 -896 16 ) eden/woodfloor -16 -8 0.00 1 1 0 0 0 +( -304 -896 112 ) ( -304 -1016 112 ) ( -304 -1016 16 ) eden/woodfloor 64 -8 0.00 1 1 0 0 0 +} +// brush 2 +{ +( -32 -896 32 ) ( -288 -896 32 ) ( -288 -1016 32 ) eden/woodfloor -32 0 0.00 1 1 0 0 0 +( -288 -1016 48 ) ( -288 -896 48 ) ( -32 -896 48 ) eden/woodfloor -32 0 0.00 1 1 0 0 0 +( -288 -1016 128 ) ( -32 -1016 128 ) ( -32 -1016 32 ) eden/woodfloor -32 8 0.00 1 1 0 0 0 +( -64 -1016 128 ) ( -64 -896 128 ) ( -64 -896 32 ) eden/woodfloor 64 8 0.00 1 1 0 0 0 +( -32 -896 128 ) ( -288 -896 128 ) ( -288 -896 32 ) eden/woodfloor -32 8 0.00 1 1 0 0 0 +( -288 -896 128 ) ( -288 -1016 128 ) ( -288 -1016 32 ) eden/woodfloor 64 8 0.00 1 1 0 0 0 +} +// brush 3 +{ +( -16 -896 48 ) ( -272 -896 48 ) ( -272 -1016 48 ) eden/woodfloor -48 0 0.00 1 1 0 0 0 +( -272 -1016 64 ) ( -272 -896 64 ) ( -16 -896 64 ) eden/woodfloor -48 0 0.00 1 1 0 0 0 +( -272 -1016 144 ) ( -16 -1016 144 ) ( -16 -1016 48 ) eden/woodfloor -48 24 0.00 1 1 0 0 0 +( -64 -1016 144 ) ( -64 -896 144 ) ( -64 -896 48 ) eden/woodfloor 64 24 0.00 1 1 0 0 0 +( -16 -896 144 ) ( -272 -896 144 ) ( -272 -896 48 ) eden/woodfloor -48 24 0.00 1 1 0 0 0 +( -272 -896 144 ) ( -272 -1016 144 ) ( -272 -1016 48 ) eden/woodfloor 64 24 0.00 1 1 0 0 0 +} +// brush 4 +{ +( 0 -896 64 ) ( -256 -896 64 ) ( -256 -1016 64 ) eden/woodfloor -64 0 0.00 1 1 0 0 0 +( -256 -1016 80 ) ( -256 -896 80 ) ( 0 -896 80 ) eden/woodfloor -64 0 0.00 1 1 0 0 0 +( -256 -1016 160 ) ( 0 -1016 160 ) ( 0 -1016 64 ) eden/woodfloor -64 -24 0.00 1 1 0 0 0 +( -64 -1016 160 ) ( -64 -896 160 ) ( -64 -896 64 ) eden/woodfloor 64 -24 0.00 1 1 0 0 0 +( 0 -896 160 ) ( -256 -896 160 ) ( -256 -896 64 ) eden/woodfloor -64 -24 0.00 1 1 0 0 0 +( -256 -896 160 ) ( -256 -1016 160 ) ( -256 -1016 64 ) eden/woodfloor 64 -24 0.00 1 1 0 0 0 +} +// brush 5 +{ +( 16 -896 80 ) ( -240 -896 80 ) ( -240 -1016 80 ) eden/woodfloor -80 0 0.00 1 1 0 0 0 +( -240 -1016 96 ) ( -240 -896 96 ) ( 16 -896 96 ) eden/woodfloor -80 0 0.00 1 1 0 0 0 +( -240 -1016 176 ) ( 16 -1016 176 ) ( 16 -1016 80 ) eden/woodfloor -80 -8 0.00 1 1 0 0 0 +( -64 -1016 176 ) ( -64 -896 176 ) ( -64 -896 80 ) eden/woodfloor 64 -8 0.00 1 1 0 0 0 +( 16 -896 176 ) ( -240 -896 176 ) ( -240 -896 80 ) eden/woodfloor -80 -8 0.00 1 1 0 0 0 +( -240 -896 176 ) ( -240 -1016 176 ) ( -240 -1016 80 ) eden/woodfloor 64 -8 0.00 1 1 0 0 0 +} +// brush 6 +{ +( 32 -896 96 ) ( -224 -896 96 ) ( -224 -1016 96 ) eden/woodfloor -96 0 0.00 1 1 0 0 0 +( -224 -1016 112 ) ( -224 -896 112 ) ( 32 -896 112 ) eden/woodfloor -96 0 0.00 1 1 0 0 0 +( -224 -1016 192 ) ( 32 -1016 192 ) ( 32 -1016 96 ) eden/woodfloor -96 8 0.00 1 1 0 0 0 +( -64 -1016 192 ) ( -64 -896 192 ) ( -64 -896 96 ) eden/woodfloor 64 8 0.00 1 1 0 0 0 +( 32 -896 192 ) ( -224 -896 192 ) ( -224 -896 96 ) eden/woodfloor -96 8 0.00 1 1 0 0 0 +( -224 -896 192 ) ( -224 -1016 192 ) ( -224 -1016 96 ) eden/woodfloor 64 8 0.00 1 1 0 0 0 +} +// brush 7 +{ +( 48 -896 112 ) ( -208 -896 112 ) ( -208 -1016 112 ) eden/woodfloor 16 0 0.00 1 1 0 0 0 +( -208 -1016 128 ) ( -208 -896 128 ) ( 48 -896 128 ) eden/woodfloor 16 0 0.00 1 1 0 0 0 +( -208 -1016 208 ) ( 48 -1016 208 ) ( 48 -1016 112 ) eden/woodfloor 16 24 0.00 1 1 0 0 0 +( -64 -1016 208 ) ( -64 -896 208 ) ( -64 -896 112 ) eden/woodfloor 64 24 0.00 1 1 0 0 0 +( 48 -896 208 ) ( -208 -896 208 ) ( -208 -896 112 ) eden/woodfloor 16 24 0.00 1 1 0 0 0 +( -208 -896 208 ) ( -208 -1016 208 ) ( -208 -1016 112 ) eden/woodfloor 64 24 0.00 1 1 0 0 0 +} +// brush 8 +{ +( 64 -896 128 ) ( -192 -896 128 ) ( -192 -1016 128 ) eden/woodfloor 0 0 0.00 1 1 0 0 0 +( -192 -1016 144 ) ( -192 -896 144 ) ( 64 -896 144 ) eden/woodfloor 0 0 0.00 1 1 0 0 0 +( -192 -1016 224 ) ( 64 -1016 224 ) ( 64 -1016 128 ) eden/woodfloor 0 -24 0.00 1 1 0 0 0 +( -64 -1008 224 ) ( -64 -888 224 ) ( -64 -888 128 ) eden/woodfloor 64 -24 0.00 1 1 0 0 0 +( 64 -896 224 ) ( -192 -896 224 ) ( -192 -896 128 ) eden/woodfloor 0 -24 0.00 1 1 0 0 0 +( -192 -896 224 ) ( -192 -1016 224 ) ( -192 -1016 128 ) eden/woodfloor 64 -24 0.00 1 1 0 0 0 +} +// brush 9 +{ +( 80 -896 144 ) ( -176 -896 144 ) ( -176 -1016 144 ) eden/woodfloor -16 0 0.00 1 1 0 0 0 +( -176 -1016 160 ) ( -176 -896 160 ) ( 80 -896 160 ) eden/woodfloor -16 0 0.00 1 1 0 0 0 +( -176 -1016 240 ) ( 80 -1016 240 ) ( 80 -1016 144 ) eden/woodfloor -16 -8 0.00 1 1 0 0 0 +( -64 -1008 240 ) ( -64 -888 240 ) ( -64 -888 144 ) eden/woodfloor 64 -8 0.00 1 1 0 0 0 +( 80 -896 240 ) ( -176 -896 240 ) ( -176 -896 144 ) eden/woodfloor -16 -8 0.00 1 1 0 0 0 +( -176 -896 240 ) ( -176 -1016 240 ) ( -176 -1016 144 ) eden/woodfloor 64 -8 0.00 1 1 0 0 0 +} +// brush 10 +{ +( 96 -896 160 ) ( -160 -896 160 ) ( -160 -1016 160 ) eden/woodfloor -32 0 0.00 1 1 0 0 0 +( -160 -1016 176 ) ( -160 -896 176 ) ( 96 -896 176 ) eden/woodfloor -32 0 0.00 1 1 0 0 0 +( -160 -1016 256 ) ( 96 -1016 256 ) ( 96 -1016 160 ) eden/woodfloor -32 8 0.00 1 1 0 0 0 +( -64 -1008 256 ) ( -64 -888 256 ) ( -64 -888 160 ) eden/woodfloor 64 8 0.00 1 1 0 0 0 +( 96 -896 256 ) ( -160 -896 256 ) ( -160 -896 160 ) eden/woodfloor -32 8 0.00 1 1 0 0 0 +( -160 -896 256 ) ( -160 -1016 256 ) ( -160 -1016 160 ) eden/woodfloor 64 8 0.00 1 1 0 0 0 +} +// brush 11 +{ +( 96 -576 160 ) ( -160 -576 160 ) ( -160 -696 160 ) eden/woodfloor -32 0 0.00 1 1 0 0 0 +( -160 -696 176 ) ( -160 -576 176 ) ( 96 -576 176 ) eden/woodfloor -32 0 0.00 1 1 0 0 0 +( -160 -696 256 ) ( 96 -696 256 ) ( 96 -696 160 ) eden/woodfloor -32 8 0.00 1 1 0 0 0 +( -64 -688 256 ) ( -64 -568 256 ) ( -64 -568 160 ) eden/woodfloor 0 8 0.00 1 1 0 0 0 +( 96 -576 256 ) ( -160 -576 256 ) ( -160 -576 160 ) eden/woodfloor -32 8 0.00 1 1 0 0 0 +( -160 -576 256 ) ( -160 -696 256 ) ( -160 -696 160 ) eden/woodfloor 0 8 0.00 1 1 0 0 0 +} +// brush 12 +{ +( 80 -576 144 ) ( -176 -576 144 ) ( -176 -696 144 ) eden/woodfloor -16 0 0.00 1 1 0 0 0 +( -176 -696 160 ) ( -176 -576 160 ) ( 80 -576 160 ) eden/woodfloor -16 0 0.00 1 1 0 0 0 +( -176 -696 240 ) ( 80 -696 240 ) ( 80 -696 144 ) eden/woodfloor -16 -8 0.00 1 1 0 0 0 +( -64 -688 240 ) ( -64 -568 240 ) ( -64 -568 144 ) eden/woodfloor 0 -8 0.00 1 1 0 0 0 +( 80 -576 240 ) ( -176 -576 240 ) ( -176 -576 144 ) eden/woodfloor -16 -8 0.00 1 1 0 0 0 +( -176 -576 240 ) ( -176 -696 240 ) ( -176 -696 144 ) eden/woodfloor 0 -8 0.00 1 1 0 0 0 +} +// brush 13 +{ +( 64 -576 128 ) ( -192 -576 128 ) ( -192 -696 128 ) eden/woodfloor 0 0 0.00 1 1 0 0 0 +( -192 -696 144 ) ( -192 -576 144 ) ( 64 -576 144 ) eden/woodfloor 0 0 0.00 1 1 0 0 0 +( -192 -696 224 ) ( 64 -696 224 ) ( 64 -696 128 ) eden/woodfloor 0 -24 0.00 1 1 0 0 0 +( -64 -688 224 ) ( -64 -568 224 ) ( -64 -568 128 ) eden/woodfloor 0 -24 0.00 1 1 0 0 0 +( 64 -576 224 ) ( -192 -576 224 ) ( -192 -576 128 ) eden/woodfloor 0 -24 0.00 1 1 0 0 0 +( -192 -576 224 ) ( -192 -696 224 ) ( -192 -696 128 ) eden/woodfloor 0 -24 0.00 1 1 0 0 0 +} +// brush 14 +{ +( 48 -576 112 ) ( -208 -576 112 ) ( -208 -696 112 ) eden/woodfloor 16 0 0.00 1 1 0 0 0 +( -208 -696 128 ) ( -208 -576 128 ) ( 48 -576 128 ) eden/woodfloor 16 0 0.00 1 1 0 0 0 +( -208 -696 208 ) ( 48 -696 208 ) ( 48 -696 112 ) eden/woodfloor 16 24 0.00 1 1 0 0 0 +( -64 -696 208 ) ( -64 -576 208 ) ( -64 -576 112 ) eden/woodfloor 0 24 0.00 1 1 0 0 0 +( 48 -576 208 ) ( -208 -576 208 ) ( -208 -576 112 ) eden/woodfloor 16 24 0.00 1 1 0 0 0 +( -208 -576 208 ) ( -208 -696 208 ) ( -208 -696 112 ) eden/woodfloor 0 24 0.00 1 1 0 0 0 +} +// brush 15 +{ +( 32 -576 96 ) ( -224 -576 96 ) ( -224 -696 96 ) eden/woodfloor -96 0 0.00 1 1 0 0 0 +( -224 -696 112 ) ( -224 -576 112 ) ( 32 -576 112 ) eden/woodfloor -96 0 0.00 1 1 0 0 0 +( -224 -696 192 ) ( 32 -696 192 ) ( 32 -696 96 ) eden/woodfloor -96 8 0.00 1 1 0 0 0 +( -64 -696 192 ) ( -64 -576 192 ) ( -64 -576 96 ) eden/woodfloor 0 8 0.00 1 1 0 0 0 +( 32 -576 192 ) ( -224 -576 192 ) ( -224 -576 96 ) eden/woodfloor -96 8 0.00 1 1 0 0 0 +( -224 -576 192 ) ( -224 -696 192 ) ( -224 -696 96 ) eden/woodfloor 0 8 0.00 1 1 0 0 0 +} +// brush 16 +{ +( 16 -576 80 ) ( -240 -576 80 ) ( -240 -696 80 ) eden/woodfloor -80 0 0.00 1 1 0 0 0 +( -240 -696 96 ) ( -240 -576 96 ) ( 16 -576 96 ) eden/woodfloor -80 0 0.00 1 1 0 0 0 +( -240 -696 176 ) ( 16 -696 176 ) ( 16 -696 80 ) eden/woodfloor -80 -8 0.00 1 1 0 0 0 +( -64 -696 176 ) ( -64 -576 176 ) ( -64 -576 80 ) eden/woodfloor 0 -8 0.00 1 1 0 0 0 +( 16 -576 176 ) ( -240 -576 176 ) ( -240 -576 80 ) eden/woodfloor -80 -8 0.00 1 1 0 0 0 +( -240 -576 176 ) ( -240 -696 176 ) ( -240 -696 80 ) eden/woodfloor 0 -8 0.00 1 1 0 0 0 +} +// brush 17 +{ +( 0 -576 64 ) ( -256 -576 64 ) ( -256 -696 64 ) eden/woodfloor -64 0 0.00 1 1 0 0 0 +( -256 -696 80 ) ( -256 -576 80 ) ( 0 -576 80 ) eden/woodfloor -64 0 0.00 1 1 0 0 0 +( -256 -696 160 ) ( 0 -696 160 ) ( 0 -696 64 ) eden/woodfloor -64 -24 0.00 1 1 0 0 0 +( -64 -696 160 ) ( -64 -576 160 ) ( -64 -576 64 ) eden/woodfloor 0 -24 0.00 1 1 0 0 0 +( 0 -576 160 ) ( -256 -576 160 ) ( -256 -576 64 ) eden/woodfloor -64 -24 0.00 1 1 0 0 0 +( -256 -576 160 ) ( -256 -696 160 ) ( -256 -696 64 ) eden/woodfloor 0 -24 0.00 1 1 0 0 0 +} +// brush 18 +{ +( -16 -576 48 ) ( -272 -576 48 ) ( -272 -696 48 ) eden/woodfloor -48 0 0.00 1 1 0 0 0 +( -272 -696 64 ) ( -272 -576 64 ) ( -16 -576 64 ) eden/woodfloor -48 0 0.00 1 1 0 0 0 +( -272 -696 144 ) ( -16 -696 144 ) ( -16 -696 48 ) eden/woodfloor -48 24 0.00 1 1 0 0 0 +( -64 -696 144 ) ( -64 -576 144 ) ( -64 -576 48 ) eden/woodfloor 0 24 0.00 1 1 0 0 0 +( -16 -576 144 ) ( -272 -576 144 ) ( -272 -576 48 ) eden/woodfloor -48 24 0.00 1 1 0 0 0 +( -272 -576 144 ) ( -272 -696 144 ) ( -272 -696 48 ) eden/woodfloor 0 24 0.00 1 1 0 0 0 +} +// brush 19 +{ +( -32 -576 32 ) ( -288 -576 32 ) ( -288 -696 32 ) eden/woodfloor -32 0 0.00 1 1 0 0 0 +( -288 -696 48 ) ( -288 -576 48 ) ( -32 -576 48 ) eden/woodfloor -32 0 0.00 1 1 0 0 0 +( -288 -696 128 ) ( -32 -696 128 ) ( -32 -696 32 ) eden/woodfloor -32 8 0.00 1 1 0 0 0 +( -64 -696 128 ) ( -64 -576 128 ) ( -64 -576 32 ) eden/woodfloor 0 8 0.00 1 1 0 0 0 +( -32 -576 128 ) ( -288 -576 128 ) ( -288 -576 32 ) eden/woodfloor -32 8 0.00 1 1 0 0 0 +( -288 -576 128 ) ( -288 -696 128 ) ( -288 -696 32 ) eden/woodfloor 0 8 0.00 1 1 0 0 0 +} +// brush 20 +{ +( -48 -576 16 ) ( -304 -576 16 ) ( -304 -696 16 ) eden/woodfloor -16 0 0.00 1 1 0 0 0 +( -304 -696 32 ) ( -304 -576 32 ) ( -48 -576 32 ) eden/woodfloor -16 0 0.00 1 1 0 0 0 +( -304 -696 112 ) ( -48 -696 112 ) ( -48 -696 16 ) eden/woodfloor -16 -8 0.00 1 1 0 0 0 +( -64 -696 112 ) ( -64 -576 112 ) ( -64 -576 16 ) eden/woodfloor 0 -8 0.00 1 1 0 0 0 +( -48 -576 112 ) ( -304 -576 112 ) ( -304 -576 16 ) eden/woodfloor -16 -8 0.00 1 1 0 0 0 +( -304 -576 112 ) ( -304 -696 112 ) ( -304 -696 16 ) eden/woodfloor 0 -8 0.00 1 1 0 0 0 +} +// brush 21 +{ +( -64 -576 0 ) ( -320 -576 0 ) ( -320 -696 0 ) eden/woodfloor 0 0 0.00 1 1 0 0 0 +( -320 -696 16 ) ( -320 -576 16 ) ( -64 -576 16 ) eden/woodfloor 0 0 0.00 1 1 0 0 0 +( -320 -696 96 ) ( -64 -696 96 ) ( -64 -696 0 ) eden/woodfloor 0 -24 0.00 1 1 0 0 0 +( -64 -696 96 ) ( -64 -576 96 ) ( -64 -576 0 ) eden/woodfloor 0 -24 0.00 1 1 0 0 0 +( -64 -576 96 ) ( -320 -576 96 ) ( -320 -576 0 ) eden/woodfloor 0 -24 0.00 1 1 0 0 0 +( -320 -576 96 ) ( -320 -696 96 ) ( -320 -696 0 ) eden/woodfloor 0 -24 0.00 1 1 0 0 0 +} +// brush 22 +{ +( -64 -264 0 ) ( -320 -264 0 ) ( -320 -384 0 ) eden/woodfloor 0 -8 0.00 1 1 0 0 0 +( -320 -384 16 ) ( -320 -264 16 ) ( -64 -264 16 ) eden/woodfloor 0 -8 0.00 1 1 0 0 0 +( -320 -384 96 ) ( -64 -384 96 ) ( -64 -384 0 ) eden/woodfloor 0 -24 0.00 1 1 0 0 0 +( -64 -384 96 ) ( -64 -264 96 ) ( -64 -264 0 ) eden/woodfloor 72 -24 0.00 1 1 0 0 0 +( -64 -264 96 ) ( -320 -264 96 ) ( -320 -264 0 ) eden/woodfloor 0 -24 0.00 1 1 0 0 0 +( -320 -264 96 ) ( -320 -384 96 ) ( -320 -384 0 ) eden/woodfloor 72 -24 0.00 1 1 0 0 0 +} +// brush 23 +{ +( -48 -264 16 ) ( -304 -264 16 ) ( -304 -384 16 ) eden/woodfloor -16 -8 0.00 1 1 0 0 0 +( -304 -384 32 ) ( -304 -264 32 ) ( -48 -264 32 ) eden/woodfloor -16 -8 0.00 1 1 0 0 0 +( -304 -384 112 ) ( -48 -384 112 ) ( -48 -384 16 ) eden/woodfloor -16 -8 0.00 1 1 0 0 0 +( -64 -384 112 ) ( -64 -264 112 ) ( -64 -264 16 ) eden/woodfloor 72 -8 0.00 1 1 0 0 0 +( -48 -264 112 ) ( -304 -264 112 ) ( -304 -264 16 ) eden/woodfloor -16 -8 0.00 1 1 0 0 0 +( -304 -264 112 ) ( -304 -384 112 ) ( -304 -384 16 ) eden/woodfloor 72 -8 0.00 1 1 0 0 0 +} +// brush 24 +{ +( -32 -264 32 ) ( -288 -264 32 ) ( -288 -384 32 ) eden/woodfloor -32 -8 0.00 1 1 0 0 0 +( -288 -384 48 ) ( -288 -264 48 ) ( -32 -264 48 ) eden/woodfloor -32 -8 0.00 1 1 0 0 0 +( -288 -384 128 ) ( -32 -384 128 ) ( -32 -384 32 ) eden/woodfloor -32 8 0.00 1 1 0 0 0 +( -64 -384 128 ) ( -64 -264 128 ) ( -64 -264 32 ) eden/woodfloor 72 8 0.00 1 1 0 0 0 +( -32 -264 128 ) ( -288 -264 128 ) ( -288 -264 32 ) eden/woodfloor -32 8 0.00 1 1 0 0 0 +( -288 -264 128 ) ( -288 -384 128 ) ( -288 -384 32 ) eden/woodfloor 72 8 0.00 1 1 0 0 0 +} +// brush 25 +{ +( -16 -264 48 ) ( -272 -264 48 ) ( -272 -384 48 ) eden/woodfloor -48 -8 0.00 1 1 0 0 0 +( -272 -384 64 ) ( -272 -264 64 ) ( -16 -264 64 ) eden/woodfloor -48 -8 0.00 1 1 0 0 0 +( -272 -384 144 ) ( -16 -384 144 ) ( -16 -384 48 ) eden/woodfloor -48 24 0.00 1 1 0 0 0 +( -64 -384 144 ) ( -64 -264 144 ) ( -64 -264 48 ) eden/woodfloor 72 24 0.00 1 1 0 0 0 +( -16 -264 144 ) ( -272 -264 144 ) ( -272 -264 48 ) eden/woodfloor -48 24 0.00 1 1 0 0 0 +( -272 -264 144 ) ( -272 -384 144 ) ( -272 -384 48 ) eden/woodfloor 72 24 0.00 1 1 0 0 0 +} +// brush 26 +{ +( 0 -264 64 ) ( -256 -264 64 ) ( -256 -384 64 ) eden/woodfloor -64 -8 0.00 1 1 0 0 0 +( -256 -384 80 ) ( -256 -264 80 ) ( 0 -264 80 ) eden/woodfloor -64 -8 0.00 1 1 0 0 0 +( -256 -384 160 ) ( 0 -384 160 ) ( 0 -384 64 ) eden/woodfloor -64 -24 0.00 1 1 0 0 0 +( -64 -384 160 ) ( -64 -264 160 ) ( -64 -264 64 ) eden/woodfloor 72 -24 0.00 1 1 0 0 0 +( 0 -264 160 ) ( -256 -264 160 ) ( -256 -264 64 ) eden/woodfloor -64 -24 0.00 1 1 0 0 0 +( -256 -264 160 ) ( -256 -384 160 ) ( -256 -384 64 ) eden/woodfloor 72 -24 0.00 1 1 0 0 0 +} +// brush 27 +{ +( 16 -264 80 ) ( -240 -264 80 ) ( -240 -384 80 ) eden/woodfloor -80 -8 0.00 1 1 0 0 0 +( -240 -384 96 ) ( -240 -264 96 ) ( 16 -264 96 ) eden/woodfloor -80 -8 0.00 1 1 0 0 0 +( -240 -384 176 ) ( 16 -384 176 ) ( 16 -384 80 ) eden/woodfloor -80 -8 0.00 1 1 0 0 0 +( -64 -384 176 ) ( -64 -264 176 ) ( -64 -264 80 ) eden/woodfloor 72 -8 0.00 1 1 0 0 0 +( 16 -264 176 ) ( -240 -264 176 ) ( -240 -264 80 ) eden/woodfloor -80 -8 0.00 1 1 0 0 0 +( -240 -264 176 ) ( -240 -384 176 ) ( -240 -384 80 ) eden/woodfloor 72 -8 0.00 1 1 0 0 0 +} +// brush 28 +{ +( 32 -264 96 ) ( -224 -264 96 ) ( -224 -384 96 ) eden/woodfloor -96 -8 0.00 1 1 0 0 0 +( -224 -384 112 ) ( -224 -264 112 ) ( 32 -264 112 ) eden/woodfloor -96 -8 0.00 1 1 0 0 0 +( -224 -384 192 ) ( 32 -384 192 ) ( 32 -384 96 ) eden/woodfloor -96 8 0.00 1 1 0 0 0 +( -64 -384 192 ) ( -64 -264 192 ) ( -64 -264 96 ) eden/woodfloor 72 8 0.00 1 1 0 0 0 +( 32 -264 192 ) ( -224 -264 192 ) ( -224 -264 96 ) eden/woodfloor -96 8 0.00 1 1 0 0 0 +( -224 -264 192 ) ( -224 -384 192 ) ( -224 -384 96 ) eden/woodfloor 72 8 0.00 1 1 0 0 0 +} +// brush 29 +{ +( 48 -264 112 ) ( -208 -264 112 ) ( -208 -384 112 ) eden/woodfloor -112 -8 0.00 1 1 0 0 0 +( -208 -384 128 ) ( -208 -264 128 ) ( 48 -264 128 ) eden/woodfloor -112 -8 0.00 1 1 0 0 0 +( -208 -384 208 ) ( 48 -384 208 ) ( 48 -384 112 ) eden/woodfloor -112 24 0.00 1 1 0 0 0 +( -64 -384 208 ) ( -64 -264 208 ) ( -64 -264 112 ) eden/woodfloor 72 24 0.00 1 1 0 0 0 +( 48 -264 208 ) ( -208 -264 208 ) ( -208 -264 112 ) eden/woodfloor -112 24 0.00 1 1 0 0 0 +( -208 -264 208 ) ( -208 -384 208 ) ( -208 -384 112 ) eden/woodfloor 72 24 0.00 1 1 0 0 0 +} +// brush 30 +{ +( 64 -264 128 ) ( -192 -264 128 ) ( -192 -384 128 ) eden/woodfloor 0 -8 0.00 1 1 0 0 0 +( -192 -384 144 ) ( -192 -264 144 ) ( 64 -264 144 ) eden/woodfloor 0 -8 0.00 1 1 0 0 0 +( -192 -384 224 ) ( 64 -384 224 ) ( 64 -384 128 ) eden/woodfloor 0 -24 0.00 1 1 0 0 0 +( -64 -376 224 ) ( -64 -256 224 ) ( -64 -256 128 ) eden/woodfloor 72 -24 0.00 1 1 0 0 0 +( 64 -264 224 ) ( -192 -264 224 ) ( -192 -264 128 ) eden/woodfloor 0 -24 0.00 1 1 0 0 0 +( -192 -264 224 ) ( -192 -384 224 ) ( -192 -384 128 ) eden/woodfloor 72 -24 0.00 1 1 0 0 0 +} +// brush 31 +{ +( 80 -264 144 ) ( -176 -264 144 ) ( -176 -384 144 ) eden/woodfloor -16 -8 0.00 1 1 0 0 0 +( -176 -384 160 ) ( -176 -264 160 ) ( 80 -264 160 ) eden/woodfloor -16 -8 0.00 1 1 0 0 0 +( -176 -384 240 ) ( 80 -384 240 ) ( 80 -384 144 ) eden/woodfloor -16 -8 0.00 1 1 0 0 0 +( -64 -376 240 ) ( -64 -256 240 ) ( -64 -256 144 ) eden/woodfloor 72 -8 0.00 1 1 0 0 0 +( 80 -264 240 ) ( -176 -264 240 ) ( -176 -264 144 ) eden/woodfloor -16 -8 0.00 1 1 0 0 0 +( -176 -264 240 ) ( -176 -384 240 ) ( -176 -384 144 ) eden/woodfloor 72 -8 0.00 1 1 0 0 0 +} +// brush 32 +{ +( 96 -264 160 ) ( -160 -264 160 ) ( -160 -384 160 ) eden/woodfloor -32 -8 0.00 1 1 0 0 0 +( -160 -384 176 ) ( -160 -264 176 ) ( 96 -264 176 ) eden/woodfloor -32 -8 0.00 1 1 0 0 0 +( -160 -384 256 ) ( 96 -384 256 ) ( 96 -384 160 ) eden/woodfloor -32 8 0.00 1 1 0 0 0 +( -64 -376 256 ) ( -64 -256 256 ) ( -64 -256 160 ) eden/woodfloor 72 8 0.00 1 1 0 0 0 +( 96 -264 256 ) ( -160 -264 256 ) ( -160 -264 160 ) eden/woodfloor -32 8 0.00 1 1 0 0 0 +( -160 -264 256 ) ( -160 -384 256 ) ( -160 -384 160 ) eden/woodfloor 72 8 0.00 1 1 0 0 0 +} +// brush 33 +{ +( 96 64 160 ) ( -160 64 160 ) ( -160 -56 160 ) eden/woodfloor -32 0 0.00 1 1 0 0 0 +( -160 -56 176 ) ( -160 64 176 ) ( 96 64 176 ) eden/woodfloor -32 0 0.00 1 1 0 0 0 +( -160 -56 256 ) ( 96 -56 256 ) ( 96 -56 160 ) eden/woodfloor -32 8 0.00 1 1 0 0 0 +( -64 -48 256 ) ( -64 72 256 ) ( -64 72 160 ) eden/woodfloor 0 8 0.00 1 1 0 0 0 +( 96 64 256 ) ( -160 64 256 ) ( -160 64 160 ) eden/woodfloor -32 8 0.00 1 1 0 0 0 +( -160 64 256 ) ( -160 -56 256 ) ( -160 -56 160 ) eden/woodfloor 0 8 0.00 1 1 0 0 0 +} +// brush 34 +{ +( 80 64 144 ) ( -176 64 144 ) ( -176 -56 144 ) eden/woodfloor -16 0 0.00 1 1 0 0 0 +( -176 -56 160 ) ( -176 64 160 ) ( 80 64 160 ) eden/woodfloor -16 0 0.00 1 1 0 0 0 +( -176 -56 240 ) ( 80 -56 240 ) ( 80 -56 144 ) eden/woodfloor -16 -8 0.00 1 1 0 0 0 +( -64 -48 240 ) ( -64 72 240 ) ( -64 72 144 ) eden/woodfloor 0 -8 0.00 1 1 0 0 0 +( 80 64 240 ) ( -176 64 240 ) ( -176 64 144 ) eden/woodfloor -16 -8 0.00 1 1 0 0 0 +( -176 64 240 ) ( -176 -56 240 ) ( -176 -56 144 ) eden/woodfloor 0 -8 0.00 1 1 0 0 0 +} +// brush 35 +{ +( 64 64 128 ) ( -192 64 128 ) ( -192 -56 128 ) eden/woodfloor 0 0 0.00 1 1 0 0 0 +( -192 -56 144 ) ( -192 64 144 ) ( 64 64 144 ) eden/woodfloor 0 0 0.00 1 1 0 0 0 +( -192 -56 224 ) ( 64 -56 224 ) ( 64 -56 128 ) eden/woodfloor 0 -24 0.00 1 1 0 0 0 +( -64 -48 224 ) ( -64 72 224 ) ( -64 72 128 ) eden/woodfloor 0 -24 0.00 1 1 0 0 0 +( 64 64 224 ) ( -192 64 224 ) ( -192 64 128 ) eden/woodfloor 0 -24 0.00 1 1 0 0 0 +( -192 64 224 ) ( -192 -56 224 ) ( -192 -56 128 ) eden/woodfloor 0 -24 0.00 1 1 0 0 0 +} +// brush 36 +{ +( 48 64 112 ) ( -208 64 112 ) ( -208 -56 112 ) eden/woodfloor -112 0 0.00 1 1 0 0 0 +( -208 -56 128 ) ( -208 64 128 ) ( 48 64 128 ) eden/woodfloor -112 0 0.00 1 1 0 0 0 +( -208 -56 208 ) ( 48 -56 208 ) ( 48 -56 112 ) eden/woodfloor -112 24 0.00 1 1 0 0 0 +( -64 -56 208 ) ( -64 64 208 ) ( -64 64 112 ) eden/woodfloor 0 24 0.00 1 1 0 0 0 +( 48 64 208 ) ( -208 64 208 ) ( -208 64 112 ) eden/woodfloor -112 24 0.00 1 1 0 0 0 +( -208 64 208 ) ( -208 -56 208 ) ( -208 -56 112 ) eden/woodfloor 0 24 0.00 1 1 0 0 0 +} +// brush 37 +{ +( 32 64 96 ) ( -224 64 96 ) ( -224 -56 96 ) eden/woodfloor -96 0 0.00 1 1 0 0 0 +( -224 -56 112 ) ( -224 64 112 ) ( 32 64 112 ) eden/woodfloor -96 0 0.00 1 1 0 0 0 +( -224 -56 192 ) ( 32 -56 192 ) ( 32 -56 96 ) eden/woodfloor -96 8 0.00 1 1 0 0 0 +( -64 -56 192 ) ( -64 64 192 ) ( -64 64 96 ) eden/woodfloor 0 8 0.00 1 1 0 0 0 +( 32 64 192 ) ( -224 64 192 ) ( -224 64 96 ) eden/woodfloor -96 8 0.00 1 1 0 0 0 +( -224 64 192 ) ( -224 -56 192 ) ( -224 -56 96 ) eden/woodfloor 0 8 0.00 1 1 0 0 0 +} +// brush 38 +{ +( 16 64 80 ) ( -240 64 80 ) ( -240 -56 80 ) eden/woodfloor -80 0 0.00 1 1 0 0 0 +( -240 -56 96 ) ( -240 64 96 ) ( 16 64 96 ) eden/woodfloor -80 0 0.00 1 1 0 0 0 +( -240 -56 176 ) ( 16 -56 176 ) ( 16 -56 80 ) eden/woodfloor -80 -8 0.00 1 1 0 0 0 +( -64 -56 176 ) ( -64 64 176 ) ( -64 64 80 ) eden/woodfloor 0 -8 0.00 1 1 0 0 0 +( 16 64 176 ) ( -240 64 176 ) ( -240 64 80 ) eden/woodfloor -80 -8 0.00 1 1 0 0 0 +( -240 64 176 ) ( -240 -56 176 ) ( -240 -56 80 ) eden/woodfloor 0 -8 0.00 1 1 0 0 0 +} +// brush 39 +{ +( 0 64 64 ) ( -256 64 64 ) ( -256 -56 64 ) eden/woodfloor -64 0 0.00 1 1 0 0 0 +( -256 -56 80 ) ( -256 64 80 ) ( 0 64 80 ) eden/woodfloor -64 0 0.00 1 1 0 0 0 +( -256 -56 160 ) ( 0 -56 160 ) ( 0 -56 64 ) eden/woodfloor -64 -24 0.00 1 1 0 0 0 +( -64 -56 160 ) ( -64 64 160 ) ( -64 64 64 ) eden/woodfloor 0 -24 0.00 1 1 0 0 0 +( 0 64 160 ) ( -256 64 160 ) ( -256 64 64 ) eden/woodfloor -64 -24 0.00 1 1 0 0 0 +( -256 64 160 ) ( -256 -56 160 ) ( -256 -56 64 ) eden/woodfloor 0 -24 0.00 1 1 0 0 0 +} +// brush 40 +{ +( -16 64 48 ) ( -272 64 48 ) ( -272 -56 48 ) eden/woodfloor -48 0 0.00 1 1 0 0 0 +( -272 -56 64 ) ( -272 64 64 ) ( -16 64 64 ) eden/woodfloor -48 0 0.00 1 1 0 0 0 +( -272 -56 144 ) ( -16 -56 144 ) ( -16 -56 48 ) eden/woodfloor -48 24 0.00 1 1 0 0 0 +( -64 -56 144 ) ( -64 64 144 ) ( -64 64 48 ) eden/woodfloor 0 24 0.00 1 1 0 0 0 +( -16 64 144 ) ( -272 64 144 ) ( -272 64 48 ) eden/woodfloor -48 24 0.00 1 1 0 0 0 +( -272 64 144 ) ( -272 -56 144 ) ( -272 -56 48 ) eden/woodfloor 0 24 0.00 1 1 0 0 0 +} +// brush 41 +{ +( -32 64 32 ) ( -288 64 32 ) ( -288 -56 32 ) eden/woodfloor -32 0 0.00 1 1 0 0 0 +( -288 -56 48 ) ( -288 64 48 ) ( -32 64 48 ) eden/woodfloor -32 0 0.00 1 1 0 0 0 +( -288 -56 128 ) ( -32 -56 128 ) ( -32 -56 32 ) eden/woodfloor -32 8 0.00 1 1 0 0 0 +( -64 -56 128 ) ( -64 64 128 ) ( -64 64 32 ) eden/woodfloor 0 8 0.00 1 1 0 0 0 +( -32 64 128 ) ( -288 64 128 ) ( -288 64 32 ) eden/woodfloor -32 8 0.00 1 1 0 0 0 +( -288 64 128 ) ( -288 -56 128 ) ( -288 -56 32 ) eden/woodfloor 0 8 0.00 1 1 0 0 0 +} +// brush 42 +{ +( -48 64 16 ) ( -304 64 16 ) ( -304 -56 16 ) eden/woodfloor -16 0 0.00 1 1 0 0 0 +( -304 -56 32 ) ( -304 64 32 ) ( -48 64 32 ) eden/woodfloor -16 0 0.00 1 1 0 0 0 +( -304 -56 112 ) ( -48 -56 112 ) ( -48 -56 16 ) eden/woodfloor -16 -8 0.00 1 1 0 0 0 +( -64 -56 112 ) ( -64 64 112 ) ( -64 64 16 ) eden/woodfloor 0 -8 0.00 1 1 0 0 0 +( -48 64 112 ) ( -304 64 112 ) ( -304 64 16 ) eden/woodfloor -16 -8 0.00 1 1 0 0 0 +( -304 64 112 ) ( -304 -56 112 ) ( -304 -56 16 ) eden/woodfloor 0 -8 0.00 1 1 0 0 0 +} +// brush 43 +{ +( -64 64 0 ) ( -320 64 0 ) ( -320 -56 0 ) eden/woodfloor 0 0 0.00 1 1 0 0 0 +( -320 -56 16 ) ( -320 64 16 ) ( -64 64 16 ) eden/woodfloor 0 0 0.00 1 1 0 0 0 +( -320 -56 96 ) ( -64 -56 96 ) ( -64 -56 0 ) eden/woodfloor 0 -24 0.00 1 1 0 0 0 +( -64 -56 96 ) ( -64 64 96 ) ( -64 64 0 ) eden/woodfloor 0 -24 0.00 1 1 0 0 0 +( -64 64 96 ) ( -320 64 96 ) ( -320 64 0 ) eden/woodfloor 0 -24 0.00 1 1 0 0 0 +( -320 64 96 ) ( -320 -56 96 ) ( -320 -56 0 ) eden/woodfloor 0 -24 0.00 1 1 0 0 0 +} +// brush 44 +{ +( 224 192 0 ) ( 224 224 0 ) ( -480 224 0 ) eden/bedtrim -224 -32 90.00 1 1 0 0 0 +( -480 224 64 ) ( 224 224 64 ) ( 224 192 64 ) eden/bedtrim -224 -32 90.00 1 1 0 0 0 +( -480 224 256 ) ( -480 192 256 ) ( -480 192 0 ) eden/bedtrim -224 0 0.00 1 1 0 0 0 +( -480 192 256 ) ( 224 192 256 ) ( 224 192 0 ) common/skip 0 0 0.00 1 1 805306368 16512 0 +( 224 224 256 ) ( -480 224 256 ) ( -480 224 0 ) eden/bedtrim 224 0 -180.00 1 -1 0 0 0 +( -416 224 0 ) ( -416 192 0 ) ( -416 208 64 ) eden/bedtrim 224 0 -180.00 1 -1 0 0 0 +} +// brush 45 +{ +( 224 192 0 ) ( 224 224 0 ) ( -480 224 0 ) eden/bedtrim -224 -32 90.00 1 1 0 0 0 +( -480 224 64 ) ( 224 224 64 ) ( 224 192 64 ) eden/bedtrim -224 -32 90.00 1 1 0 0 0 +( -480 192 256 ) ( 224 192 256 ) ( 224 192 0 ) eden/bedtrim 224 0 -180.00 1 -1 0 0 0 +( 224 192 256 ) ( 224 224 256 ) ( 224 224 0 ) eden/bedtrim -224 0 0.00 1 1 0 0 0 +( 224 224 256 ) ( -480 224 256 ) ( -480 224 0 ) eden/bedtrim 224 0 -180.00 1 -1 0 0 0 +( -480 192 0 ) ( -480 224 0 ) ( -480 208 64 ) eden/bedtrim 224 0 -180.00 1 -1 0 0 0 +} +// brush 46 +{ +( 224 192 64 ) ( 224 224 64 ) ( -480 224 64 ) eden/edenmetalwall -224 -224 90.00 1 1 0 0 0 +( -480 224 320 ) ( 224 224 320 ) ( 224 192 320 ) eden/edenmetalwall -224 -224 90.00 1 1 0 0 0 +( -480 224 96 ) ( -480 192 96 ) ( -480 192 64 ) eden/edenmetalwall -224 64 0.00 1 1 0 0 0 +( -480 192 96 ) ( 224 192 96 ) ( 224 192 64 ) common/skip 0 0 0.00 1 1 805306368 16512 0 +( 224 224 96 ) ( -480 224 96 ) ( -480 224 64 ) eden/edenmetalwall 224 63 -180.00 1 -1 0 0 0 +( -416 224 64 ) ( -416 192 64 ) ( -416 208 320 ) eden/edenmetalwall 224 63 -180.00 1 -1 0 0 0 +} +// brush 47 +{ +( 224 192 64 ) ( 224 224 64 ) ( -480 224 64 ) eden/edenmetalwall -224 -224 90.00 1 1 0 0 0 +( -480 224 640 ) ( 224 224 640 ) ( 224 192 640 ) eden/edenmetalwall -224 -224 90.00 1 1 0 0 0 +( -480 192 96 ) ( 224 192 96 ) ( 224 192 64 ) eden/edenmetalwall 224 63 -180.00 1 -1 0 0 0 +( 224 192 96 ) ( 224 224 96 ) ( 224 224 64 ) eden/edenmetalwall -224 64 0.00 1 1 0 0 0 +( 224 224 96 ) ( -480 224 96 ) ( -480 224 64 ) eden/edenmetalwall 224 63 -180.00 1 -1 0 0 0 +( -480 192 384 ) ( -480 224 384 ) ( -480 208 640 ) eden/edenmetalwall 224 63 -180.00 1 -1 0 0 0 +} +// brush 48 + { + patchDef2 + { + eden/edenmetalwall + ( 3 3 0 536870912 0 ) +( +( ( -480 96 63.999981 0 0 ) ( -480 96 352.000061 0 0.500000 ) ( -480 96 640 0 1 ) ) +( ( -384 96 63.999981 0.500000 0 ) ( -384 96 352.000061 0.500000 0.500000 ) ( -384 96 640 0.500000 1 ) ) +( ( -384 192 63.999981 1 0 ) ( -384 192 352.000061 1 0.500000 ) ( -384 192 640 1 1 ) ) +) + } + } +// brush 49 +{ +( -480 192 0 ) ( -512 192 0 ) ( -512 -512 0 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +( -512 -512 64 ) ( -512 192 64 ) ( -480 192 64 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +( -480 -512 256 ) ( -480 192 256 ) ( -480 192 0 ) common/skip 0 0 0.00 1 1 805306368 16512 0 +( -480 192 256 ) ( -512 192 256 ) ( -512 192 0 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +( -512 192 256 ) ( -512 -512 256 ) ( -512 -512 0 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +( -480 128 0 ) ( -512 128 0 ) ( -496 128 64 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +} +// brush 50 +{ +( -480 192 0 ) ( -512 192 0 ) ( -512 -512 0 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +( -512 -512 64 ) ( -512 192 64 ) ( -480 192 64 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +( -512 -1272 256 ) ( -480 -1272 256 ) ( -480 -1272 0 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +( -480 -1272 256 ) ( -480 -568 256 ) ( -480 -568 0 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +( -512 192 256 ) ( -512 -512 256 ) ( -512 -512 0 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +( -512 192 0 ) ( -480 192 0 ) ( -496 192 64 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +} +// brush 51 +{ +( -480 192 64 ) ( -512 192 64 ) ( -512 -512 64 ) eden/edenmetalwall 0 0 0.00 1 1 0 0 0 +( -512 -512 320 ) ( -512 192 320 ) ( -480 192 320 ) eden/edenmetalwall 0 0 0.00 1 1 0 0 0 +( -480 -512 96 ) ( -480 192 96 ) ( -480 192 64 ) common/skip 0 0 0.00 1 1 805306368 16512 0 +( -480 192 96 ) ( -512 192 96 ) ( -512 192 64 ) eden/edenmetalwall 0 64 0.00 1 1 0 0 0 +( -512 192 96 ) ( -512 -512 96 ) ( -512 -512 64 ) eden/edenmetalwall 0 64 0.00 1 1 0 0 0 +( -480 128 64 ) ( -512 128 64 ) ( -496 128 320 ) eden/edenmetalwall 0 64 0.00 1 1 0 0 0 +} +// brush 52 +{ +( -480 192 64 ) ( -512 192 64 ) ( -512 -512 64 ) eden/edenmetalwall 0 0 0.00 1 1 0 0 0 +( -512 -512 640 ) ( -512 192 640 ) ( -480 192 640 ) eden/edenmetalwall 0 0 0.00 1 1 0 0 0 +( -512 -1272 96 ) ( -480 -1272 96 ) ( -480 -1272 64 ) eden/edenmetalwall 0 64 0.00 1 1 0 0 0 +( -480 -1272 416 ) ( -480 -568 416 ) ( -480 -568 384 ) eden/edenmetalwall 0 64 0.00 1 1 0 0 0 +( -512 192 96 ) ( -512 -512 96 ) ( -512 -512 64 ) eden/edenmetalwall 0 64 0.00 1 1 0 0 0 +( -512 192 64 ) ( -480 192 64 ) ( -496 192 320 ) eden/edenmetalwall 0 64 0.00 1 1 0 0 0 +} +// brush 53 + { + patchDef2 + { + eden/bedtrim + ( 3 3 0 536870912 0 ) +( +( ( -480 96 0 0 0 ) ( -480 96 32 0 0.500000 ) ( -480 96 64 0 1 ) ) +( ( -384 96 0 0.500000 0 ) ( -384 96 32 0.500000 0.500000 ) ( -384 96 64 0.500000 1 ) ) +( ( -384 192 0 1 0 ) ( -384 192 32 1 0.500000 ) ( -384 192 64 1 1 ) ) +) + } + } +// brush 54 +{ +( 192 192 608 ) ( -480 192 608 ) ( -480 -512 608 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( -480 -512 640 ) ( -480 192 640 ) ( 192 192 640 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( -480 -1272 640 ) ( 192 -1272 640 ) ( 192 -1272 608 ) eden/CL_edenroof3 0 -96 0.00 1 1 0 0 0 +( 192 192 640 ) ( -480 192 640 ) ( -480 192 608 ) eden/CL_edenroof3 0 -96 0.00 1 1 0 0 0 +( -480 -568 640 ) ( -480 -1272 640 ) ( -480 -1272 608 ) eden/CL_edenroof3 0 -96 0.00 1 1 0 0 0 +( 216 -112 608 ) ( 216 -240 608 ) ( 216 -176 640 ) eden/CL_edenroof3 0 -96 0.00 1 1 0 0 0 +} +// brush 55 +{ +( 192 192 -32 ) ( -480 192 -32 ) ( -480 -512 -32 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( -480 -512 0 ) ( -480 192 0 ) ( 192 192 0 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( -480 -1272 224 ) ( 192 -1272 224 ) ( 192 -1272 -32 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 192 -1272 224 ) ( 192 -568 224 ) ( 192 -568 -32 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 192 192 224 ) ( -480 192 224 ) ( -480 192 -32 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( -480 -568 224 ) ( -480 -1272 224 ) ( -480 -1272 -32 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +} +// brush 56 +{ +( -480 -512 64 ) ( -480 -544 64 ) ( 224 -544 64 ) eden/edenmetalwall -31 31 -90.00 1 1 0 0 0 +( 224 -544 640 ) ( -480 -544 640 ) ( -480 -512 640 ) eden/edenmetalwall -31 31 -90.00 1 1 0 0 0 +( 224 -544 96 ) ( 224 -512 96 ) ( 224 -512 64 ) eden/edenmetalwall -32 63 -180.00 1 -1 0 0 0 +( 224 -1272 96 ) ( -480 -1272 96 ) ( -480 -1272 64 ) eden/edenmetalwall -32 62 0.00 1.000008 1 0 0 0 +( -480 -1272 416 ) ( -480 -1304 416 ) ( -480 -1304 384 ) eden/edenmetalwall -33 63 -180.00 1 -1 0 0 0 +( -480 -1304 96 ) ( 224 -1304 96 ) ( 224 -1304 64 ) eden/edenmetalwall -32 62 0.00 1.000008 1 0 0 0 +} +// brush 57 +{ +( -496 -1240 0 ) ( -496 -1272 0 ) ( 208 -1272 0 ) eden/bedtrim -247 16 -90.00 1 1 0 0 0 +( 208 -1272 64 ) ( -496 -1272 64 ) ( -496 -1240 64 ) eden/bedtrim -247 16 -90.00 1 1 0 0 0 +( 208 -1272 256 ) ( 208 -1240 256 ) ( 208 -1240 0 ) eden/bedtrim -248 0 -180.00 1 -1 0 0 0 +( 208 -1240 256 ) ( -496 -1240 256 ) ( -496 -1240 0 ) eden/bedtrim -16 0 0.00 1 1 0 0 0 +( -496 -1240 256 ) ( -496 -1272 256 ) ( -496 -1272 0 ) eden/bedtrim -249 0 -180.00 1 -1 0 0 0 +( -496 -1272 256 ) ( 208 -1272 256 ) ( 208 -1272 0 ) eden/bedtrim -16 0 0.00 1 1 0 0 0 +} +// brush 58 +{ +( 192 -512 0 ) ( 224 -512 0 ) ( 224 192 0 ) eden/bedtrim 160 0 -180.00 1 1 0 0 0 +( 224 192 64 ) ( 224 -512 64 ) ( 192 -512 64 ) eden/bedtrim 160 0 -180.00 1 1 0 0 0 +( 224 192 256 ) ( 192 192 256 ) ( 192 192 0 ) eden/bedtrim 160 0 -180.00 1 -1 0 0 0 +( 192 -568 256 ) ( 192 -1272 256 ) ( 192 -1272 0 ) eden/bedtrim -64 0 -180.00 1 -1 0 0 0 +( 192 -1272 256 ) ( 224 -1272 256 ) ( 224 -1272 0 ) eden/bedtrim 159 0 -180.00 1 -1 0 0 0 +( 224 -512 256 ) ( 224 192 256 ) ( 224 192 0 ) eden/bedtrim -64 0 -180.00 1 -1 0 0 0 +} +// brush 59 +{ +( 192 -512 64 ) ( 224 -512 64 ) ( 224 192 64 ) eden/edenmetalwall 160 63 -180.00 1 1 0 0 0 +( 224 192 640 ) ( 224 -512 640 ) ( 192 -512 640 ) eden/edenmetalwall 160 63 -180.00 1 1 0 0 0 +( 224 192 96 ) ( 192 192 96 ) ( 192 192 64 ) eden/edenmetalwall 160 64 -180.00 1 -1 0 0 0 +( 192 -568 416 ) ( 192 -1272 416 ) ( 192 -1272 384 ) eden/edenmetalwall -64 62 -180.00 1 -1 0 0 0 +( 192 -1272 96 ) ( 224 -1272 96 ) ( 224 -1272 64 ) eden/edenmetalwall 159 64 -180.00 1 -1 0 0 0 +( 224 -512 96 ) ( 224 192 96 ) ( 224 192 64 ) eden/edenmetalwall -64 62 -180.00 1 -1 0 0 0 +} +} +// entity 1 +{ +"classname" "func_sinkobject" +// brush 0 +{ +( 112 64 144 ) ( 0 64 144 ) ( 0 -56 144 ) swamps/FL_lilypad 0 0 0.00 1 1 0 0 0 +( 0 -56 160 ) ( 0 64 160 ) ( 112 64 160 ) swamps/FL_lilypad 72 128 0.00 1 1 0 0 0 +( 8 -96 160 ) ( 120 -96 160 ) ( 120 -96 144 ) swamps/FL_lilypad 0 0 0.00 1 1 0 0 0 +( 160 -48 160 ) ( 160 72 160 ) ( 160 72 144 ) swamps/FL_lilypad 0 0 0.00 1 1 0 0 0 +( 112 104 160 ) ( 0 104 160 ) ( 0 104 144 ) swamps/FL_lilypad 0 0 0.00 1 1 0 0 0 +( -40 56 160 ) ( -40 -64 160 ) ( -40 -64 144 ) swamps/FL_lilypad 0 0 0.00 1 1 0 0 0 +} +} +// entity 2 +{ +"_color" "1.000000 0.724409 0.523622" +"light" "200" +"origin" "-352 56 168" +"spawnflags" "0" +"classname" "light" +} +// entity 3 +{ +"origin" "-416 -176 24" +"angle" "0" +"classname" "info_player_start" +} +// entity 4 +{ +"_color" "0.629921 0.846457 1.000000" +"light" "200" +"classname" "light" +"spawnflags" "0" +"origin" "8 56 168" +} +// entity 5 +{ +"light" "200" +"classname" "light" +"spawnflags" "0" +"origin" "-344 -376 168" +} +// entity 6 +{ +"light" "200" +"origin" "8 -376 168" +"spawnflags" "0" +"classname" "light" +} +// entity 7 +{ +"origin" "-168 -160 168" +"spawnflags" "0" +"classname" "light" +"light" "200" +} +// entity 8 +{ +"classname" "light" +"spawnflags" "0" +"origin" "-352 56 384" +"light" "200" +"_color" "1.000000 0.724409 0.523622" +} +// entity 9 +{ +"origin" "8 56 384" +"spawnflags" "0" +"classname" "light" +"light" "200" +"_color" "0.629921 0.846457 1.000000" +} +// entity 10 +{ +"origin" "-344 -376 384" +"spawnflags" "0" +"classname" "light" +"light" "200" +} +// entity 11 +{ +"classname" "light" +"spawnflags" "0" +"origin" "8 -376 384" +"light" "200" +} +// entity 12 +{ +"light" "200" +"classname" "light" +"spawnflags" "0" +"origin" "-168 -160 384" +} +// entity 13 +{ +"_color" "1.000000 0.724409 0.523622" +"light" "200" +"origin" "-344 -656 384" +"spawnflags" "0" +"classname" "light" +} +// entity 14 +{ +"_color" "0.629921 0.846457 1.000000" +"light" "200" +"classname" "light" +"spawnflags" "0" +"origin" "16 -656 384" +} +// entity 15 +{ +"light" "200" +"classname" "light" +"spawnflags" "0" +"origin" "-336 -1088 384" +} +// entity 16 +{ +"light" "200" +"origin" "16 -1088 384" +"spawnflags" "0" +"classname" "light" +} +// entity 17 +{ +"origin" "-160 -872 384" +"spawnflags" "0" +"classname" "light" +"light" "200" +} +// entity 18 +{ +"classname" "func_sinkobject" +"spawnflags" "4" +// brush 0 +{ +( 112 -264 144 ) ( 0 -264 144 ) ( 0 -384 144 ) swamps/FL_lilypad 0 -8 0.00 1 1 0 0 0 +( 0 -384 160 ) ( 0 -264 160 ) ( 112 -264 160 ) swamps/FL_lilypad 72 -200 0.00 1 1 0 0 0 +( 8 -424 160 ) ( 120 -424 160 ) ( 120 -424 144 ) swamps/FL_lilypad 0 0 0.00 1 1 0 0 0 +( 160 -376 160 ) ( 160 -256 160 ) ( 160 -256 144 ) swamps/FL_lilypad 8 0 0.00 1 1 0 0 0 +( 112 -224 160 ) ( 0 -224 160 ) ( 0 -224 144 ) swamps/FL_lilypad 0 0 0.00 1 1 0 0 0 +( -40 -272 160 ) ( -40 -392 160 ) ( -40 -392 144 ) swamps/FL_lilypad 8 0 0.00 1 1 0 0 0 +} +} +// entity 19 +{ +"classname" "func_sinkobject" +"spawnflags" "2" +// brush 0 +{ +( 112 -576 144 ) ( 0 -576 144 ) ( 0 -696 144 ) swamps/FL_lilypad 0 0 0.00 1 1 0 0 0 +( 0 -696 160 ) ( 0 -576 160 ) ( 112 -576 160 ) swamps/FL_lilypad 72 0 0.00 1 1 0 0 0 +( 8 -736 160 ) ( 120 -736 160 ) ( 120 -736 144 ) swamps/FL_lilypad 0 0 0.00 1 1 0 0 0 +( 160 -688 160 ) ( 160 -568 160 ) ( 160 -568 144 ) swamps/FL_lilypad 0 0 0.00 1 1 0 0 0 +( 112 -536 160 ) ( 0 -536 160 ) ( 0 -536 144 ) swamps/FL_lilypad 0 0 0.00 1 1 0 0 0 +( -40 -584 160 ) ( -40 -704 160 ) ( -40 -704 144 ) swamps/FL_lilypad 0 0 0.00 1 1 0 0 0 +} +} +// entity 20 +{ +"classname" "func_sinkobject" +"speed" "1" +// brush 0 +{ +( 112 -896 144 ) ( 0 -896 144 ) ( 0 -1016 144 ) swamps/FL_lilypad 0 0 0.00 1 1 0 0 0 +( 0 -1016 160 ) ( 0 -896 160 ) ( 112 -896 160 ) swamps/FL_lilypad 72 -64 0.00 1 1 0 0 0 +( 8 -1056 160 ) ( 120 -1056 160 ) ( 120 -1056 144 ) swamps/FL_lilypad 0 0 0.00 1 1 0 0 0 +( 160 -1008 160 ) ( 160 -888 160 ) ( 160 -888 144 ) swamps/FL_lilypad 0 0 0.00 1 1 0 0 0 +( 112 -856 160 ) ( 0 -856 160 ) ( 0 -856 144 ) swamps/FL_lilypad 0 0 0.00 1 1 0 0 0 +( -40 -904 160 ) ( -40 -1024 160 ) ( -40 -1024 144 ) swamps/FL_lilypad 0 0 0.00 1 1 0 0 0 +} +} diff --git a/fakk/maps/example/sinkobject.prt b/fakk/maps/example/sinkobject.prt new file mode 100644 index 0000000..86e3e9d --- /dev/null +++ b/fakk/maps/example/sinkobject.prt @@ -0,0 +1,510 @@ +PRT1 +73 +217 +289 +4 0 4 0 (0 0 0 ) (0 0 608 ) (0 192 608 ) (0 192 0 ) +4 0 1 0 (0 0 608 ) (0 0 0 ) (192 0 0 ) (192 0 608 ) +4 1 18 0 (0 -1024 0 ) (0 -1024 608 ) (0 0 608 ) (0 0 0 ) +4 1 3 0 (0 -1024 64 ) (0 -1024 0 ) (192 -1024 0 ) (192 -1024 64 ) +4 1 2 0 (0 -1024 608 ) (0 -1024 64 ) (192 -1024 64 ) (192 -1024 608 ) +4 2 71 0 (0 -1272 608 ) (0 -1024 608 ) (0 -1024 64 ) (0 -1272 64 ) +4 2 3 0 (0 -1240 64 ) (0 -1024 64 ) (192 -1024 64 ) (192 -1240 64 ) +4 3 72 0 (0 -1240 64 ) (0 -1024 64 ) (0 -1024 0 ) (0 -1240 0 ) +4 4 18 0 (0 0 0 ) (0 0 608 ) (-64 0 608 ) (-64 0 0 ) +4 4 6 0 (-64 0 176 ) (-64 0 608 ) (-64 64 608 ) (-64 64 176 ) +4 4 5 0 (-64 64 608 ) (-64 192 608 ) (-64 192 0 ) (-64 64 0 ) +4 5 12 0 (-256 64 96 ) (-256 64 80 ) (-240 64 80 ) (-240 64 96 ) +4 5 11 0 (-224 64 112 ) (-256 64 112 ) (-256 64 96 ) (-224 64 96 ) +4 5 13 0 (-256 64 112 ) (-272 64 112 ) (-272 64 64 ) (-256 64 64 ) +4 5 10 0 (-208 64 112 ) (-208 64 128 ) (-272 64 128 ) (-272 64 112 ) +4 5 14 0 (-288 64 128 ) (-288 64 48 ) (-272 64 48 ) (-272 64 128 ) +4 5 9 0 (-192 64 144 ) (-288 64 144 ) (-288 64 128 ) (-192 64 128 ) +4 5 15 0 (-288 64 144 ) (-304 64 144 ) (-304 64 32 ) (-288 64 32 ) +4 5 8 0 (-176 64 144 ) (-176 64 160 ) (-304 64 160 ) (-304 64 144 ) +4 5 16 0 (-320 64 160 ) (-320 64 16 ) (-304 64 16 ) (-304 64 160 ) +4 5 7 0 (-160 64 176 ) (-320 64 176 ) (-320 64 160 ) (-160 64 160 ) +4 5 17 0 (-320 64 176 ) (-480 64 176 ) (-480 64 0 ) (-320 64 0 ) +4 5 6 0 (-64 64 176 ) (-64 64 608 ) (-480 64 608 ) (-480 64 176 ) +4 6 19 0 (-64 0 176 ) (-64 0 608 ) (-480 0 608 ) (-480 0 176 ) +4 6 7 0 (-320 64 176 ) (-160 64 176 ) (-160 0 176 ) (-320 0 176 ) +4 6 17 0 (-480 0 176 ) (-480 64 176 ) (-320 64 176 ) (-320 0 176 ) +4 7 20 0 (-160 0 176 ) (-320 0 176 ) (-320 0 160 ) (-160 0 160 ) +4 7 8 0 (-304 64 160 ) (-176 64 160 ) (-176 0 160 ) (-304 0 160 ) +4 7 16 0 (-320 0 160 ) (-320 64 160 ) (-304 64 160 ) (-304 0 160 ) +4 7 17 0 (-320 0 160 ) (-320 0 176 ) (-320 64 176 ) (-320 64 160 ) +4 8 21 0 (-176 0 144 ) (-176 0 160 ) (-304 0 160 ) (-304 0 144 ) +4 8 9 0 (-288 64 144 ) (-192 64 144 ) (-192 0 144 ) (-288 0 144 ) +4 8 15 0 (-304 0 144 ) (-304 64 144 ) (-288 64 144 ) (-288 0 144 ) +4 8 16 0 (-304 0 144 ) (-304 0 160 ) (-304 64 160 ) (-304 64 144 ) +4 9 22 0 (-192 0 144 ) (-288 0 144 ) (-288 0 128 ) (-192 0 128 ) +4 9 10 0 (-272 64 128 ) (-208 64 128 ) (-208 0 128 ) (-272 0 128 ) +4 9 14 0 (-288 0 128 ) (-288 64 128 ) (-272 64 128 ) (-272 0 128 ) +4 9 15 0 (-288 0 128 ) (-288 0 144 ) (-288 64 144 ) (-288 64 128 ) +4 10 23 0 (-208 0 112 ) (-208 0 128 ) (-272 0 128 ) (-272 0 112 ) +4 10 11 0 (-256 64 112 ) (-224 64 112 ) (-224 0 112 ) (-256 0 112 ) +4 10 13 0 (-272 0 112 ) (-272 64 112 ) (-256 64 112 ) (-256 0 112 ) +4 10 14 0 (-272 0 112 ) (-272 0 128 ) (-272 64 128 ) (-272 64 112 ) +4 11 24 0 (-224 0 112 ) (-256 0 112 ) (-256 0 96 ) (-224 0 96 ) +4 11 12 0 (-256 0 96 ) (-256 64 96 ) (-240 64 96 ) (-240 0 96 ) +4 11 13 0 (-256 0 96 ) (-256 0 112 ) (-256 64 112 ) (-256 64 96 ) +4 12 25 0 (-256 0 96 ) (-256 0 80 ) (-240 0 80 ) (-240 0 96 ) +4 12 13 0 (-256 0 80 ) (-256 0 96 ) (-256 64 96 ) (-256 64 80 ) +4 13 26 0 (-256 0 112 ) (-272 0 112 ) (-272 0 64 ) (-256 0 64 ) +4 13 14 0 (-272 0 64 ) (-272 0 112 ) (-272 64 112 ) (-272 64 64 ) +4 14 27 0 (-288 0 128 ) (-288 0 48 ) (-272 0 48 ) (-272 0 128 ) +4 14 15 0 (-288 0 48 ) (-288 0 128 ) (-288 64 128 ) (-288 64 48 ) +4 15 28 0 (-288 0 144 ) (-304 0 144 ) (-304 0 32 ) (-288 0 32 ) +4 15 16 0 (-304 0 32 ) (-304 0 144 ) (-304 64 144 ) (-304 64 32 ) +4 16 29 0 (-320 0 160 ) (-320 0 16 ) (-304 0 16 ) (-304 0 160 ) +4 16 17 0 (-320 0 16 ) (-320 0 160 ) (-320 64 160 ) (-320 64 16 ) +4 17 30 0 (-320 0 176 ) (-480 0 176 ) (-480 0 0 ) (-320 0 0 ) +4 18 72 0 (0 -1024 0 ) (0 -1024 64 ) (-64 -1024 64 ) (-64 -1024 0 ) +4 18 71 0 (0 -1024 64 ) (0 -1024 608 ) (-64 -1024 608 ) (-64 -1024 64 ) +4 18 70 0 (-64 -1016 0 ) (-64 -1024 0 ) (-64 -1024 608 ) (-64 -1016 608 ) +4 18 58 0 (-64 -1016 176 ) (-64 -1016 608 ) (-64 -896 608 ) (-64 -896 176 ) +4 18 57 0 (-64 -696 0 ) (-64 -896 0 ) (-64 -896 608 ) (-64 -696 608 ) +4 18 45 0 (-64 -696 176 ) (-64 -696 608 ) (-64 -576 608 ) (-64 -576 176 ) +4 18 44 0 (-64 -384 0 ) (-64 -576 0 ) (-64 -576 608 ) (-64 -384 608 ) +4 18 32 0 (-64 -384 176 ) (-64 -384 608 ) (-64 -264 608 ) (-64 -264 176 ) +4 18 31 0 (-64 -56 0 ) (-64 -264 0 ) (-64 -264 608 ) (-64 -56 608 ) +4 18 19 0 (-64 0 608 ) (-64 0 176 ) (-64 -56 176 ) (-64 -56 608 ) +4 19 31 0 (-64 -56 176 ) (-64 -56 608 ) (-480 -56 608 ) (-480 -56 176 ) +4 19 20 0 (-160 -56 176 ) (-320 -56 176 ) (-320 0 176 ) (-160 0 176 ) +4 19 30 0 (-320 -56 176 ) (-480 -56 176 ) (-480 0 176 ) (-320 0 176 ) +4 20 31 0 (-160 -56 176 ) (-320 -56 176 ) (-320 -56 160 ) (-160 -56 160 ) +4 20 21 0 (-304 0 160 ) (-176 0 160 ) (-176 -56 160 ) (-304 -56 160 ) +4 20 29 0 (-320 -56 160 ) (-320 0 160 ) (-304 0 160 ) (-304 -56 160 ) +4 20 30 0 (-320 -56 160 ) (-320 -56 176 ) (-320 0 176 ) (-320 0 160 ) +4 21 31 0 (-176 -56 144 ) (-176 -56 160 ) (-304 -56 160 ) (-304 -56 144 ) +4 21 22 0 (-288 0 144 ) (-192 0 144 ) (-192 -56 144 ) (-288 -56 144 ) +4 21 28 0 (-304 -56 144 ) (-304 0 144 ) (-288 0 144 ) (-288 -56 144 ) +4 21 29 0 (-304 -56 144 ) (-304 -56 160 ) (-304 0 160 ) (-304 0 144 ) +4 22 31 0 (-192 -56 144 ) (-288 -56 144 ) (-288 -56 128 ) (-192 -56 128 ) +4 22 23 0 (-272 0 128 ) (-208 0 128 ) (-208 -56 128 ) (-272 -56 128 ) +4 22 27 0 (-288 -56 128 ) (-288 0 128 ) (-272 0 128 ) (-272 -56 128 ) +4 22 28 0 (-288 -56 128 ) (-288 -56 144 ) (-288 0 144 ) (-288 0 128 ) +4 23 31 0 (-208 -56 112 ) (-208 -56 128 ) (-272 -56 128 ) (-272 -56 112 ) +4 23 24 0 (-256 0 112 ) (-224 0 112 ) (-224 -56 112 ) (-256 -56 112 ) +4 23 26 0 (-272 -56 112 ) (-272 0 112 ) (-256 0 112 ) (-256 -56 112 ) +4 23 27 0 (-272 -56 112 ) (-272 -56 128 ) (-272 0 128 ) (-272 0 112 ) +4 24 31 0 (-224 -56 112 ) (-256 -56 112 ) (-256 -56 96 ) (-224 -56 96 ) +4 24 25 0 (-256 -56 96 ) (-256 0 96 ) (-240 0 96 ) (-240 -56 96 ) +4 24 26 0 (-256 -56 96 ) (-256 -56 112 ) (-256 0 112 ) (-256 0 96 ) +4 25 31 0 (-256 -56 96 ) (-256 -56 80 ) (-240 -56 80 ) (-240 -56 96 ) +4 25 26 0 (-256 -56 80 ) (-256 -56 96 ) (-256 0 96 ) (-256 0 80 ) +4 26 31 0 (-256 -56 112 ) (-272 -56 112 ) (-272 -56 64 ) (-256 -56 64 ) +4 26 27 0 (-272 -56 64 ) (-272 -56 112 ) (-272 0 112 ) (-272 0 64 ) +4 27 31 0 (-288 -56 128 ) (-288 -56 48 ) (-272 -56 48 ) (-272 -56 128 ) +4 27 28 0 (-288 -56 48 ) (-288 -56 128 ) (-288 0 128 ) (-288 0 48 ) +4 28 31 0 (-288 -56 144 ) (-304 -56 144 ) (-304 -56 32 ) (-288 -56 32 ) +4 28 29 0 (-304 -56 32 ) (-304 -56 144 ) (-304 0 144 ) (-304 0 32 ) +4 29 31 0 (-320 -56 160 ) (-320 -56 16 ) (-304 -56 16 ) (-304 -56 160 ) +4 29 30 0 (-320 -56 16 ) (-320 -56 160 ) (-320 0 160 ) (-320 0 16 ) +4 30 31 0 (-320 -56 176 ) (-480 -56 176 ) (-480 -56 0 ) (-320 -56 0 ) +4 31 43 0 (-320 -264 16 ) (-480 -264 16 ) (-480 -264 0 ) (-320 -264 0 ) +4 31 42 0 (-304 -264 32 ) (-480 -264 32 ) (-480 -264 16 ) (-304 -264 16 ) +4 31 41 0 (-480 -264 48 ) (-480 -264 32 ) (-288 -264 32 ) (-288 -264 48 ) +4 31 40 0 (-480 -264 64 ) (-480 -264 48 ) (-272 -264 48 ) (-272 -264 64 ) +4 31 39 0 (-480 -264 80 ) (-480 -264 64 ) (-256 -264 64 ) (-256 -264 80 ) +4 31 38 0 (-480 -264 96 ) (-480 -264 80 ) (-240 -264 80 ) (-240 -264 96 ) +4 31 36 0 (-208 -264 608 ) (-224 -264 608 ) (-224 -264 112 ) (-208 -264 112 ) +4 31 37 0 (-224 -264 608 ) (-480 -264 608 ) (-480 -264 96 ) (-224 -264 96 ) +4 31 35 0 (-192 -264 608 ) (-208 -264 608 ) (-208 -264 128 ) (-192 -264 128 ) +4 31 34 0 (-176 -264 608 ) (-192 -264 608 ) (-192 -264 144 ) (-176 -264 144 ) +4 31 33 0 (-160 -264 608 ) (-176 -264 608 ) (-176 -264 160 ) (-160 -264 160 ) +4 31 32 0 (-64 -264 176 ) (-64 -264 608 ) (-160 -264 608 ) (-160 -264 176 ) +4 32 44 0 (-64 -384 176 ) (-64 -384 608 ) (-160 -384 608 ) (-160 -384 176 ) +4 32 33 0 (-160 -384 176 ) (-160 -384 608 ) (-160 -264 608 ) (-160 -264 176 ) +4 33 44 0 (-160 -384 608 ) (-176 -384 608 ) (-176 -384 160 ) (-160 -384 160 ) +4 33 34 0 (-176 -384 160 ) (-176 -384 608 ) (-176 -264 608 ) (-176 -264 160 ) +4 34 44 0 (-176 -384 608 ) (-192 -384 608 ) (-192 -384 144 ) (-176 -384 144 ) +4 34 35 0 (-192 -384 144 ) (-192 -384 608 ) (-192 -264 608 ) (-192 -264 144 ) +4 35 44 0 (-192 -384 608 ) (-208 -384 608 ) (-208 -384 128 ) (-192 -384 128 ) +4 35 36 0 (-208 -384 128 ) (-208 -384 608 ) (-208 -264 608 ) (-208 -264 128 ) +4 36 44 0 (-208 -384 608 ) (-224 -384 608 ) (-224 -384 112 ) (-208 -384 112 ) +4 36 37 0 (-224 -384 112 ) (-224 -384 608 ) (-224 -264 608 ) (-224 -264 112 ) +4 37 44 0 (-224 -384 608 ) (-480 -384 608 ) (-480 -384 96 ) (-224 -384 96 ) +4 37 38 0 (-480 -384 96 ) (-480 -264 96 ) (-240 -264 96 ) (-240 -384 96 ) +4 38 44 0 (-480 -384 96 ) (-480 -384 80 ) (-240 -384 80 ) (-240 -384 96 ) +4 38 39 0 (-480 -384 80 ) (-480 -264 80 ) (-256 -264 80 ) (-256 -384 80 ) +4 39 44 0 (-480 -384 80 ) (-480 -384 64 ) (-256 -384 64 ) (-256 -384 80 ) +4 39 40 0 (-480 -384 64 ) (-480 -264 64 ) (-272 -264 64 ) (-272 -384 64 ) +4 40 44 0 (-480 -384 64 ) (-480 -384 48 ) (-272 -384 48 ) (-272 -384 64 ) +4 40 41 0 (-480 -384 48 ) (-480 -264 48 ) (-288 -264 48 ) (-288 -384 48 ) +4 41 44 0 (-480 -384 48 ) (-480 -384 32 ) (-288 -384 32 ) (-288 -384 48 ) +4 41 42 0 (-304 -384 32 ) (-480 -384 32 ) (-480 -264 32 ) (-304 -264 32 ) +4 42 44 0 (-304 -384 32 ) (-480 -384 32 ) (-480 -384 16 ) (-304 -384 16 ) +4 42 43 0 (-320 -384 16 ) (-480 -384 16 ) (-480 -264 16 ) (-320 -264 16 ) +4 43 44 0 (-320 -384 16 ) (-480 -384 16 ) (-480 -384 0 ) (-320 -384 0 ) +4 44 51 0 (-256 -576 96 ) (-256 -576 80 ) (-240 -576 80 ) (-240 -576 96 ) +4 44 50 0 (-224 -576 112 ) (-256 -576 112 ) (-256 -576 96 ) (-224 -576 96 ) +4 44 52 0 (-256 -576 112 ) (-272 -576 112 ) (-272 -576 64 ) (-256 -576 64 ) +4 44 49 0 (-208 -576 112 ) (-208 -576 128 ) (-272 -576 128 ) (-272 -576 112 ) +4 44 53 0 (-288 -576 128 ) (-288 -576 48 ) (-272 -576 48 ) (-272 -576 128 ) +4 44 48 0 (-192 -576 144 ) (-288 -576 144 ) (-288 -576 128 ) (-192 -576 128 ) +4 44 54 0 (-288 -576 144 ) (-304 -576 144 ) (-304 -576 32 ) (-288 -576 32 ) +4 44 47 0 (-176 -576 144 ) (-176 -576 160 ) (-304 -576 160 ) (-304 -576 144 ) +4 44 55 0 (-320 -576 160 ) (-320 -576 16 ) (-304 -576 16 ) (-304 -576 160 ) +4 44 46 0 (-160 -576 176 ) (-320 -576 176 ) (-320 -576 160 ) (-160 -576 160 ) +4 44 56 0 (-320 -576 176 ) (-480 -576 176 ) (-480 -576 0 ) (-320 -576 0 ) +4 44 45 0 (-64 -576 176 ) (-64 -576 608 ) (-480 -576 608 ) (-480 -576 176 ) +4 45 57 0 (-64 -696 176 ) (-64 -696 608 ) (-480 -696 608 ) (-480 -696 176 ) +4 45 46 0 (-160 -696 176 ) (-320 -696 176 ) (-320 -576 176 ) (-160 -576 176 ) +4 45 56 0 (-320 -696 176 ) (-480 -696 176 ) (-480 -576 176 ) (-320 -576 176 ) +4 46 57 0 (-160 -696 176 ) (-320 -696 176 ) (-320 -696 160 ) (-160 -696 160 ) +4 46 47 0 (-304 -576 160 ) (-176 -576 160 ) (-176 -696 160 ) (-304 -696 160 ) +4 46 55 0 (-320 -696 160 ) (-320 -576 160 ) (-304 -576 160 ) (-304 -696 160 ) +4 46 56 0 (-320 -696 160 ) (-320 -696 176 ) (-320 -576 176 ) (-320 -576 160 ) +4 47 57 0 (-176 -696 144 ) (-176 -696 160 ) (-304 -696 160 ) (-304 -696 144 ) +4 47 48 0 (-288 -576 144 ) (-192 -576 144 ) (-192 -696 144 ) (-288 -696 144 ) +4 47 54 0 (-304 -696 144 ) (-304 -576 144 ) (-288 -576 144 ) (-288 -696 144 ) +4 47 55 0 (-304 -696 144 ) (-304 -696 160 ) (-304 -576 160 ) (-304 -576 144 ) +4 48 57 0 (-192 -696 144 ) (-288 -696 144 ) (-288 -696 128 ) (-192 -696 128 ) +4 48 49 0 (-272 -576 128 ) (-208 -576 128 ) (-208 -696 128 ) (-272 -696 128 ) +4 48 53 0 (-288 -696 128 ) (-288 -576 128 ) (-272 -576 128 ) (-272 -696 128 ) +4 48 54 0 (-288 -696 128 ) (-288 -696 144 ) (-288 -576 144 ) (-288 -576 128 ) +4 49 57 0 (-208 -696 112 ) (-208 -696 128 ) (-272 -696 128 ) (-272 -696 112 ) +4 49 50 0 (-256 -576 112 ) (-224 -576 112 ) (-224 -696 112 ) (-256 -696 112 ) +4 49 52 0 (-272 -696 112 ) (-272 -576 112 ) (-256 -576 112 ) (-256 -696 112 ) +4 49 53 0 (-272 -696 112 ) (-272 -696 128 ) (-272 -576 128 ) (-272 -576 112 ) +4 50 57 0 (-224 -696 112 ) (-256 -696 112 ) (-256 -696 96 ) (-224 -696 96 ) +4 50 51 0 (-256 -696 96 ) (-256 -576 96 ) (-240 -576 96 ) (-240 -696 96 ) +4 50 52 0 (-256 -696 96 ) (-256 -696 112 ) (-256 -576 112 ) (-256 -576 96 ) +4 51 57 0 (-256 -696 96 ) (-256 -696 80 ) (-240 -696 80 ) (-240 -696 96 ) +4 51 52 0 (-256 -696 80 ) (-256 -696 96 ) (-256 -576 96 ) (-256 -576 80 ) +4 52 57 0 (-256 -696 112 ) (-272 -696 112 ) (-272 -696 64 ) (-256 -696 64 ) +4 52 53 0 (-272 -696 64 ) (-272 -696 112 ) (-272 -576 112 ) (-272 -576 64 ) +4 53 57 0 (-288 -696 128 ) (-288 -696 48 ) (-272 -696 48 ) (-272 -696 128 ) +4 53 54 0 (-288 -696 48 ) (-288 -696 128 ) (-288 -576 128 ) (-288 -576 48 ) +4 54 57 0 (-288 -696 144 ) (-304 -696 144 ) (-304 -696 32 ) (-288 -696 32 ) +4 54 55 0 (-304 -696 32 ) (-304 -696 144 ) (-304 -576 144 ) (-304 -576 32 ) +4 55 57 0 (-320 -696 160 ) (-320 -696 16 ) (-304 -696 16 ) (-304 -696 160 ) +4 55 56 0 (-320 -696 16 ) (-320 -696 160 ) (-320 -576 160 ) (-320 -576 16 ) +4 56 57 0 (-320 -696 176 ) (-480 -696 176 ) (-480 -696 0 ) (-320 -696 0 ) +4 57 69 0 (-320 -896 16 ) (-480 -896 16 ) (-480 -896 0 ) (-320 -896 0 ) +4 57 68 0 (-304 -896 32 ) (-480 -896 32 ) (-480 -896 16 ) (-304 -896 16 ) +4 57 67 0 (-480 -896 48 ) (-480 -896 32 ) (-288 -896 32 ) (-288 -896 48 ) +4 57 66 0 (-480 -896 64 ) (-480 -896 48 ) (-272 -896 48 ) (-272 -896 64 ) +4 57 65 0 (-480 -896 80 ) (-480 -896 64 ) (-256 -896 64 ) (-256 -896 80 ) +4 57 64 0 (-480 -896 96 ) (-480 -896 80 ) (-240 -896 80 ) (-240 -896 96 ) +4 57 62 0 (-208 -896 608 ) (-224 -896 608 ) (-224 -896 112 ) (-208 -896 112 ) +4 57 63 0 (-224 -896 608 ) (-480 -896 608 ) (-480 -896 96 ) (-224 -896 96 ) +4 57 61 0 (-192 -896 608 ) (-208 -896 608 ) (-208 -896 128 ) (-192 -896 128 ) +4 57 60 0 (-176 -896 608 ) (-192 -896 608 ) (-192 -896 144 ) (-176 -896 144 ) +4 57 59 0 (-160 -896 608 ) (-176 -896 608 ) (-176 -896 160 ) (-160 -896 160 ) +4 57 58 0 (-64 -896 176 ) (-64 -896 608 ) (-160 -896 608 ) (-160 -896 176 ) +4 58 70 0 (-64 -1016 176 ) (-64 -1016 608 ) (-160 -1016 608 ) (-160 -1016 176 ) +4 58 59 0 (-160 -1016 176 ) (-160 -1016 608 ) (-160 -896 608 ) (-160 -896 176 ) +4 59 70 0 (-160 -1016 608 ) (-176 -1016 608 ) (-176 -1016 160 ) (-160 -1016 160 ) +4 59 60 0 (-176 -1016 160 ) (-176 -1016 608 ) (-176 -896 608 ) (-176 -896 160 ) +4 60 70 0 (-176 -1016 608 ) (-192 -1016 608 ) (-192 -1016 144 ) (-176 -1016 144 ) +4 60 61 0 (-192 -1016 144 ) (-192 -1016 608 ) (-192 -896 608 ) (-192 -896 144 ) +4 61 70 0 (-192 -1016 608 ) (-208 -1016 608 ) (-208 -1016 128 ) (-192 -1016 128 ) +4 61 62 0 (-208 -1016 128 ) (-208 -1016 608 ) (-208 -896 608 ) (-208 -896 128 ) +4 62 70 0 (-208 -1016 608 ) (-224 -1016 608 ) (-224 -1016 112 ) (-208 -1016 112 ) +4 62 63 0 (-224 -1016 112 ) (-224 -1016 608 ) (-224 -896 608 ) (-224 -896 112 ) +4 63 70 0 (-224 -1016 608 ) (-480 -1016 608 ) (-480 -1016 96 ) (-224 -1016 96 ) +4 63 64 0 (-480 -1016 96 ) (-480 -896 96 ) (-240 -896 96 ) (-240 -1016 96 ) +4 64 70 0 (-480 -1016 96 ) (-480 -1016 80 ) (-240 -1016 80 ) (-240 -1016 96 ) +4 64 65 0 (-480 -1016 80 ) (-480 -896 80 ) (-256 -896 80 ) (-256 -1016 80 ) +4 65 70 0 (-480 -1016 80 ) (-480 -1016 64 ) (-256 -1016 64 ) (-256 -1016 80 ) +4 65 66 0 (-480 -1016 64 ) (-480 -896 64 ) (-272 -896 64 ) (-272 -1016 64 ) +4 66 70 0 (-480 -1016 64 ) (-480 -1016 48 ) (-272 -1016 48 ) (-272 -1016 64 ) +4 66 67 0 (-480 -1016 48 ) (-480 -896 48 ) (-288 -896 48 ) (-288 -1016 48 ) +4 67 70 0 (-480 -1016 48 ) (-480 -1016 32 ) (-288 -1016 32 ) (-288 -1016 48 ) +4 67 68 0 (-304 -1016 32 ) (-480 -1016 32 ) (-480 -896 32 ) (-304 -896 32 ) +4 68 70 0 (-304 -1016 32 ) (-480 -1016 32 ) (-480 -1016 16 ) (-304 -1016 16 ) +4 68 69 0 (-320 -1016 16 ) (-480 -1016 16 ) (-480 -896 16 ) (-320 -896 16 ) +4 69 70 0 (-320 -1016 16 ) (-480 -1016 16 ) (-480 -1016 0 ) (-320 -1016 0 ) +4 70 72 0 (-64 -1024 0 ) (-64 -1024 64 ) (-480 -1024 64 ) (-480 -1024 0 ) +4 70 71 0 (-64 -1024 64 ) (-64 -1024 608 ) (-480 -1024 608 ) (-480 -1024 64 ) +4 71 72 0 (-480 -1240 64 ) (-480 -1024 64 ) (0 -1024 64 ) (0 -1240 64 ) +4 0 (0 192 0 ) (192 192 0 ) (192 0 0 ) (0 0 0 ) +4 0 (192 192 0 ) (192 192 608 ) (192 0 608 ) (192 0 0 ) +4 0 (192 192 608 ) (192 192 0 ) (0 192 0 ) (0 192 608 ) +4 0 (0 0 608 ) (192 0 608 ) (192 192 608 ) (0 192 608 ) +4 1 (0 -1024 608 ) (192 -1024 608 ) (192 0 608 ) (0 0 608 ) +4 1 (192 -1024 608 ) (192 -1024 0 ) (192 0 0 ) (192 0 608 ) +4 1 (0 0 0 ) (192 0 0 ) (192 -1024 0 ) (0 -1024 0 ) +4 2 (0 -1272 64 ) (0 -1240 64 ) (192 -1240 64 ) (192 -1272 64 ) +4 2 (192 -1272 608 ) (192 -1024 608 ) (0 -1024 608 ) (0 -1272 608 ) +4 2 (192 -1272 608 ) (192 -1272 64 ) (192 -1024 64 ) (192 -1024 608 ) +4 2 (0 -1272 64 ) (192 -1272 64 ) (192 -1272 608 ) (0 -1272 608 ) +4 3 (0 -1240 0 ) (0 -1024 0 ) (192 -1024 0 ) (192 -1240 0 ) +4 3 (192 -1240 64 ) (192 -1240 0 ) (192 -1024 0 ) (192 -1024 64 ) +4 3 (0 -1240 0 ) (192 -1240 0 ) (192 -1240 64 ) (0 -1240 64 ) +4 4 (-64 0 0 ) (-64 0 176 ) (-64 64 176 ) (-64 64 0 ) +4 4 (0 0 0 ) (-64 0 0 ) (-64 192 0 ) (0 192 0 ) +4 4 (0 192 608 ) (0 192 0 ) (-64 192 0 ) (-64 192 608 ) +4 4 (0 192 608 ) (-64 192 608 ) (-64 0 608 ) (0 0 608 ) +4 5 (-240 64 80 ) (-224 64 80 ) (-224 64 96 ) (-240 64 96 ) +4 5 (-256 64 80 ) (-256 64 64 ) (-224 64 64 ) (-224 64 80 ) +4 5 (-208 64 64 ) (-208 64 112 ) (-224 64 112 ) (-224 64 64 ) +4 5 (-272 64 48 ) (-208 64 48 ) (-208 64 64 ) (-272 64 64 ) +4 5 (-208 64 48 ) (-192 64 48 ) (-192 64 128 ) (-208 64 128 ) +4 5 (-288 64 48 ) (-288 64 32 ) (-192 64 32 ) (-192 64 48 ) +4 5 (-176 64 32 ) (-176 64 144 ) (-192 64 144 ) (-192 64 32 ) +4 5 (-304 64 16 ) (-176 64 16 ) (-176 64 32 ) (-304 64 32 ) +4 5 (-176 64 16 ) (-160 64 16 ) (-160 64 160 ) (-176 64 160 ) +4 5 (-320 64 16 ) (-320 64 0 ) (-160 64 0 ) (-160 64 16 ) +4 5 (-64 64 0 ) (-64 64 176 ) (-160 64 176 ) (-160 64 0 ) +4 5 (-64 64 0 ) (-480 64 0 ) (-480 192 0 ) (-64 192 0 ) +4 5 (-480 64 0 ) (-480 64 608 ) (-480 192 608 ) (-480 192 0 ) +4 5 (-64 192 608 ) (-64 192 0 ) (-480 192 0 ) (-480 192 608 ) +4 5 (-64 192 608 ) (-480 192 608 ) (-480 64 608 ) (-64 64 608 ) +4 6 (-160 64 176 ) (-64 64 176 ) (-64 0 176 ) (-160 0 176 ) +4 6 (-480 64 608 ) (-480 64 176 ) (-480 0 176 ) (-480 0 608 ) +4 6 (-64 0 608 ) (-64 64 608 ) (-480 64 608 ) (-480 0 608 ) +4 7 (-176 64 160 ) (-160 64 160 ) (-160 0 160 ) (-176 0 160 ) +4 7 (-160 64 160 ) (-160 64 176 ) (-160 0 176 ) (-160 0 160 ) +4 8 (-192 64 144 ) (-176 64 144 ) (-176 0 144 ) (-192 0 144 ) +4 8 (-176 64 144 ) (-176 64 160 ) (-176 0 160 ) (-176 0 144 ) +4 9 (-208 64 128 ) (-192 64 128 ) (-192 0 128 ) (-208 0 128 ) +4 9 (-192 64 128 ) (-192 64 144 ) (-192 0 144 ) (-192 0 128 ) +4 10 (-224 64 112 ) (-208 64 112 ) (-208 0 112 ) (-224 0 112 ) +4 10 (-208 64 112 ) (-208 64 128 ) (-208 0 128 ) (-208 0 112 ) +4 11 (-240 64 96 ) (-224 64 96 ) (-224 0 96 ) (-240 0 96 ) +4 11 (-224 64 96 ) (-224 64 112 ) (-224 0 112 ) (-224 0 96 ) +4 12 (-256 0 80 ) (-256 64 80 ) (-240 64 80 ) (-240 0 80 ) +4 12 (-240 64 96 ) (-240 0 96 ) (-240 0 80 ) (-240 64 80 ) +4 13 (-256 64 80 ) (-256 0 80 ) (-256 0 64 ) (-256 64 64 ) +4 13 (-272 0 64 ) (-272 64 64 ) (-256 64 64 ) (-256 0 64 ) +4 14 (-272 64 64 ) (-272 0 64 ) (-272 0 48 ) (-272 64 48 ) +4 14 (-288 0 48 ) (-288 64 48 ) (-272 64 48 ) (-272 0 48 ) +4 15 (-288 64 48 ) (-288 0 48 ) (-288 0 32 ) (-288 64 32 ) +4 15 (-304 0 32 ) (-304 64 32 ) (-288 64 32 ) (-288 0 32 ) +4 16 (-304 64 32 ) (-304 0 32 ) (-304 0 16 ) (-304 64 16 ) +4 16 (-320 0 16 ) (-320 64 16 ) (-304 64 16 ) (-304 0 16 ) +4 17 (-320 64 16 ) (-320 0 16 ) (-320 0 0 ) (-320 64 0 ) +4 17 (-480 64 176 ) (-480 64 0 ) (-480 0 0 ) (-480 0 176 ) +4 17 (-480 0 0 ) (-480 64 0 ) (-320 64 0 ) (-320 0 0 ) +4 18 (-64 -896 0 ) (-64 -1016 0 ) (-64 -1016 16 ) (-64 -896 16 ) +4 18 (-64 -1016 16 ) (-64 -1016 32 ) (-64 -896 32 ) (-64 -896 16 ) +4 18 (-64 -1016 32 ) (-64 -1016 176 ) (-64 -896 176 ) (-64 -896 32 ) +4 18 (-64 -576 0 ) (-64 -696 0 ) (-64 -696 176 ) (-64 -576 176 ) +4 18 (-64 -264 0 ) (-64 -384 0 ) (-64 -384 16 ) (-64 -264 16 ) +4 18 (-64 -384 16 ) (-64 -384 32 ) (-64 -264 32 ) (-64 -264 16 ) +4 18 (-64 -384 32 ) (-64 -384 176 ) (-64 -264 176 ) (-64 -264 32 ) +4 18 (-64 0 176 ) (-64 0 0 ) (-64 -56 0 ) (-64 -56 176 ) +4 18 (0 0 608 ) (-64 0 608 ) (-64 -1024 608 ) (0 -1024 608 ) +4 18 (0 -1024 0 ) (-64 -1024 0 ) (-64 0 0 ) (0 0 0 ) +4 19 (-64 -56 176 ) (-160 -56 176 ) (-160 0 176 ) (-64 0 176 ) +4 19 (-480 0 608 ) (-480 0 176 ) (-480 -56 176 ) (-480 -56 608 ) +4 19 (-64 0 608 ) (-480 0 608 ) (-480 -56 608 ) (-64 -56 608 ) +4 20 (-176 0 160 ) (-160 0 160 ) (-160 -56 160 ) (-176 -56 160 ) +4 20 (-160 0 160 ) (-160 0 176 ) (-160 -56 176 ) (-160 -56 160 ) +4 21 (-192 0 144 ) (-176 0 144 ) (-176 -56 144 ) (-192 -56 144 ) +4 21 (-176 0 144 ) (-176 0 160 ) (-176 -56 160 ) (-176 -56 144 ) +4 22 (-208 0 128 ) (-192 0 128 ) (-192 -56 128 ) (-208 -56 128 ) +4 22 (-192 0 128 ) (-192 0 144 ) (-192 -56 144 ) (-192 -56 128 ) +4 23 (-224 0 112 ) (-208 0 112 ) (-208 -56 112 ) (-224 -56 112 ) +4 23 (-208 0 112 ) (-208 0 128 ) (-208 -56 128 ) (-208 -56 112 ) +4 24 (-240 0 96 ) (-224 0 96 ) (-224 -56 96 ) (-240 -56 96 ) +4 24 (-224 0 96 ) (-224 0 112 ) (-224 -56 112 ) (-224 -56 96 ) +4 25 (-256 -56 80 ) (-256 0 80 ) (-240 0 80 ) (-240 -56 80 ) +4 25 (-240 0 96 ) (-240 -56 96 ) (-240 -56 80 ) (-240 0 80 ) +4 26 (-256 0 80 ) (-256 -56 80 ) (-256 -56 64 ) (-256 0 64 ) +4 26 (-272 -56 64 ) (-272 0 64 ) (-256 0 64 ) (-256 -56 64 ) +4 27 (-272 0 64 ) (-272 -56 64 ) (-272 -56 48 ) (-272 0 48 ) +4 27 (-288 -56 48 ) (-288 0 48 ) (-272 0 48 ) (-272 -56 48 ) +4 28 (-288 0 48 ) (-288 -56 48 ) (-288 -56 32 ) (-288 0 32 ) +4 28 (-304 -56 32 ) (-304 0 32 ) (-288 0 32 ) (-288 -56 32 ) +4 29 (-304 0 32 ) (-304 -56 32 ) (-304 -56 16 ) (-304 0 16 ) +4 29 (-320 -56 16 ) (-320 0 16 ) (-304 0 16 ) (-304 -56 16 ) +4 30 (-320 0 16 ) (-320 -56 16 ) (-320 -56 0 ) (-320 0 0 ) +4 30 (-480 0 176 ) (-480 0 0 ) (-480 -56 0 ) (-480 -56 176 ) +4 30 (-320 -56 0 ) (-480 -56 0 ) (-480 0 0 ) (-320 0 0 ) +4 31 (-64 -264 0 ) (-64 -264 16 ) (-320 -264 16 ) (-320 -264 0 ) +4 31 (-64 -264 16 ) (-64 -264 32 ) (-304 -264 32 ) (-304 -264 16 ) +4 31 (-288 -264 32 ) (-160 -264 32 ) (-160 -264 48 ) (-288 -264 48 ) +4 31 (-272 -264 48 ) (-176 -264 48 ) (-176 -264 64 ) (-272 -264 64 ) +4 31 (-256 -264 64 ) (-192 -264 64 ) (-192 -264 80 ) (-256 -264 80 ) +4 31 (-240 -264 80 ) (-208 -264 80 ) (-208 -264 96 ) (-240 -264 96 ) +4 31 (-224 -264 112 ) (-224 -264 96 ) (-208 -264 96 ) (-208 -264 112 ) +4 31 (-208 -264 128 ) (-208 -264 80 ) (-192 -264 80 ) (-192 -264 128 ) +4 31 (-192 -264 144 ) (-192 -264 64 ) (-176 -264 64 ) (-176 -264 144 ) +4 31 (-176 -264 160 ) (-176 -264 48 ) (-160 -264 48 ) (-160 -264 160 ) +4 31 (-64 -264 32 ) (-64 -264 176 ) (-160 -264 176 ) (-160 -264 32 ) +4 31 (-64 -56 608 ) (-480 -56 608 ) (-480 -264 608 ) (-64 -264 608 ) +4 31 (-240 -56 96 ) (-224 -56 96 ) (-224 -56 80 ) (-240 -56 80 ) +4 31 (-224 -56 80 ) (-224 -56 64 ) (-256 -56 64 ) (-256 -56 80 ) +4 31 (-224 -56 64 ) (-224 -56 112 ) (-208 -56 112 ) (-208 -56 64 ) +4 31 (-272 -56 64 ) (-208 -56 64 ) (-208 -56 48 ) (-272 -56 48 ) +4 31 (-208 -56 128 ) (-192 -56 128 ) (-192 -56 48 ) (-208 -56 48 ) +4 31 (-192 -56 48 ) (-192 -56 32 ) (-288 -56 32 ) (-288 -56 48 ) +4 31 (-192 -56 32 ) (-192 -56 144 ) (-176 -56 144 ) (-176 -56 32 ) +4 31 (-304 -56 32 ) (-176 -56 32 ) (-176 -56 16 ) (-304 -56 16 ) +4 31 (-176 -56 160 ) (-160 -56 160 ) (-160 -56 16 ) (-176 -56 16 ) +4 31 (-160 -56 16 ) (-160 -56 0 ) (-320 -56 0 ) (-320 -56 16 ) +4 31 (-160 -56 0 ) (-160 -56 176 ) (-64 -56 176 ) (-64 -56 0 ) +4 31 (-480 -56 608 ) (-480 -56 0 ) (-480 -264 0 ) (-480 -264 608 ) +4 31 (-64 -264 0 ) (-480 -264 0 ) (-480 -56 0 ) (-64 -56 0 ) +4 32 (-64 -264 608 ) (-160 -264 608 ) (-160 -384 608 ) (-64 -384 608 ) +4 32 (-64 -384 176 ) (-160 -384 176 ) (-160 -264 176 ) (-64 -264 176 ) +4 33 (-160 -264 608 ) (-176 -264 608 ) (-176 -384 608 ) (-160 -384 608 ) +4 33 (-160 -264 160 ) (-160 -264 176 ) (-160 -384 176 ) (-160 -384 160 ) +4 33 (-176 -384 160 ) (-176 -264 160 ) (-160 -264 160 ) (-160 -384 160 ) +4 34 (-176 -264 608 ) (-192 -264 608 ) (-192 -384 608 ) (-176 -384 608 ) +4 34 (-176 -264 144 ) (-176 -264 160 ) (-176 -384 160 ) (-176 -384 144 ) +4 34 (-192 -384 144 ) (-192 -264 144 ) (-176 -264 144 ) (-176 -384 144 ) +4 35 (-192 -264 608 ) (-208 -264 608 ) (-208 -384 608 ) (-192 -384 608 ) +4 35 (-192 -264 128 ) (-192 -264 144 ) (-192 -384 144 ) (-192 -384 128 ) +4 35 (-208 -384 128 ) (-208 -264 128 ) (-192 -264 128 ) (-192 -384 128 ) +4 36 (-208 -264 608 ) (-224 -264 608 ) (-224 -384 608 ) (-208 -384 608 ) +4 36 (-208 -264 112 ) (-208 -264 128 ) (-208 -384 128 ) (-208 -384 112 ) +4 36 (-224 -384 112 ) (-224 -264 112 ) (-208 -264 112 ) (-208 -384 112 ) +4 37 (-240 -264 96 ) (-224 -264 96 ) (-224 -384 96 ) (-240 -384 96 ) +4 37 (-224 -264 112 ) (-224 -384 112 ) (-224 -384 96 ) (-224 -264 96 ) +4 37 (-480 -264 608 ) (-480 -264 96 ) (-480 -384 96 ) (-480 -384 608 ) +4 37 (-224 -264 608 ) (-480 -264 608 ) (-480 -384 608 ) (-224 -384 608 ) +4 38 (-256 -264 80 ) (-240 -264 80 ) (-240 -384 80 ) (-256 -384 80 ) +4 38 (-480 -264 96 ) (-480 -264 80 ) (-480 -384 80 ) (-480 -384 96 ) +4 38 (-240 -264 96 ) (-240 -384 96 ) (-240 -384 80 ) (-240 -264 80 ) +4 39 (-272 -264 64 ) (-256 -264 64 ) (-256 -384 64 ) (-272 -384 64 ) +4 39 (-480 -264 80 ) (-480 -264 64 ) (-480 -384 64 ) (-480 -384 80 ) +4 39 (-256 -264 80 ) (-256 -384 80 ) (-256 -384 64 ) (-256 -264 64 ) +4 40 (-288 -264 48 ) (-272 -264 48 ) (-272 -384 48 ) (-288 -384 48 ) +4 40 (-480 -264 64 ) (-480 -264 48 ) (-480 -384 48 ) (-480 -384 64 ) +4 40 (-272 -264 64 ) (-272 -384 64 ) (-272 -384 48 ) (-272 -264 48 ) +4 41 (-288 -384 32 ) (-304 -384 32 ) (-304 -264 32 ) (-288 -264 32 ) +4 41 (-480 -264 48 ) (-480 -264 32 ) (-480 -384 32 ) (-480 -384 48 ) +4 41 (-288 -264 48 ) (-288 -384 48 ) (-288 -384 32 ) (-288 -264 32 ) +4 42 (-304 -384 16 ) (-320 -384 16 ) (-320 -264 16 ) (-304 -264 16 ) +4 42 (-480 -264 32 ) (-480 -264 16 ) (-480 -384 16 ) (-480 -384 32 ) +4 42 (-304 -264 32 ) (-304 -384 32 ) (-304 -384 16 ) (-304 -264 16 ) +4 43 (-320 -384 0 ) (-480 -384 0 ) (-480 -264 0 ) (-320 -264 0 ) +4 43 (-480 -264 16 ) (-480 -264 0 ) (-480 -384 0 ) (-480 -384 16 ) +4 43 (-320 -264 16 ) (-320 -384 16 ) (-320 -384 0 ) (-320 -264 0 ) +4 44 (-240 -576 80 ) (-224 -576 80 ) (-224 -576 96 ) (-240 -576 96 ) +4 44 (-256 -576 80 ) (-256 -576 64 ) (-224 -576 64 ) (-224 -576 80 ) +4 44 (-208 -576 64 ) (-208 -576 112 ) (-224 -576 112 ) (-224 -576 64 ) +4 44 (-272 -576 48 ) (-208 -576 48 ) (-208 -576 64 ) (-272 -576 64 ) +4 44 (-208 -576 48 ) (-192 -576 48 ) (-192 -576 128 ) (-208 -576 128 ) +4 44 (-288 -576 48 ) (-288 -576 32 ) (-192 -576 32 ) (-192 -576 48 ) +4 44 (-176 -576 32 ) (-176 -576 144 ) (-192 -576 144 ) (-192 -576 32 ) +4 44 (-304 -576 16 ) (-176 -576 16 ) (-176 -576 32 ) (-304 -576 32 ) +4 44 (-176 -576 16 ) (-160 -576 16 ) (-160 -576 160 ) (-176 -576 160 ) +4 44 (-320 -576 16 ) (-320 -576 0 ) (-160 -576 0 ) (-160 -576 16 ) +4 44 (-64 -576 0 ) (-64 -576 176 ) (-160 -576 176 ) (-160 -576 0 ) +4 44 (-64 -576 0 ) (-480 -576 0 ) (-480 -384 0 ) (-64 -384 0 ) +4 44 (-160 -384 32 ) (-160 -384 176 ) (-64 -384 176 ) (-64 -384 32 ) +4 44 (-160 -384 160 ) (-160 -384 48 ) (-176 -384 48 ) (-176 -384 160 ) +4 44 (-176 -384 144 ) (-176 -384 64 ) (-192 -384 64 ) (-192 -384 144 ) +4 44 (-192 -384 128 ) (-192 -384 80 ) (-208 -384 80 ) (-208 -384 128 ) +4 44 (-208 -384 112 ) (-208 -384 96 ) (-224 -384 96 ) (-224 -384 112 ) +4 44 (-240 -384 96 ) (-208 -384 96 ) (-208 -384 80 ) (-240 -384 80 ) +4 44 (-256 -384 80 ) (-192 -384 80 ) (-192 -384 64 ) (-256 -384 64 ) +4 44 (-272 -384 64 ) (-176 -384 64 ) (-176 -384 48 ) (-272 -384 48 ) +4 44 (-288 -384 48 ) (-160 -384 48 ) (-160 -384 32 ) (-288 -384 32 ) +4 44 (-304 -384 16 ) (-304 -384 32 ) (-64 -384 32 ) (-64 -384 16 ) +4 44 (-320 -384 0 ) (-320 -384 16 ) (-64 -384 16 ) (-64 -384 0 ) +4 44 (-480 -384 608 ) (-480 -384 0 ) (-480 -576 0 ) (-480 -576 608 ) +4 44 (-64 -384 608 ) (-480 -384 608 ) (-480 -576 608 ) (-64 -576 608 ) +4 45 (-64 -696 176 ) (-160 -696 176 ) (-160 -576 176 ) (-64 -576 176 ) +4 45 (-480 -576 608 ) (-480 -576 176 ) (-480 -696 176 ) (-480 -696 608 ) +4 45 (-64 -576 608 ) (-480 -576 608 ) (-480 -696 608 ) (-64 -696 608 ) +4 46 (-176 -576 160 ) (-160 -576 160 ) (-160 -696 160 ) (-176 -696 160 ) +4 46 (-160 -576 160 ) (-160 -576 176 ) (-160 -696 176 ) (-160 -696 160 ) +4 47 (-192 -576 144 ) (-176 -576 144 ) (-176 -696 144 ) (-192 -696 144 ) +4 47 (-176 -576 144 ) (-176 -576 160 ) (-176 -696 160 ) (-176 -696 144 ) +4 48 (-208 -576 128 ) (-192 -576 128 ) (-192 -696 128 ) (-208 -696 128 ) +4 48 (-192 -576 128 ) (-192 -576 144 ) (-192 -696 144 ) (-192 -696 128 ) +4 49 (-224 -576 112 ) (-208 -576 112 ) (-208 -696 112 ) (-224 -696 112 ) +4 49 (-208 -576 112 ) (-208 -576 128 ) (-208 -696 128 ) (-208 -696 112 ) +4 50 (-240 -576 96 ) (-224 -576 96 ) (-224 -696 96 ) (-240 -696 96 ) +4 50 (-224 -576 96 ) (-224 -576 112 ) (-224 -696 112 ) (-224 -696 96 ) +4 51 (-256 -696 80 ) (-256 -576 80 ) (-240 -576 80 ) (-240 -696 80 ) +4 51 (-240 -576 96 ) (-240 -696 96 ) (-240 -696 80 ) (-240 -576 80 ) +4 52 (-256 -576 80 ) (-256 -696 80 ) (-256 -696 64 ) (-256 -576 64 ) +4 52 (-272 -696 64 ) (-272 -576 64 ) (-256 -576 64 ) (-256 -696 64 ) +4 53 (-272 -576 64 ) (-272 -696 64 ) (-272 -696 48 ) (-272 -576 48 ) +4 53 (-288 -696 48 ) (-288 -576 48 ) (-272 -576 48 ) (-272 -696 48 ) +4 54 (-288 -576 48 ) (-288 -696 48 ) (-288 -696 32 ) (-288 -576 32 ) +4 54 (-304 -696 32 ) (-304 -576 32 ) (-288 -576 32 ) (-288 -696 32 ) +4 55 (-304 -576 32 ) (-304 -696 32 ) (-304 -696 16 ) (-304 -576 16 ) +4 55 (-320 -696 16 ) (-320 -576 16 ) (-304 -576 16 ) (-304 -696 16 ) +4 56 (-320 -576 16 ) (-320 -696 16 ) (-320 -696 0 ) (-320 -576 0 ) +4 56 (-480 -576 176 ) (-480 -576 0 ) (-480 -696 0 ) (-480 -696 176 ) +4 56 (-320 -696 0 ) (-480 -696 0 ) (-480 -576 0 ) (-320 -576 0 ) +4 57 (-64 -896 0 ) (-64 -896 16 ) (-320 -896 16 ) (-320 -896 0 ) +4 57 (-64 -896 16 ) (-64 -896 32 ) (-304 -896 32 ) (-304 -896 16 ) +4 57 (-288 -896 32 ) (-160 -896 32 ) (-160 -896 48 ) (-288 -896 48 ) +4 57 (-272 -896 48 ) (-176 -896 48 ) (-176 -896 64 ) (-272 -896 64 ) +4 57 (-256 -896 64 ) (-192 -896 64 ) (-192 -896 80 ) (-256 -896 80 ) +4 57 (-240 -896 80 ) (-208 -896 80 ) (-208 -896 96 ) (-240 -896 96 ) +4 57 (-224 -896 112 ) (-224 -896 96 ) (-208 -896 96 ) (-208 -896 112 ) +4 57 (-208 -896 128 ) (-208 -896 80 ) (-192 -896 80 ) (-192 -896 128 ) +4 57 (-192 -896 144 ) (-192 -896 64 ) (-176 -896 64 ) (-176 -896 144 ) +4 57 (-176 -896 160 ) (-176 -896 48 ) (-160 -896 48 ) (-160 -896 160 ) +4 57 (-64 -896 32 ) (-64 -896 176 ) (-160 -896 176 ) (-160 -896 32 ) +4 57 (-64 -896 0 ) (-480 -896 0 ) (-480 -696 0 ) (-64 -696 0 ) +4 57 (-160 -696 0 ) (-160 -696 176 ) (-64 -696 176 ) (-64 -696 0 ) +4 57 (-160 -696 16 ) (-160 -696 0 ) (-320 -696 0 ) (-320 -696 16 ) +4 57 (-176 -696 160 ) (-160 -696 160 ) (-160 -696 16 ) (-176 -696 16 ) +4 57 (-304 -696 32 ) (-176 -696 32 ) (-176 -696 16 ) (-304 -696 16 ) +4 57 (-192 -696 32 ) (-192 -696 144 ) (-176 -696 144 ) (-176 -696 32 ) +4 57 (-192 -696 48 ) (-192 -696 32 ) (-288 -696 32 ) (-288 -696 48 ) +4 57 (-208 -696 128 ) (-192 -696 128 ) (-192 -696 48 ) (-208 -696 48 ) +4 57 (-272 -696 64 ) (-208 -696 64 ) (-208 -696 48 ) (-272 -696 48 ) +4 57 (-224 -696 64 ) (-224 -696 112 ) (-208 -696 112 ) (-208 -696 64 ) +4 57 (-224 -696 80 ) (-224 -696 64 ) (-256 -696 64 ) (-256 -696 80 ) +4 57 (-240 -696 96 ) (-224 -696 96 ) (-224 -696 80 ) (-240 -696 80 ) +4 57 (-480 -696 608 ) (-480 -696 0 ) (-480 -896 0 ) (-480 -896 608 ) +4 57 (-64 -696 608 ) (-480 -696 608 ) (-480 -896 608 ) (-64 -896 608 ) +4 58 (-64 -896 608 ) (-160 -896 608 ) (-160 -1016 608 ) (-64 -1016 608 ) +4 58 (-64 -1016 176 ) (-160 -1016 176 ) (-160 -896 176 ) (-64 -896 176 ) +4 59 (-160 -896 608 ) (-176 -896 608 ) (-176 -1016 608 ) (-160 -1016 608 ) +4 59 (-160 -896 160 ) (-160 -896 176 ) (-160 -1016 176 ) (-160 -1016 160 ) +4 59 (-176 -1016 160 ) (-176 -896 160 ) (-160 -896 160 ) (-160 -1016 160 ) +4 60 (-176 -896 608 ) (-192 -896 608 ) (-192 -1016 608 ) (-176 -1016 608 ) +4 60 (-176 -896 144 ) (-176 -896 160 ) (-176 -1016 160 ) (-176 -1016 144 ) +4 60 (-192 -1016 144 ) (-192 -896 144 ) (-176 -896 144 ) (-176 -1016 144 ) +4 61 (-192 -896 608 ) (-208 -896 608 ) (-208 -1016 608 ) (-192 -1016 608 ) +4 61 (-192 -896 128 ) (-192 -896 144 ) (-192 -1016 144 ) (-192 -1016 128 ) +4 61 (-208 -1016 128 ) (-208 -896 128 ) (-192 -896 128 ) (-192 -1016 128 ) +4 62 (-208 -896 608 ) (-224 -896 608 ) (-224 -1016 608 ) (-208 -1016 608 ) +4 62 (-208 -896 112 ) (-208 -896 128 ) (-208 -1016 128 ) (-208 -1016 112 ) +4 62 (-224 -1016 112 ) (-224 -896 112 ) (-208 -896 112 ) (-208 -1016 112 ) +4 63 (-240 -896 96 ) (-224 -896 96 ) (-224 -1016 96 ) (-240 -1016 96 ) +4 63 (-224 -896 112 ) (-224 -1016 112 ) (-224 -1016 96 ) (-224 -896 96 ) +4 63 (-480 -896 608 ) (-480 -896 96 ) (-480 -1016 96 ) (-480 -1016 608 ) +4 63 (-224 -896 608 ) (-480 -896 608 ) (-480 -1016 608 ) (-224 -1016 608 ) +4 64 (-256 -896 80 ) (-240 -896 80 ) (-240 -1016 80 ) (-256 -1016 80 ) +4 64 (-480 -896 96 ) (-480 -896 80 ) (-480 -1016 80 ) (-480 -1016 96 ) +4 64 (-240 -896 96 ) (-240 -1016 96 ) (-240 -1016 80 ) (-240 -896 80 ) +4 65 (-272 -896 64 ) (-256 -896 64 ) (-256 -1016 64 ) (-272 -1016 64 ) +4 65 (-480 -896 80 ) (-480 -896 64 ) (-480 -1016 64 ) (-480 -1016 80 ) +4 65 (-256 -896 80 ) (-256 -1016 80 ) (-256 -1016 64 ) (-256 -896 64 ) +4 66 (-288 -896 48 ) (-272 -896 48 ) (-272 -1016 48 ) (-288 -1016 48 ) +4 66 (-480 -896 64 ) (-480 -896 48 ) (-480 -1016 48 ) (-480 -1016 64 ) +4 66 (-272 -896 64 ) (-272 -1016 64 ) (-272 -1016 48 ) (-272 -896 48 ) +4 67 (-288 -1016 32 ) (-304 -1016 32 ) (-304 -896 32 ) (-288 -896 32 ) +4 67 (-480 -896 48 ) (-480 -896 32 ) (-480 -1016 32 ) (-480 -1016 48 ) +4 67 (-288 -896 48 ) (-288 -1016 48 ) (-288 -1016 32 ) (-288 -896 32 ) +4 68 (-304 -1016 16 ) (-320 -1016 16 ) (-320 -896 16 ) (-304 -896 16 ) +4 68 (-480 -896 32 ) (-480 -896 16 ) (-480 -1016 16 ) (-480 -1016 32 ) +4 68 (-304 -896 32 ) (-304 -1016 32 ) (-304 -1016 16 ) (-304 -896 16 ) +4 69 (-480 -896 16 ) (-480 -896 0 ) (-480 -1016 0 ) (-480 -1016 16 ) +4 69 (-320 -1016 0 ) (-480 -1016 0 ) (-480 -896 0 ) (-320 -896 0 ) +4 69 (-320 -896 16 ) (-320 -1016 16 ) (-320 -1016 0 ) (-320 -896 0 ) +4 70 (-480 -1024 0 ) (-480 -1016 0 ) (-64 -1016 0 ) (-64 -1024 0 ) +4 70 (-160 -1016 32 ) (-160 -1016 176 ) (-64 -1016 176 ) (-64 -1016 32 ) +4 70 (-160 -1016 160 ) (-160 -1016 48 ) (-176 -1016 48 ) (-176 -1016 160 ) +4 70 (-176 -1016 144 ) (-176 -1016 64 ) (-192 -1016 64 ) (-192 -1016 144 ) +4 70 (-192 -1016 128 ) (-192 -1016 80 ) (-208 -1016 80 ) (-208 -1016 128 ) +4 70 (-208 -1016 112 ) (-208 -1016 96 ) (-224 -1016 96 ) (-224 -1016 112 ) +4 70 (-240 -1016 96 ) (-208 -1016 96 ) (-208 -1016 80 ) (-240 -1016 80 ) +4 70 (-256 -1016 80 ) (-192 -1016 80 ) (-192 -1016 64 ) (-256 -1016 64 ) +4 70 (-272 -1016 64 ) (-176 -1016 64 ) (-176 -1016 48 ) (-272 -1016 48 ) +4 70 (-288 -1016 48 ) (-160 -1016 48 ) (-160 -1016 32 ) (-288 -1016 32 ) +4 70 (-304 -1016 16 ) (-304 -1016 32 ) (-64 -1016 32 ) (-64 -1016 16 ) +4 70 (-320 -1016 0 ) (-320 -1016 16 ) (-64 -1016 16 ) (-64 -1016 0 ) +4 70 (-480 -1016 608 ) (-480 -1016 0 ) (-480 -1024 0 ) (-480 -1024 608 ) +4 70 (-64 -1024 608 ) (-64 -1016 608 ) (-480 -1016 608 ) (-480 -1024 608 ) +4 71 (-480 -1272 64 ) (-480 -1240 64 ) (0 -1240 64 ) (0 -1272 64 ) +4 71 (0 -1272 608 ) (0 -1024 608 ) (-480 -1024 608 ) (-480 -1272 608 ) +4 71 (-480 -1024 608 ) (-480 -1024 64 ) (-480 -1272 64 ) (-480 -1272 608 ) +4 71 (-480 -1272 64 ) (0 -1272 64 ) (0 -1272 608 ) (-480 -1272 608 ) +4 72 (-480 -1240 0 ) (-480 -1024 0 ) (0 -1024 0 ) (0 -1240 0 ) +4 72 (-480 -1024 64 ) (-480 -1024 0 ) (-480 -1240 0 ) (-480 -1240 64 ) +4 72 (-480 -1240 0 ) (0 -1240 0 ) (0 -1240 64 ) (-480 -1240 64 ) diff --git a/fakk/maps/example/teleporter.bsp b/fakk/maps/example/teleporter.bsp new file mode 100644 index 0000000..6f6c0c3 Binary files /dev/null and b/fakk/maps/example/teleporter.bsp differ diff --git a/fakk/maps/example/teleporter.map b/fakk/maps/example/teleporter.map new file mode 100644 index 0000000..185f01c --- /dev/null +++ b/fakk/maps/example/teleporter.map @@ -0,0 +1,208 @@ +{ +"classname" "worldspawn" +// brush 0 +{ +( 264 264 -8 ) ( -264 264 -8 ) ( -264 -272 -8 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 -272 264 ) ( -264 264 264 ) ( 264 264 264 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( -64 -280 8 ) ( -64 256 8 ) ( -64 256 0 ) eden/FL_edenhouse2 0 0 0.00 1 1 0 0 0 +( 264 264 8 ) ( -264 264 8 ) ( -264 264 0 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 264 8 ) ( -264 -272 8 ) ( -264 -272 0 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 256 8 ) ( 264 256 8 ) ( -264 256 0 ) eden/FL_edenhouse2 0 0 0.00 1 1 0 0 0 +} +// brush 1 +{ +( 592 264 -8 ) ( 64 264 -8 ) ( 64 -272 -8 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( 64 -272 264 ) ( 64 264 264 ) ( 592 264 264 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( 264 -280 8 ) ( 264 256 8 ) ( 264 256 0 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( 592 264 8 ) ( 64 264 8 ) ( 64 264 0 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( 64 264 8 ) ( 64 -272 8 ) ( 64 -272 0 ) eden/FL_edenhouse2 0 0 0.00 1 1 0 0 0 +( 256 256 8 ) ( 784 256 8 ) ( 256 256 0 ) eden/FL_edenhouse2 0 0 0.00 1 1 0 0 0 +} +// brush 2 +{ +( 472 264 128 ) ( -56 264 128 ) ( -56 -272 128 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( -64 -272 264 ) ( -64 264 264 ) ( 464 264 264 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( 64 -288 8 ) ( 64 248 8 ) ( 64 248 0 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( 464 264 8 ) ( -64 264 8 ) ( -64 264 0 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( -64 264 8 ) ( -64 -272 8 ) ( -64 -272 0 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( 128 256 8 ) ( 656 256 8 ) ( 128 256 0 ) eden/FL_edenhouse2 0 0 0.00 1 1 0 0 0 +} +// brush 3 +{ +( 472 272 128 ) ( -56 272 128 ) ( -56 -264 128 ) eden/WL_darkbrick 0 0 0.00 1 1 0 0 0 +( -64 -264 264 ) ( -64 272 264 ) ( 464 272 264 ) eden/WL_darkbrick 0 0 0.00 1 1 0 0 0 +( 64 -280 8 ) ( 64 256 8 ) ( 64 256 0 ) eden/WL_darkbrick 0 0 0.00 1 1 0 0 0 +( 464 272 8 ) ( -64 272 8 ) ( -64 272 0 ) eden/FL_edenhouse2 0 0 0.00 1 1 0 0 0 +( -64 272 8 ) ( -64 -264 8 ) ( -64 -264 0 ) eden/WL_darkbrick 0 0 0.00 1 1 0 0 0 +( 128 264 8 ) ( 656 264 8 ) ( 128 264 0 ) eden/WL_darkbrick 0 0 0.00 1 1 0 0 0 +} +// brush 4 +{ +( 592 272 -8 ) ( 64 272 -8 ) ( 64 -264 -8 ) eden/WL_darkbrick 0 0 0.00 1 1 0 0 0 +( 64 -264 264 ) ( 64 272 264 ) ( 592 272 264 ) eden/WL_darkbrick 0 0 0.00 1 1 0 0 0 +( 264 -272 8 ) ( 264 264 8 ) ( 264 264 0 ) eden/WL_darkbrick 0 0 0.00 1 1 0 0 0 +( 592 272 8 ) ( 64 272 8 ) ( 64 272 0 ) eden/FL_edenhouse2 0 0 0.00 1 1 0 0 0 +( 64 272 8 ) ( 64 -264 8 ) ( 64 -264 0 ) eden/FL_edenhouse2 0 0 0.00 1 1 0 0 0 +( 256 264 8 ) ( 784 264 8 ) ( 256 264 0 ) eden/WL_darkbrick 0 0 0.00 1 1 0 0 0 +} +// brush 5 +{ +( 264 784 -8 ) ( -264 784 -8 ) ( -264 248 -8 ) eden/FL_edenhouse2 0 16 0.00 0.500000 0.500000 0 0 0 +( -264 256 8 ) ( 264 256 8 ) ( 264 256 0 ) eden/FL_edenhouse2 0 0 0.00 0.500000 0.500000 0 0 0 +( 264 248 8 ) ( 264 784 8 ) ( 264 784 0 ) eden/FL_edenhouse2 -16 0 0.00 0.500000 0.500000 0 0 0 +( 264 784 8 ) ( -264 784 8 ) ( -264 784 0 ) eden/FL_edenhouse2 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 784 8 ) ( -264 248 8 ) ( -264 248 0 ) eden/FL_edenhouse2 -16 0 0.00 0.500000 0.500000 0 0 0 +( -264 784 0 ) ( 264 784 0 ) ( -264 248 0 ) eden/FL_edenhouse2 0 16 0.00 0.500000 0.500000 0 0 0 +} +// brush 6 +{ +( -264 248 264 ) ( -264 784 264 ) ( 264 784 264 ) eden/WL_darkbrick 0 0 0.00 1 1 0 0 0 +( -264 256 8 ) ( 264 256 8 ) ( 264 256 0 ) eden/WL_darkbrick 0 0 0.00 1 1 0 0 0 +( 264 248 8 ) ( 264 784 8 ) ( 264 784 0 ) eden/WL_darkbrick 0 0 0.00 1 1 0 0 0 +( 264 784 8 ) ( -264 784 8 ) ( -264 784 0 ) eden/WL_darkbrick 0 0 0.00 1 1 0 0 0 +( -264 784 8 ) ( -264 248 8 ) ( -264 248 0 ) eden/WL_darkbrick 0 0 0.00 1 1 0 0 0 +( -264 784 256 ) ( -264 248 256 ) ( 264 784 256 ) eden/FL_edenhouse2 0 0 0.00 1 1 0 0 0 +} +// brush 7 +{ +( 264 784 -8 ) ( -264 784 -8 ) ( -264 248 -8 ) eden/WL_darkbrick 0 0 0.00 1 1 0 0 0 +( -264 248 264 ) ( -264 784 264 ) ( 264 784 264 ) eden/WL_darkbrick 0 0 0.00 1 1 0 0 0 +( -264 256 8 ) ( 264 256 8 ) ( 264 256 0 ) eden/WL_darkbrick 0 0 0.00 1 1 0 0 0 +( 264 248 8 ) ( 264 784 8 ) ( 264 784 0 ) eden/WL_darkbrick 0 0 0.00 1 1 0 0 0 +( 264 784 8 ) ( -264 784 8 ) ( -264 784 0 ) eden/WL_darkbrick 0 0 0.00 1 1 0 0 0 +( 256 784 8 ) ( 256 248 8 ) ( 256 784 0 ) eden/FL_edenhouse2 0 0 0.00 1 1 0 0 0 +} +// brush 8 +{ +( 264 784 -8 ) ( -264 784 -8 ) ( -264 248 -8 ) eden/WL_darkbrick 0 0 0.00 1 1 0 0 0 +( -264 248 264 ) ( -264 784 264 ) ( 264 784 264 ) eden/WL_darkbrick 0 0 0.00 1 1 0 0 0 +( 264 248 8 ) ( 264 784 8 ) ( 264 784 0 ) eden/WL_darkbrick 0 0 0.00 1 1 0 0 0 +( 264 784 8 ) ( -264 784 8 ) ( -264 784 0 ) eden/WL_darkbrick 0 0 0.00 1 1 0 0 0 +( -264 784 8 ) ( -264 248 8 ) ( -264 248 0 ) eden/WL_darkbrick 0 0 0.00 1 1 0 0 0 +( -264 776 8 ) ( 264 776 8 ) ( -264 776 0 ) eden/FL_edenhouse2 0 0 0.00 1 1 0 0 0 +} +// brush 9 +{ +( 264 784 -8 ) ( -264 784 -8 ) ( -264 248 -8 ) eden/WL_darkbrick 0 0 0.00 1 1 0 0 0 +( -264 248 264 ) ( -264 784 264 ) ( 264 784 264 ) eden/WL_darkbrick 0 0 0.00 1 1 0 0 0 +( -264 256 8 ) ( 264 256 8 ) ( 264 256 0 ) eden/WL_darkbrick 0 0 0.00 1 1 0 0 0 +( 264 784 8 ) ( -264 784 8 ) ( -264 784 0 ) eden/WL_darkbrick 0 0 0.00 1 1 0 0 0 +( -264 784 8 ) ( -264 248 8 ) ( -264 248 0 ) eden/WL_darkbrick 0 0 0.00 1 1 0 0 0 +( -256 248 8 ) ( -256 784 8 ) ( -256 248 0 ) eden/FL_edenhouse2 0 0 0.00 1 1 0 0 0 +} +// brush 10 +{ +( 96 600 8 ) ( -32 600 8 ) ( -32 472 8 ) eden/FL_underground 64 64 0.00 -0.500000 0.500000 0 0 0 +( -32 472 16 ) ( -32 600 16 ) ( 96 600 16 ) eden/FL_underground 64 64 0.00 -0.500000 0.500000 0 0 0 +( -104 480 16 ) ( 24 480 16 ) ( 24 480 8 ) eden/FL_underground 64 0 0.00 -0.500000 0.062500 0 0 0 +( 32 480 16 ) ( 32 608 16 ) ( 32 608 8 ) eden/FL_underground 64 0 0.00 -0.500000 0.062500 0 0 0 +( 104 544 16 ) ( -24 544 16 ) ( -24 544 8 ) eden/FL_underground 64 0 0.00 -0.500000 0.062500 0 0 0 +( -32 600 16 ) ( -32 472 16 ) ( -32 472 8 ) eden/FL_underground 64 0 0.00 -0.500000 0.062500 0 0 0 +} +// brush 11 +{ +( 64 64 0 ) ( -64 64 0 ) ( -64 -64 0 ) eden/FL_underground 0 0 0.00 1 1 0 0 0 +( -64 -64 8 ) ( -64 64 8 ) ( 64 64 8 ) eden/FL_underground 0 0 0.00 1 1 0 0 0 +( -72 -64 8 ) ( 56 -64 8 ) ( 56 -64 0 ) eden/FL_underground 0 0 0.00 1 1 0 0 0 +( 64 -64 8 ) ( 64 64 8 ) ( 64 64 0 ) eden/FL_underground 0 0 0.00 1 1 0 0 0 +( 64 64 8 ) ( -64 64 8 ) ( -64 64 0 ) eden/FL_underground 0 0 0.00 1 1 0 0 0 +( -64 64 8 ) ( -64 -64 8 ) ( -64 -64 0 ) eden/FL_underground 0 0 0.00 1 1 0 0 0 +} +// brush 12 +{ +( 264 264 -8 ) ( -264 264 -8 ) ( -264 -272 -8 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 -272 264 ) ( -264 264 264 ) ( 264 264 264 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 -264 8 ) ( 264 -264 8 ) ( 264 -264 0 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( 264 264 8 ) ( -264 264 8 ) ( -264 264 0 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 264 8 ) ( -264 -272 8 ) ( -264 -272 0 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( -256 -272 8 ) ( -256 264 8 ) ( -256 -272 0 ) eden/FL_edenhouse2 0 0 0.00 1 1 0 0 0 +} +// brush 13 +{ +( 264 272 -8 ) ( -264 272 -8 ) ( -264 -264 -8 ) eden/WL_darkbrick 0 0 0.00 1 1 0 0 0 +( -264 -264 264 ) ( -264 272 264 ) ( 264 272 264 ) eden/WL_darkbrick 0 0 0.00 1 1 0 0 0 +( -64 -272 8 ) ( -64 264 8 ) ( -64 264 0 ) eden/FL_edenhouse2 0 0 0.00 1 1 0 0 0 +( 264 272 8 ) ( -264 272 8 ) ( -264 272 0 ) eden/FL_edenhouse2 0 0 0.00 1 1 0 0 0 +( -264 272 8 ) ( -264 -264 8 ) ( -264 -264 0 ) eden/WL_darkbrick 0 0 0.00 1 1 0 0 0 +( -264 264 8 ) ( 264 264 8 ) ( -264 264 0 ) eden/WL_darkbrick 0 0 0.00 1 1 0 0 0 +} +// brush 14 +{ +( 264 264 -8 ) ( -264 264 -8 ) ( -264 -272 -8 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 -272 264 ) ( -264 264 264 ) ( 264 264 264 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 -264 8 ) ( 264 -264 8 ) ( 264 -264 0 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( 264 -272 8 ) ( 264 264 8 ) ( 264 264 0 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( 264 264 8 ) ( -264 264 8 ) ( -264 264 0 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( 256 264 8 ) ( 256 -272 8 ) ( 256 264 0 ) eden/FL_edenhouse2 0 0 0.00 1 1 0 0 0 +} +// brush 15 +{ +( 264 264 -8 ) ( -264 264 -8 ) ( -264 -272 -8 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 -272 264 ) ( -264 264 264 ) ( 264 264 264 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 -264 8 ) ( 264 -264 8 ) ( 264 -264 0 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( 264 -272 8 ) ( 264 264 8 ) ( 264 264 0 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 264 8 ) ( -264 -272 8 ) ( -264 -272 0 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( 264 -256 8 ) ( -264 -256 8 ) ( 264 -256 0 ) eden/FL_edenhouse2 0 0 0.00 1 1 0 0 0 +} +// brush 16 +{ +( -264 -272 264 ) ( -264 264 264 ) ( 264 264 264 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 -264 8 ) ( 264 -264 8 ) ( 264 -264 0 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( 264 -272 8 ) ( 264 264 8 ) ( 264 264 0 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( 264 264 8 ) ( -264 264 8 ) ( -264 264 0 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 264 8 ) ( -264 -272 8 ) ( -264 -272 0 ) eden/bedroom 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 264 256 ) ( -264 -272 256 ) ( 264 264 256 ) eden/FL_edenhouse2 0 0 0.00 1 1 0 0 0 +} +// brush 17 +{ +( 264 264 -8 ) ( -264 264 -8 ) ( -264 -272 -8 ) eden/FL_edenhouse2 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 -264 8 ) ( 264 -264 8 ) ( 264 -264 0 ) eden/FL_edenhouse2 0 0 0.00 0.500000 0.500000 0 0 0 +( 264 -272 8 ) ( 264 264 8 ) ( 264 264 0 ) eden/FL_edenhouse2 0 0 0.00 0.500000 0.500000 0 0 0 +( 264 264 8 ) ( -264 264 8 ) ( -264 264 0 ) eden/FL_edenhouse2 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 264 8 ) ( -264 -272 8 ) ( -264 -272 0 ) eden/FL_edenhouse2 0 0 0.00 0.500000 0.500000 0 0 0 +( -264 264 0 ) ( 264 264 0 ) ( -264 -272 0 ) eden/FL_edenhouse2 0 0 0.00 0.500000 0.500000 0 0 0 +} +} +// entity 1 +{ +"origin" "-2.38 6.55 8.20" +"spawnflags" "1" +"make_static" "1" +"model" "obj_pad.tik" +"scale" "0.70" +"classname" "Objects_TeleportPad" +} +// entity 2 +{ +"origin" "0 512 8" +"targetname" "t1" +"angle" "270" +"classname" "func_teleportdest" +} +// entity 3 +{ +"classname" "light" +"light" "1000" +"origin" "0 0 128" +} +// entity 4 +{ +"classname" "info_player_start" +"angle" "90" +"origin" "0 -192 16" +} +// entity 5 +{ +"origin" "0 512 128" +"light" "1000" +"classname" "light" +} +// entity 6 +{ +"classname" "Objects_TeleportPad" +"scale" "0.70" +"model" "obj_pad.tik" +"make_static" "1" +"spawnflags" "1" +"origin" " 5.62 510.55 8.20" +} diff --git a/fakk/maps/example/teleporter.prt b/fakk/maps/example/teleporter.prt new file mode 100644 index 0000000..463768f --- /dev/null +++ b/fakk/maps/example/teleporter.prt @@ -0,0 +1,142 @@ +PRT1 +24 +51 +87 +4 0 3 0 (32 544 0 ) (32 480 0 ) (32 480 8 ) (32 544 8 ) +4 0 2 0 (32 776 16 ) (32 776 0 ) (32 544 0 ) (32 544 16 ) +4 0 1 0 (32 776 256 ) (32 776 16 ) (32 480 16 ) (32 480 256 ) +4 0 4 0 (32 480 0 ) (256 480 0 ) (256 480 256 ) (32 480 256 ) +4 1 12 0 (0 480 256 ) (0 776 256 ) (0 776 16 ) (0 480 16 ) +4 1 2 0 (0 776 16 ) (32 776 16 ) (32 544 16 ) (0 544 16 ) +4 1 4 0 (32 480 16 ) (32 480 256 ) (0 480 256 ) (0 480 16 ) +4 2 13 0 (0 776 16 ) (0 776 8 ) (0 544 8 ) (0 544 16 ) +4 2 14 0 (0 776 8 ) (0 776 0 ) (0 544 0 ) (0 544 8 ) +4 2 3 0 (0 544 0 ) (32 544 0 ) (32 544 8 ) (0 544 8 ) +4 3 14 0 (0 544 0 ) (0 480 0 ) (0 480 8 ) (0 544 8 ) +4 3 4 0 (0 480 0 ) (32 480 0 ) (32 480 8 ) (0 480 8 ) +4 4 15 0 (0 480 16 ) (0 480 0 ) (0 272 0 ) (0 272 16 ) +4 4 12 0 (0 272 256 ) (0 480 256 ) (0 480 16 ) (0 272 16 ) +4 4 5 0 (0 272 0 ) (64 272 0 ) (64 272 128 ) (0 272 128 ) +4 5 17 0 (0 272 128 ) (0 272 0 ) (0 256 0 ) (0 256 128 ) +4 5 8 0 (0 256 0 ) (64 256 0 ) (64 256 8 ) (0 256 8 ) +4 5 6 0 (64 256 8 ) (64 256 128 ) (0 256 128 ) (0 256 8 ) +4 6 18 0 (0 0 8 ) (0 0 256 ) (0 256 256 ) (0 256 8 ) +4 6 9 0 (0 0 256 ) (0 0 8 ) (256 0 8 ) (256 0 256 ) +4 6 8 0 (0 256 8 ) (64 256 8 ) (64 64 8 ) (0 64 8 ) +4 6 7 0 (64 256 8 ) (256 256 8 ) (256 0 8 ) (64 0 8 ) +4 7 10 0 (64 0 0 ) (256 0 0 ) (256 0 8 ) (64 0 8 ) +4 7 8 0 (64 64 8 ) (64 256 8 ) (64 256 0 ) (64 64 0 ) +4 8 19 0 (0 64 8 ) (0 256 8 ) (0 256 0 ) (0 64 0 ) +4 9 21 0 (0 0 256 ) (0 0 8 ) (0 -256 8 ) (0 -256 256 ) +4 9 11 0 (64 -256 8 ) (0 -256 8 ) (0 -64 8 ) (64 -64 8 ) +4 9 10 0 (256 -256 8 ) (64 -256 8 ) (64 0 8 ) (256 0 8 ) +4 10 11 0 (64 -64 0 ) (64 -256 0 ) (64 -256 8 ) (64 -64 8 ) +4 11 22 0 (0 -64 0 ) (0 -256 0 ) (0 -256 8 ) (0 -64 8 ) +4 12 17 0 (0 272 16 ) (0 272 128 ) (-32 272 128 ) (-32 272 16 ) +4 12 16 0 (-32 776 256 ) (-32 776 16 ) (-32 272 16 ) (-32 272 256 ) +4 12 13 0 (-32 544 16 ) (-32 776 16 ) (0 776 16 ) (0 544 16 ) +4 12 15 0 (0 272 16 ) (-32 272 16 ) (-32 480 16 ) (0 480 16 ) +4 13 16 0 (-32 776 16 ) (-32 776 8 ) (-32 544 8 ) (-32 544 16 ) +4 13 14 0 (-32 544 8 ) (-32 776 8 ) (0 776 8 ) (0 544 8 ) +4 14 16 0 (-32 776 8 ) (-32 776 0 ) (-32 480 0 ) (-32 480 8 ) +4 14 15 0 (-32 480 8 ) (-32 480 0 ) (0 480 0 ) (0 480 8 ) +4 15 17 0 (-32 272 0 ) (0 272 0 ) (0 272 16 ) (-32 272 16 ) +4 15 16 0 (-32 480 0 ) (-32 272 0 ) (-32 272 16 ) (-32 480 16 ) +4 16 17 0 (-64 272 0 ) (-32 272 0 ) (-32 272 128 ) (-64 272 128 ) +4 17 19 0 (-64 256 0 ) (0 256 0 ) (0 256 8 ) (-64 256 8 ) +4 17 18 0 (0 256 8 ) (0 256 128 ) (-64 256 128 ) (-64 256 8 ) +4 18 21 0 (0 0 8 ) (0 0 256 ) (-256 0 256 ) (-256 0 8 ) +4 18 19 0 (-64 64 8 ) (-64 256 8 ) (0 256 8 ) (0 64 8 ) +4 18 20 0 (-64 0 8 ) (-256 0 8 ) (-256 256 8 ) (-64 256 8 ) +4 19 20 0 (-64 64 8 ) (-64 256 8 ) (-64 256 0 ) (-64 64 0 ) +4 20 23 0 (-256 0 0 ) (-64 0 0 ) (-64 0 8 ) (-256 0 8 ) +4 21 22 0 (0 -256 8 ) (-64 -256 8 ) (-64 -64 8 ) (0 -64 8 ) +4 21 23 0 (-64 -256 8 ) (-256 -256 8 ) (-256 0 8 ) (-64 0 8 ) +4 22 23 0 (-64 -64 0 ) (-64 -256 0 ) (-64 -256 8 ) (-64 -64 8 ) +4 0 (32 480 8 ) (32 480 16 ) (32 544 16 ) (32 544 8 ) +4 0 (32 776 256 ) (256 776 256 ) (256 776 0 ) (32 776 0 ) +4 0 (256 776 256 ) (256 480 256 ) (256 480 0 ) (256 776 0 ) +4 0 (32 776 0 ) (256 776 0 ) (256 480 0 ) (32 480 0 ) +4 0 (32 480 256 ) (256 480 256 ) (256 776 256 ) (32 776 256 ) +4 1 (32 544 16 ) (32 480 16 ) (0 480 16 ) (0 544 16 ) +4 1 (32 480 256 ) (32 776 256 ) (0 776 256 ) (0 480 256 ) +4 1 (0 776 16 ) (0 776 256 ) (32 776 256 ) (32 776 16 ) +4 2 (32 544 8 ) (32 544 16 ) (0 544 16 ) (0 544 8 ) +4 2 (0 776 16 ) (32 776 16 ) (32 776 0 ) (0 776 0 ) +4 2 (0 544 0 ) (0 776 0 ) (32 776 0 ) (32 544 0 ) +4 3 (0 480 0 ) (0 544 0 ) (32 544 0 ) (32 480 0 ) +4 3 (0 480 8 ) (32 480 8 ) (32 544 8 ) (0 544 8 ) +4 4 (64 272 128 ) (64 272 256 ) (0 272 256 ) (0 272 128 ) +4 4 (64 272 0 ) (256 272 0 ) (256 272 256 ) (64 272 256 ) +4 4 (0 480 8 ) (0 480 16 ) (32 480 16 ) (32 480 8 ) +4 4 (256 480 256 ) (256 272 256 ) (256 272 0 ) (256 480 0 ) +4 4 (0 272 0 ) (0 480 0 ) (256 480 0 ) (256 272 0 ) +4 4 (256 272 256 ) (256 480 256 ) (0 480 256 ) (0 272 256 ) +4 5 (64 256 128 ) (64 256 0 ) (64 272 0 ) (64 272 128 ) +4 5 (0 256 0 ) (0 272 0 ) (64 272 0 ) (64 256 0 ) +4 5 (0 256 128 ) (64 256 128 ) (64 272 128 ) (0 272 128 ) +4 6 (64 64 8 ) (64 0 8 ) (0 0 8 ) (0 64 8 ) +4 6 (256 0 256 ) (256 0 8 ) (256 256 8 ) (256 256 256 ) +4 6 (0 256 128 ) (0 256 256 ) (64 256 256 ) (64 256 128 ) +4 6 (64 256 8 ) (64 256 256 ) (256 256 256 ) (256 256 8 ) +4 6 (256 256 256 ) (0 256 256 ) (0 0 256 ) (256 0 256 ) +4 7 (64 0 8 ) (64 64 8 ) (64 64 0 ) (64 0 0 ) +4 7 (256 0 0 ) (64 0 0 ) (64 256 0 ) (256 256 0 ) +4 7 (64 256 8 ) (256 256 8 ) (256 256 0 ) (64 256 0 ) +4 7 (256 0 8 ) (256 0 0 ) (256 256 0 ) (256 256 8 ) +4 8 (0 64 0 ) (0 256 0 ) (64 256 0 ) (64 64 0 ) +4 8 (0 64 0 ) (64 64 0 ) (64 64 8 ) (0 64 8 ) +4 9 (0 -64 8 ) (0 0 8 ) (64 0 8 ) (64 -64 8 ) +4 9 (256 0 256 ) (0 0 256 ) (0 -256 256 ) (256 -256 256 ) +4 9 (256 -256 256 ) (256 -256 8 ) (256 0 8 ) (256 0 256 ) +4 9 (0 -256 256 ) (0 -256 8 ) (256 -256 8 ) (256 -256 256 ) +4 10 (64 0 0 ) (64 -64 0 ) (64 -64 8 ) (64 0 8 ) +4 10 (64 -256 0 ) (256 -256 0 ) (256 -256 8 ) (64 -256 8 ) +4 10 (256 -256 8 ) (256 -256 0 ) (256 0 0 ) (256 0 8 ) +4 10 (64 0 0 ) (256 0 0 ) (256 -256 0 ) (64 -256 0 ) +4 11 (0 -256 0 ) (0 -64 0 ) (64 -64 0 ) (64 -256 0 ) +4 11 (0 -256 8 ) (0 -256 0 ) (64 -256 0 ) (64 -256 8 ) +4 11 (0 -64 8 ) (64 -64 8 ) (64 -64 0 ) (0 -64 0 ) +4 12 (0 272 128 ) (0 272 256 ) (-32 272 256 ) (-32 272 128 ) +4 12 (-32 480 16 ) (-32 544 16 ) (0 544 16 ) (0 480 16 ) +4 12 (-32 272 256 ) (0 272 256 ) (0 776 256 ) (-32 776 256 ) +4 12 (-32 776 16 ) (-32 776 256 ) (0 776 256 ) (0 776 16 ) +4 13 (-32 776 8 ) (-32 776 16 ) (0 776 16 ) (0 776 8 ) +4 13 (-32 544 8 ) (0 544 8 ) (0 544 16 ) (-32 544 16 ) +4 14 (0 544 8 ) (-32 544 8 ) (-32 480 8 ) (0 480 8 ) +4 14 (-32 776 0 ) (0 776 0 ) (0 480 0 ) (-32 480 0 ) +4 14 (-32 776 8 ) (0 776 8 ) (0 776 0 ) (-32 776 0 ) +4 15 (0 480 8 ) (-32 480 8 ) (-32 480 16 ) (0 480 16 ) +4 15 (0 480 0 ) (0 272 0 ) (-32 272 0 ) (-32 480 0 ) +4 16 (-32 272 128 ) (-32 272 256 ) (-64 272 256 ) (-64 272 128 ) +4 16 (-256 272 0 ) (-64 272 0 ) (-64 272 256 ) (-256 272 256 ) +4 16 (-256 272 256 ) (-32 272 256 ) (-32 776 256 ) (-256 776 256 ) +4 16 (-256 776 0 ) (-32 776 0 ) (-32 272 0 ) (-256 272 0 ) +4 16 (-256 776 256 ) (-32 776 256 ) (-32 776 0 ) (-256 776 0 ) +4 16 (-32 544 16 ) (-32 480 16 ) (-32 480 8 ) (-32 544 8 ) +4 16 (-256 776 256 ) (-256 776 0 ) (-256 272 0 ) (-256 272 256 ) +4 17 (-64 272 128 ) (-64 272 0 ) (-64 256 0 ) (-64 256 128 ) +4 17 (-64 272 0 ) (0 272 0 ) (0 256 0 ) (-64 256 0 ) +4 17 (0 272 128 ) (-64 272 128 ) (-64 256 128 ) (0 256 128 ) +4 18 (0 0 8 ) (-64 0 8 ) (-64 64 8 ) (0 64 8 ) +4 18 (-256 256 256 ) (-256 256 8 ) (-256 0 8 ) (-256 0 256 ) +4 18 (-64 256 128 ) (-64 256 256 ) (0 256 256 ) (0 256 128 ) +4 18 (-256 256 8 ) (-256 256 256 ) (-64 256 256 ) (-64 256 8 ) +4 18 (0 256 256 ) (-256 256 256 ) (-256 0 256 ) (0 0 256 ) +4 19 (-64 64 0 ) (-64 256 0 ) (0 256 0 ) (0 64 0 ) +4 19 (-64 64 8 ) (-64 64 0 ) (0 64 0 ) (0 64 8 ) +4 20 (-64 0 0 ) (-64 64 0 ) (-64 64 8 ) (-64 0 8 ) +4 20 (-64 0 0 ) (-256 0 0 ) (-256 256 0 ) (-64 256 0 ) +4 20 (-256 256 8 ) (-64 256 8 ) (-64 256 0 ) (-256 256 0 ) +4 20 (-256 256 8 ) (-256 256 0 ) (-256 0 0 ) (-256 0 8 ) +4 21 (-64 -64 8 ) (-64 0 8 ) (0 0 8 ) (0 -64 8 ) +4 21 (0 0 256 ) (-256 0 256 ) (-256 -256 256 ) (0 -256 256 ) +4 21 (-256 0 256 ) (-256 0 8 ) (-256 -256 8 ) (-256 -256 256 ) +4 21 (-256 -256 256 ) (-256 -256 8 ) (0 -256 8 ) (0 -256 256 ) +4 22 (0 -64 0 ) (0 -256 0 ) (-64 -256 0 ) (-64 -64 0 ) +4 22 (-64 -256 0 ) (0 -256 0 ) (0 -256 8 ) (-64 -256 8 ) +4 22 (0 -64 8 ) (0 -64 0 ) (-64 -64 0 ) (-64 -64 8 ) +4 23 (-64 0 8 ) (-64 -64 8 ) (-64 -64 0 ) (-64 0 0 ) +4 23 (-256 -256 8 ) (-256 -256 0 ) (-64 -256 0 ) (-64 -256 8 ) +4 23 (-256 0 8 ) (-256 0 0 ) (-256 -256 0 ) (-256 -256 8 ) +4 23 (-256 -256 0 ) (-256 0 0 ) (-64 0 0 ) (-64 -256 0 ) diff --git a/fakk/maps/example/useanim.bsp b/fakk/maps/example/useanim.bsp new file mode 100644 index 0000000..acdf5cc Binary files /dev/null and b/fakk/maps/example/useanim.bsp differ diff --git a/fakk/maps/example/useanim.map b/fakk/maps/example/useanim.map new file mode 100644 index 0000000..c3f61ed --- /dev/null +++ b/fakk/maps/example/useanim.map @@ -0,0 +1,348 @@ +{ +"classname" "worldspawn" +// brush 0 +{ +( 224 192 0 ) ( 224 224 0 ) ( -480 224 0 ) eden/bedtrim -224 -32 90.00 1 1 0 0 0 +( -480 224 64 ) ( 224 224 64 ) ( 224 192 64 ) eden/bedtrim -224 -32 90.00 1 1 0 0 0 +( -480 224 256 ) ( -480 192 256 ) ( -480 192 0 ) eden/bedtrim -224 0 0.00 1 1 0 0 0 +( -480 192 256 ) ( 224 192 256 ) ( 224 192 0 ) common/skip 0 0 0.00 1 1 805306368 16512 0 +( 224 224 256 ) ( -480 224 256 ) ( -480 224 0 ) eden/bedtrim 224 0 -180.00 1 -1 0 0 0 +( -416 224 0 ) ( -416 192 0 ) ( -416 208 64 ) eden/bedtrim 224 0 -180.00 1 -1 0 0 0 +} +// brush 1 +{ +( 224 192 0 ) ( 224 224 0 ) ( -480 224 0 ) eden/bedtrim -224 -32 90.00 1 1 0 0 0 +( -480 224 64 ) ( 224 224 64 ) ( 224 192 64 ) eden/bedtrim -224 -32 90.00 1 1 0 0 0 +( -480 192 256 ) ( 224 192 256 ) ( 224 192 0 ) eden/bedtrim 224 0 -180.00 1 -1 0 0 0 +( 224 192 256 ) ( 224 224 256 ) ( 224 224 0 ) eden/bedtrim -224 0 0.00 1 1 0 0 0 +( 224 224 256 ) ( -480 224 256 ) ( -480 224 0 ) eden/bedtrim 224 0 -180.00 1 -1 0 0 0 +( -480 192 0 ) ( -480 224 0 ) ( -480 208 64 ) eden/bedtrim 224 0 -180.00 1 -1 0 0 0 +} +// brush 2 +{ +( 224 192 64 ) ( 224 224 64 ) ( -480 224 64 ) eden/edenmetalwall -224 -224 90.00 1 1 0 0 0 +( -480 224 320 ) ( 224 224 320 ) ( 224 192 320 ) eden/edenmetalwall -224 -224 90.00 1 1 0 0 0 +( -480 224 96 ) ( -480 192 96 ) ( -480 192 64 ) eden/edenmetalwall -224 64 0.00 1 1 0 0 0 +( -480 192 96 ) ( 224 192 96 ) ( 224 192 64 ) common/skip 0 0 0.00 1 1 805306368 16512 0 +( 224 224 96 ) ( -480 224 96 ) ( -480 224 64 ) eden/edenmetalwall 224 63 -180.00 1 -1 0 0 0 +( -416 224 64 ) ( -416 192 64 ) ( -416 208 320 ) eden/edenmetalwall 224 63 -180.00 1 -1 0 0 0 +} +// brush 3 +{ +( 224 192 64 ) ( 224 224 64 ) ( -480 224 64 ) eden/edenmetalwall -224 -224 90.00 1 1 0 0 0 +( -480 224 320 ) ( 224 224 320 ) ( 224 192 320 ) eden/edenmetalwall -224 -224 90.00 1 1 0 0 0 +( -480 192 96 ) ( 224 192 96 ) ( 224 192 64 ) eden/edenmetalwall 224 63 -180.00 1 -1 0 0 0 +( 224 192 96 ) ( 224 224 96 ) ( 224 224 64 ) eden/edenmetalwall -224 64 0.00 1 1 0 0 0 +( 224 224 96 ) ( -480 224 96 ) ( -480 224 64 ) eden/edenmetalwall 224 63 -180.00 1 -1 0 0 0 +( -480 192 64 ) ( -480 224 64 ) ( -480 208 320 ) eden/edenmetalwall 224 63 -180.00 1 -1 0 0 0 +} +// brush 4 + { + patchDef2 + { + eden/edenmetalwall + ( 3 3 0 536870912 0 ) +( +( ( -480 96 63.999992 0 0 ) ( -480 96 192 0 0.500000 ) ( -480 96 320 0 1 ) ) +( ( -384 96 63.999992 0.500000 0 ) ( -384 96 192 0.500000 0.500000 ) ( -384 96 320 0.500000 1 ) ) +( ( -384 192 63.999992 1 0 ) ( -384 192 192 1 0.500000 ) ( -384 192 320 1 1 ) ) +) + } + } +// brush 5 +{ +( -480 192 0 ) ( -512 192 0 ) ( -512 -512 0 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +( -512 -512 64 ) ( -512 192 64 ) ( -480 192 64 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +( -480 -512 256 ) ( -480 192 256 ) ( -480 192 0 ) common/skip 0 0 0.00 1 1 805306368 16512 0 +( -480 192 256 ) ( -512 192 256 ) ( -512 192 0 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +( -512 192 256 ) ( -512 -512 256 ) ( -512 -512 0 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +( -480 128 0 ) ( -512 128 0 ) ( -496 128 64 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +} +// brush 6 +{ +( -480 192 0 ) ( -512 192 0 ) ( -512 -512 0 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +( -512 -512 64 ) ( -512 192 64 ) ( -480 192 64 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +( -512 -512 256 ) ( -480 -512 256 ) ( -480 -512 0 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +( -480 -512 256 ) ( -480 192 256 ) ( -480 192 0 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +( -512 192 256 ) ( -512 -512 256 ) ( -512 -512 0 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +( -512 192 0 ) ( -480 192 0 ) ( -496 192 64 ) eden/bedtrim 0 0 0.00 1 1 0 0 0 +} +// brush 7 +{ +( -480 192 64 ) ( -512 192 64 ) ( -512 -512 64 ) eden/edenmetalwall 0 0 0.00 1 1 0 0 0 +( -512 -512 320 ) ( -512 192 320 ) ( -480 192 320 ) eden/edenmetalwall 0 0 0.00 1 1 0 0 0 +( -480 -512 96 ) ( -480 192 96 ) ( -480 192 64 ) common/skip 0 0 0.00 1 1 805306368 16512 0 +( -480 192 96 ) ( -512 192 96 ) ( -512 192 64 ) eden/edenmetalwall 0 64 0.00 1 1 0 0 0 +( -512 192 96 ) ( -512 -512 96 ) ( -512 -512 64 ) eden/edenmetalwall 0 64 0.00 1 1 0 0 0 +( -480 128 64 ) ( -512 128 64 ) ( -496 128 320 ) eden/edenmetalwall 0 64 0.00 1 1 0 0 0 +} +// brush 8 +{ +( -480 192 64 ) ( -512 192 64 ) ( -512 -512 64 ) eden/edenmetalwall 0 0 0.00 1 1 0 0 0 +( -512 -512 320 ) ( -512 192 320 ) ( -480 192 320 ) eden/edenmetalwall 0 0 0.00 1 1 0 0 0 +( -512 -512 96 ) ( -480 -512 96 ) ( -480 -512 64 ) eden/edenmetalwall 0 64 0.00 1 1 0 0 0 +( -480 -512 96 ) ( -480 192 96 ) ( -480 192 64 ) eden/edenmetalwall 0 64 0.00 1 1 0 0 0 +( -512 192 96 ) ( -512 -512 96 ) ( -512 -512 64 ) eden/edenmetalwall 0 64 0.00 1 1 0 0 0 +( -512 192 64 ) ( -480 192 64 ) ( -496 192 320 ) eden/edenmetalwall 0 64 0.00 1 1 0 0 0 +} +// brush 9 + { + patchDef2 + { + eden/bedtrim + ( 3 3 0 536870912 0 ) +( +( ( -480 96 0 0 0 ) ( -480 96 32 0 0.500000 ) ( -480 96 64 0 1 ) ) +( ( -384 96 0 0.500000 0 ) ( -384 96 32 0.500000 0.500000 ) ( -384 96 64 0.500000 1 ) ) +( ( -384 192 0 1 0 ) ( -384 192 32 1 0.500000 ) ( -384 192 64 1 1 ) ) +) + } + } +// brush 10 +{ +( 96 96 352 ) ( -32 96 352 ) ( -32 -416 352 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( -32 -416 416 ) ( -32 96 416 ) ( 96 96 416 ) we_cemetary_test/levelord_sky 0 0 0.00 1 1 0 0 0 +( -32 -416 416 ) ( 96 -416 416 ) ( 96 -416 352 ) we_cemetary_test/levelord_sky 0 0 0.00 1 1 0 0 0 +( 96 -416 416 ) ( 96 96 416 ) ( 96 96 352 ) we_cemetary_test/levelord_sky 0 0 0.00 1 1 0 0 0 +( 96 96 416 ) ( -32 96 416 ) ( -32 96 352 ) we_cemetary_test/levelord_sky 0 0 0.00 1 1 0 0 0 +( -32 96 416 ) ( -32 -416 416 ) ( -32 -416 352 ) we_cemetary_test/levelord_sky 0 0 0.00 1 1 0 0 0 +} +// brush 11 +{ +( -64 -416 304 ) ( -64 -448 304 ) ( 128 -448 304 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( 128 -448 352 ) ( -64 -448 352 ) ( -64 -416 352 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( 96 -416 352 ) ( -32 -416 352 ) ( -32 -416 320 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( 128 -448 352 ) ( 96 -416 352 ) ( 96 -416 320 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( -64 -448 320 ) ( -64 -448 352 ) ( 128 -448 352 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( -64 -448 320 ) ( -32 -416 320 ) ( -32 -416 352 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +} +// brush 12 +{ +( -32 128 304 ) ( -64 128 304 ) ( -64 -64 304 ) eden/FL_edenhouse 0 32 90.00 1 1 0 0 0 +( -64 -64 352 ) ( -64 128 352 ) ( -32 128 352 ) eden/FL_edenhouse 0 32 90.00 1 1 0 0 0 +( -32 -32 352 ) ( -32 96 352 ) ( -32 96 320 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( -64 -448 352 ) ( -32 -416 352 ) ( -32 -416 320 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( -64 128 320 ) ( -64 128 352 ) ( -64 -64 352 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( -64 128 320 ) ( -32 96 320 ) ( -32 96 352 ) eden/FL_edenhouse -64 0 -180.00 1 -1 0 0 0 +} +// brush 13 +{ +( 128 -64 304 ) ( 128 128 304 ) ( 96 128 304 ) eden/FL_edenhouse 0 -96 90.00 1 1 0 0 0 +( 96 128 352 ) ( 128 128 352 ) ( 128 -64 352 ) eden/FL_edenhouse 0 -96 90.00 1 1 0 0 0 +( 96 96 320 ) ( 96 96 352 ) ( 96 -32 352 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( 96 -416 320 ) ( 96 -416 352 ) ( 128 -448 352 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( 128 -64 352 ) ( 128 128 352 ) ( 128 128 320 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( 96 96 352 ) ( 96 96 320 ) ( 128 128 320 ) eden/FL_edenhouse -64 0 -180.00 1 -1 0 0 0 +} +// brush 14 +{ +( 128 128 304 ) ( -64 128 304 ) ( -64 96 304 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( -64 96 352 ) ( -64 128 352 ) ( 128 128 352 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( -32 96 320 ) ( -32 96 352 ) ( 96 96 352 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( 96 96 320 ) ( 96 96 352 ) ( 128 128 352 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( 128 128 352 ) ( -64 128 352 ) ( -64 128 320 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +( -32 96 352 ) ( -32 96 320 ) ( -64 128 320 ) eden/FL_edenhouse 0 0 0.00 1 1 0 0 0 +} +// brush 15 +{ +( 128 192 320 ) ( -64 192 320 ) ( -64 128 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( -64 128 352 ) ( -64 192 352 ) ( 128 192 352 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( -64 128 352 ) ( 128 128 352 ) ( 128 128 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( 128 128 352 ) ( 128 192 352 ) ( 128 192 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( 128 192 352 ) ( -64 192 352 ) ( -64 192 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( -64 192 352 ) ( -64 128 352 ) ( -64 128 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +} +// brush 16 +{ +( 192 192 320 ) ( 128 192 320 ) ( 128 -448 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( 128 -448 352 ) ( 128 192 352 ) ( 192 192 352 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( 128 -448 352 ) ( 192 -448 352 ) ( 192 -448 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( 192 -448 352 ) ( 192 192 352 ) ( 192 192 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( 192 192 352 ) ( 128 192 352 ) ( 128 192 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( 128 192 352 ) ( 128 -448 352 ) ( 128 -448 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +} +// brush 17 +{ +( 192 192 320 ) ( -480 192 320 ) ( -480 -512 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( -480 -512 352 ) ( -480 192 352 ) ( 192 192 352 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( -480 -512 352 ) ( 192 -512 352 ) ( 192 -512 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( 192 -512 352 ) ( 192 192 352 ) ( 192 192 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( 224 -448 352 ) ( -448 -448 352 ) ( -448 -448 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( -64 -256 320 ) ( -64 -128 320 ) ( -64 -192 352 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +} +// brush 18 +{ +( 192 192 320 ) ( -480 192 320 ) ( -480 -512 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( -480 -512 352 ) ( -480 192 352 ) ( 192 192 352 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( -480 -512 352 ) ( 192 -512 352 ) ( 192 -512 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( 192 192 352 ) ( -480 192 352 ) ( -480 192 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( -480 192 352 ) ( -480 -512 352 ) ( -480 -512 320 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +( -64 -128 320 ) ( -64 -256 320 ) ( -64 -192 352 ) eden/CL_edenroof3 0 0 0.00 1 1 0 0 0 +} +// brush 19 +{ +( 192 192 -32 ) ( -480 192 -32 ) ( -480 -512 -32 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( -480 -512 0 ) ( -480 192 0 ) ( 192 192 0 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( -480 -512 224 ) ( 192 -512 224 ) ( 192 -512 -32 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 192 -512 224 ) ( 192 192 224 ) ( 192 192 -32 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( 192 192 224 ) ( -480 192 224 ) ( -480 192 -32 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( -480 192 224 ) ( -480 -512 224 ) ( -480 -512 -32 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +} +// brush 20 +{ +( -480 -512 64 ) ( -480 -544 64 ) ( 224 -544 64 ) eden/edenmetalwall -31 31 -90.00 1 1 0 0 0 +( 224 -544 320 ) ( -480 -544 320 ) ( -480 -512 320 ) eden/edenmetalwall -31 31 -90.00 1 1 0 0 0 +( 224 -544 96 ) ( 224 -512 96 ) ( 224 -512 64 ) eden/edenmetalwall -32 63 -180.00 1 -1 0 0 0 +( 224 -512 96 ) ( -480 -512 96 ) ( -480 -512 64 ) eden/edenmetalwall -32 62 0.00 1.000008 1 0 0 0 +( -480 -512 96 ) ( -480 -544 96 ) ( -480 -544 64 ) eden/edenmetalwall -33 63 -180.00 1 -1 0 0 0 +( -480 -544 96 ) ( 224 -544 96 ) ( 224 -544 64 ) eden/edenmetalwall -32 62 0.00 1.000008 1 0 0 0 +} +// brush 21 +{ +( -480 -512 0 ) ( -480 -544 0 ) ( 224 -544 0 ) eden/bedtrim -31 32 -90.00 1 1 0 0 0 +( 224 -544 64 ) ( -480 -544 64 ) ( -480 -512 64 ) eden/bedtrim -31 32 -90.00 1 1 0 0 0 +( 224 -544 256 ) ( 224 -512 256 ) ( 224 -512 0 ) eden/bedtrim -32 0 -180.00 1 -1 0 0 0 +( 224 -512 256 ) ( -480 -512 256 ) ( -480 -512 0 ) eden/bedtrim -32 0 0.00 1 1 0 0 0 +( -480 -512 256 ) ( -480 -544 256 ) ( -480 -544 0 ) eden/bedtrim -33 0 -180.00 1 -1 0 0 0 +( -480 -544 256 ) ( 224 -544 256 ) ( 224 -544 0 ) eden/bedtrim -32 0 0.00 1 1 0 0 0 +} +// brush 22 +{ +( 192 -512 0 ) ( 224 -512 0 ) ( 224 192 0 ) eden/bedtrim 160 0 -180.00 1 1 0 0 0 +( 224 192 64 ) ( 224 -512 64 ) ( 192 -512 64 ) eden/bedtrim 160 0 -180.00 1 1 0 0 0 +( 224 192 256 ) ( 192 192 256 ) ( 192 192 0 ) eden/bedtrim 160 0 -180.00 1 -1 0 0 0 +( 192 192 256 ) ( 192 -512 256 ) ( 192 -512 0 ) eden/bedtrim -64 0 -180.00 1 -1 0 0 0 +( 192 -512 256 ) ( 224 -512 256 ) ( 224 -512 0 ) eden/bedtrim 159 0 -180.00 1 -1 0 0 0 +( 224 -512 256 ) ( 224 192 256 ) ( 224 192 0 ) eden/bedtrim -64 0 -180.00 1 -1 0 0 0 +} +// brush 23 +{ +( 192 -512 64 ) ( 224 -512 64 ) ( 224 192 64 ) eden/edenmetalwall 160 63 -180.00 1 1 0 0 0 +( 224 192 320 ) ( 224 -512 320 ) ( 192 -512 320 ) eden/edenmetalwall 160 63 -180.00 1 1 0 0 0 +( 224 192 96 ) ( 192 192 96 ) ( 192 192 64 ) eden/edenmetalwall 160 64 -180.00 1 -1 0 0 0 +( 192 192 96 ) ( 192 -512 96 ) ( 192 -512 64 ) eden/edenmetalwall -64 62 -180.00 1 -1 0 0 0 +( 192 -512 96 ) ( 224 -512 96 ) ( 224 -512 64 ) eden/edenmetalwall 159 64 -180.00 1 -1 0 0 0 +( 224 -512 96 ) ( 224 192 96 ) ( 224 192 64 ) eden/edenmetalwall -64 62 -180.00 1 -1 0 0 0 +} +} +// entity 1 +{ +"classname" "script_object" +"targetname" "pushwall" +// brush 0 +{ +( -160 40 0 ) ( -320 40 0 ) ( -320 -104 0 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( -320 -104 128 ) ( -320 40 128 ) ( -160 40 128 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( -320 -102 104 ) ( -160 -102 104 ) ( -160 -102 0 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( -200 -104 104 ) ( -200 40 104 ) ( -200 40 0 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( -154 -34 104 ) ( -314 -34 104 ) ( -314 -34 0 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( -264 34 104 ) ( -264 -110 104 ) ( -264 -110 0 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +} +} +// entity 2 +{ +"targetname" "t1" +"origin" "-219.66 -118.36 4.27" +"model" "func_useanimdest.tik" +"scale" "1.0" +"classname" "func_useanimdest" +"angle" "90" +"anim" "push" +} +// entity 3 +{ +"target" "t1" +"classname" "func_useanim" +"spawnflags" "2" +// brush 0 +{ +( -146 -54 0 ) ( -298 -54 0 ) ( -298 -134 0 ) eden/CL_edenroof3 2 58 0.00 1 1 0 0 0 +( -298 -134 120 ) ( -298 -54 120 ) ( -146 -54 120 ) eden/CL_edenroof3 2 58 0.00 1 1 0 0 0 +( -298 -134 8 ) ( -146 -134 8 ) ( -146 -134 0 ) eden/CL_edenroof3 2 0 0.00 1 1 0 0 0 +( -204 -134 8 ) ( -204 -54 8 ) ( -204 -54 0 ) eden/CL_edenroof3 -58 0 0.00 1 1 0 0 0 +( -146 -102 8 ) ( -298 -102 8 ) ( -298 -102 0 ) eden/CL_edenroof3 2 0 0.00 1 1 0 0 0 +( -262 -54 8 ) ( -262 -134 8 ) ( -262 -134 0 ) eden/CL_edenroof3 -58 0 0.00 1 1 0 0 0 +} +} +// entity 4 +{ +"classname" "light" +"spawnflags" "0" +"origin" "-352 56 168" +"light" "200" +"_color" "1.000000 0.724409 0.523622" +} +// entity 5 +{ +"classname" "info_player_start" +"angle" "45" +"origin" "-432 -464 24" +} +// entity 6 +{ +"origin" "8 56 168" +"spawnflags" "0" +"classname" "light" +"light" "200" +"_color" "0.629921 0.846457 1.000000" +} +// entity 7 +{ +"origin" "-344 -376 168" +"spawnflags" "0" +"classname" "light" +"light" "200" +} +// entity 8 +{ +"classname" "light" +"spawnflags" "0" +"origin" "8 -376 168" +"light" "200" +} +// entity 9 +{ +"light" "200" +"classname" "light" +"spawnflags" "0" +"origin" "-168 -160 168" +} +// entity 10 +{ +"targetname" "t2" +"classname" "script_object" +// brush 0 +{ +( 104 -248 0 ) ( -56 -248 0 ) ( -56 -392 0 ) eden/FL_edenhouse3 -8 -32 0.00 1 1 0 0 0 +( -56 -392 128 ) ( -56 -248 128 ) ( 104 -248 128 ) eden/FL_edenhouse3 -8 -32 0.00 1 1 0 0 0 +( -56 -390 104 ) ( 104 -390 104 ) ( 104 -390 0 ) eden/FL_edenhouse3 -8 0 0.00 1 1 0 0 0 +( 64 -392 104 ) ( 64 -248 104 ) ( 64 -248 0 ) eden/FL_edenhouse3 31 0 0.00 1 1 0 0 0 +( 110 -322 104 ) ( -50 -322 104 ) ( -50 -322 0 ) eden/FL_edenhouse3 -8 0 0.00 1 1 0 0 0 +( 0 -254 104 ) ( 0 -398 104 ) ( 0 -398 0 ) eden/FL_edenhouse3 31 0 0.00 1 1 0 0 0 +} +} +// entity 11 +{ +"anim" "push" +"angle" "0" +"classname" "func_useanimdest" +"scale" "1.00" +"model" "func_useanimdest.tik" +"origin" "-16.36 -377.79 4.27" +"targetname" "t3" +} +// entity 12 +{ +"spawnflags" "1" +"classname" "func_useanim" +"target" "t3" +// brush 0 +{ +( -70 -392 -2 ) ( -222 -392 -2 ) ( -222 -472 -2 ) eden/CL_edenroof3 54 -24 0.00 1 1 0 0 0 +( -222 -472 118 ) ( -222 -392 118 ) ( -70 -392 118 ) eden/CL_edenroof3 54 -24 0.00 1 1 0 0 0 +( -220 -508 6 ) ( -68 -508 6 ) ( -68 -508 -2 ) eden/CL_edenroof3 54 -2 0.00 1 1 0 0 0 +( -128 -472 6 ) ( -128 -392 6 ) ( -128 -392 -2 ) eden/CL_edenroof3 23 -2 0.00 1 1 0 0 0 +( -68 -448 6 ) ( -220 -448 6 ) ( -220 -448 -2 ) eden/CL_edenroof3 54 -2 0.00 1 1 0 0 0 +( -186 -392 6 ) ( -186 -472 6 ) ( -186 -472 -2 ) eden/CL_edenroof3 23 -2 0.00 1 1 0 0 0 +} +} diff --git a/fakk/maps/example/useanim.prt b/fakk/maps/example/useanim.prt new file mode 100644 index 0000000..63b4d74 --- /dev/null +++ b/fakk/maps/example/useanim.prt @@ -0,0 +1,96 @@ +PRT1 +16 +28 +64 +4 0 4 0 (128 0 304 ) (192 0 304 ) (192 0 320 ) (128 0 320 ) +4 0 3 0 (128 192 304 ) (192 192 304 ) (192 0 304 ) (128 0 304 ) +4 0 1 0 (128 192 320 ) (128 192 304 ) (128 128 304 ) (128 128 320 ) +4 1 8 0 (0 192 320 ) (0 192 304 ) (0 128 304 ) (0 128 320 ) +4 1 3 0 (0 192 304 ) (128 192 304 ) (128 128 304 ) (0 128 304 ) +4 2 9 0 (0 0 304 ) (0 0 352 ) (0 96 352 ) (0 96 304 ) +4 2 5 0 (0 0 352 ) (0 0 304 ) (96 0 304 ) (96 0 352 ) +4 2 3 0 (96 0 304 ) (0 0 304 ) (0 96 304 ) (96 96 304 ) +4 3 11 0 (0 0 0 ) (0 0 304 ) (0 192 304 ) (0 192 0 ) +4 3 7 0 (0 0 304 ) (0 0 0 ) (192 0 0 ) (192 0 304 ) +4 4 7 0 (128 0 304 ) (192 0 304 ) (192 -448 304 ) (128 -448 304 ) +4 4 6 0 (128 -448 304 ) (192 -448 304 ) (192 -448 320 ) (128 -448 320 ) +4 5 12 0 (0 0 352 ) (0 0 304 ) (0 -416 304 ) (0 -416 352 ) +4 5 7 0 (0 0 304 ) (96 0 304 ) (96 -416 304 ) (0 -416 304 ) +4 6 13 0 (0 -512 304 ) (0 -512 320 ) (0 -448 320 ) (0 -448 304 ) +4 6 7 0 (192 -448 304 ) (192 -512 304 ) (0 -512 304 ) (0 -448 304 ) +4 7 15 0 (0 -512 0 ) (0 -512 304 ) (0 0 304 ) (0 0 0 ) +4 8 11 0 (-64 128 304 ) (-64 192 304 ) (0 192 304 ) (0 128 304 ) +4 8 10 0 (-64 192 320 ) (-64 192 304 ) (-64 128 304 ) (-64 128 320 ) +4 9 12 0 (0 0 304 ) (0 0 352 ) (-32 0 352 ) (-32 0 304 ) +4 9 11 0 (0 0 304 ) (-32 0 304 ) (-32 96 304 ) (0 96 304 ) +4 10 14 0 (-480 0 320 ) (-480 0 304 ) (-64 0 304 ) (-64 0 320 ) +4 10 11 0 (-64 0 304 ) (-480 0 304 ) (-480 192 304 ) (-64 192 304 ) +4 11 15 0 (0 0 0 ) (0 0 304 ) (-480 0 304 ) (-480 0 0 ) +4 12 15 0 (-32 0 304 ) (0 0 304 ) (0 -416 304 ) (-32 -416 304 ) +4 13 15 0 (0 -512 304 ) (-64 -512 304 ) (-64 -448 304 ) (0 -448 304 ) +4 13 14 0 (-64 -448 304 ) (-64 -512 304 ) (-64 -512 320 ) (-64 -448 320 ) +4 14 15 0 (-64 -512 304 ) (-480 -512 304 ) (-480 0 304 ) (-64 0 304 ) +4 0 (128 96 304 ) (128 0 304 ) (128 0 320 ) (128 96 320 ) +4 0 (128 128 304 ) (128 96 304 ) (128 96 320 ) (128 128 320 ) +4 0 (192 0 320 ) (192 0 304 ) (192 192 304 ) (192 192 320 ) +4 0 (128 192 320 ) (192 192 320 ) (192 192 304 ) (128 192 304 ) +4 0 (192 0 320 ) (192 192 320 ) (128 192 320 ) (128 0 320 ) +4 1 (0 128 304 ) (128 128 304 ) (128 128 320 ) (0 128 320 ) +4 1 (128 192 320 ) (128 192 304 ) (0 192 304 ) (0 192 320 ) +4 1 (128 192 320 ) (0 192 320 ) (0 128 320 ) (128 128 320 ) +4 2 (96 96 352 ) (0 96 352 ) (0 0 352 ) (96 0 352 ) +4 2 (0 96 352 ) (96 96 352 ) (96 96 304 ) (0 96 304 ) +4 2 (96 0 352 ) (96 0 304 ) (96 96 304 ) (96 96 352 ) +4 3 (192 192 304 ) (192 192 0 ) (0 192 0 ) (0 192 304 ) +4 3 (192 0 304 ) (192 0 0 ) (192 192 0 ) (192 192 304 ) +4 3 (0 128 304 ) (0 96 304 ) (128 96 304 ) (128 128 304 ) +4 3 (96 96 304 ) (96 0 304 ) (128 0 304 ) (128 96 304 ) +4 3 (0 192 0 ) (192 192 0 ) (192 0 0 ) (0 0 0 ) +4 4 (128 0 304 ) (128 -448 304 ) (128 -448 320 ) (128 0 320 ) +4 4 (192 -448 320 ) (192 -448 304 ) (192 0 304 ) (192 0 320 ) +4 4 (192 0 320 ) (128 0 320 ) (128 -448 320 ) (192 -448 320 ) +4 5 (96 -416 352 ) (96 0 352 ) (0 0 352 ) (0 -416 352 ) +4 5 (96 0 352 ) (96 -416 352 ) (96 -416 304 ) (96 0 304 ) +4 5 (0 -416 304 ) (96 -416 304 ) (96 -416 352 ) (0 -416 352 ) +4 6 (192 -448 320 ) (192 -512 320 ) (192 -512 304 ) (192 -448 304 ) +4 6 (0 -512 320 ) (0 -512 304 ) (192 -512 304 ) (192 -512 320 ) +4 6 (96 -448 320 ) (128 -448 320 ) (128 -448 304 ) (96 -448 304 ) +4 6 (96 -448 320 ) (96 -448 304 ) (0 -448 304 ) (0 -448 320 ) +4 6 (0 -512 320 ) (192 -512 320 ) (192 -448 320 ) (0 -448 320 ) +4 7 (0 -512 304 ) (0 -512 0 ) (192 -512 0 ) (192 -512 304 ) +4 7 (192 -512 304 ) (192 -512 0 ) (192 0 0 ) (192 0 304 ) +4 7 (96 -448 304 ) (128 -448 304 ) (128 0 304 ) (96 0 304 ) +4 7 (0 -416 304 ) (0 -448 304 ) (96 -448 304 ) (96 -416 304 ) +4 7 (0 0 0 ) (192 0 0 ) (192 -512 0 ) (0 -512 0 ) +4 8 (-64 128 320 ) (-64 128 304 ) (0 128 304 ) (0 128 320 ) +4 8 (-64 192 304 ) (-64 192 320 ) (0 192 320 ) (0 192 304 ) +4 8 (0 192 320 ) (-64 192 320 ) (-64 128 320 ) (0 128 320 ) +4 9 (0 96 352 ) (-32 96 352 ) (-32 0 352 ) (0 0 352 ) +4 9 (0 96 304 ) (-32 96 304 ) (-32 96 352 ) (0 96 352 ) +4 9 (-32 96 352 ) (-32 96 304 ) (-32 0 304 ) (-32 0 352 ) +4 10 (-480 192 320 ) (-480 192 304 ) (-480 0 304 ) (-480 0 320 ) +4 10 (-64 192 320 ) (-64 192 304 ) (-480 192 304 ) (-480 192 320 ) +4 10 (-64 128 320 ) (-64 96 320 ) (-64 96 304 ) (-64 128 304 ) +4 10 (-64 96 320 ) (-64 0 320 ) (-64 0 304 ) (-64 96 304 ) +4 10 (-64 0 320 ) (-64 192 320 ) (-480 192 320 ) (-480 0 320 ) +4 11 (-480 192 0 ) (-480 192 304 ) (0 192 304 ) (0 192 0 ) +4 11 (-480 192 304 ) (-480 192 0 ) (-480 0 0 ) (-480 0 304 ) +4 11 (0 96 304 ) (0 128 304 ) (-64 128 304 ) (-64 96 304 ) +4 11 (-32 96 304 ) (-64 96 304 ) (-64 0 304 ) (-32 0 304 ) +4 11 (0 0 0 ) (-480 0 0 ) (-480 192 0 ) (0 192 0 ) +4 12 (0 -416 352 ) (-32 -416 352 ) (-32 -416 304 ) (0 -416 304 ) +4 12 (-32 -416 352 ) (0 -416 352 ) (0 0 352 ) (-32 0 352 ) +4 12 (-32 0 304 ) (-32 -416 304 ) (-32 -416 352 ) (-32 0 352 ) +4 13 (-64 -512 304 ) (0 -512 304 ) (0 -512 320 ) (-64 -512 320 ) +4 13 (0 -448 320 ) (0 -448 304 ) (-64 -448 304 ) (-64 -448 320 ) +4 13 (0 -448 320 ) (-64 -448 320 ) (-64 -512 320 ) (0 -512 320 ) +4 14 (-480 -512 320 ) (-480 -512 304 ) (-64 -512 304 ) (-64 -512 320 ) +4 14 (-480 0 320 ) (-480 0 304 ) (-480 -512 304 ) (-480 -512 320 ) +4 14 (-64 -416 320 ) (-64 -448 320 ) (-64 -448 304 ) (-64 -416 304 ) +4 14 (-64 -416 320 ) (-64 -416 304 ) (-64 0 304 ) (-64 0 320 ) +4 14 (-480 0 320 ) (-480 -512 320 ) (-64 -512 320 ) (-64 0 320 ) +4 15 (-480 0 304 ) (-480 0 0 ) (-480 -512 0 ) (-480 -512 304 ) +4 15 (-480 -512 304 ) (-480 -512 0 ) (0 -512 0 ) (0 -512 304 ) +4 15 (0 -448 304 ) (0 -416 304 ) (-64 -416 304 ) (-64 -448 304 ) +4 15 (-32 -416 304 ) (-32 0 304 ) (-64 0 304 ) (-64 -416 304 ) +4 15 (0 -512 0 ) (-480 -512 0 ) (-480 0 0 ) (0 0 0 ) diff --git a/fakk/maps/example/useobject.bsp b/fakk/maps/example/useobject.bsp new file mode 100644 index 0000000..4dc7500 Binary files /dev/null and b/fakk/maps/example/useobject.bsp differ diff --git a/fakk/maps/example/useobject.map b/fakk/maps/example/useobject.map new file mode 100644 index 0000000..2217b3c --- /dev/null +++ b/fakk/maps/example/useobject.map @@ -0,0 +1,225 @@ +{ +"classname" "worldspawn" +// brush 0 +{ +( 176 48 32 ) ( -32 48 32 ) ( -32 -112 32 ) eden/wood -96 0 -180.00 1 -1 0 0 0 +( -16 -112 48 ) ( -16 48 48 ) ( 192 48 48 ) eden/wood -96 0 -180.00 1 -1 0 0 0 +( -32 -96 96 ) ( 176 -96 96 ) ( 176 -96 32 ) eden/wood -96 0 -180.00 1 -1 0 0 0 +( 176 -112 96 ) ( 176 48 96 ) ( 176 48 32 ) eden/wood -96 0 -180.00 1 -1 0 0 0 +( 176 16 96 ) ( -32 16 96 ) ( -32 16 32 ) eden/wood -96 0 -180.00 1 -1 0 0 0 +( 0 48 96 ) ( 0 -112 96 ) ( 0 -112 32 ) eden/wood -96 0 -180.00 1 -1 0 0 0 +} +// brush 1 +{ +( -288 -256 384 ) ( 544 -256 384 ) ( 544 -1120 384 ) eden/wood -96 96 90.00 1 1 0 0 0 +( -288 -256 32 ) ( -288 -1120 32 ) ( -288 -1120 0 ) eden/wood -96 0 0.00 1 1 0 0 0 +( 512 -1120 32 ) ( 512 -256 32 ) ( 512 -256 0 ) eden/wood -95 0 0.00 1 1 0 0 0 +( 544 -256 32 ) ( -288 -256 32 ) ( -288 -256 0 ) eden/wood -96 0 -180.00 1 -1 0 0 0 +( -288 -288 32 ) ( 544 -288 32 ) ( -288 -288 0 ) eden/wood -96 0 -180.00 1 -1 0 0 0 +( 512 -544 320 ) ( -288 -512 320 ) ( -288 -576 320 ) eden/wood -96 96 90.00 1 1 0 0 0 +} +// brush 2 +{ +( -288 -64 384 ) ( 544 -64 384 ) ( 544 -928 384 ) eden/wood -96 96 90.00 1 1 0 0 0 +( -288 -64 32 ) ( -288 -928 32 ) ( -288 -928 0 ) eden/wood -96 0 0.00 1 1 0 0 0 +( 512 -928 32 ) ( 512 -64 32 ) ( 512 -64 0 ) eden/wood -95 0 0.00 1 1 0 0 0 +( 544 -64 32 ) ( -288 -64 32 ) ( -288 -64 0 ) eden/wood -96 0 -180.00 1 -1 0 0 0 +( -288 -96 32 ) ( 544 -96 32 ) ( -288 -96 0 ) eden/wood -96 0 -180.00 1 -1 0 0 0 +( 512 -352 320 ) ( -288 -320 320 ) ( -288 -384 320 ) eden/wood -96 96 90.00 1 1 0 0 0 +} +// brush 3 +{ +( -288 96 384 ) ( 544 96 384 ) ( 544 -768 384 ) eden/wood -96 96 90.00 1 1 0 0 0 +( -288 96 32 ) ( -288 -768 32 ) ( -288 -768 0 ) eden/wood -96 0 0.00 1 1 0 0 0 +( 512 -768 32 ) ( 512 96 32 ) ( 512 96 0 ) eden/wood -95 0 0.00 1 1 0 0 0 +( 544 96 32 ) ( -288 96 32 ) ( -288 96 0 ) eden/wood -96 0 -180.00 1 -1 0 0 0 +( -288 64 32 ) ( 544 64 32 ) ( -288 64 0 ) eden/wood -96 0 -180.00 1 -1 0 0 0 +( 512 -192 320 ) ( -288 -160 320 ) ( -288 -224 320 ) eden/wood -96 96 90.00 1 1 0 0 0 +} +// brush 4 +{ +( -288 256 384 ) ( 544 256 384 ) ( 544 -608 384 ) eden/wood -96 96 90.00 1 1 0 0 0 +( -288 256 32 ) ( -288 -608 32 ) ( -288 -608 0 ) eden/wood -96 0 0.00 1 1 0 0 0 +( 512 -608 32 ) ( 512 256 32 ) ( 512 256 0 ) eden/wood -95 0 0.00 1 1 0 0 0 +( 544 256 32 ) ( -288 256 32 ) ( -288 256 0 ) eden/wood -96 0 -180.00 1 -1 0 0 0 +( -288 224 32 ) ( 544 224 32 ) ( -288 224 0 ) eden/wood -96 0 -180.00 1 -1 0 0 0 +( 512 -32 320 ) ( -288 0 320 ) ( -288 -64 320 ) eden/wood -96 96 90.00 1 1 0 0 0 +} +// brush 5 +{ +( 544 416 0 ) ( -320 416 0 ) ( -320 -416 0 ) eden/wood 0 0 0.00 1 1 0 0 0 +( -320 -416 32 ) ( 544 -416 32 ) ( 544 -416 0 ) eden/wood 0 0 0.00 1 1 0 0 0 +( 544 384 32 ) ( -320 384 32 ) ( -320 384 0 ) eden/wood 0 0 0.00 1 1 0 0 0 +( -320 416 32 ) ( -320 -416 32 ) ( -320 -416 0 ) eden/wood 0 0 0.00 1 1 0 0 0 +( -288 -416 32 ) ( -288 416 32 ) ( -288 -416 0 ) eden/wood 0 0 0.00 1 1 0 0 0 +( -128 -416 64 ) ( -64 384 64 ) ( 0 -416 64 ) eden/wood 0 0 0.00 1 1 0 0 0 +} +// brush 6 +{ +( 544 416 0 ) ( -320 416 0 ) ( -320 -416 0 ) eden/wood 0 0 0.00 1 1 0 0 0 +( 544 -416 32 ) ( 544 416 32 ) ( 544 416 0 ) eden/wood 0 0 0.00 1 1 0 0 0 +( 544 384 32 ) ( -320 384 32 ) ( -320 384 0 ) eden/wood 0 0 0.00 1 1 0 0 0 +( -320 416 32 ) ( -320 -416 32 ) ( -320 -416 0 ) eden/wood 0 0 0.00 1 1 0 0 0 +( -320 352 32 ) ( 544 352 32 ) ( -320 352 0 ) eden/wood 0 0 0.00 1 1 0 0 0 +( -128 352 64 ) ( -64 384 64 ) ( 0 352 64 ) eden/wood 0 0 0.00 1 1 0 0 0 +} +// brush 7 +{ +( 544 416 0 ) ( -320 416 0 ) ( -320 -416 0 ) eden/wood 0 0 0.00 1 1 0 0 0 +( -320 -416 32 ) ( 544 -416 32 ) ( 544 -416 0 ) eden/wood 0 0 0.00 1 1 0 0 0 +( 544 -416 32 ) ( 544 416 32 ) ( 544 416 0 ) eden/wood 0 0 0.00 1 1 0 0 0 +( -320 416 32 ) ( -320 -416 32 ) ( -320 -416 0 ) eden/wood 0 0 0.00 1 1 0 0 0 +( 544 -384 32 ) ( -320 -384 32 ) ( 544 -384 0 ) eden/wood 0 0 0.00 1 1 0 0 0 +( -128 -416 64 ) ( -64 -384 64 ) ( 0 -416 64 ) eden/wood 0 0 0.00 1 1 0 0 0 +} +// brush 8 +{ +( 544 416 0 ) ( -320 416 0 ) ( -320 -416 0 ) eden/wood 0 0 0.00 1 1 0 0 0 +( -320 -416 32 ) ( 544 -416 32 ) ( 544 -416 0 ) eden/wood 0 0 0.00 1 1 0 0 0 +( 544 -416 32 ) ( 544 416 32 ) ( 544 416 0 ) eden/wood 0 0 0.00 1 1 0 0 0 +( 544 384 32 ) ( -320 384 32 ) ( -320 384 0 ) eden/wood 0 0 0.00 1 1 0 0 0 +( 512 416 32 ) ( 512 -416 32 ) ( 512 416 0 ) eden/wood 0 0 0.00 1 1 0 0 0 +( -128 -416 64 ) ( -64 384 64 ) ( 0 -416 64 ) eden/wood 0 0 0.00 1 1 0 0 0 +} +// brush 9 +{ +( -320 -416 32 ) ( 544 -416 32 ) ( 544 -416 0 ) eden/WL_church_2big 0 0 0.00 1 1 0 0 0 +( 544 384 32 ) ( -320 384 32 ) ( -320 384 0 ) eden/WL_church_2big 0 0 0.00 1 1 0 0 0 +( -320 416 32 ) ( -320 -416 32 ) ( -320 -416 0 ) eden/WL_church_2big 0 0 0.00 1 1 0 0 0 +( -288 -416 32 ) ( -288 416 32 ) ( -288 -416 0 ) eden/WL_church_2big 0 0 0.00 1 1 0 0 0 +( -64 384 64 ) ( -128 -416 64 ) ( 0 -416 64 ) eden/WL_church_2big 0 0 0.00 1 1 0 0 0 +( -64 -416 320 ) ( -32 384 320 ) ( 0 -416 320 ) eden/WL_church_2big 0 0 0.00 1 1 0 0 0 +} +// brush 10 +{ +( -320 -416 384 ) ( -320 416 384 ) ( 544 416 384 ) eden/wood 0 0 0.00 1 1 0 0 0 +( -320 -416 32 ) ( 544 -416 32 ) ( 544 -416 0 ) eden/wood 0 0 0.00 1 1 0 0 0 +( 544 384 32 ) ( -320 384 32 ) ( -320 384 0 ) eden/wood 0 0 0.00 1 1 0 0 0 +( -320 416 32 ) ( -320 -416 32 ) ( -320 -416 0 ) eden/wood 0 0 0.00 1 1 0 0 0 +( -288 -416 32 ) ( -288 416 32 ) ( -288 -416 0 ) eden/wood 0 0 0.00 1 1 0 0 0 +( -32 384 320 ) ( -64 -416 320 ) ( 0 -416 320 ) eden/wood 0 0 0.00 1 1 0 0 0 +} +// brush 11 +{ +( 544 -416 32 ) ( 544 416 32 ) ( 544 416 0 ) eden/WL_church_2big 0 0 0.00 1 1 0 0 0 +( 544 384 32 ) ( -320 384 32 ) ( -320 384 0 ) eden/WL_church_2big 0 0 0.00 1 1 0 0 0 +( -320 416 32 ) ( -320 -416 32 ) ( -320 -416 0 ) eden/WL_church_2big 0 0 0.00 1 1 0 0 0 +( -320 352 32 ) ( 544 352 32 ) ( -320 352 0 ) eden/WL_church_2big 0 0 0.00 1 1 0 0 0 +( -64 384 64 ) ( -128 352 64 ) ( 0 352 64 ) eden/WL_church_2big 0 0 0.00 1 1 0 0 0 +( -64 352 320 ) ( -32 384 320 ) ( 0 352 320 ) eden/WL_church_2big 0 0 0.00 1 1 0 0 0 +} +// brush 12 +{ +( -320 -416 384 ) ( -320 416 384 ) ( 544 416 384 ) eden/wood 0 0 0.00 1 1 0 0 0 +( 544 -416 32 ) ( 544 416 32 ) ( 544 416 0 ) eden/wood 0 0 0.00 1 1 0 0 0 +( 544 384 32 ) ( -320 384 32 ) ( -320 384 0 ) eden/wood 0 0 0.00 1 1 0 0 0 +( -320 416 32 ) ( -320 -416 32 ) ( -320 -416 0 ) eden/wood 0 0 0.00 1 1 0 0 0 +( -320 352 32 ) ( 544 352 32 ) ( -320 352 0 ) eden/wood 0 0 0.00 1 1 0 0 0 +( -32 384 320 ) ( -64 352 320 ) ( 0 352 320 ) eden/wood 0 0 0.00 1 1 0 0 0 +} +// brush 13 +{ +( -320 -416 32 ) ( 544 -416 32 ) ( 544 -416 0 ) eden/WL_church_2big 0 0 0.00 1 1 0 0 0 +( 544 -416 32 ) ( 544 416 32 ) ( 544 416 0 ) eden/WL_church_2big 0 0 0.00 1 1 0 0 0 +( -320 416 32 ) ( -320 -416 32 ) ( -320 -416 0 ) eden/WL_church_2big 0 0 0.00 1 1 0 0 0 +( 544 -384 32 ) ( -320 -384 32 ) ( 544 -384 0 ) eden/WL_church_2big 0 0 0.00 1 1 0 0 0 +( -64 -384 64 ) ( -128 -416 64 ) ( 0 -416 64 ) eden/WL_church_2big 0 0 0.00 1 1 0 0 0 +( -64 -416 320 ) ( -32 -384 320 ) ( 0 -416 320 ) eden/WL_church_2big 0 0 0.00 1 1 0 0 0 +} +// brush 14 +{ +( -320 -416 384 ) ( -320 416 384 ) ( 544 416 384 ) eden/wood 0 0 0.00 1 1 0 0 0 +( -320 -416 32 ) ( 544 -416 32 ) ( 544 -416 0 ) eden/wood 0 0 0.00 1 1 0 0 0 +( 544 -416 32 ) ( 544 416 32 ) ( 544 416 0 ) eden/wood 0 0 0.00 1 1 0 0 0 +( -320 416 32 ) ( -320 -416 32 ) ( -320 -416 0 ) eden/wood 0 0 0.00 1 1 0 0 0 +( 544 -384 32 ) ( -320 -384 32 ) ( 544 -384 0 ) eden/wood 0 0 0.00 1 1 0 0 0 +( -32 -384 320 ) ( -64 -416 320 ) ( 0 -416 320 ) eden/wood 0 0 0.00 1 1 0 0 0 +} +// brush 15 +{ +( -320 -416 32 ) ( 544 -416 32 ) ( 544 -416 0 ) eden/WL_church_2big 0 0 0.00 1 1 0 0 0 +( 544 -416 32 ) ( 544 416 32 ) ( 544 416 0 ) eden/WL_church_2big 0 0 0.00 1 1 0 0 0 +( 544 384 32 ) ( -320 384 32 ) ( -320 384 0 ) eden/WL_church_2big 0 0 0.00 1 1 0 0 0 +( 512 416 32 ) ( 512 -416 32 ) ( 512 416 0 ) eden/WL_church_2big 0 0 0.00 1 1 0 0 0 +( -64 384 64 ) ( -128 -416 64 ) ( 0 -416 64 ) eden/WL_church_2big 0 0 0.00 1 1 0 0 0 +( -64 -416 320 ) ( -32 384 320 ) ( 0 -416 320 ) eden/WL_church_2big 0 0 0.00 1 1 0 0 0 +} +// brush 16 +{ +( -320 -416 384 ) ( -320 416 384 ) ( 544 416 384 ) eden/wood 0 0 0.00 1 1 0 0 0 +( -320 -416 32 ) ( 544 -416 32 ) ( 544 -416 0 ) eden/wood 0 0 0.00 1 1 0 0 0 +( 544 -416 32 ) ( 544 416 32 ) ( 544 416 0 ) eden/wood 0 0 0.00 1 1 0 0 0 +( 544 384 32 ) ( -320 384 32 ) ( -320 384 0 ) eden/wood 0 0 0.00 1 1 0 0 0 +( 512 416 32 ) ( 512 -416 32 ) ( 512 416 0 ) eden/wood 0 0 0.00 1 1 0 0 0 +( -32 384 320 ) ( -64 -416 320 ) ( 0 -416 320 ) eden/wood 0 0 0.00 1 1 0 0 0 +} +// brush 17 +{ +( -320 -416 384 ) ( -320 416 384 ) ( 544 416 384 ) eden/CL_church 0 0 0.00 1 1 0 0 0 +( -320 -416 32 ) ( 544 -416 32 ) ( 544 -416 0 ) eden/CL_church 0 0 0.00 1 1 0 0 0 +( 544 -416 32 ) ( 544 416 32 ) ( 544 416 0 ) eden/CL_church 0 0 0.00 1 1 0 0 0 +( 544 384 32 ) ( -320 384 32 ) ( -320 384 0 ) eden/CL_church 0 0 0.00 1 1 0 0 0 +( -320 416 32 ) ( -320 -416 32 ) ( -320 -416 0 ) eden/CL_church 0 0 0.00 1 1 0 0 0 +( -320 416 352 ) ( -320 -416 352 ) ( 544 416 352 ) eden/CL_church 0 0 0.00 1 1 0 0 0 +} +// brush 18 +{ +( 544 416 0 ) ( -320 416 0 ) ( -320 -416 0 ) eden/FL_basement2 0 0 0.00 1 1 0 0 0 +( -320 -416 32 ) ( 544 -416 32 ) ( 544 -416 0 ) eden/FL_basement2 0 0 0.00 1 1 0 0 0 +( 544 -416 32 ) ( 544 416 32 ) ( 544 416 0 ) eden/FL_basement2 0 0 0.00 1 1 0 0 0 +( 544 384 32 ) ( -320 384 32 ) ( -320 384 0 ) eden/FL_basement2 0 0 0.00 1 1 0 0 0 +( -320 416 32 ) ( -320 -416 32 ) ( -320 -416 0 ) eden/FL_basement2 0 0 0.00 1 1 0 0 0 +( -320 416 32 ) ( 544 416 32 ) ( -320 -416 32 ) eden/FL_basement2 0 0 0.00 1 1 0 0 0 +} +} +// entity 1 +{ +"origin" "-120 168 184" +"classname" "light" +} +// entity 2 +{ +"origin" "-176 -272 32" +"angle" "45" +"classname" "info_player_start" +} +// entity 3 +{ +"targetname" "t1" +"origin" "105.34 -40.46 48.27" +"anim" "crank_turn_forward" +"model" "func_useanimdest.tik" +"scale" "1.0" +"classname" "func_useanimdest" +} +// entity 4 +{ +"target" "t1" +"count" "1" +"spawnflags" "2" +"classname" "func_useanim" +// brush 0 +{ +( 64 -32 48 ) ( 32 -32 48 ) ( 32 -64 48 ) eden/FL_basement2 0 0 0.00 1 1 0 0 0 +( 32 -64 112 ) ( 32 -32 112 ) ( 64 -32 112 ) eden/FL_basement2 0 0 0.00 1 1 0 0 0 +( 32 -64 112 ) ( 64 -64 112 ) ( 64 -64 48 ) eden/FL_basement2 0 0 0.00 1 1 0 0 0 +( 64 -64 112 ) ( 64 -32 112 ) ( 64 -32 48 ) eden/FL_basement2 0 0 0.00 1 1 0 0 0 +( 64 -16 112 ) ( 32 -16 112 ) ( 32 -16 48 ) eden/FL_basement2 0 0 0.00 1 1 0 0 0 +( 32 -32 112 ) ( 32 -64 112 ) ( 32 -64 48 ) eden/FL_basement2 0 0 0.00 1 1 0 0 0 +} +} +// entity 5 +{ +"classname" "light" +"origin" "344 136 184" +} +// entity 6 +{ +"origin" "360 -248 184" +"classname" "light" +} +// entity 7 +{ +"classname" "light" +"origin" "-104 -264 184" +} diff --git a/fakk/maps/example/useobject.prt b/fakk/maps/example/useobject.prt new file mode 100644 index 0000000..633801e --- /dev/null +++ b/fakk/maps/example/useobject.prt @@ -0,0 +1,117 @@ +PRT1 +20 +33 +80 +4 0 12 0 (0 256 352 ) (0 352 352 ) (0 352 320 ) (0 256 320 ) +4 0 3 0 (0 352 320 ) (512 352 320 ) (512 256 320 ) (0 256 320 ) +4 1 13 0 (0 96 352 ) (0 224 352 ) (0 224 320 ) (0 96 320 ) +4 1 3 0 (512 224 320 ) (512 96 320 ) (0 96 320 ) (0 224 320 ) +4 2 14 0 (0 0 320 ) (0 0 352 ) (0 64 352 ) (0 64 320 ) +4 2 6 0 (0 0 352 ) (0 0 320 ) (512 0 320 ) (512 0 352 ) +4 2 3 0 (512 64 320 ) (512 0 320 ) (0 0 320 ) (0 64 320 ) +4 3 15 0 (0 0 48 ) (0 0 320 ) (0 352 320 ) (0 352 48 ) +4 3 9 0 (0 0 320 ) (0 0 48 ) (512 0 48 ) (512 0 320 ) +4 3 5 0 (0 352 48 ) (176 352 48 ) (176 16 48 ) (0 16 48 ) +4 3 4 0 (176 352 48 ) (512 352 48 ) (512 0 48 ) (176 0 48 ) +4 4 10 0 (176 0 32 ) (512 0 32 ) (512 0 48 ) (176 0 48 ) +4 4 5 0 (176 352 32 ) (176 16 32 ) (176 16 48 ) (176 352 48 ) +4 5 15 0 (0 16 48 ) (0 352 48 ) (0 352 32 ) (0 16 32 ) +4 6 16 0 (0 -64 352 ) (0 0 352 ) (0 0 320 ) (0 -64 320 ) +4 6 9 0 (0 0 320 ) (512 0 320 ) (512 -64 320 ) (0 -64 320 ) +4 7 17 0 (0 -256 352 ) (0 -96 352 ) (0 -96 320 ) (0 -256 320 ) +4 7 9 0 (512 -96 320 ) (512 -256 320 ) (0 -256 320 ) (0 -96 320 ) +4 8 18 0 (0 -384 320 ) (0 -384 352 ) (0 -288 352 ) (0 -288 320 ) +4 8 9 0 (512 -288 320 ) (512 -384 320 ) (0 -384 320 ) (0 -288 320 ) +4 9 19 0 (0 -384 48 ) (0 -384 320 ) (0 0 320 ) (0 0 48 ) +4 9 11 0 (176 -96 48 ) (176 -384 48 ) (0 -384 48 ) (0 -96 48 ) +4 9 10 0 (176 0 48 ) (512 0 48 ) (512 -384 48 ) (176 -384 48 ) +4 10 11 0 (176 -96 32 ) (176 -384 32 ) (176 -384 48 ) (176 -96 48 ) +4 11 19 0 (0 -384 32 ) (0 -384 48 ) (0 -96 48 ) (0 -96 32 ) +4 12 15 0 (-288 256 320 ) (-288 352 320 ) (0 352 320 ) (0 256 320 ) +4 13 15 0 (-288 96 320 ) (-288 224 320 ) (0 224 320 ) (0 96 320 ) +4 14 16 0 (0 0 320 ) (0 0 352 ) (-288 0 352 ) (-288 0 320 ) +4 14 15 0 (0 0 320 ) (-288 0 320 ) (-288 64 320 ) (0 64 320 ) +4 15 19 0 (0 0 32 ) (0 0 320 ) (-288 0 320 ) (-288 0 32 ) +4 16 19 0 (-288 -64 320 ) (-288 0 320 ) (0 0 320 ) (0 -64 320 ) +4 17 19 0 (-288 -256 320 ) (-288 -96 320 ) (0 -96 320 ) (0 -256 320 ) +4 18 19 0 (0 -384 320 ) (-288 -384 320 ) (-288 -288 320 ) (0 -288 320 ) +4 0 (0 256 352 ) (512 256 352 ) (512 352 352 ) (0 352 352 ) +4 0 (512 256 352 ) (512 256 320 ) (512 352 320 ) (512 352 352 ) +4 0 (512 352 352 ) (512 352 320 ) (0 352 320 ) (0 352 352 ) +4 0 (0 256 320 ) (512 256 320 ) (512 256 352 ) (0 256 352 ) +4 1 (0 96 320 ) (512 96 320 ) (512 96 352 ) (0 96 352 ) +4 1 (0 224 352 ) (512 224 352 ) (512 224 320 ) (0 224 320 ) +4 1 (512 224 352 ) (512 96 352 ) (512 96 320 ) (512 224 320 ) +4 1 (0 224 352 ) (0 96 352 ) (512 96 352 ) (512 224 352 ) +4 2 (512 64 352 ) (512 0 352 ) (512 0 320 ) (512 64 320 ) +4 2 (0 64 352 ) (0 0 352 ) (512 0 352 ) (512 64 352 ) +4 2 (0 64 352 ) (512 64 352 ) (512 64 320 ) (0 64 320 ) +4 3 (176 16 48 ) (176 0 48 ) (0 0 48 ) (0 16 48 ) +4 3 (0 96 320 ) (0 64 320 ) (512 64 320 ) (512 96 320 ) +4 3 (0 256 320 ) (0 224 320 ) (512 224 320 ) (512 256 320 ) +4 3 (512 0 320 ) (512 0 48 ) (512 352 48 ) (512 352 320 ) +4 3 (512 352 320 ) (512 352 48 ) (0 352 48 ) (0 352 320 ) +4 4 (176 16 32 ) (176 0 32 ) (176 0 48 ) (176 16 48 ) +4 4 (176 352 48 ) (512 352 48 ) (512 352 32 ) (176 352 32 ) +4 4 (512 0 48 ) (512 0 32 ) (512 352 32 ) (512 352 48 ) +4 4 (176 352 32 ) (512 352 32 ) (512 0 32 ) (176 0 32 ) +4 5 (0 352 32 ) (176 352 32 ) (176 16 32 ) (0 16 32 ) +4 5 (176 352 48 ) (176 352 32 ) (0 352 32 ) (0 352 48 ) +4 5 (0 16 32 ) (176 16 32 ) (176 16 48 ) (0 16 48 ) +4 6 (0 -64 352 ) (512 -64 352 ) (512 0 352 ) (0 0 352 ) +4 6 (512 -64 352 ) (512 -64 320 ) (512 0 320 ) (512 0 352 ) +4 6 (0 -64 320 ) (512 -64 320 ) (512 -64 352 ) (0 -64 352 ) +4 7 (0 -256 320 ) (512 -256 320 ) (512 -256 352 ) (0 -256 352 ) +4 7 (0 -96 352 ) (512 -96 352 ) (512 -96 320 ) (0 -96 320 ) +4 7 (512 -96 352 ) (512 -256 352 ) (512 -256 320 ) (512 -96 320 ) +4 7 (0 -96 352 ) (0 -256 352 ) (512 -256 352 ) (512 -96 352 ) +4 8 (0 -384 352 ) (0 -384 320 ) (512 -384 320 ) (512 -384 352 ) +4 8 (512 -288 352 ) (512 -384 352 ) (512 -384 320 ) (512 -288 320 ) +4 8 (0 -288 352 ) (0 -384 352 ) (512 -384 352 ) (512 -288 352 ) +4 8 (0 -288 352 ) (512 -288 352 ) (512 -288 320 ) (0 -288 320 ) +4 9 (0 0 48 ) (176 0 48 ) (176 -96 48 ) (0 -96 48 ) +4 9 (0 -256 320 ) (0 -288 320 ) (512 -288 320 ) (512 -256 320 ) +4 9 (0 -64 320 ) (0 -96 320 ) (512 -96 320 ) (512 -64 320 ) +4 9 (512 -384 320 ) (512 -384 48 ) (512 0 48 ) (512 0 320 ) +4 9 (0 -384 320 ) (0 -384 48 ) (512 -384 48 ) (512 -384 320 ) +4 10 (176 0 32 ) (176 -96 32 ) (176 -96 48 ) (176 0 48 ) +4 10 (176 -384 32 ) (512 -384 32 ) (512 -384 48 ) (176 -384 48 ) +4 10 (512 -384 48 ) (512 -384 32 ) (512 0 32 ) (512 0 48 ) +4 10 (176 0 32 ) (512 0 32 ) (512 -384 32 ) (176 -384 32 ) +4 11 (176 -96 32 ) (176 -384 32 ) (0 -384 32 ) (0 -96 32 ) +4 11 (0 -384 48 ) (0 -384 32 ) (176 -384 32 ) (176 -384 48 ) +4 11 (0 -96 48 ) (176 -96 48 ) (176 -96 32 ) (0 -96 32 ) +4 12 (0 256 352 ) (0 352 352 ) (-288 352 352 ) (-288 256 352 ) +4 12 (0 352 352 ) (0 352 320 ) (-288 352 320 ) (-288 352 352 ) +4 12 (-288 256 352 ) (-288 352 352 ) (-288 352 320 ) (-288 256 320 ) +4 12 (-288 256 320 ) (0 256 320 ) (0 256 352 ) (-288 256 352 ) +4 13 (-288 96 320 ) (0 96 320 ) (0 96 352 ) (-288 96 352 ) +4 13 (-288 224 352 ) (0 224 352 ) (0 224 320 ) (-288 224 320 ) +4 13 (-288 96 352 ) (-288 224 352 ) (-288 224 320 ) (-288 96 320 ) +4 13 (0 96 352 ) (0 224 352 ) (-288 224 352 ) (-288 96 352 ) +4 14 (-288 0 320 ) (-288 0 352 ) (-288 64 352 ) (-288 64 320 ) +4 14 (0 64 352 ) (-288 64 352 ) (-288 0 352 ) (0 0 352 ) +4 14 (-288 64 352 ) (0 64 352 ) (0 64 320 ) (-288 64 320 ) +4 15 (-288 0 32 ) (-288 0 320 ) (-288 352 320 ) (-288 352 32 ) +4 15 (0 16 32 ) (0 16 48 ) (0 0 48 ) (0 0 32 ) +4 15 (0 352 320 ) (0 352 32 ) (-288 352 32 ) (-288 352 320 ) +4 15 (0 224 320 ) (0 256 320 ) (-288 256 320 ) (-288 224 320 ) +4 15 (0 64 320 ) (0 96 320 ) (-288 96 320 ) (-288 64 320 ) +4 15 (0 0 32 ) (-288 0 32 ) (-288 352 32 ) (0 352 32 ) +4 16 (0 -64 352 ) (0 0 352 ) (-288 0 352 ) (-288 -64 352 ) +4 16 (-288 0 352 ) (-288 0 320 ) (-288 -64 320 ) (-288 -64 352 ) +4 16 (-288 -64 320 ) (0 -64 320 ) (0 -64 352 ) (-288 -64 352 ) +4 17 (-288 -256 320 ) (0 -256 320 ) (0 -256 352 ) (-288 -256 352 ) +4 17 (-288 -96 352 ) (0 -96 352 ) (0 -96 320 ) (-288 -96 320 ) +4 17 (-288 -96 320 ) (-288 -256 320 ) (-288 -256 352 ) (-288 -96 352 ) +4 17 (0 -256 352 ) (0 -96 352 ) (-288 -96 352 ) (-288 -256 352 ) +4 18 (-288 -288 320 ) (-288 -384 320 ) (-288 -384 352 ) (-288 -288 352 ) +4 18 (-288 -384 352 ) (-288 -384 320 ) (0 -384 320 ) (0 -384 352 ) +4 18 (0 -288 352 ) (-288 -288 352 ) (-288 -384 352 ) (0 -384 352 ) +4 18 (-288 -288 352 ) (0 -288 352 ) (0 -288 320 ) (-288 -288 320 ) +4 19 (-288 0 320 ) (-288 0 32 ) (-288 -384 32 ) (-288 -384 320 ) +4 19 (0 -96 32 ) (0 0 32 ) (0 0 48 ) (0 -96 48 ) +4 19 (-288 -384 320 ) (-288 -384 32 ) (0 -384 32 ) (0 -384 320 ) +4 19 (0 -96 320 ) (0 -64 320 ) (-288 -64 320 ) (-288 -96 320 ) +4 19 (0 -288 320 ) (0 -256 320 ) (-288 -256 320 ) (-288 -288 320 ) +4 19 (0 -384 32 ) (-288 -384 32 ) (-288 0 32 ) (0 0 32 ) diff --git a/fakk/maps/example/vehicle.bsp b/fakk/maps/example/vehicle.bsp new file mode 100644 index 0000000..a409eb8 Binary files /dev/null and b/fakk/maps/example/vehicle.bsp differ diff --git a/fakk/maps/example/vehicle.map b/fakk/maps/example/vehicle.map new file mode 100644 index 0000000..754c48f --- /dev/null +++ b/fakk/maps/example/vehicle.map @@ -0,0 +1,328 @@ +{ +"classname" "worldspawn" +// brush 0 +{ +( -1424 168 0 ) ( -2128 168 0 ) ( -2128 -152 0 ) eden/CL_church 56 0 0.00 1 1 0 0 0 +( -2128 -152 16 ) ( -1424 -152 16 ) ( -1424 -152 0 ) eden/CL_church 56 -96 0.00 1 1 0 0 0 +( -1424 168 16 ) ( -2128 168 16 ) ( -2128 168 0 ) eden/CL_church 56 -96 0.00 1 1 0 0 0 +( -1208 -152 104 ) ( -1028 168 -36 ) ( -848 -152 -176 ) eden/CL_church 56 -96 0.00 1 1 0 0 0 +( -1576 -152 264 ) ( -1320 168 132 ) ( -1064 -152 0 ) eden/CL_church 56 -96 0.00 1 1 0 0 0 +( -2120 -152 0 ) ( -1848 168 132 ) ( -1576 -152 264 ) eden/CL_church 56 -96 0.00 1 1 0 0 0 +} +// brush 1 +{ +( -2624 512 -32 ) ( -3448 512 -32 ) ( -3448 -512 -32 ) eden/CL_church 64 0 0.00 1 1 0 0 0 +( -3448 -512 1568 ) ( -3448 512 1568 ) ( -2624 512 1568 ) eden/CL_church 64 0 0.00 1 1 0 0 0 +( -3440 -520 32 ) ( -2616 -520 32 ) ( -2616 -520 0 ) eden/CL_church 64 0 0.00 1 1 0 0 0 +( -2624 520 32 ) ( -3448 520 32 ) ( -3448 520 0 ) eden/CL_church 64 0 0.00 1 1 0 0 0 +( -3656 512 32 ) ( -3656 -512 32 ) ( -3656 -512 0 ) eden/CL_church 0 0 0.00 1 1 0 0 0 +( -3648 -512 32 ) ( -3648 512 32 ) ( -3648 -512 0 ) eden/CL_church 0 0 0.00 1 1 0 0 0 +} +// brush 2 +{ +( 512 512 -22 ) ( -312 512 -22 ) ( -312 -512 -22 ) eden/CL_church 0 0 0.00 1 1 0 0 0 +( -314 -512 1578 ) ( -314 512 1578 ) ( 510 512 1578 ) eden/CL_church 0 0 0.00 1 1 0 0 0 +( 518 512 1578 ) ( 518 520 1578 ) ( 520 520 -22 ) eden/CL_church 0 10 0.00 1 1 0 0 0 +( 517.999939 520 1578 ) ( -3658.000244 520 1578 ) ( -3656.000244 520 -22 ) eden/CL_church 0 10 0.00 1 1 0 0 0 +( -3658.000244 520 1578 ) ( -3658.000244 512 1578 ) ( -3656.000244 512 -22 ) eden/CL_church 0 10 0.00 1 1 0 0 0 +( -3658.000244 512 1578 ) ( 517.999939 512 1578 ) ( 519.999939 512 -22 ) eden/CL_church 0 10 0.00 1 1 0 0 0 +} +// brush 3 +{ +( 512 512 -32 ) ( -312 512 -32 ) ( -312 -512 -32 ) eden/CL_church 0 0 0.00 1 1 0 0 0 +( -312 -512 1568 ) ( -312 512 1568 ) ( 512 512 1568 ) eden/CL_church 0 0 0.00 1 1 0 0 0 +( -304 -520 32 ) ( 520 -520 32 ) ( 520 -520 0 ) eden/CL_church 0 0 0.00 1 1 0 0 0 +( 520 -520 32 ) ( 520 504 32 ) ( 520 504 0 ) eden/CL_church 0 0 0.00 1 1 0 0 0 +( 512 520 32 ) ( -312 520 32 ) ( -312 520 0 ) eden/CL_church 0 0 0.00 1 1 0 0 0 +( 512 504 32 ) ( 512 -520 32 ) ( 512 504 0 ) eden/CL_church 0 0 0.00 1 1 0 0 0 +} +// brush 4 +{ +( 512 512 -32 ) ( -312 512 -32 ) ( -312 -512 -32 ) eden/CL_church 0 0 0.00 1 1 0 0 0 +( -312 -512 1568 ) ( -312 512 1568 ) ( 512 512 1568 ) eden/CL_church 0 0 0.00 1 1 0 0 0 +( -304 -520 32 ) ( 520 -520 32 ) ( 520 -520 0 ) eden/CL_church 0 0 0.00 1 1 0 0 0 +( 520 -520 32 ) ( 520 504 32 ) ( 520 504 0 ) eden/CL_church 0 0 0.00 1 1 0 0 0 +( -3656 512 32 ) ( -3656 -512 32 ) ( -3656 -512 0 ) eden/CL_church 0 0 0.00 1 1 0 0 0 +( -2616 -512 32 ) ( -3440 -512 32 ) ( -2616 -512 0 ) eden/CL_church 0 0 0.00 1 1 0 0 0 +} +// brush 5 +{ +( -312 -512 1576 ) ( -312 512 1576 ) ( 512 512 1576 ) tom/wl_wood_dark 0 0 0.00 1 1 0 0 0 +( -304 -520 1192 ) ( 520 -520 1192 ) ( 520 -520 1184 ) tom/wl_wood_dark 0 0 0.00 1 1 0 0 0 +( 520 -520 1192 ) ( 520 504 1192 ) ( 520 504 1184 ) tom/wl_wood_dark 0 0 0.00 1 1 0 0 0 +( 512 520 1192 ) ( -312 520 1192 ) ( -312 520 1184 ) tom/wl_wood_dark 0 0 0.00 1 1 0 0 0 +( -3656 512 1192 ) ( -3656 -512 1192 ) ( -3656 -512 1184 ) tom/wl_wood_dark 0 0 0.00 1 1 0 0 0 +( -312 512 1568 ) ( -312 -512 1568 ) ( 512 512 1568 ) tom/wl_wood_dark 0 0 0.00 1 1 0 0 0 +} +// brush 6 +{ +( 512 512 -8 ) ( -312 512 -8 ) ( -312 -512 -8 ) tom/fl_wgmarb 0 0 0.00 1 1 0 0 0 +( -304 -520 8 ) ( 520 -520 8 ) ( 520 -520 0 ) tom/fl_wgmarb 0 0 0.00 1 1 0 0 0 +( 520 -520 8 ) ( 520 504 8 ) ( 520 504 0 ) tom/fl_wgmarb 0 0 0.00 1 1 0 0 0 +( 512 520 8 ) ( -312 520 8 ) ( -312 520 0 ) tom/fl_wgmarb 0 0 0.00 1 1 0 0 0 +( -3656 512 8 ) ( -3656 -512 8 ) ( -3656 -512 0 ) tom/fl_wgmarb 0 0 0.00 1 1 0 0 0 +( -312 512 0 ) ( 512 512 0 ) ( -312 -512 0 ) tom/fl_wgmarb 0 0 0.00 1 1 0 0 0 +} +} +// entity 1 +{ +"classname" "vehicles_atv_backtire" +"scale" "1.0" +"model" "obj_atvbacktire.tik" +"origin" "80.45 -203.25 62.41" +} +// entity 2 +{ +"classname" "vehicles_atv_fronttire" +"scale" "1.0" +"model" "obj_atvfronttire.tik" +"origin" "10.45 -203.25 62.41" +} +// entity 3 +{ +"classname" "vehicles_atv" +"scale" "1.0" +"model" "obj_atv.tik" +"angle" "180" +"origin" "46.00 -182.00 46.00" +} +// entity 4 +{ +"origin" "136 264 776" +"classname" "light" +} +// entity 5 +{ +"origin" "336 -304 0" +"angle" "135" +"classname" "info_player_start" +} +// entity 6 +{ +"classname" "light" +"origin" "-216 264 1064" +} +// entity 7 +{ +"origin" "136 -88 424" +"classname" "light" +} +// entity 8 +{ +"classname" "light" +"origin" "-216 -88 328" +} +// entity 9 +{ +"origin" "-216 -344 328" +"classname" "light" +} +// entity 10 +{ +"classname" "light" +"origin" "136 -312 328" +} +// entity 11 +{ +"origin" "424 -312 328" +"classname" "light" +} +// entity 12 +{ +"classname" "light" +"origin" "392 104 328" +} +// entity 13 +{ +"origin" "-24 72 456" +"classname" "light" +} +// entity 14 +{ +"origin" "-128 192 1256" +"classname" "light" +} +// entity 15 +{ +"classname" "light" +"origin" "-256 296 1256" +} +// entity 16 +{ +"classname" "light" +"origin" "-864 304 776" +} +// entity 17 +{ +"origin" "-1216 304 1064" +"classname" "light" +} +// entity 18 +{ +"classname" "light" +"origin" "-864 -48 424" +} +// entity 19 +{ +"origin" "-1216 -48 328" +"classname" "light" +} +// entity 20 +{ +"classname" "light" +"origin" "-1216 -304 328" +} +// entity 21 +{ +"origin" "-864 -272 328" +"classname" "light" +} +// entity 22 +{ +"classname" "light" +"origin" "-576 -272 328" +} +// entity 23 +{ +"origin" "-608 144 328" +"classname" "light" +} +// entity 24 +{ +"classname" "light" +"origin" "-1024 112 456" +} +// entity 25 +{ +"classname" "light" +"origin" "-1128 232 1256" +} +// entity 26 +{ +"origin" "-1256 336 1256" +"classname" "light" +} +// entity 27 +{ +"origin" "-1784 304 776" +"classname" "light" +} +// entity 28 +{ +"classname" "light" +"origin" "-2136 304 1064" +} +// entity 29 +{ +"origin" "-1784 -48 424" +"classname" "light" +} +// entity 30 +{ +"classname" "light" +"origin" "-2136 -48 328" +} +// entity 31 +{ +"origin" "-2136 -304 328" +"classname" "light" +} +// entity 32 +{ +"classname" "light" +"origin" "-1784 -272 328" +} +// entity 33 +{ +"origin" "-1496 -272 328" +"classname" "light" +} +// entity 34 +{ +"classname" "light" +"origin" "-1528 144 328" +} +// entity 35 +{ +"origin" "-1944 112 456" +"classname" "light" +} +// entity 36 +{ +"origin" "-2048 232 1256" +"classname" "light" +} +// entity 37 +{ +"classname" "light" +"origin" "-2176 336 1256" +} +// entity 38 +{ +"classname" "light" +"origin" "-2784 304 776" +} +// entity 39 +{ +"origin" "-3136 304 1064" +"classname" "light" +} +// entity 40 +{ +"classname" "light" +"origin" "-2784 -48 424" +} +// entity 41 +{ +"origin" "-3136 -48 328" +"classname" "light" +} +// entity 42 +{ +"classname" "light" +"origin" "-3136 -304 328" +} +// entity 43 +{ +"origin" "-2784 -272 328" +"classname" "light" +} +// entity 44 +{ +"classname" "light" +"origin" "-2496 -272 328" +} +// entity 45 +{ +"origin" "-2528 144 328" +"classname" "light" +} +// entity 46 +{ +"classname" "light" +"origin" "-2944 112 456" +} +// entity 47 +{ +"classname" "light" +"origin" "-3048 232 1256" +} +// entity 48 +{ +"origin" "-3176 336 1256" +"classname" "light" +} +// entity 49 +{ +"origin" "10.45 -163.25 62.41" +"model" "obj_atvfronttire.tik" +"scale" "1.0" +"classname" "vehicles_atv_fronttire" +} +// entity 50 +{ +"origin" "80.45 -161.25 62.41" +"model" "obj_atvbacktire.tik" +"scale" "1.0" +"classname" "vehicles_atv_backtire" +} diff --git a/fakk/maps/example/vehicle.prt b/fakk/maps/example/vehicle.prt new file mode 100644 index 0000000..001daa4 --- /dev/null +++ b/fakk/maps/example/vehicle.prt @@ -0,0 +1,95 @@ +PRT1 +18 +35 +56 +4 0 2 0 (0 512 0 ) (0 0 0 ) (0 0 1568 ) (0 512 1568 ) +4 0 1 0 (0 0 1568 ) (0 0 0 ) (512 0 0 ) (512 0 1568 ) +4 1 3 0 (0 -512 1568 ) (0 0 1568 ) (0 0 0 ) (0 -512 0 ) +4 2 6 0 (-1024 0 0 ) (-1024 0 531.882385 ) (-1024 168 531.882385 ) (-1024 168 0 ) +4 2 5 0 (-1024 0 531.882385 ) (-1024 0 1568 ) (-1024 168 1568 ) (-1024 168 531.882385 ) +4 2 4 0 (-1024 168 1568 ) (-1024 512 1568 ) (-1024 512 0 ) (-1024 168 0 ) +4 2 3 0 (-1024 0 1568 ) (-1024 0 0 ) (0 0 0 ) (0 0 1568 ) +4 3 9 0 (-1024 0 531.882385 ) (-1024 0 0 ) (-1024 -152 0 ) (-1024 -152 531.882385 ) +4 3 8 0 (-1024 0 1568 ) (-1024 0 531.882385 ) (-1024 -152 531.882385 ) (-1024 -152 1568 ) +4 3 11 0 (-1024 -152 0 ) (-1024 -512 0 ) (-1024 -512 1568 ) (-1024 -152 1568 ) +4 4 12 0 (-2048 168 1568 ) (-2048 512 1568 ) (-2048 512 0 ) (-2048 168 0 ) +3 4 7 0 (-1074.285645 168 0 ) (-1064 168 0 ) (-1094.516479 168 15.735089 ) +4 4 6 0 (-1064 168 0 ) (-1024 168 0 ) (-1024 168 531.882385 ) (-1576 168 264 ) +4 4 5 0 (-1024 168 531.882385 ) (-1024 168 1568 ) (-2048 168 1568 ) (-2048 168 34.941174 ) +4 5 13 0 (-2048 0 34.941174 ) (-2048 0 1568 ) (-2048 168 1568 ) (-2048 168 34.941174 ) +4 5 8 0 (-2048 0 1568 ) (-2048 0 34.941174 ) (-1024 0 531.882385 ) (-1024 0 1568 ) +4 5 6 0 (-1576 168 264 ) (-1024 168 531.882751 ) (-1024 0 531.882751 ) (-1576 0 264 ) +4 6 9 0 (-1064 0 0 ) (-1024 0 0 ) (-1024 0 531.882385 ) (-1576 0 264 ) +4 6 7 0 (-1094.515991 168 15.734704 ) (-1064 168 0 ) (-1064 0 0 ) (-1094.515991 0 15.734711 ) +3 7 10 0 (-1074.285645 0 0 ) (-1064 0 0 ) (-1094.516479 0 15.735089 ) +4 8 14 0 (-2048 -152 1568 ) (-2048 0 1568 ) (-2048 0 34.941174 ) (-2048 -152 34.941174 ) +4 8 9 0 (-1024 -152 531.882813 ) (-1576 -152 264 ) (-1576 0 264 ) (-1024 0 531.882813 ) +4 8 11 0 (-1024 -152 531.882385 ) (-1024 -152 1568 ) (-2048 -152 1568 ) (-2048 -152 34.941174 ) +4 9 10 0 (-1064 -152 0 ) (-1094.516235 -152 15.734886 ) (-1094.516235 0 15.734893 ) (-1064 0 0 ) +4 9 11 0 (-1064 -152 0 ) (-1024 -152 0 ) (-1024 -152 531.882385 ) (-1576 -152 264 ) +3 10 11 0 (-1074.285645 -152 0 ) (-1064 -152 0 ) (-1094.516479 -152 15.735089 ) +4 11 15 0 (-2048 -512 0 ) (-2048 -512 1568 ) (-2048 -152 1568 ) (-2048 -152 0 ) +4 12 16 0 (-3072 168 1568 ) (-3072 512 1568 ) (-3072 512 0 ) (-3072 168 0 ) +5 12 13 0 (-3072 168 0 ) (-2120 168 0 ) (-2048 168 34.941174 ) (-2048 168 1568 ) (-3072 168 1568 ) +4 13 16 0 (-3072 0 0 ) (-3072 0 1568 ) (-3072 168 1568 ) (-3072 168 0 ) +5 13 14 0 (-3072 0 1568 ) (-3072 0 0 ) (-2120 0 0 ) (-2048 0 34.941174 ) (-2048 0 1568 ) +4 14 17 0 (-3072 0 1568 ) (-3072 0 0 ) (-3072 -152 0 ) (-3072 -152 1568 ) +5 14 15 0 (-3072 -152 0 ) (-2120 -152 0 ) (-2048 -152 34.941174 ) (-2048 -152 1568 ) (-3072 -152 1568 ) +4 15 17 0 (-3072 -152 0 ) (-3072 -512 0 ) (-3072 -512 1568 ) (-3072 -152 1568 ) +4 16 17 0 (-3072 0 0 ) (-3072 0 1568 ) (-3648 0 1568 ) (-3648 0 0 ) +4 0 (512 512 1568 ) (0 512 1568 ) (0 0 1568 ) (512 0 1568 ) +4 0 (512 0 0 ) (0 0 0 ) (0 512 0 ) (512 512 0 ) +4 0 (512 512 1568 ) (512 512 0 ) (0 512 0 ) (0 512 1568 ) +4 0 (512 0 0 ) (512 512 0 ) (512 512 1568 ) (512 0 1568 ) +4 1 (512 -512 1568 ) (512 0 1568 ) (0 0 1568 ) (0 -512 1568 ) +4 1 (0 -512 0 ) (0 0 0 ) (512 0 0 ) (512 -512 0 ) +4 1 (512 -512 1568 ) (512 -512 0 ) (512 0 0 ) (512 0 1568 ) +4 1 (0 -512 0 ) (512 -512 0 ) (512 -512 1568 ) (0 -512 1568 ) +4 2 (0 512 1568 ) (0 512 0 ) (-1024 512 0 ) (-1024 512 1568 ) +4 2 (0 0 0 ) (-1024 0 0 ) (-1024 512 0 ) (0 512 0 ) +4 2 (0 512 1568 ) (-1024 512 1568 ) (-1024 0 1568 ) (0 0 1568 ) +4 3 (-1024 -512 1568 ) (-1024 -512 0 ) (0 -512 0 ) (0 -512 1568 ) +4 3 (-1024 -512 0 ) (-1024 0 0 ) (0 0 0 ) (0 -512 0 ) +4 3 (0 0 1568 ) (-1024 0 1568 ) (-1024 -512 1568 ) (0 -512 1568 ) +5 4 (-2048 168 0 ) (-1074.285645 168 0 ) (-1094.516479 168 15.735089 ) (-1576 168 264 ) (-2048 168 34.941174 ) +4 4 (-1024 168 1568 ) (-1024 512 1568 ) (-2048 512 1568 ) (-2048 168 1568 ) +4 4 (-1024 512 1568 ) (-1024 512 0 ) (-2048 512 0 ) (-2048 512 1568 ) +4 4 (-2048 168 0 ) (-2048 512 0 ) (-1024 512 0 ) (-1024 168 0 ) +4 5 (-2048 168 34.941536 ) (-1576 168 264 ) (-1576 0 264 ) (-2048 0 34.941525 ) +4 5 (-1024 168 1568 ) (-2048 168 1568 ) (-2048 0 1568 ) (-1024 0 1568 ) +4 6 (-1576 0 264 ) (-1576 168 264 ) (-1094.515991 168 15.734704 ) (-1094.515991 0 15.734711 ) +4 6 (-1024 0 0 ) (-1064 0 0 ) (-1064 168 0 ) (-1024 168 0 ) +4 7 (-1064 0 0 ) (-1074.285767 0 0 ) (-1074.285645 168 0 ) (-1064 168 0 ) +4 7 (-1094.515625 0 15.734722 ) (-1094.515625 168 15.734719 ) (-1074.285278 168 0 ) (-1074.285278 0 0 ) +4 8 (-1576 -152 264 ) (-2048 -152 34.941654 ) (-2048 0 34.941650 ) (-1576 0 264 ) +4 8 (-1024 -152 1568 ) (-1024 0 1568 ) (-2048 0 1568 ) (-2048 -152 1568 ) +4 9 (-1094.516235 -152 15.734886 ) (-1576 -152 264 ) (-1576 0 264 ) (-1094.516235 0 15.734893 ) +4 9 (-1064 0 0 ) (-1024 0 0 ) (-1024 -152 0 ) (-1064 -152 0 ) +4 10 (-1074.285645 0 0 ) (-1064 0 0 ) (-1064 -152 0 ) (-1074.285767 -152 0 ) +4 10 (-1074.284912 -152 0 ) (-1094.515625 -152 15.734725 ) (-1094.515625 0 15.734722 ) (-1074.284912 0 0 ) +5 11 (-2048 -152 34.941174 ) (-1576 -152 264 ) (-1094.516479 -152 15.735089 ) (-1074.285645 -152 0 ) (-2048 -152 0 ) +4 11 (-1024 -152 1568 ) (-2048 -152 1568 ) (-2048 -512 1568 ) (-1024 -512 1568 ) +4 11 (-2048 -512 1568 ) (-2048 -512 0 ) (-1024 -512 0 ) (-1024 -512 1568 ) +4 11 (-1024 -512 0 ) (-2048 -512 0 ) (-2048 -152 0 ) (-1024 -152 0 ) +3 12 (-2120 168 0 ) (-2048 168 0 ) (-2048 168 34.941174 ) +4 12 (-2048 168 1568 ) (-2048 512 1568 ) (-3072 512 1568 ) (-3072 168 1568 ) +4 12 (-3072 168 0 ) (-3072 512 0 ) (-2048 512 0 ) (-2048 168 0 ) +4 12 (-2048 512 1568 ) (-2048 512 0 ) (-3072 512 0 ) (-3072 512 1568 ) +4 13 (-2120 0 0 ) (-3072 0 0 ) (-3072 168 0 ) (-2120 168 0 ) +4 13 (-2048 168 1568 ) (-3072 168 1568 ) (-3072 0 1568 ) (-2048 0 1568 ) +4 13 (-2120 0 0 ) (-2120 168 0 ) (-2048 168 34.941536 ) (-2048 0 34.941547 ) +4 14 (-3072 -152 0 ) (-3072 0 0 ) (-2120 0 0 ) (-2120 -152 0 ) +4 14 (-2048 -152 1568 ) (-2048 0 1568 ) (-3072 0 1568 ) (-3072 -152 1568 ) +4 14 (-2048 -152 34.941643 ) (-2120 -152 0 ) (-2120 0 0 ) (-2048 0 34.941650 ) +3 15 (-2048 -152 34.941174 ) (-2048 -152 0 ) (-2120 -152 0 ) +4 15 (-2048 -152 1568 ) (-3072 -152 1568 ) (-3072 -512 1568 ) (-2048 -512 1568 ) +4 15 (-3072 -512 0 ) (-3072 -152 0 ) (-2048 -152 0 ) (-2048 -512 0 ) +4 15 (-3072 -512 1568 ) (-3072 -512 0 ) (-2048 -512 0 ) (-2048 -512 1568 ) +4 16 (-3072 512 1568 ) (-3072 512 0 ) (-3648 512 0 ) (-3648 512 1568 ) +4 16 (-3648 0 0 ) (-3648 0 1568 ) (-3648 512 1568 ) (-3648 512 0 ) +4 16 (-3072 0 0 ) (-3648 0 0 ) (-3648 512 0 ) (-3072 512 0 ) +4 16 (-3072 512 1568 ) (-3648 512 1568 ) (-3648 0 1568 ) (-3072 0 1568 ) +4 17 (-3648 -512 1568 ) (-3648 -512 0 ) (-3072 -512 0 ) (-3072 -512 1568 ) +4 17 (-3648 0 1568 ) (-3648 0 0 ) (-3648 -512 0 ) (-3648 -512 1568 ) +4 17 (-3648 -512 0 ) (-3648 0 0 ) (-3072 0 0 ) (-3072 -512 0 ) +4 17 (-3072 0 1568 ) (-3648 0 1568 ) (-3648 -512 1568 ) (-3072 -512 1568 ) diff --git a/fakk/maps/example/zoo.bsp b/fakk/maps/example/zoo.bsp new file mode 100644 index 0000000..b137765 Binary files /dev/null and b/fakk/maps/example/zoo.bsp differ diff --git a/fakk/maps/example/zoo.map b/fakk/maps/example/zoo.map new file mode 100644 index 0000000..7e075a6 --- /dev/null +++ b/fakk/maps/example/zoo.map @@ -0,0 +1,10786 @@ +{ +"classname" "worldspawn" +// brush 0 +{ +( -2560 1664 336 ) ( -2848 1664 336 ) ( -2848 1456 336 ) sky/cliffsky 0 0 0.00 1 1 0 1044 0 +( -2848 1456 368 ) ( -2848 1664 368 ) ( -2560 1664 368 ) sky/cliffsky 0 0 0.00 1 1 0 1044 0 +( -2848 1472 400 ) ( -2560 1472 400 ) ( -2560 1472 336 ) sky/cliffsky 0 0 0.00 1 1 0 1044 0 +( -2560 1456 400 ) ( -2560 1664 400 ) ( -2560 1664 336 ) sky/cliffsky 0 0 0.00 1 1 0 1044 0 +( -2560 1664 400 ) ( -2848 1664 400 ) ( -2848 1664 336 ) sky/cliffsky 0 0 0.00 1 1 0 1044 0 +( -3648 1536 336 ) ( -3648 1664 336 ) ( -3648 1600 368 ) sky/cliffsky 0 0 0.00 1 1 0 1044 0 +} +// brush 1 +{ +( -2560 1664 336 ) ( -2848 1664 336 ) ( -2848 1456 336 ) sky/cliffsky 0 0 0.00 1 1 0 1044 0 +( -2848 1456 368 ) ( -2848 1664 368 ) ( -2560 1664 368 ) sky/cliffsky 0 0 0.00 1 1 0 1044 0 +( -2848 1472 400 ) ( -2560 1472 400 ) ( -2560 1472 336 ) sky/cliffsky 0 0 0.00 1 1 0 1044 0 +( -2560 1664 400 ) ( -2848 1664 400 ) ( -2848 1664 336 ) sky/cliffsky 0 0 0.00 1 1 0 1044 0 +( -5376 1536 336 ) ( -5376 1600 336 ) ( -5376 1568 368 ) sky/cliffsky 0 0 0.00 1 1 0 1044 0 +( -3648 1664 336 ) ( -3648 1536 336 ) ( -3648 1600 368 ) sky/cliffsky 0 0 0.00 1 1 0 1044 0 +} +// brush 2 +{ +( -2560 1664 336 ) ( -2848 1664 336 ) ( -2848 1456 336 ) sky/cliffsky 0 0 0.00 1 1 0 1044 0 +( -2848 1456 368 ) ( -2848 1664 368 ) ( -2560 1664 368 ) sky/cliffsky 0 0 0.00 1 1 0 1044 0 +( -2848 1472 400 ) ( -2560 1472 400 ) ( -2560 1472 336 ) sky/cliffsky 0 0 0.00 1 1 0 1044 0 +( -2560 1664 400 ) ( -2848 1664 400 ) ( -2848 1664 336 ) sky/cliffsky 0 0 0.00 1 1 0 1044 0 +( -7472 1728 400 ) ( -7472 1520 400 ) ( -7472 1520 336 ) sky/cliffsky 0 0 0.00 1 1 0 1044 0 +( -6784 1664 336 ) ( -6784 1600 336 ) ( -6784 1632 368 ) sky/cliffsky 0 0 0.00 1 1 0 1044 0 +} +// brush 3 +{ +( -2560 1664 336 ) ( -2848 1664 336 ) ( -2848 1456 336 ) sky/cliffsky 0 0 0.00 1 1 0 1044 0 +( -2848 1456 368 ) ( -2848 1664 368 ) ( -2560 1664 368 ) sky/cliffsky 0 0 0.00 1 1 0 1044 0 +( -2848 1472 400 ) ( -2560 1472 400 ) ( -2560 1472 336 ) sky/cliffsky 0 0 0.00 1 1 0 1044 0 +( -2560 1664 400 ) ( -2848 1664 400 ) ( -2848 1664 336 ) sky/cliffsky 0 0 0.00 1 1 0 1044 0 +( -6784 1600 336 ) ( -6784 1664 336 ) ( -6784 1632 368 ) sky/cliffsky 0 0 0.00 1 1 0 1044 0 +( -5376 1600 336 ) ( -5376 1536 336 ) ( -5376 1568 368 ) sky/cliffsky 0 0 0.00 1 1 0 1044 0 +} +// brush 4 +{ +( -3488 1728 -64 ) ( -3744 1728 -64 ) ( -3744 1344 -64 ) eden/wl_rock 32 224 0.00 1 1 0 0 0 +( -3744 1376 -32 ) ( -3744 1760 -32 ) ( -3488 1760 -32 ) eden/wl_rock 32 224 0.00 1 1 0 0 0 +( -5280 1376 -32 ) ( -5024 1376 -32 ) ( -5024 1376 -64 ) eden/wl_rock 32 192 0.00 1 1 0 0 0 +( -3488 1344 -32 ) ( -3488 1728 -32 ) ( -3488 1728 -64 ) eden/wl_rock 32 192 0.00 1 1 0 0 0 +( -5024 1760 -32 ) ( -5280 1760 -32 ) ( -5280 1760 -64 ) eden/wl_rock 32 192 0.00 1 1 0 0 0 +( -5536 1760 -32 ) ( -5536 1376 -32 ) ( -5536 1376 -64 ) eden/wl_rock 32 192 0.00 1 1 0 0 0 +} +// brush 5 +{ +( -5536 1728 -32 ) ( -5792 1728 -32 ) ( -5792 1344 -32 ) swamps/FL_swamp10 0 16 0.00 1 1 0 0 0 +( -5792 1376 0 ) ( -5792 1760 0 ) ( -5536 1760 0 ) swamps/FL_swamp10 0 16 0.00 1 1 0 0 0 +( -5792 1376 0 ) ( -5536 1376 0 ) ( -5536 1376 -32 ) swamps/FL_swamp10 0 16 0.00 1 1 0 0 0 +( -5536 1344 0 ) ( -5536 1728 0 ) ( -5536 1728 -32 ) swamps/FL_swamp10 0 16 0.00 1 1 0 0 0 +( -5536 1760 0 ) ( -5792 1760 0 ) ( -5792 1760 -32 ) swamps/FL_swamp10 0 16 0.00 1 1 0 0 0 +( -6048 1760 0 ) ( -6048 1376 0 ) ( -6048 1376 -32 ) swamps/FL_swamp10 0 16 0.00 1 1 0 0 0 +} +// brush 6 +{ +( -5024 1728 -32 ) ( -5280 1728 -32 ) ( -5280 1344 -32 ) eden/tr_chainlink 0 0 0.00 1 1 536870912 16 0 +( -5280 1376 0 ) ( -5280 1760 0 ) ( -5024 1760 0 ) eden/tr_chainlink 0 0 0.00 1 1 536870912 16 0 +( -5280 1376 0 ) ( -5024 1376 0 ) ( -5024 1376 -32 ) eden/tr_chainlink 0 0 0.00 1 1 536870912 16 0 +( -5024 1344 0 ) ( -5024 1728 0 ) ( -5024 1728 -32 ) eden/tr_chainlink 0 0 0.00 1 1 536870912 16 0 +( -5024 1760 0 ) ( -5280 1760 0 ) ( -5280 1760 -32 ) eden/tr_chainlink 0 0 0.00 1 1 536870912 16 0 +( -5536 1760 0 ) ( -5536 1376 0 ) ( -5536 1376 -32 ) eden/tr_chainlink 0 0 0.00 1 1 536870912 16 0 +} +// brush 7 +{ +( -4512 1728 -32 ) ( -4768 1728 -32 ) ( -4768 1344 -32 ) eden/fl_grass 32 96 0.00 1 1 0 0 0 +( -4768 1376 0 ) ( -4768 1760 0 ) ( -4512 1760 0 ) eden/fl_grass 32 96 0.00 1 1 0 0 0 +( -4768 1376 0 ) ( -4512 1376 0 ) ( -4512 1376 -32 ) eden/fl_grass 32 96 0.00 1 1 0 0 0 +( -4512 1344 0 ) ( -4512 1728 0 ) ( -4512 1728 -32 ) eden/fl_grass 32 96 0.00 1 1 0 0 0 +( -4512 1760 0 ) ( -4768 1760 0 ) ( -4768 1760 -32 ) eden/fl_grass 32 96 0.00 1 1 0 0 0 +( -5024 1760 0 ) ( -5024 1376 0 ) ( -5024 1376 -32 ) eden/fl_grass 32 96 0.00 1 1 0 0 0 +} +// brush 8 +{ +( -4000 1728 -32 ) ( -4256 1728 -32 ) ( -4256 1344 -32 ) eden/fl_ground 32 96 0.00 1 1 0 0 0 +( -4256 1376 0 ) ( -4256 1760 0 ) ( -4000 1760 0 ) eden/fl_ground 32 96 0.00 1 1 0 0 0 +( -4256 1376 0 ) ( -4000 1376 0 ) ( -4000 1376 -32 ) eden/fl_ground 32 96 0.00 1 1 0 0 0 +( -4000 1344 0 ) ( -4000 1728 0 ) ( -4000 1728 -32 ) eden/fl_ground 32 96 0.00 1 1 0 0 0 +( -4000 1760 0 ) ( -4256 1760 0 ) ( -4256 1760 -32 ) eden/fl_ground 32 96 0.00 1 1 0 0 0 +( -4512 1760 0 ) ( -4512 1376 0 ) ( -4512 1376 -32 ) eden/fl_ground 32 96 0.00 1 1 0 0 0 +} +// brush 9 +{ +( -2496 2496 -32 ) ( -2752 2496 -32 ) ( -2752 2112 -32 ) eden/FL_edenhouse3 32 96 0.00 1 1 0 0 0 +( -2752 2112 0 ) ( -2752 2496 0 ) ( -2496 2496 0 ) eden/FL_edenhouse3 32 96 0.00 1 1 0 0 0 +( -2752 2112 0 ) ( -2496 2112 0 ) ( -2496 2112 -32 ) eden/FL_edenhouse3 32 0 0.00 1 1 0 0 0 +( -2496 2112 0 ) ( -2496 2496 0 ) ( -2496 2496 -32 ) eden/FL_edenhouse3 -96 0 0.00 1 1 0 0 0 +( -2496 2496 0 ) ( -2752 2496 0 ) ( -2752 2496 -32 ) eden/FL_edenhouse3 32 0 0.00 1 1 0 0 0 +( -2752 2496 0 ) ( -2752 2112 0 ) ( -2752 2112 -32 ) eden/FL_edenhouse3 -96 0 0.00 1 1 0 0 0 +} +// brush 10 +{ +( -2752 2496 -32 ) ( -3008 2496 -32 ) ( -3008 2112 -32 ) eden/WL_basement 32 32 0.00 1 1 0 0 0 +( -3008 2112 0 ) ( -3008 2496 0 ) ( -2752 2496 0 ) eden/WL_basement 32 32 0.00 1 1 0 0 0 +( -3008 2112 0 ) ( -2752 2112 0 ) ( -2752 2112 -32 ) eden/WL_basement 32 0 0.00 1 1 0 0 0 +( -2752 2112 0 ) ( -2752 2496 0 ) ( -2752 2496 -32 ) eden/WL_basement -96 0 0.00 1 1 0 0 0 +( -2752 2496 0 ) ( -3008 2496 0 ) ( -3008 2496 -32 ) eden/WL_basement 32 0 0.00 1 1 0 0 0 +( -3008 2496 0 ) ( -3008 2112 0 ) ( -3008 2112 -32 ) eden/WL_basement -96 0 0.00 1 1 0 0 0 +} +// brush 11 +{ +( -3008 2496 -32 ) ( -3264 2496 -32 ) ( -3264 2112 -32 ) eden/wl_rock 32 224 0.00 1 1 0 0 0 +( -3264 2112 0 ) ( -3264 2496 0 ) ( -3008 2496 0 ) eden/wl_rock 32 224 0.00 1 1 0 0 0 +( -3264 2112 0 ) ( -3008 2112 0 ) ( -3008 2112 -32 ) eden/wl_rock 32 0 0.00 1 1 0 0 0 +( -3008 2112 0 ) ( -3008 2496 0 ) ( -3008 2496 -32 ) eden/wl_rock -224 0 0.00 1 1 0 0 0 +( -3008 2496 0 ) ( -3264 2496 0 ) ( -3264 2496 -32 ) eden/wl_rock 32 0 0.00 1 1 0 0 0 +( -3264 2496 0 ) ( -3264 2112 0 ) ( -3264 2112 -32 ) eden/wl_rock -224 0 0.00 1 1 0 0 0 +} +// brush 12 +{ +( -3264 2496 -32 ) ( -3520 2496 -32 ) ( -3520 2112 -32 ) eden/fl_ground 32 96 0.00 1 1 0 0 0 +( -3520 2112 0 ) ( -3520 2496 0 ) ( -3264 2496 0 ) eden/fl_ground 32 96 0.00 1 1 0 0 0 +( -3520 2112 0 ) ( -3264 2112 0 ) ( -3264 2112 -32 ) eden/fl_ground 32 0 0.00 1 1 0 0 0 +( -3264 2112 0 ) ( -3264 2496 0 ) ( -3264 2496 -32 ) eden/fl_ground -96 0 0.00 1 1 0 0 0 +( -3264 2496 0 ) ( -3520 2496 0 ) ( -3520 2496 -32 ) eden/fl_ground 32 0 0.00 1 1 0 0 0 +( -3520 2496 0 ) ( -3520 2112 0 ) ( -3520 2112 -32 ) eden/fl_ground -96 0 0.00 1 1 0 0 0 +} +// brush 13 +{ +( -3520 2464 -32 ) ( -3776 2464 -32 ) ( -3776 2080 -32 ) eden/fl_grass 32 96 0.00 1 1 0 0 0 +( -3776 2112 0 ) ( -3776 2496 0 ) ( -3520 2496 0 ) eden/fl_grass 32 96 0.00 1 1 0 0 0 +( -3776 2112 0 ) ( -3520 2112 0 ) ( -3520 2112 -32 ) eden/fl_grass 32 0 0.00 1 1 0 0 0 +( -3520 2080 0 ) ( -3520 2464 0 ) ( -3520 2464 -32 ) eden/fl_grass -96 0 0.00 1 1 0 0 0 +( -3520 2496 0 ) ( -3776 2496 0 ) ( -3776 2496 -32 ) eden/fl_grass 32 0 0.00 1 1 0 0 0 +( -3776 2496 0 ) ( -3776 2112 0 ) ( -3776 2112 -32 ) eden/fl_grass -96 0 0.00 1 1 0 0 0 +} +// brush 14 +{ +( -3776 2496 -32 ) ( -4032 2496 -32 ) ( -4032 2112 -32 ) eden/tr_chainlink 0 0 0.00 1 1 536870912 16 0 +( -4032 2112 0 ) ( -4032 2496 0 ) ( -3776 2496 0 ) eden/tr_chainlink 0 0 0.00 1 1 536870912 16 0 +( -4032 2112 0 ) ( -3776 2112 0 ) ( -3776 2112 -32 ) eden/tr_chainlink 0 0 0.00 1 1 536870912 16 0 +( -3776 2112 0 ) ( -3776 2496 0 ) ( -3776 2496 -32 ) eden/tr_chainlink 0 0 0.00 1 1 536870912 16 0 +( -3776 2496 0 ) ( -4032 2496 0 ) ( -4032 2496 -32 ) eden/tr_chainlink 0 0 0.00 1 1 536870912 16 0 +( -4032 2496 0 ) ( -4032 2112 0 ) ( -4032 2112 -32 ) eden/tr_chainlink 0 0 0.00 1 1 536870912 16 0 +} +// brush 15 +{ +( -4032 2496 -32 ) ( -4288 2496 -32 ) ( -4288 2112 -32 ) swamps/FL_swamp10 32 224 0.00 1 1 0 0 0 +( -4288 2112 0 ) ( -4288 2496 0 ) ( -4032 2496 0 ) swamps/FL_swamp10 32 224 0.00 1 1 0 0 0 +( -4288 2112 0 ) ( -4032 2112 0 ) ( -4032 2112 -32 ) swamps/FL_swamp10 32 0 0.00 1 1 0 0 0 +( -4032 2112 0 ) ( -4032 2496 0 ) ( -4032 2496 -32 ) swamps/FL_swamp10 -224 0 0.00 1 1 0 0 0 +( -4032 2496 0 ) ( -4288 2496 0 ) ( -4288 2496 -32 ) swamps/FL_swamp10 32 0 0.00 1 1 0 0 0 +( -4176 2496 0 ) ( -4176 2112 0 ) ( -4176 2112 -32 ) swamps/FL_swamp10 -224 0 0.00 1 1 0 0 0 +} +// brush 16 +{ +( -4672 1456 272 ) ( -4672 1408 272 ) ( -4192 1408 272 ) eden/WL_basement 0 0 0.00 1 1 0 0 0 +( -4192 1408 336 ) ( -4672 1408 336 ) ( -4672 1456 336 ) eden/WL_basement 0 0 0.00 1 1 0 0 0 +( -4608 1472 272 ) ( -2560 1472 272 ) ( -2560 1472 336 ) eden/WL_basement 0 0 0.00 1 1 0 0 0 +( -2496 1408 336 ) ( -2560 1472 336 ) ( -2560 1472 272 ) eden/WL_basement 0 0 0.00 1 1 0 0 0 +( -4672 1408 272 ) ( -4672 1408 336 ) ( -4192 1408 336 ) eden/WL_basement 0 0 0.00 1 1 0 0 0 +( -2816 1648 272 ) ( -2816 1696 272 ) ( -2816 1672 336 ) eden/WL_basement 0 0 0.00 1 1 0 0 0 +} +// brush 17 +{ +( -4672 1456 272 ) ( -4672 1408 272 ) ( -4192 1408 272 ) eden/WL_basement 0 0 0.00 1 1 0 0 0 +( -4192 1408 336 ) ( -4672 1408 336 ) ( -4672 1456 336 ) eden/WL_basement 0 0 0.00 1 1 0 0 0 +( -4608 1472 272 ) ( -2560 1472 272 ) ( -2560 1472 336 ) eden/WL_basement 0 0 0.00 1 1 0 0 0 +( -4672 1408 272 ) ( -4672 1408 336 ) ( -4192 1408 336 ) eden/WL_basement 0 0 0.00 1 1 0 0 0 +( -3232 1664 272 ) ( -3232 1696 272 ) ( -3232 1680 336 ) eden/WL_basement 0 0 0.00 1 1 0 0 0 +( -2816 1696 272 ) ( -2816 1648 272 ) ( -2816 1672 336 ) eden/WL_basement 0 0 0.00 1 1 0 0 0 +} +// brush 18 +{ +( -4192 1728 272 ) ( -4672 1728 272 ) ( -4672 1680 272 ) eden/WL_basement 0 0 0.00 1 1 0 0 0 +( -4672 1680 336 ) ( -4672 1728 336 ) ( -4192 1728 336 ) eden/WL_basement 0 0 0.00 1 1 0 0 0 +( -2560 1664 336 ) ( -2560 1664 272 ) ( -4608 1664 272 ) eden/WL_basement 0 0 0.00 1 1 0 0 0 +( -2560 1664 272 ) ( -2560 1664 336 ) ( -2496 1728 336 ) eden/WL_basement 0 0 0.00 1 1 0 0 0 +( -4192 1728 336 ) ( -4672 1728 336 ) ( -4672 1728 272 ) eden/WL_basement 0 0 0.00 1 1 0 0 0 +( -2816 1648 272 ) ( -2816 1696 272 ) ( -2816 1672 336 ) eden/WL_basement 0 0 0.00 1 1 0 0 0 +} +// brush 19 +{ +( -4192 1728 272 ) ( -4672 1728 272 ) ( -4672 1680 272 ) eden/WL_basement 0 0 0.00 1 1 0 0 0 +( -4672 1680 336 ) ( -4672 1728 336 ) ( -4192 1728 336 ) eden/WL_basement 0 0 0.00 1 1 0 0 0 +( -2560 1664 336 ) ( -2560 1664 272 ) ( -4608 1664 272 ) eden/WL_basement 0 0 0.00 1 1 0 0 0 +( -4192 1728 336 ) ( -4672 1728 336 ) ( -4672 1728 272 ) eden/WL_basement 0 0 0.00 1 1 0 0 0 +( -3232 1664 272 ) ( -3232 1696 272 ) ( -3232 1680 336 ) eden/WL_basement 0 0 0.00 1 1 0 0 0 +( -2816 1696 272 ) ( -2816 1648 272 ) ( -2816 1672 336 ) eden/WL_basement 0 0 0.00 1 1 0 0 0 +} +// brush 20 +{ +( -4672 1456 272 ) ( -4672 1408 272 ) ( -4192 1408 272 ) eden/WL_basement 0 0 0.00 1 1 0 0 0 +( -4192 1408 336 ) ( -4672 1408 336 ) ( -4672 1456 336 ) eden/WL_basement 0 0 0.00 1 1 0 0 0 +( -6512 1472 272 ) ( -4464 1472 272 ) ( -4464 1472 336 ) eden/WL_basement 0 0 0.00 1 1 0 0 0 +( -4672 1408 272 ) ( -4672 1408 336 ) ( -4192 1408 336 ) eden/WL_basement 0 0 0.00 1 1 0 0 0 +( -6144 1632 272 ) ( -6144 1696 272 ) ( -6144 1664 336 ) eden/WL_basement 0 0 0.00 1 1 0 0 0 +( -3744 1696 272 ) ( -3744 1664 272 ) ( -3744 1680 336 ) eden/WL_basement 0 0 0.00 1 1 0 0 0 +} +// brush 21 +{ +( -4192 1728 272 ) ( -4672 1728 272 ) ( -4672 1680 272 ) eden/WL_basement 0 0 0.00 1 1 0 0 0 +( -4672 1680 336 ) ( -4672 1728 336 ) ( -4192 1728 336 ) eden/WL_basement 0 0 0.00 1 1 0 0 0 +( -2560 1664 336 ) ( -2560 1664 272 ) ( -4608 1664 272 ) eden/WL_basement 0 0 0.00 1 1 0 0 0 +( -6240 1728 336 ) ( -6720 1728 336 ) ( -6720 1728 272 ) eden/WL_basement 0 0 0.00 1 1 0 0 0 +( -6144 1632 272 ) ( -6144 1696 272 ) ( -6144 1664 336 ) eden/WL_basement 0 0 0.00 1 1 0 0 0 +( -3744 1696 272 ) ( -3744 1664 272 ) ( -3744 1680 336 ) eden/WL_basement 0 0 0.00 1 1 0 0 0 +} +// brush 22 +{ +( -6576 1456 272 ) ( -6576 1408 272 ) ( -6096 1408 272 ) eden/WL_basement -16 0 0.00 1 1 0 0 0 +( -6096 1408 336 ) ( -6576 1408 336 ) ( -6576 1456 336 ) eden/WL_basement -16 0 0.00 1 1 0 0 0 +( -7472 1472 272 ) ( -5424 1472 272 ) ( -5424 1472 336 ) eden/WL_basement -16 0 0.00 1 1 0 0 0 +( -7536 1408 272 ) ( -7536 1408 336 ) ( -7056 1408 336 ) eden/WL_basement -16 0 0.00 1 1 0 0 0 +( -7536 1408 272 ) ( -7472 1472 272 ) ( -7472 1472 336 ) eden/WL_basement 0 0 0.00 1 1 0 0 0 +( -6144 1696 272 ) ( -6144 1632 272 ) ( -6144 1664 336 ) eden/WL_basement 0 0 0.00 1 1 0 0 0 +} +// brush 23 +{ +( -6096 1728 272 ) ( -6576 1728 272 ) ( -6576 1680 272 ) eden/WL_basement -16 0 0.00 1 1 0 0 0 +( -6576 1680 336 ) ( -6576 1728 336 ) ( -6096 1728 336 ) eden/WL_basement -16 0 0.00 1 1 0 0 0 +( -4464 1664 336 ) ( -4464 1664 272 ) ( -6512 1664 272 ) eden/WL_basement -16 0 0.00 1 1 0 0 0 +( -7056 1728 336 ) ( -7536 1728 336 ) ( -7536 1728 272 ) eden/WL_basement -16 0 0.00 1 1 0 0 0 +( -7472 1664 336 ) ( -7472 1664 272 ) ( -7536 1728 272 ) eden/WL_basement 0 0 0.00 1 1 0 0 0 +( -6144 1696 272 ) ( -6144 1632 272 ) ( -6144 1664 336 ) eden/WL_basement 0 0 0.00 1 1 0 0 0 +} +// brush 24 +{ +( -4672 1456 272 ) ( -4672 1408 272 ) ( -4192 1408 272 ) eden/WL_basement 0 0 0.00 1 1 0 0 0 +( -4192 1408 336 ) ( -4672 1408 336 ) ( -4672 1456 336 ) eden/WL_basement 0 0 0.00 1 1 0 0 0 +( -4608 1472 272 ) ( -2560 1472 272 ) ( -2560 1472 336 ) eden/WL_basement 0 0 0.00 1 1 0 0 0 +( -4672 1408 272 ) ( -4672 1408 336 ) ( -4192 1408 336 ) eden/WL_basement 0 0 0.00 1 1 0 0 0 +( -3744 1664 272 ) ( -3744 1696 272 ) ( -3744 1680 336 ) eden/WL_basement 0 0 0.00 1 1 0 0 0 +( -3232 1696 272 ) ( -3232 1664 272 ) ( -3232 1680 336 ) eden/WL_basement 0 0 0.00 1 1 0 0 0 +} +// brush 25 +{ +( -4192 1728 272 ) ( -4672 1728 272 ) ( -4672 1680 272 ) eden/WL_basement 0 0 0.00 1 1 0 0 0 +( -4672 1680 336 ) ( -4672 1728 336 ) ( -4192 1728 336 ) eden/WL_basement 0 0 0.00 1 1 0 0 0 +( -2560 1664 336 ) ( -2560 1664 272 ) ( -4608 1664 272 ) eden/WL_basement 0 0 0.00 1 1 0 0 0 +( -4192 1728 336 ) ( -4672 1728 336 ) ( -4672 1728 272 ) eden/WL_basement 0 0 0.00 1 1 0 0 0 +( -3744 1664 272 ) ( -3744 1696 272 ) ( -3744 1680 336 ) eden/WL_basement 0 0 0.00 1 1 0 0 0 +( -3232 1696 272 ) ( -3232 1664 272 ) ( -3232 1680 336 ) eden/WL_basement 0 0 0.00 1 1 0 0 0 +} +// brush 26 +{ +( -7472 1472 272 ) ( -7472 1664 272 ) ( -7536 1664 272 ) eden/WL_basement 0 48 90.00 1 1 0 0 0 +( -7536 1664 336 ) ( -7472 1664 336 ) ( -7472 1472 336 ) eden/WL_basement 0 48 90.00 1 1 0 0 0 +( -7472 1472 272 ) ( -7536 1408 272 ) ( -7536 1408 336 ) eden/WL_basement 0 0 90.00 1 1 0 0 0 +( -7536 1408 272 ) ( -7536 1728 272 ) ( -7536 1728 336 ) eden/WL_basement 0 0 90.00 1 1 0 0 0 +( -7472 1664 336 ) ( -7536 1728 336 ) ( -7536 1728 272 ) eden/WL_basement 0 0 90.00 1 1 0 0 0 +( -7472 1472 272 ) ( -7472 1472 336 ) ( -7472 1664 336 ) eden/WL_basement 0 0 90.00 1 1 0 0 0 +} +// brush 27 +{ +( -2496 1664 272 ) ( -2560 1664 272 ) ( -2560 1472 272 ) eden/WL_basement 0 0 90.00 1 1 0 0 0 +( -2560 1472 336 ) ( -2560 1664 336 ) ( -2496 1664 336 ) eden/WL_basement 0 0 90.00 1 1 0 0 0 +( -2496 1408 336 ) ( -2496 1408 272 ) ( -2560 1472 272 ) eden/WL_basement 0 0 90.00 1 1 0 0 0 +( -2496 1728 336 ) ( -2496 1728 272 ) ( -2496 1408 272 ) eden/WL_basement 0 0 90.00 1 1 0 0 0 +( -2496 1728 272 ) ( -2496 1728 336 ) ( -2560 1664 336 ) eden/WL_basement 0 0 90.00 1 1 0 0 0 +( -2560 1664 336 ) ( -2560 1472 336 ) ( -2560 1472 272 ) eden/WL_basement 0 0 90.00 1 1 0 0 0 +} +// brush 28 +{ +( -6144 1760 0 ) ( -6400 1760 0 ) ( -6400 1376 0 ) phook/water4 0 0 0.00 1 1 536870944 17408 0 +( -6400 1376 64 ) ( -6400 1760 64 ) ( -6144 1760 64 ) phook/water4 0 0 0.00 1 1 536870944 17408 0 +( -6400 1376 64 ) ( -6144 1376 64 ) ( -6144 1376 32 ) phook/water4 0 0 0.00 1 1 536870944 17408 0 +( -6144 1376 64 ) ( -6144 1760 64 ) ( -6144 1760 32 ) phook/water4 0 0 0.00 1 1 536870944 17408 0 +( -6144 1760 64 ) ( -6400 1760 64 ) ( -6400 1760 32 ) phook/water4 0 0 0.00 1 1 536870944 17408 0 +( -7568 1744 64 ) ( -7568 1360 64 ) ( -7568 1360 32 ) phook/water4 0 0 0.00 1 1 536870944 17408 0 +} +// brush 29 +{ +( -7360 1760 0 ) ( -7568 1760 0 ) ( -7568 1376 0 ) swamps/FL_swamp10 48 0 0.00 1 1 0 0 0 +( -7568 1376 16 ) ( -7568 1760 16 ) ( -7360 1760 16 ) swamps/FL_swamp10 48 0 0.00 1 1 0 0 0 +( -7568 1376 32 ) ( -7360 1376 32 ) ( -7360 1376 0 ) swamps/FL_swamp10 48 0 0.00 1 1 0 0 0 +( -7040 1360 0 ) ( -7040 1744 0 ) ( -7040 1744 -32 ) swamps/FL_swamp10 0 0 0.00 1 1 0 0 0 +( -7360 1760 32 ) ( -7568 1760 32 ) ( -7568 1760 0 ) swamps/FL_swamp10 48 0 0.00 1 1 0 0 0 +( -7568 1760 32 ) ( -7568 1376 32 ) ( -7568 1376 0 ) swamps/FL_swamp10 0 0 0.00 1 1 0 0 0 +} +// brush 30 +{ +( -6912 1616 0 ) ( -7040 1616 0 ) ( -7040 1600 0 ) swamps/FL_swamp10 128 0 0.00 1 1 0 0 0 +( -7040 1600 32 ) ( -7040 1616 32 ) ( -6912 1616 32 ) swamps/FL_swamp10 128 0 0.00 1 1 0 0 0 +( -7040 1376 32 ) ( -6912 1376 32 ) ( -6912 1376 0 ) swamps/FL_swamp10 128 0 0.00 1 1 0 0 0 +( -6512 1520 32 ) ( -6512 1536 32 ) ( -6512 1536 0 ) swamps/FL_swamp10 0 0 0.00 1 1 0 0 0 +( -6912 1760 32 ) ( -7040 1760 32 ) ( -7040 1760 0 ) swamps/FL_swamp10 128 0 0.00 1 1 0 0 0 +( -7040 1616 32 ) ( -7040 1600 32 ) ( -7040 1600 0 ) swamps/FL_swamp10 0 0 0.00 1 1 0 0 0 +} +// brush 31 +{ +( -6144 1616 0 ) ( -6272 1616 0 ) ( -6272 1600 0 ) swamps/FL_swamp10 0 0 0.00 1 1 0 0 0 +( -6272 1600 48 ) ( -6272 1616 48 ) ( -6144 1616 48 ) swamps/FL_swamp10 0 0 0.00 1 1 0 0 0 +( -6272 1376 48 ) ( -6144 1376 48 ) ( -6144 1376 0 ) swamps/FL_swamp10 0 0 0.00 1 1 0 0 0 +( -6144 1600 48 ) ( -6144 1616 48 ) ( -6144 1616 0 ) swamps/FL_swamp10 0 0 0.00 1 1 0 0 0 +( -6144 1760 48 ) ( -6272 1760 48 ) ( -6272 1760 0 ) swamps/FL_swamp10 0 0 0.00 1 1 0 0 0 +( -6512 1552 48 ) ( -6512 1536 48 ) ( -6512 1536 0 ) swamps/FL_swamp10 0 0 0.00 1 1 0 0 0 +} +// brush 32 +{ +( -6256 1760 -16 ) ( -6416 1760 -16 ) ( -6416 1376 -16 ) swamps/FL_swamp10 -144 0 0.00 1 1 0 0 0 +( -6416 1376 0 ) ( -6416 1760 0 ) ( -6256 1760 0 ) swamps/FL_swamp10 -144 0 0.00 1 1 0 0 0 +( -6416 1376 80 ) ( -6256 1376 80 ) ( -6256 1376 -16 ) swamps/FL_swamp10 -144 16 0.00 1 1 0 0 0 +( -6144 1376 80 ) ( -6144 1760 80 ) ( -6144 1760 -16 ) swamps/FL_swamp10 0 16 0.00 1 1 0 0 0 +( -6256 1760 80 ) ( -6416 1760 80 ) ( -6416 1760 -16 ) swamps/FL_swamp10 -144 16 0.00 1 1 0 0 0 +( -6608 1760 80 ) ( -6608 1376 80 ) ( -6608 1376 -16 ) swamps/FL_swamp10 0 16 0.00 1 1 0 0 0 +} +// brush 33 +{ +( -6048 1760 -32 ) ( -6144 1760 -32 ) ( -6144 1376 -32 ) swamps/FL_swamp10 0 0 0.00 1 1 0 0 0 +( -6144 1376 80 ) ( -6144 1760 80 ) ( -6048 1760 0 ) swamps/FL_swamp10 0 0 0.00 1 1 0 0 0 +( -6144 1376 0 ) ( -6048 1376 0 ) ( -6048 1376 -32 ) swamps/FL_swamp10 0 0 0.00 1 1 0 0 0 +( -6048 1376 0 ) ( -6048 1760 0 ) ( -6048 1760 -32 ) swamps/FL_swamp10 0 0 0.00 1 1 0 0 0 +( -6048 1760 0 ) ( -6144 1760 0 ) ( -6144 1760 -32 ) swamps/FL_swamp10 0 0 0.00 1 1 0 0 0 +( -6144 1760 80 ) ( -6144 1376 80 ) ( -6144 1376 -32 ) swamps/FL_swamp10 0 0 0.00 1 1 0 0 0 +} +// brush 34 +{ +( -3744 1792 -64 ) ( -4000 1792 -64 ) ( -4000 1760 -64 ) swamps/FL_swamp10 0 160 0.00 1 1 0 0 0 +( -4000 1760 0 ) ( -4000 1792 0 ) ( -3744 1792 0 ) swamps/FL_swamp10 0 160 0.00 1 1 0 0 0 +( -5280 1760 -32 ) ( -5024 1760 -32 ) ( -5024 1760 -64 ) swamps/FL_swamp10 0 0 0.00 1 1 0 0 0 +( -3488 1760 -32 ) ( -3488 1792 -32 ) ( -3488 1792 -64 ) swamps/FL_swamp10 -160 0 0.00 1 1 0 0 0 +( -3744 1792 -32 ) ( -4000 1792 -32 ) ( -4000 1792 -64 ) swamps/FL_swamp10 0 0 0.00 1 1 0 0 0 +( -5536 1792 -32 ) ( -5536 1760 -32 ) ( -5536 1760 -64 ) swamps/FL_swamp10 -160 0 0.00 1 1 0 0 0 +} +// brush 35 +{ +( -3744 1376 -64 ) ( -4000 1376 -64 ) ( -4000 1344 -64 ) swamps/FL_swamp10 0 0 0.00 1 1 0 0 0 +( -4000 1344 0 ) ( -4000 1376 0 ) ( -3744 1376 0 ) swamps/FL_swamp10 0 0 0.00 1 1 0 0 0 +( -4000 1344 -32 ) ( -3744 1344 -32 ) ( -3744 1344 -64 ) swamps/FL_swamp10 0 0 0.00 1 1 0 0 0 +( -3488 1344 -32 ) ( -3488 1376 -32 ) ( -3488 1376 -64 ) swamps/FL_swamp10 0 0 0.00 1 1 0 0 0 +( -5024 1376 -32 ) ( -5280 1376 -32 ) ( -5280 1376 -64 ) swamps/FL_swamp10 0 0 0.00 1 1 0 0 0 +( -5536 1376 -32 ) ( -5536 1344 -32 ) ( -5536 1344 -64 ) swamps/FL_swamp10 0 0 0.00 1 1 0 0 0 +} +// brush 36 +{ +( -3488 1728 -32 ) ( -3744 1728 -32 ) ( -3744 1344 -32 ) eden/wl_rock 32 224 0.00 1 1 0 0 0 +( -3744 1376 0 ) ( -3744 1760 0 ) ( -3488 1760 0 ) eden/wl_rock 32 224 0.00 1 1 0 0 0 +( -3744 1376 0 ) ( -3488 1376 0 ) ( -3488 1376 -32 ) eden/wl_rock 32 224 0.00 1 1 0 0 0 +( -3488 1344 0 ) ( -3488 1728 0 ) ( -3488 1728 -32 ) eden/wl_rock 32 224 0.00 1 1 0 0 0 +( -3488 1760 0 ) ( -3744 1760 0 ) ( -3744 1760 -32 ) eden/wl_rock 32 224 0.00 1 1 0 0 0 +( -4000 1760 0 ) ( -4000 1376 0 ) ( -4000 1376 -32 ) eden/wl_rock 32 224 0.00 1 1 0 0 0 +} +// brush 37 +{ +( -2976 1760 -32 ) ( -3232 1760 -32 ) ( -3232 1376 -32 ) eden/WL_basement 32 32 0.00 1 1 0 0 0 +( -3232 1376 0 ) ( -3232 1760 0 ) ( -2976 1760 0 ) eden/WL_basement 32 32 0.00 1 1 0 0 0 +( -3232 1376 0 ) ( -2976 1376 0 ) ( -2976 1376 -32 ) eden/WL_basement 32 32 0.00 1 1 0 0 0 +( -2976 1376 0 ) ( -2976 1760 0 ) ( -2976 1760 -32 ) eden/WL_basement 32 32 0.00 1 1 0 0 0 +( -2976 1760 0 ) ( -3232 1760 0 ) ( -3232 1760 -32 ) eden/WL_basement 32 32 0.00 1 1 0 0 0 +( -3488 1792 0 ) ( -3488 1408 0 ) ( -3488 1408 -32 ) eden/WL_basement 32 32 0.00 1 1 0 0 0 +} +// brush 38 +{ +( -2464 1760 -32 ) ( -2720 1760 -32 ) ( -2720 1376 -32 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( -2720 1376 0 ) ( -2720 1760 0 ) ( -2464 1760 0 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( -2720 1376 0 ) ( -2464 1376 0 ) ( -2464 1376 -32 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( -2464 1376 0 ) ( -2464 1760 0 ) ( -2464 1760 -32 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( -2464 1760 0 ) ( -2720 1760 0 ) ( -2720 1760 -32 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +( -2976 1792 0 ) ( -2976 1408 0 ) ( -2976 1408 -32 ) eden/FL_edenhouse3 0 0 0.00 1 1 0 0 0 +} +// brush 39 +{ +( -2000 1744 -32 ) ( -2432 1744 -32 ) ( -2432 1376 -32 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( -2432 1376 0 ) ( -2432 1744 0 ) ( -2000 1744 0 ) we_cemetary/cemtrim2 -80 -33 90.00 1 1 0 0 0 +( -2432 1376 0 ) ( -2000 1376 0 ) ( -2000 1376 -32 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( -2000 1760 0 ) ( -2432 1760 0 ) ( -2432 1760 -32 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( -2464 1744 0 ) ( -2464 1376 0 ) ( -2464 1376 -32 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( -2400 1664 -32 ) ( -2400 1632 -32 ) ( -2400 1648 0 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +} +// brush 40 +{ +( -2000 1744 -32 ) ( -2432 1744 -32 ) ( -2432 1376 -32 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( -2432 1376 0 ) ( -2432 1744 0 ) ( -2000 1744 0 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( -2432 1376 0 ) ( -2000 1376 0 ) ( -2000 1376 -32 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( -2000 1760 0 ) ( -2432 1760 0 ) ( -2432 1760 -32 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( -1664 1728 -32 ) ( -1664 1696 -32 ) ( -1664 1712 0 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( -2400 1632 -32 ) ( -2400 1664 -32 ) ( -2400 1648 0 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +} +// brush 41 +{ +( -7568 -32 272 ) ( -7568 -224 272 ) ( -7536 -224 272 ) we_cemetary/cemrunner2 110 1 0.00 1 1 0 0 0 +( -7536 -224 336 ) ( -7568 -224 336 ) ( -7568 -32 336 ) we_cemetary/cemtrim2 14 1 0.00 1 1 0 0 0 +( -7536 1536 272 ) ( -7536 1536 592 ) ( -7536 1728 592 ) we_cemetary/cemtrim2 -32 15 0.00 1 1 0 0 0 +( -7600 -32 272 ) ( -7600 -32 592 ) ( -7600 -224 592 ) we_cemetary/cemtrim2 -32 15 0.00 1 1 0 0 0 +( -7600 1792 272 ) ( -7568 1760 272 ) ( -7584 1776 336 ) we_cemetary/cemtrim2 0 16 0.00 1 1 0 0 0 +( -7536 1408 272 ) ( -7568 1376 272 ) ( -7552 1392 336 ) we_cemetary/cemtrim2 0 16 0.00 1 1 0 0 0 +} +// brush 42 +{ +( -7600 -32 64 ) ( -7600 -224 64 ) ( -7568 -224 64 ) we_cemetary/cemstair2 110 -31 0.00 1 1 0 0 0 +( -7600 -32 64 ) ( -7600 -32 384 ) ( -7600 -224 384 ) we_cemetary/cemstair2 160 0 0.00 1 1 0 0 0 +( -7568 1728 64 ) ( -7560 1536 80 ) ( -7552 1728 96 ) we_cemetary/cemstair2 160 0 0.00 1 1 0 0 0 +( -7600 -32 256 ) ( -7536 -32 256 ) ( -7536 -224 256 ) we_cemetary/cemstair2 110 -31 0.00 1 1 0 0 0 +( -7552 -32 144 ) ( -7552 -224 176 ) ( -7552 -32 208 ) we_cemetary/cemstair2 160 0 0.00 1 1 0 0 0 +( -7600 1792 64 ) ( -7568 1760 64 ) ( -7584 1776 256 ) we_cemetary/cemstair2 128 0 0.00 1 1 0 0 0 +( -7536 1408 64 ) ( -7568 1376 64 ) ( -7552 1392 256 ) we_cemetary/cemstair2 128 0 0.00 1 1 0 0 0 +} +// brush 43 +{ +( -7600 -32 0 ) ( -7600 -224 0 ) ( -7568 -224 0 ) we_cemetary/cemtrim2 46 1 0.00 1 1 0 0 0 +( -7568 -224 64 ) ( -7600 -224 64 ) ( -7600 -32 64 ) we_cemetary/cemtrim2 46 1 0.00 1 1 0 0 0 +( -7568 1728 0 ) ( -7568 1728 320 ) ( -7568 1920 320 ) we_cemetary/cemtrim2 -32 0 0.00 1 1 0 0 0 +( -7600 -32 0 ) ( -7600 -32 320 ) ( -7600 -224 320 ) we_cemetary/cemtrim2 -32 0 0.00 1 1 0 0 0 +( -7600 1792 0 ) ( -7568 1760 0 ) ( -7584 1776 64 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( -7536 1408 0 ) ( -7568 1376 0 ) ( -7552 1392 64 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +} +// brush 44 +{ +( -7600 -224 256 ) ( -7552 -224 256 ) ( -7552 -32 256 ) we_cemetary/fogtrunk 110 -160 0.00 1 1 0 0 0 +( -7536 -224 272 ) ( -7600 -224 272 ) ( -7600 -32 272 ) we_cemetary/fogtrunk 110 -160 0.00 1 1 0 0 0 +( -7536 1728 272 ) ( -7552 1728 256 ) ( -7552 1536 256 ) we_cemetary/fogtrunk 110 -160 0.00 1 1 0 0 0 +( -7600 -32 256 ) ( -7600 -32 272 ) ( -7600 -224 272 ) we_cemetary/fogtrunk 160 0 0.00 1 1 0 0 0 +( -7600 1792 256 ) ( -7568 1760 256 ) ( -7584 1776 272 ) we_cemetary/fogtrunk 128 0 0.00 1 1 0 0 0 +( -7536 1408 256 ) ( -7568 1376 256 ) ( -7552 1392 272 ) we_cemetary/fogtrunk 128 0 0.00 1 1 0 0 0 +} +// brush 45 +{ +( -2528 1376 272 ) ( -2336 1376 272 ) ( -2336 1408 272 ) we_cemetary/cemrunner2 62 1 -90.00 1 1 0 0 0 +( -2336 1408 336 ) ( -2336 1376 336 ) ( -2528 1376 336 ) we_cemetary/cemtrim2 30 33 -90.00 1 1 0 0 0 +( -7344 1408 272 ) ( -7344 1408 592 ) ( -7536 1408 592 ) we_cemetary/cemtrim2 96 15 0.00 1 1 0 0 0 +( -2528 1344 272 ) ( -2528 1344 592 ) ( -2336 1344 592 ) we_cemetary/cemtrim2 96 15 0.00 1 1 0 0 0 +( -2464 1792 272 ) ( -2464 1728 272 ) ( -2464 1760 336 ) we_cemetary/cemtrim2 0 16 0.00 1 1 0 0 0 +( -7600 1344 272 ) ( -7568 1376 272 ) ( -7584 1360 336 ) we_cemetary/cemtrim2 0 16 0.00 1 1 0 0 0 +} +// brush 46 +{ +( -2528 1344 64 ) ( -2336 1344 64 ) ( -2336 1376 64 ) we_cemetary/cemstair2 62 33 -90.00 1 1 0 0 0 +( -2528 1344 64 ) ( -2528 1344 384 ) ( -2336 1344 384 ) we_cemetary/cemstair2 96 0 0.00 1 1 0 0 0 +( -7536 1376 64 ) ( -7344 1384 80 ) ( -7536 1392 96 ) we_cemetary/cemstair2 96 0 0.00 1 1 0 0 0 +( -2528 1344 256 ) ( -2528 1408 256 ) ( -2336 1408 256 ) we_cemetary/cemstair2 62 33 -90.00 1 1 0 0 0 +( -2528 1392 144 ) ( -2336 1392 176 ) ( -2528 1392 208 ) we_cemetary/cemstair2 96 0 0.00 1 1 0 0 0 +( -2464 1792 64 ) ( -2464 1728 64 ) ( -2464 1760 256 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( -7600 1344 64 ) ( -7568 1376 64 ) ( -7584 1360 256 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +} +// brush 47 +{ +( -2528 1344 0 ) ( -2336 1344 0 ) ( -2336 1376 0 ) we_cemetary/cemtrim2 62 33 -90.00 1 1 0 0 0 +( -2336 1376 64 ) ( -2336 1344 64 ) ( -2528 1344 64 ) we_cemetary/cemtrim2 62 33 -90.00 1 1 0 0 0 +( -7536 1376 0 ) ( -7536 1376 320 ) ( -7728 1376 320 ) we_cemetary/cemtrim2 96 0 0.00 1 1 0 0 0 +( -2528 1344 0 ) ( -2528 1344 320 ) ( -2336 1344 320 ) we_cemetary/cemtrim2 96 0 0.00 1 1 0 0 0 +( -2464 1792 0 ) ( -2464 1728 0 ) ( -2464 1760 64 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( -7600 1344 0 ) ( -7568 1376 0 ) ( -7584 1360 64 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +} +// brush 48 +{ +( -2336 1344 256 ) ( -2336 1392 256 ) ( -2528 1392 256 ) we_cemetary/fogtrunk 62 -96 -90.00 1 1 0 0 0 +( -2336 1408 272 ) ( -2336 1344 272 ) ( -2528 1344 272 ) we_cemetary/fogtrunk 62 -96 -90.00 1 1 0 0 0 +( -7536 1408 272 ) ( -7536 1392 256 ) ( -7344 1392 256 ) we_cemetary/fogtrunk 62 -96 -90.00 1 1 0 0 0 +( -2528 1344 256 ) ( -2528 1344 272 ) ( -2336 1344 272 ) we_cemetary/fogtrunk 96 0 0.00 1 1 0 0 0 +( -2464 1792 256 ) ( -2464 1728 256 ) ( -2464 1760 272 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +( -7600 1344 256 ) ( -7568 1376 256 ) ( -7584 1360 272 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +} +// brush 49 +{ +( -2336 1728 272 ) ( -2336 1760 272 ) ( -2528 1760 272 ) we_cemetary/cemrunner2 -1 31 -90.00 1 1 0 0 0 +( -2528 1760 336 ) ( -2336 1760 336 ) ( -2336 1728 336 ) we_cemetary/cemtrim2 -161 31 -90.00 1 1 0 0 0 +( -3488 1728 592 ) ( -3296 1728 592 ) ( -3296 1728 272 ) we_cemetary/cemtrim2 96 15 0.00 1 1 0 0 0 +( -2320 1792 592 ) ( -2512 1792 592 ) ( -2512 1792 272 ) we_cemetary/cemtrim2 96 15 0.00 1 1 0 0 0 +( -2464 1792 272 ) ( -2464 1728 272 ) ( -2464 1760 336 ) we_cemetary/cemtrim2 192 16 0.00 1 1 0 0 0 +( -7536 1728 272 ) ( -7568 1760 272 ) ( -7552 1744 336 ) we_cemetary/cemtrim2 192 16 0.00 1 1 0 0 0 +} +// brush 50 +{ +( -2336 1760 64 ) ( -2336 1792 64 ) ( -2528 1792 64 ) we_cemetary/cemstair2 -129 31 -90.00 1 1 0 0 0 +( -2320 1792 384 ) ( -2512 1792 384 ) ( -2512 1792 64 ) we_cemetary/cemstair2 96 0 0.00 1 1 0 0 0 +( -2528 1744 96 ) ( -2336 1752 80 ) ( -2528 1760 64 ) we_cemetary/cemstair2 96 0 0.00 1 1 0 0 0 +( -2336 1728 256 ) ( -2528 1728 256 ) ( -2528 1792 256 ) we_cemetary/cemstair2 -129 31 -90.00 1 1 0 0 0 +( -3488 1744 208 ) ( -3296 1744 176 ) ( -3488 1744 144 ) we_cemetary/cemstair2 96 0 0.00 1 1 0 0 0 +( -2464 1792 64 ) ( -2464 1728 64 ) ( -2464 1760 256 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +( -7536 1728 64 ) ( -7568 1760 64 ) ( -7552 1744 256 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +} +// brush 51 +{ +( -2336 1760 0 ) ( -2336 1792 0 ) ( -2528 1792 0 ) we_cemetary/cemtrim2 -129 31 -90.00 1 1 0 0 0 +( -2528 1792 64 ) ( -2336 1792 64 ) ( -2336 1760 64 ) we_cemetary/cemtrim2 -129 31 -90.00 1 1 0 0 0 +( -4992 1760 320 ) ( -4800 1760 320 ) ( -4800 1760 0 ) we_cemetary/cemtrim2 96 0 0.00 1 1 0 0 0 +( -2320 1792 320 ) ( -2512 1792 320 ) ( -2512 1792 0 ) we_cemetary/cemtrim2 96 0 0.00 1 1 0 0 0 +( -2464 1792 0 ) ( -2464 1728 0 ) ( -2464 1760 64 ) we_cemetary/cemtrim2 192 0 0.00 1 1 0 0 0 +( -7536 1728 0 ) ( -7568 1760 0 ) ( -7552 1744 64 ) we_cemetary/cemtrim2 192 0 0.00 1 1 0 0 0 +} +// brush 52 +{ +( -2528 1744 256 ) ( -2336 1744 256 ) ( -2336 1792 256 ) we_cemetary/fogtrunk -129 -96 -90.00 1 1 0 0 0 +( -2528 1792 272 ) ( -2336 1792 272 ) ( -2336 1728 272 ) we_cemetary/fogtrunk -129 -96 -90.00 1 1 0 0 0 +( -3296 1744 256 ) ( -3488 1744 256 ) ( -3488 1728 272 ) we_cemetary/fogtrunk -129 -96 -90.00 1 1 0 0 0 +( -2320 1792 272 ) ( -2512 1792 272 ) ( -2512 1792 256 ) we_cemetary/fogtrunk 96 0 0.00 1 1 0 0 0 +( -2464 1792 256 ) ( -2464 1728 256 ) ( -2464 1760 272 ) we_cemetary/fogtrunk 192 0 0.00 1 1 0 0 0 +( -7536 1728 256 ) ( -7568 1760 256 ) ( -7552 1744 272 ) we_cemetary/fogtrunk 192 0 0.00 1 1 0 0 0 +} +// brush 53 +{ +( -2496 1616 272 ) ( -2464 1616 272 ) ( -2464 1808 272 ) we_cemetary/cemrunner2 0 -15 0.00 1 1 0 0 0 +( -2464 1808 336 ) ( -2464 1616 336 ) ( -2496 1616 336 ) we_cemetary/cemtrim2 97 17 0.00 1 1 0 0 0 +( -2496 1808 592 ) ( -2496 1616 592 ) ( -2496 1616 272 ) we_cemetary/cemtrim2 -16 15 0.00 1 1 0 0 0 +( -2432 1616 592 ) ( -2432 1808 592 ) ( -2432 1808 272 ) we_cemetary/cemtrim2 -16 15 0.00 1 1 0 0 0 +( -2432 1360 272 ) ( -2496 1360 272 ) ( -2464 1360 336 ) we_cemetary/cemtrim2 -64 15 -180.00 1 -1 0 0 0 +( -2496 1776 272 ) ( -2416 1776 272 ) ( -2456 1776 336 ) we_cemetary/cemtrim2 -64 15 -180.00 1 -1 0 0 0 +} +// brush 54 +{ +( -2480 1808 256 ) ( -2480 1616 256 ) ( -2432 1616 256 ) we_cemetary/fogtrunk 129 16 0.00 1 1 0 0 0 +( -2432 1808 272 ) ( -2432 1616 272 ) ( -2496 1616 272 ) we_cemetary/fogtrunk 129 16 0.00 1 1 0 0 0 +( -2480 1616 256 ) ( -2480 1808 256 ) ( -2496 1808 272 ) we_cemetary/fogtrunk 129 16 0.00 1 1 0 0 0 +( -2432 1616 272 ) ( -2432 1808 272 ) ( -2432 1808 256 ) we_cemetary/fogtrunk -16 0 0.00 1 1 0 0 0 +( -2432 1360 256 ) ( -2496 1360 256 ) ( -2464 1360 272 ) we_cemetary/fogtrunk -64 0 -180.00 1 -1 0 0 0 +( -2496 1776 256 ) ( -2416 1776 256 ) ( -2456 1776 272 ) we_cemetary/fogtrunk -64 0 -180.00 1 -1 0 0 0 +} +// brush 55 +{ +( -2464 1616 0 ) ( -2432 1616 0 ) ( -2432 1808 0 ) we_cemetary/cemtrim2 129 17 0.00 1 1 0 0 0 +( -2432 1744 64 ) ( -2432 1552 64 ) ( -2464 1552 64 ) we_cemetary/cemtrim2 129 17 0.00 1 1 0 0 0 +( -2464 1664 320 ) ( -2464 1472 320 ) ( -2464 1472 0 ) we_cemetary/cemtrim2 -16 0 0.00 1 1 0 0 0 +( -2432 1584 320 ) ( -2432 1776 320 ) ( -2432 1776 0 ) we_cemetary/cemtrim2 -16 0 0.00 1 1 0 0 0 +( -2464 1440 0 ) ( -2400 1440 0 ) ( -2432 1440 64 ) we_cemetary/cemtrim2 -64 0 -180.00 1 -1 0 0 0 +( -2432 1360 0 ) ( -2496 1360 0 ) ( -2464 1360 64 ) we_cemetary/cemtrim2 -64 0 -180.00 1 -1 0 0 0 +} +// brush 56 +{ +( -2464 1552 64 ) ( -2432 1552 64 ) ( -2432 1744 64 ) we_cemetary/cemstair2 129 17 0.00 1 1 0 0 0 +( -2432 1584 384 ) ( -2432 1776 384 ) ( -2432 1776 64 ) we_cemetary/cemstair2 -16 0 0.00 1 1 0 0 0 +( -2480 1808 96 ) ( -2472 1616 80 ) ( -2464 1808 64 ) we_cemetary/cemstair2 -16 0 0.00 1 1 0 0 0 +( -2496 1616 256 ) ( -2496 1808 256 ) ( -2432 1808 256 ) we_cemetary/cemstair2 129 17 0.00 1 1 0 0 0 +( -2480 1728 208 ) ( -2480 1536 176 ) ( -2480 1728 144 ) we_cemetary/cemstair2 -16 0 0.00 1 1 0 0 0 +( -2464 1440 64 ) ( -2400 1440 64 ) ( -2432 1440 256 ) we_cemetary/cemstair2 -64 0 -180.00 1 -1 0 0 0 +( -2432 1360 64 ) ( -2496 1360 64 ) ( -2464 1360 256 ) we_cemetary/cemstair2 -64 0 -180.00 1 -1 0 0 0 +} +// brush 57 +{ +( -2464 1904 64 ) ( -2432 1904 64 ) ( -2432 2096 64 ) we_cemetary/cemstair2 129 -15 0.00 1 1 0 0 0 +( -2432 1904 384 ) ( -2432 2096 384 ) ( -2432 2096 64 ) we_cemetary/cemstair2 16 0 0.00 1 1 0 0 0 +( -2480 2032 96 ) ( -2472 1840 80 ) ( -2464 2032 64 ) we_cemetary/cemstair2 16 0 0.00 1 1 0 0 0 +( -2496 1840 256 ) ( -2496 2032 256 ) ( -2432 2032 256 ) we_cemetary/cemstair2 129 -15 0.00 1 1 0 0 0 +( -2480 1936 208 ) ( -2480 1744 176 ) ( -2480 1936 144 ) we_cemetary/cemstair2 16 0 0.00 1 1 0 0 0 +( -2464 1776 64 ) ( -2400 1776 64 ) ( -2432 1776 256 ) we_cemetary/cemstair2 -64 0 -180.00 1 -1 0 0 0 +( -2448 1696 64 ) ( -2512 1696 64 ) ( -2480 1696 256 ) we_cemetary/cemstair2 -64 0 -180.00 1 -1 0 0 0 +} +// brush 58 +{ +( -2464 1840 0 ) ( -2432 1840 0 ) ( -2432 2032 0 ) we_cemetary/cemtrim2 129 -15 0.00 1 1 0 0 0 +( -2432 2096 64 ) ( -2432 1904 64 ) ( -2464 1904 64 ) we_cemetary/cemtrim2 129 -15 0.00 1 1 0 0 0 +( -2464 1936 320 ) ( -2464 1744 320 ) ( -2464 1744 0 ) we_cemetary/cemtrim2 16 0 0.00 1 1 0 0 0 +( -2432 1904 320 ) ( -2432 2096 320 ) ( -2432 2096 0 ) we_cemetary/cemtrim2 16 0 0.00 1 1 0 0 0 +( -2464 1776 0 ) ( -2400 1776 0 ) ( -2432 1776 64 ) we_cemetary/cemtrim2 -64 0 -180.00 1 -1 0 0 0 +( -2448 1696 0 ) ( -2512 1696 0 ) ( -2480 1696 64 ) we_cemetary/cemtrim2 -64 0 -180.00 1 -1 0 0 0 +} +// brush 59 +{ +( -2432 2032 0 ) ( -2432 1840 0 ) ( -2400 1840 0 ) we_cemetary/cemtrim2 65 -15 0.00 1 1 0 0 0 +( -2400 1904 64 ) ( -2432 1904 64 ) ( -2432 2096 64 ) we_cemetary/cemtrim2 65 -15 0.00 1 1 0 0 0 +( -2400 1808 0 ) ( -2400 1808 320 ) ( -2400 2000 320 ) we_cemetary/cemtrim2 16 0 0.00 1 1 0 0 0 +( -2432 2032 0 ) ( -2432 2032 320 ) ( -2432 1840 320 ) we_cemetary/cemtrim2 16 0 0.00 1 1 0 0 0 +( -2432 1776 64 ) ( -2464 1776 0 ) ( -2400 1776 0 ) we_cemetary/cemtrim2 0 0 -180.00 1 -1 0 0 0 +( -2384 1696 64 ) ( -2352 1696 0 ) ( -2416 1696 0 ) we_cemetary/cemtrim2 0 0 -180.00 1 -1 0 0 0 +} +// brush 60 +{ +( -2432 2096 64 ) ( -2432 1904 64 ) ( -2400 1904 64 ) we_cemetary/cemstair2 65 -15 0.00 1 1 0 0 0 +( -2432 2032 64 ) ( -2432 2032 384 ) ( -2432 1840 384 ) we_cemetary/cemstair2 16 0 0.00 1 1 0 0 0 +( -2400 2032 64 ) ( -2392 1840 80 ) ( -2384 2032 96 ) we_cemetary/cemstair2 16 0 0.00 1 1 0 0 0 +( -2432 2032 256 ) ( -2368 2032 256 ) ( -2368 1840 256 ) we_cemetary/cemstair2 65 -15 0.00 1 1 0 0 0 +( -2384 1936 144 ) ( -2384 1744 176 ) ( -2384 1936 208 ) we_cemetary/cemstair2 16 0 0.00 1 1 0 0 0 +( -2432 1776 256 ) ( -2464 1776 64 ) ( -2400 1776 64 ) we_cemetary/cemstair2 0 0 -180.00 1 -1 0 0 0 +( -2384 1696 256 ) ( -2352 1696 64 ) ( -2416 1696 64 ) we_cemetary/cemstair2 0 0 -180.00 1 -1 0 0 0 +} +// brush 61 +{ +( -2432 1744 64 ) ( -2432 1552 64 ) ( -2400 1552 64 ) we_cemetary/cemstair2 65 17 0.00 1 1 0 0 0 +( -2432 1808 64 ) ( -2432 1808 384 ) ( -2432 1616 384 ) we_cemetary/cemstair2 -16 0 0.00 1 1 0 0 0 +( -2400 1808 64 ) ( -2392 1616 80 ) ( -2384 1808 96 ) we_cemetary/cemstair2 -16 0 0.00 1 1 0 0 0 +( -2432 1808 256 ) ( -2368 1808 256 ) ( -2368 1616 256 ) we_cemetary/cemstair2 65 17 0.00 1 1 0 0 0 +( -2384 1728 144 ) ( -2384 1536 176 ) ( -2384 1728 208 ) we_cemetary/cemstair2 -16 0 0.00 1 1 0 0 0 +( -2432 1440 256 ) ( -2464 1440 64 ) ( -2400 1440 64 ) we_cemetary/cemstair2 0 0 -180.00 1 -1 0 0 0 +( -2400 1360 256 ) ( -2368 1360 64 ) ( -2432 1360 64 ) we_cemetary/cemstair2 0 0 -180.00 1 -1 0 0 0 +} +// brush 62 +{ +( -2432 1808 0 ) ( -2432 1616 0 ) ( -2400 1616 0 ) we_cemetary/cemtrim2 65 17 0.00 1 1 0 0 0 +( -2400 1552 64 ) ( -2432 1552 64 ) ( -2432 1744 64 ) we_cemetary/cemtrim2 65 17 0.00 1 1 0 0 0 +( -2400 1408 0 ) ( -2400 1408 320 ) ( -2400 1600 320 ) we_cemetary/cemtrim2 -16 0 0.00 1 1 0 0 0 +( -2432 1808 0 ) ( -2432 1808 320 ) ( -2432 1616 320 ) we_cemetary/cemtrim2 -16 0 0.00 1 1 0 0 0 +( -2432 1440 64 ) ( -2464 1440 0 ) ( -2400 1440 0 ) we_cemetary/cemtrim2 0 0 -180.00 1 -1 0 0 0 +( -2400 1360 64 ) ( -2368 1360 0 ) ( -2432 1360 0 ) we_cemetary/cemtrim2 0 0 -180.00 1 -1 0 0 0 +} +// brush 63 +{ +( -2432 1616 256 ) ( -2384 1616 256 ) ( -2384 1808 256 ) we_cemetary/fogtrunk 65 16 0.00 1 1 0 0 0 +( -2368 1616 272 ) ( -2432 1616 272 ) ( -2432 1808 272 ) we_cemetary/fogtrunk 65 16 0.00 1 1 0 0 0 +( -2368 1808 272 ) ( -2384 1808 256 ) ( -2384 1616 256 ) we_cemetary/fogtrunk 65 16 0.00 1 1 0 0 0 +( -2432 1808 256 ) ( -2432 1808 272 ) ( -2432 1616 272 ) we_cemetary/fogtrunk -16 0 0.00 1 1 0 0 0 +( -2400 1360 272 ) ( -2368 1360 256 ) ( -2432 1360 256 ) we_cemetary/fogtrunk 0 0 -180.00 1 -1 0 0 0 +( -2408 1776 272 ) ( -2448 1776 256 ) ( -2368 1776 256 ) we_cemetary/fogtrunk 0 0 -180.00 1 -1 0 0 0 +} +// brush 64 +{ +( -2400 1808 272 ) ( -2400 1616 272 ) ( -2368 1616 272 ) we_cemetary/cemrunner2 64 -15 0.00 1 1 0 0 0 +( -2368 1616 336 ) ( -2400 1616 336 ) ( -2400 1808 336 ) we_cemetary/cemtrim2 33 17 0.00 1 1 0 0 0 +( -2368 1616 272 ) ( -2368 1616 592 ) ( -2368 1808 592 ) we_cemetary/cemtrim2 -16 15 0.00 1 1 0 0 0 +( -2432 1808 272 ) ( -2432 1808 592 ) ( -2432 1616 592 ) we_cemetary/cemtrim2 -16 15 0.00 1 1 0 0 0 +( -2400 1360 336 ) ( -2368 1360 272 ) ( -2432 1360 272 ) we_cemetary/cemtrim2 0 15 -180.00 1 -1 0 0 0 +( -2408 1776 336 ) ( -2448 1776 272 ) ( -2368 1776 272 ) we_cemetary/cemtrim2 0 15 -180.00 1 -1 0 0 0 +} +// brush 65 +{ +( -2400 1632 208 ) ( -2464 1632 208 ) ( -2464 1504 208 ) we_cemetary/cemstair2 32 16 0.00 1 1 0 0 0 +( -2464 1504 256 ) ( -2464 1632 256 ) ( -2400 1632 256 ) we_cemetary/cemstair2 32 16 0.00 1 1 0 0 0 +( -2464 1440 256 ) ( -2400 1440 256 ) ( -2400 1440 64 ) we_cemetary/cemstair2 32 0 0.00 1 1 0 0 0 +( -2384 1504 256 ) ( -2384 1632 256 ) ( -2384 1632 64 ) we_cemetary/cemstair2 16 0 0.00 1 1 0 0 0 +( -2400 1696 256 ) ( -2464 1696 256 ) ( -2464 1696 64 ) we_cemetary/cemstair2 32 0 0.00 1 1 0 0 0 +( -2480 1632 256 ) ( -2480 1504 256 ) ( -2480 1504 64 ) we_cemetary/cemstair2 16 0 0.00 1 1 0 0 0 +} +// brush 66 +{ +( -2384 1792 336 ) ( -2496 1792 336 ) ( -2496 1376 336 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( -2496 1376 400 ) ( -2496 1792 400 ) ( -2384 1792 400 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( -2496 1376 400 ) ( -2384 1376 400 ) ( -2384 1376 336 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( -2384 1376 400 ) ( -2384 1792 400 ) ( -2384 1792 336 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( -2384 1792 400 ) ( -2496 1792 400 ) ( -2496 1792 336 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( -2496 1792 400 ) ( -2496 1376 400 ) ( -2496 1376 336 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +} +// brush 67 +{ +( -1984 1408 336 ) ( -1984 1472 368 ) ( -2432 1472 368 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( -2432 1408 352 ) ( -2432 1472 384 ) ( -1984 1472 384 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( 5248 1472 336 ) ( 5248 1472 400 ) ( 4800 1472 400 ) water/waterfloor2 32 0 0.00 1 1 0 0 0 +( -2432 1408 304 ) ( -2432 1408 368 ) ( -1984 1408 368 ) water/waterfloor2 32 0 0.00 1 1 0 0 0 +( 384 1568 336 ) ( 384 1536 336 ) ( 384 1552 384 ) water/waterfloor2 32 0 0.00 1 1 0 0 0 +( -384 1472 336 ) ( -384 1536 336 ) ( -384 1504 384 ) water/waterfloor2 32 0 0.00 1 1 0 0 0 +} +// brush 68 +{ +( -1984 1552 383.999847 ) ( -2432 1552 383.999847 ) ( -2432 1472 367.999847 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( -2432 1552 400 ) ( -1984 1552 400 ) ( -1984 1472 384 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( 4800 1472 384 ) ( 5248 1472 384 ) ( 5248 1472 368 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( 5248 1552 400 ) ( 4800 1552 400 ) ( 4800 1552 384 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( 384 1568 367.999847 ) ( 384 1536 367.999847 ) ( 384 1552 400.000153 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( -384 1472 367.999847 ) ( -384 1536 367.999847 ) ( -384 1504 400.000153 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +} +// brush 69 +{ +( -1984 1584 384 ) ( -2432 1584 384 ) ( -2432 1552 384 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( -2432 1552 400 ) ( -2432 1584 400 ) ( -1984 1584 400 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( 4800 1552 400 ) ( 5248 1552 400 ) ( 5248 1552 384 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( 5248 1584 400 ) ( 4800 1584 400 ) ( 4800 1584 384 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( 384 1568 384 ) ( 384 1536 384 ) ( 384 1552 400 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( -384 1472 384 ) ( -384 1536 384 ) ( -384 1504 400 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +} +// brush 70 +{ +( -2432 1584 384 ) ( -1984 1584 384 ) ( -1984 1664 368 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( -1984 1584 400 ) ( -2432 1584 400 ) ( -2432 1664 384 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( 4800 1584 400 ) ( 5248 1584 400 ) ( 5248 1584 384 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( 5248 1664 384 ) ( 4800 1664 384 ) ( 4800 1664 368 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( 384 1568 368 ) ( 384 1536 368 ) ( 384 1552 400.000153 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( -384 1472 368 ) ( -384 1536 368 ) ( -384 1504 400.000153 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +} +// brush 71 +{ +( -2432 1664 368 ) ( -1984 1664 368 ) ( -1984 1728 336 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( -1984 1664 384 ) ( -2432 1664 384 ) ( -2432 1728 352 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( 4800 1664 400 ) ( 5248 1664 400 ) ( 5248 1664 336 ) water/waterfloor2 32 0 0.00 1 1 0 0 0 +( -1984 1728 368 ) ( -2432 1728 368 ) ( -2432 1728 304 ) water/waterfloor2 32 0 0.00 1 1 0 0 0 +( 384 1568 336 ) ( 384 1536 336 ) ( 384 1552 384 ) water/waterfloor2 32 0 0.00 1 1 0 0 0 +( -384 1472 336 ) ( -384 1536 336 ) ( -384 1504 384 ) water/waterfloor2 32 0 0.00 1 1 0 0 0 +} +// brush 72 +{ +( -1984 1408 336 ) ( -1984 1472 368 ) ( -2432 1472 368 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( -2432 1408 352 ) ( -2432 1472 384 ) ( -1984 1472 384 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( 5248 1472 336 ) ( 5248 1472 400 ) ( 4800 1472 400 ) water/waterfloor2 32 0 0.00 1 1 0 0 0 +( -2432 1408 304 ) ( -2432 1408 368 ) ( -1984 1408 368 ) water/waterfloor2 32 0 0.00 1 1 0 0 0 +( 2944 1600 336 ) ( 2944 1536 336 ) ( 2944 1568 384 ) water/waterfloor2 32 0 0.00 1 1 0 0 0 +( 1664 1536 336 ) ( 1664 1600 336 ) ( 1664 1568 384 ) water/waterfloor2 32 0 0.00 1 1 0 0 0 +} +// brush 73 +{ +( -1984 1552 383.999847 ) ( -2432 1552 383.999847 ) ( -2432 1472 367.999847 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( -2432 1552 400 ) ( -1984 1552 400 ) ( -1984 1472 384 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( 4800 1472 384 ) ( 5248 1472 384 ) ( 5248 1472 368 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( 5248 1552 400 ) ( 4800 1552 400 ) ( 4800 1552 384 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( 2944 1600 367.999847 ) ( 2944 1536 367.999847 ) ( 2944 1568 400.000153 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( 1664 1536 367.999847 ) ( 1664 1600 367.999847 ) ( 1664 1568 400.000153 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +} +// brush 74 +{ +( -1984 1584 384 ) ( -2432 1584 384 ) ( -2432 1552 384 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( -2432 1552 400 ) ( -2432 1584 400 ) ( -1984 1584 400 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( 4800 1552 400 ) ( 5248 1552 400 ) ( 5248 1552 384 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( 5248 1584 400 ) ( 4800 1584 400 ) ( 4800 1584 384 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( 2944 1600 384 ) ( 2944 1536 384 ) ( 2944 1568 400 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( 1664 1536 384 ) ( 1664 1600 384 ) ( 1664 1568 400 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +} +// brush 75 +{ +( -2432 1584 384 ) ( -1984 1584 384 ) ( -1984 1664 368 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( -1984 1584 400 ) ( -2432 1584 400 ) ( -2432 1664 384 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( 4800 1584 400 ) ( 5248 1584 400 ) ( 5248 1584 384 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( 5248 1664 384 ) ( 4800 1664 384 ) ( 4800 1664 368 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( 2944 1600 368 ) ( 2944 1536 368 ) ( 2944 1568 400.000153 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( 1664 1536 368 ) ( 1664 1600 368 ) ( 1664 1568 400.000153 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +} +// brush 76 +{ +( -2432 1664 368 ) ( -1984 1664 368 ) ( -1984 1728 336 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( -1984 1664 384 ) ( -2432 1664 384 ) ( -2432 1728 352 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( 4800 1664 400 ) ( 5248 1664 400 ) ( 5248 1664 336 ) water/waterfloor2 32 0 0.00 1 1 0 0 0 +( -1984 1728 368 ) ( -2432 1728 368 ) ( -2432 1728 304 ) water/waterfloor2 32 0 0.00 1 1 0 0 0 +( 2944 1600 336 ) ( 2944 1536 336 ) ( 2944 1568 384 ) water/waterfloor2 32 0 0.00 1 1 0 0 0 +( 1664 1536 336 ) ( 1664 1600 336 ) ( 1664 1568 384 ) water/waterfloor2 32 0 0.00 1 1 0 0 0 +} +// brush 77 +{ +( -1984 1408 336 ) ( -1984 1472 368 ) ( -2432 1472 368 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( -2432 1408 352 ) ( -2432 1472 384 ) ( -1984 1472 384 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( 5248 1472 336 ) ( 5248 1472 400 ) ( 4800 1472 400 ) water/waterfloor2 32 0 0.00 1 1 0 0 0 +( -2432 1408 304 ) ( -2432 1408 368 ) ( -1984 1408 368 ) water/waterfloor2 32 0 0.00 1 1 0 0 0 +( 4480 1568 335.999786 ) ( 4480 1504 335.999786 ) ( 4480 1536 384 ) water/waterfloor2 32 0 0.00 1 1 0 0 0 +( 3712 1504 336 ) ( 3712 1568 336 ) ( 3712 1536 384 ) water/waterfloor2 32 0 0.00 1 1 0 0 0 +} +// brush 78 +{ +( -1984 1552 383.999847 ) ( -2432 1552 383.999847 ) ( -2432 1472 367.999847 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( -2432 1552 400 ) ( -1984 1552 400 ) ( -1984 1472 384 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( 4800 1472 384 ) ( 5248 1472 384 ) ( 5248 1472 368 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( 5248 1552 400 ) ( 4800 1552 400 ) ( 4800 1552 384 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( 4480 1568 367.999817 ) ( 4480 1504 367.999817 ) ( 4480 1536 400 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( 3712 1504 367.999847 ) ( 3712 1568 367.999847 ) ( 3712 1536 400.000153 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +} +// brush 79 +{ +( -1984 1584 384 ) ( -2432 1584 384 ) ( -2432 1552 384 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +( -2432 1552 400 ) ( -2432 1584 400 ) ( -1984 1584 400 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( 4800 1552 400 ) ( 5248 1552 400 ) ( 5248 1552 384 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( 5248 1584 400 ) ( 4800 1584 400 ) ( 4800 1584 384 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( 4480 1568 384 ) ( 4480 1504 384 ) ( 4480 1536 400 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( 3712 1504 384 ) ( 3712 1568 384 ) ( 3712 1536 400 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +} +// brush 80 +{ +( -2432 1584 384 ) ( -1984 1584 384 ) ( -1984 1664 368 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( -1984 1584 400 ) ( -2432 1584 400 ) ( -2432 1664 384 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( 4800 1584 400 ) ( 5248 1584 400 ) ( 5248 1584 384 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( 5248 1664 384 ) ( 4800 1664 384 ) ( 4800 1664 368 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( 4480 1568 367.999695 ) ( 4480 1504 367.999695 ) ( 4480 1536 400 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( 3712 1504 368 ) ( 3712 1568 368 ) ( 3712 1536 400.000153 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +} +// brush 81 +{ +( -2432 1664 368 ) ( -1984 1664 368 ) ( -1984 1728 336 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( -1984 1664 384 ) ( -2432 1664 384 ) ( -2432 1728 352 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( 4800 1664 400 ) ( 5248 1664 400 ) ( 5248 1664 336 ) water/waterfloor2 32 0 0.00 1 1 0 0 0 +( -1984 1728 368 ) ( -2432 1728 368 ) ( -2432 1728 304 ) water/waterfloor2 32 0 0.00 1 1 0 0 0 +( 4480 1568 335.999786 ) ( 4480 1504 335.999786 ) ( 4480 1536 384 ) water/waterfloor2 32 0 0.00 1 1 0 0 0 +( 3712 1504 336 ) ( 3712 1568 336 ) ( 3712 1536 384 ) water/waterfloor2 32 0 0.00 1 1 0 0 0 +} +// brush 82 +{ +( -1984 1408 336 ) ( -1984 1472 368 ) ( -2432 1472 368 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( -2432 1408 352 ) ( -2432 1472 384 ) ( -1984 1472 384 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( 5248 1472 336 ) ( 5248 1472 400 ) ( 4800 1472 400 ) water/waterfloor2 32 0 0.00 1 1 0 0 0 +( 5248 1408 352 ) ( 5248 1472 384 ) ( 5248 1472 368 ) water/waterfloor2 32 0 0.00 1 1 0 0 0 +( -2432 1408 304 ) ( -2432 1408 368 ) ( -1984 1408 368 ) water/waterfloor2 32 0 0.00 1 1 0 0 0 +( 4480 1504 335.999786 ) ( 4480 1568 335.999786 ) ( 4480 1536 384 ) water/waterfloor2 32 0 0.00 1 1 0 0 0 +} +// brush 83 +{ +( -1984 1552 383.999847 ) ( -2432 1552 383.999847 ) ( -2432 1472 367.999847 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( -2432 1552 400 ) ( -1984 1552 400 ) ( -1984 1472 384 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( 4800 1472 384 ) ( 5248 1472 384 ) ( 5248 1472 368 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( 5248 1552 399.999969 ) ( 5248 1552 383.999725 ) ( 5248 1472 367.999725 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( 5248 1552 400 ) ( 4800 1552 400 ) ( 4800 1552 384 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( 4480 1504 367.999817 ) ( 4480 1568 367.999817 ) ( 4480 1536 400 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +} +// brush 84 +{ +( -1984 1584 384 ) ( -2432 1584 384 ) ( -2432 1552 384 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( -2432 1552 400 ) ( -2432 1584 400 ) ( -1984 1584 400 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( 4800 1552 400 ) ( 5248 1552 400 ) ( 5248 1552 384 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( 5248 1552 400 ) ( 5248 1584 400 ) ( 5248 1584 384 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( 5248 1584 400 ) ( 4800 1584 400 ) ( 4800 1584 384 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( 4480 1504 384 ) ( 4480 1568 384 ) ( 4480 1536 400 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +} +// brush 85 +{ +( -2432 1584 384 ) ( -1984 1584 384 ) ( -1984 1664 368 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( -1984 1584 400 ) ( -2432 1584 400 ) ( -2432 1664 384 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( 4800 1584 400 ) ( 5248 1584 400 ) ( 5248 1584 384 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( 5248 1584 384 ) ( 5248 1584 400 ) ( 5248 1664 384 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( 5248 1664 384 ) ( 4800 1664 384 ) ( 4800 1664 368 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( 4480 1504 367.999695 ) ( 4480 1568 367.999695 ) ( 4480 1536 400 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +} +// brush 86 +{ +( -2432 1664 368 ) ( -1984 1664 368 ) ( -1984 1728 336 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( -1984 1664 384 ) ( -2432 1664 384 ) ( -2432 1728 352 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( 4800 1664 400 ) ( 5248 1664 400 ) ( 5248 1664 336 ) water/waterfloor2 32 0 0.00 1 1 0 0 0 +( 5248 1664 368 ) ( 5248 1664 384 ) ( 5248 1728 352 ) water/waterfloor2 32 0 0.00 1 1 0 0 0 +( -1984 1728 368 ) ( -2432 1728 368 ) ( -2432 1728 304 ) water/waterfloor2 32 0 0.00 1 1 0 0 0 +( 4480 1504 335.999786 ) ( 4480 1568 335.999786 ) ( 4480 1536 384 ) water/waterfloor2 32 0 0.00 1 1 0 0 0 +} +// brush 87 +{ +( -1984 1408 336 ) ( -1984 1472 368 ) ( -2432 1472 368 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( -2432 1408 352 ) ( -2432 1472 384 ) ( -1984 1472 384 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( 5248 1472 336 ) ( 5248 1472 400 ) ( 4800 1472 400 ) water/waterfloor2 32 0 0.00 1 1 0 0 0 +( -2432 1408 304 ) ( -2432 1408 368 ) ( -1984 1408 368 ) water/waterfloor2 32 0 0.00 1 1 0 0 0 +( 3712 1568 336 ) ( 3712 1504 336 ) ( 3712 1536 384 ) water/waterfloor2 32 0 0.00 1 1 0 0 0 +( 2944 1536 336 ) ( 2944 1600 336 ) ( 2944 1568 384 ) water/waterfloor2 32 0 0.00 1 1 0 0 0 +} +// brush 88 +{ +( -1984 1552 383.999847 ) ( -2432 1552 383.999847 ) ( -2432 1472 367.999847 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( -2432 1552 400 ) ( -1984 1552 400 ) ( -1984 1472 384 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( 4800 1472 384 ) ( 5248 1472 384 ) ( 5248 1472 368 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( 5248 1552 400 ) ( 4800 1552 400 ) ( 4800 1552 384 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( 3712 1568 367.999847 ) ( 3712 1504 367.999847 ) ( 3712 1536 400.000153 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( 2944 1536 367.999847 ) ( 2944 1600 367.999847 ) ( 2944 1568 400.000153 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +} +// brush 89 +{ +( -1984 1584 384 ) ( -2432 1584 384 ) ( -2432 1552 384 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( -2432 1552 400 ) ( -2432 1584 400 ) ( -1984 1584 400 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( 4800 1552 400 ) ( 5248 1552 400 ) ( 5248 1552 384 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( 5248 1584 400 ) ( 4800 1584 400 ) ( 4800 1584 384 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( 3712 1568 384 ) ( 3712 1504 384 ) ( 3712 1536 400 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( 2944 1536 384 ) ( 2944 1600 384 ) ( 2944 1568 400 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +} +// brush 90 +{ +( -2432 1584 384 ) ( -1984 1584 384 ) ( -1984 1664 368 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( -1984 1584 400 ) ( -2432 1584 400 ) ( -2432 1664 384 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( 4800 1584 400 ) ( 5248 1584 400 ) ( 5248 1584 384 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( 5248 1664 384 ) ( 4800 1664 384 ) ( 4800 1664 368 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( 3712 1568 368 ) ( 3712 1504 368 ) ( 3712 1536 400.000153 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( 2944 1536 368 ) ( 2944 1600 368 ) ( 2944 1568 400.000153 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +} +// brush 91 +{ +( -2432 1664 368 ) ( -1984 1664 368 ) ( -1984 1728 336 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( -1984 1664 384 ) ( -2432 1664 384 ) ( -2432 1728 352 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( 4800 1664 400 ) ( 5248 1664 400 ) ( 5248 1664 336 ) water/waterfloor2 32 0 0.00 1 1 0 0 0 +( -1984 1728 368 ) ( -2432 1728 368 ) ( -2432 1728 304 ) water/waterfloor2 32 0 0.00 1 1 0 0 0 +( 3712 1568 336 ) ( 3712 1504 336 ) ( 3712 1536 384 ) water/waterfloor2 32 0 0.00 1 1 0 0 0 +( 2944 1536 336 ) ( 2944 1600 336 ) ( 2944 1568 384 ) water/waterfloor2 32 0 0.00 1 1 0 0 0 +} +// brush 92 +{ +( -1984 1408 336 ) ( -1984 1472 368 ) ( -2432 1472 368 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( -2432 1408 352 ) ( -2432 1472 384 ) ( -1984 1472 384 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( 5248 1472 336 ) ( 5248 1472 400 ) ( 4800 1472 400 ) water/waterfloor2 32 0 0.00 1 1 0 0 0 +( -2432 1408 304 ) ( -2432 1408 368 ) ( -1984 1408 368 ) water/waterfloor2 32 0 0.00 1 1 0 0 0 +( 1664 1600 336 ) ( 1664 1536 336 ) ( 1664 1568 384 ) water/waterfloor2 32 0 0.00 1 1 0 0 0 +( 384 1536 336 ) ( 384 1568 336 ) ( 384 1552 384 ) water/waterfloor2 32 0 0.00 1 1 0 0 0 +} +// brush 93 +{ +( -1984 1552 383.999847 ) ( -2432 1552 383.999847 ) ( -2432 1472 367.999847 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( -2432 1552 400 ) ( -1984 1552 400 ) ( -1984 1472 384 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( 4800 1472 384 ) ( 5248 1472 384 ) ( 5248 1472 368 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( 5248 1552 400 ) ( 4800 1552 400 ) ( 4800 1552 384 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( 1664 1600 367.999847 ) ( 1664 1536 367.999847 ) ( 1664 1568 400.000153 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( 384 1536 367.999847 ) ( 384 1568 367.999847 ) ( 384 1552 400.000153 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +} +// brush 94 +{ +( -1984 1584 384 ) ( -2432 1584 384 ) ( -2432 1552 384 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( -2432 1552 400 ) ( -2432 1584 400 ) ( -1984 1584 400 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( 4800 1552 400 ) ( 5248 1552 400 ) ( 5248 1552 384 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( 5248 1584 400 ) ( 4800 1584 400 ) ( 4800 1584 384 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( 1664 1600 384 ) ( 1664 1536 384 ) ( 1664 1568 400 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( 384 1536 384 ) ( 384 1568 384 ) ( 384 1552 400 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +} +// brush 95 +{ +( -2432 1584 384 ) ( -1984 1584 384 ) ( -1984 1664 368 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( -1984 1584 400 ) ( -2432 1584 400 ) ( -2432 1664 384 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( 4800 1584 400 ) ( 5248 1584 400 ) ( 5248 1584 384 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( 5248 1664 384 ) ( 4800 1664 384 ) ( 4800 1664 368 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( 1664 1600 368 ) ( 1664 1536 368 ) ( 1664 1568 400.000153 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( 384 1536 368 ) ( 384 1568 368 ) ( 384 1552 400.000153 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +} +// brush 96 +{ +( -2432 1664 368 ) ( -1984 1664 368 ) ( -1984 1728 336 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( -1984 1664 384 ) ( -2432 1664 384 ) ( -2432 1728 352 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( 4800 1664 400 ) ( 5248 1664 400 ) ( 5248 1664 336 ) water/waterfloor2 32 0 0.00 1 1 0 0 0 +( -1984 1728 368 ) ( -2432 1728 368 ) ( -2432 1728 304 ) water/waterfloor2 32 0 0.00 1 1 0 0 0 +( 1664 1600 336 ) ( 1664 1536 336 ) ( 1664 1568 384 ) water/waterfloor2 32 0 0.00 1 1 0 0 0 +( 384 1536 336 ) ( 384 1568 336 ) ( 384 1552 384 ) water/waterfloor2 32 0 0.00 1 1 0 0 0 +} +// brush 97 +{ +( -1984 1408 336 ) ( -1984 1472 368 ) ( -2432 1472 368 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( -2432 1408 352 ) ( -2432 1472 384 ) ( -1984 1472 384 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( 5248 1472 336 ) ( 5248 1472 400 ) ( 4800 1472 400 ) water/waterfloor2 32 0 0.00 1 1 0 0 0 +( -2432 1408 304 ) ( -2432 1408 368 ) ( -1984 1408 368 ) water/waterfloor2 32 0 0.00 1 1 0 0 0 +( -384 1536 336 ) ( -384 1472 336 ) ( -384 1504 384 ) water/waterfloor2 32 0 0.00 1 1 0 0 0 +( -1664 1504 336 ) ( -1664 1536 336 ) ( -1664 1520 384 ) water/waterfloor2 32 0 0.00 1 1 0 0 0 +} +// brush 98 +{ +( -1984 1408 336 ) ( -1984 1472 368 ) ( -2432 1472 368 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( -2432 1408 352 ) ( -2432 1472 384 ) ( -1984 1472 384 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( 5248 1472 336 ) ( 5248 1472 400 ) ( 4800 1472 400 ) water/waterfloor2 32 0 0.00 1 1 0 0 0 +( -2432 1408 304 ) ( -2432 1408 368 ) ( -1984 1408 368 ) water/waterfloor2 32 0 0.00 1 1 0 0 0 +( -2432 1408 336 ) ( -2432 1472 368 ) ( -2432 1472 384 ) water/waterfloor2 32 0 0.00 1 1 0 0 0 +( -1664 1536 336 ) ( -1664 1504 336 ) ( -1664 1520 384 ) water/waterfloor2 32 0 0.00 1 1 0 0 0 +} +// brush 99 +{ +( -1984 1552 383.999847 ) ( -2432 1552 383.999847 ) ( -2432 1472 367.999847 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( -2432 1552 400 ) ( -1984 1552 400 ) ( -1984 1472 384 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( 4800 1472 384 ) ( 5248 1472 384 ) ( 5248 1472 368 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( 5248 1552 400 ) ( 4800 1552 400 ) ( 4800 1552 384 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( -384 1536 367.999847 ) ( -384 1472 367.999847 ) ( -384 1504 400.000153 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( -1664 1504 367.999847 ) ( -1664 1536 367.999847 ) ( -1664 1520 400.000153 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +} +// brush 100 +{ +( -1984 1552 383.999847 ) ( -2432 1552 383.999847 ) ( -2432 1472 367.999847 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( -2432 1552 400 ) ( -1984 1552 400 ) ( -1984 1472 384 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( 4800 1472 384 ) ( 5248 1472 384 ) ( 5248 1472 368 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( 5248 1552 400 ) ( 4800 1552 400 ) ( 4800 1552 384 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( -2432 1552 383.999725 ) ( -2432 1552 399.999969 ) ( -2432 1472 383.999969 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( -1664 1536 367.999847 ) ( -1664 1504 367.999847 ) ( -1664 1520 400.000153 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +} +// brush 101 +{ +( -1984 1584 384 ) ( -2432 1584 384 ) ( -2432 1552 384 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( -2432 1552 400 ) ( -2432 1584 400 ) ( -1984 1584 400 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( 4800 1552 400 ) ( 5248 1552 400 ) ( 5248 1552 384 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( 5248 1584 400 ) ( 4800 1584 400 ) ( 4800 1584 384 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( -384 1536 384 ) ( -384 1472 384 ) ( -384 1504 400 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( -1664 1504 384 ) ( -1664 1536 384 ) ( -1664 1520 400 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +} +// brush 102 +{ +( -1984 1584 384 ) ( -2432 1584 384 ) ( -2432 1552 384 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( -2432 1552 400 ) ( -2432 1584 400 ) ( -1984 1584 400 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( 4800 1552 400 ) ( 5248 1552 400 ) ( 5248 1552 384 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( 5248 1584 400 ) ( 4800 1584 400 ) ( 4800 1584 384 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( -2432 1584 400 ) ( -2432 1552 400 ) ( -2432 1552 384 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( -1664 1536 384 ) ( -1664 1504 384 ) ( -1664 1520 400 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +} +// brush 103 +{ +( -2432 1584 384 ) ( -1984 1584 384 ) ( -1984 1664 368 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( -1984 1584 400 ) ( -2432 1584 400 ) ( -2432 1664 384 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( 4800 1584 400 ) ( 5248 1584 400 ) ( 5248 1584 384 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( 5248 1664 384 ) ( 4800 1664 384 ) ( 4800 1664 368 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( -384 1536 368 ) ( -384 1472 368 ) ( -384 1504 400.000153 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( -1664 1504 368 ) ( -1664 1536 368 ) ( -1664 1520 400.000153 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +} +// brush 104 +{ +( -2432 1584 384 ) ( -1984 1584 384 ) ( -1984 1664 368 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( -1984 1584 400 ) ( -2432 1584 400 ) ( -2432 1664 384 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( 4800 1584 400 ) ( 5248 1584 400 ) ( 5248 1584 384 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( 5248 1664 384 ) ( 4800 1664 384 ) ( 4800 1664 368 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( -2432 1584 400 ) ( -2432 1584 384 ) ( -2432 1664 368 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( -1664 1536 368 ) ( -1664 1504 368 ) ( -1664 1520 400.000153 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +} +// brush 105 +{ +( -2432 1664 368 ) ( -1984 1664 368 ) ( -1984 1728 336 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( -1984 1664 384 ) ( -2432 1664 384 ) ( -2432 1728 352 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( 4800 1664 400 ) ( 5248 1664 400 ) ( 5248 1664 336 ) water/waterfloor2 32 0 0.00 1 1 0 0 0 +( -1984 1728 368 ) ( -2432 1728 368 ) ( -2432 1728 304 ) water/waterfloor2 32 0 0.00 1 1 0 0 0 +( -384 1536 336 ) ( -384 1472 336 ) ( -384 1504 384 ) water/waterfloor2 32 0 0.00 1 1 0 0 0 +( -1664 1504 336 ) ( -1664 1536 336 ) ( -1664 1520 384 ) water/waterfloor2 32 0 0.00 1 1 0 0 0 +} +// brush 106 +{ +( -2432 1664 368 ) ( -1984 1664 368 ) ( -1984 1728 336 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( -1984 1664 384 ) ( -2432 1664 384 ) ( -2432 1728 352 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( 4800 1664 400 ) ( 5248 1664 400 ) ( 5248 1664 336 ) water/waterfloor2 32 0 0.00 1 1 0 0 0 +( -1984 1728 368 ) ( -2432 1728 368 ) ( -2432 1728 304 ) water/waterfloor2 32 0 0.00 1 1 0 0 0 +( -2432 1664 384 ) ( -2432 1664 368 ) ( -2432 1728 336 ) water/waterfloor2 32 0 0.00 1 1 0 0 0 +( -1664 1536 336 ) ( -1664 1504 336 ) ( -1664 1520 384 ) water/waterfloor2 32 0 0.00 1 1 0 0 0 +} +// brush 107 +{ +( -2000 1744 -32 ) ( -2432 1744 -32 ) ( -2432 1376 -32 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( -2432 1376 0 ) ( -2432 1744 0 ) ( -2000 1744 0 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( -2432 1376 0 ) ( -2000 1376 0 ) ( -2000 1376 -32 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 5248 1424 0 ) ( 5248 1792 0 ) ( 5248 1792 -32 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( -2000 1760 0 ) ( -2432 1760 0 ) ( -2432 1760 -32 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 4480 1632 -32 ) ( 4480 1696 -32 ) ( 4480 1664 0 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +} +// brush 108 +{ +( -2000 1744 -32 ) ( -2432 1744 -32 ) ( -2432 1376 -32 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( -2432 1376 0 ) ( -2432 1744 0 ) ( -2000 1744 0 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( -2432 1376 0 ) ( -2000 1376 0 ) ( -2000 1376 -32 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( -2000 1760 0 ) ( -2432 1760 0 ) ( -2432 1760 -32 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 3712 1536 -32 ) ( 3712 1600 -32 ) ( 3712 1568 0 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 4480 1696 -32 ) ( 4480 1632 -32 ) ( 4480 1664 0 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +} +// brush 109 +{ +( -2000 1744 -32 ) ( -2432 1744 -32 ) ( -2432 1376 -32 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( -2432 1376 0 ) ( -2432 1744 0 ) ( -2000 1744 0 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( -2432 1376 0 ) ( -2000 1376 0 ) ( -2000 1376 -32 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( -2000 1760 0 ) ( -2432 1760 0 ) ( -2432 1760 -32 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 3712 1600 -32 ) ( 3712 1536 -32 ) ( 3712 1568 0 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 2432 1600 -32 ) ( 2432 1696 -32 ) ( 2432 1648 0 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +} +// brush 110 +{ +( -2000 1744 -32 ) ( -2432 1744 -32 ) ( -2432 1376 -32 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( -2432 1376 0 ) ( -2432 1744 0 ) ( -2000 1744 0 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( -2432 1376 0 ) ( -2000 1376 0 ) ( -2000 1376 -32 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( -2000 1760 0 ) ( -2432 1760 0 ) ( -2432 1760 -32 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 1664 1568 -32 ) ( 1664 1632 -32 ) ( 1664 1600 0 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 2432 1696 -32 ) ( 2432 1600 -32 ) ( 2432 1648 0 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +} +// brush 111 +{ +( -2000 1744 -32 ) ( -2432 1744 -32 ) ( -2432 1376 -32 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( -2432 1376 0 ) ( -2432 1744 0 ) ( -2000 1744 0 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( -2432 1376 0 ) ( -2000 1376 0 ) ( -2000 1376 -32 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( -2000 1760 0 ) ( -2432 1760 0 ) ( -2432 1760 -32 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 1664 1632 -32 ) ( 1664 1568 -32 ) ( 1664 1600 0 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 384 1632 -32 ) ( 384 1696 -32 ) ( 384 1664 0 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +} +// brush 112 +{ +( -2000 1744 -32 ) ( -2432 1744 -32 ) ( -2432 1376 -32 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( -2432 1376 0 ) ( -2432 1744 0 ) ( -2000 1744 0 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( -2432 1376 0 ) ( -2000 1376 0 ) ( -2000 1376 -32 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( -2000 1760 0 ) ( -2432 1760 0 ) ( -2432 1760 -32 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( -384 1568 -32 ) ( -384 1632 -32 ) ( -384 1600 0 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 384 1696 -32 ) ( 384 1632 -32 ) ( 384 1664 0 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +} +// brush 113 +{ +( -2000 1744 -32 ) ( -2432 1744 -32 ) ( -2432 1376 -32 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( -2432 1376 0 ) ( -2432 1744 0 ) ( -2000 1744 0 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( -2432 1376 0 ) ( -2000 1376 0 ) ( -2000 1376 -32 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( -2000 1760 0 ) ( -2432 1760 0 ) ( -2432 1760 -32 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( -384 1632 -32 ) ( -384 1568 -32 ) ( -384 1600 0 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( -1664 1696 -32 ) ( -1664 1728 -32 ) ( -1664 1712 0 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +} +// brush 114 +{ +( 992 864 336 ) ( 784 864 336 ) ( 784 320 336 ) water/waterfloor2 0 -64 0.00 1 1 0 0 0 +( 784 320 352 ) ( 784 864 352 ) ( 992 864 352 ) water/waterfloor2 0 -64 0.00 1 1 0 0 0 +( 784 320 352 ) ( 992 320 352 ) ( 992 320 336 ) water/waterfloor2 0 -64 0.00 1 1 0 0 0 +( 1008 320 352 ) ( 1008 864 352 ) ( 1008 864 336 ) water/waterfloor2 0 -64 0.00 1 1 0 0 0 +( 992 864 352 ) ( 784 864 352 ) ( 784 864 336 ) water/waterfloor2 0 -64 0.00 1 1 0 0 0 +( 784 864 352 ) ( 784 320 352 ) ( 784 320 336 ) water/waterfloor2 0 -64 0.00 1 1 0 0 0 +} +// brush 115 +{ +( 992 832 -32 ) ( 800 832 -32 ) ( 800 336 -32 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 800 336 0 ) ( 800 832 0 ) ( 992 832 0 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 800 320 0 ) ( 992 320 0 ) ( 992 320 -32 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 1008 336 0 ) ( 1008 832 0 ) ( 1008 832 -32 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 992 832 0 ) ( 800 832 0 ) ( 800 832 -32 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 784 832 0 ) ( 784 336 0 ) ( 784 336 -32 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +} +// brush 116 +{ +( 896 272 64 ) ( 1088 272 64 ) ( 1088 304 64 ) we_cemetary/cemstair2 -73 63 -90.00 1 1 0 0 0 +( 896 272 64 ) ( 896 272 384 ) ( 1088 272 384 ) we_cemetary/cemstair2 -128 0 0.00 1 1 0 0 0 +( 896 304 64 ) ( 1088 312 80 ) ( 896 320 96 ) we_cemetary/cemstair2 -128 0 0.00 1 1 0 0 0 +( 896 272 256 ) ( 896 336 256 ) ( 1088 336 256 ) we_cemetary/cemstair2 -73 63 -90.00 1 1 0 0 0 +( 896 320 144 ) ( 1088 320 176 ) ( 896 320 208 ) we_cemetary/cemstair2 -128 0 0.00 1 1 0 0 0 +( 992 336 64 ) ( 1008 320 64 ) ( 1000 328 256 ) we_cemetary/cemstair2 -32 0 0.00 1 1 0 0 0 +( 784 320 64 ) ( 800 336 64 ) ( 792 328 256 ) we_cemetary/cemstair2 -32 0 0.00 1 1 0 0 0 +} +// brush 117 +{ +( 896 272 0 ) ( 1088 272 0 ) ( 1088 304 0 ) we_cemetary/cemtrim2 -73 63 -90.00 1 1 0 0 0 +( 1088 304 64 ) ( 1088 272 64 ) ( 896 272 64 ) we_cemetary/cemtrim2 -73 63 -90.00 1 1 0 0 0 +( 720 320 0 ) ( 720 320 320 ) ( 528 320 320 ) we_cemetary/cemtrim2 -128 0 0.00 1 1 0 0 0 +( 896 272 0 ) ( 896 272 320 ) ( 1088 272 320 ) we_cemetary/cemtrim2 -128 0 0.00 1 1 0 0 0 +( 992 336 0 ) ( 1008 320 0 ) ( 1000 328 64 ) we_cemetary/cemtrim2 -32 0 0.00 1 1 0 0 0 +( 784 320 0 ) ( 800 336 0 ) ( 792 328 64 ) we_cemetary/cemtrim2 -32 0 0.00 1 1 0 0 0 +} +// brush 118 +{ +( 1088 272 256 ) ( 1088 320 256 ) ( 896 320 256 ) we_cemetary/fogtrunk -73 128 -90.00 1 1 0 0 0 +( 1088 336 272 ) ( 1088 272 272 ) ( 896 272 272 ) we_cemetary/fogtrunk -73 128 -90.00 1 1 0 0 0 +( 896 336 272 ) ( 896 320 256 ) ( 1088 320 256 ) we_cemetary/fogtrunk -73 128 -90.00 1 1 0 0 0 +( 896 272 256 ) ( 896 272 272 ) ( 1088 272 272 ) we_cemetary/fogtrunk -128 0 0.00 1 1 0 0 0 +( 992 336 256 ) ( 1008 320 256 ) ( 1000 328 272 ) we_cemetary/fogtrunk -32 0 0.00 1 1 0 0 0 +( 784 320 256 ) ( 800 336 256 ) ( 792 328 272 ) we_cemetary/fogtrunk -32 0 0.00 1 1 0 0 0 +} +// brush 119 +{ +( 896 304 272 ) ( 1088 304 272 ) ( 1088 336 272 ) we_cemetary/cemrunner2 55 1 -90.00 1 1.000122 0 0 0 +( 1088 336 336 ) ( 1088 304 336 ) ( 896 304 336 ) we_cemetary/cemtrim2 -105 63 -90.00 1 1 0 0 0 +( 1088 336 272 ) ( 1088 336 592 ) ( 896 336 592 ) we_cemetary/cemtrim2 -128 14 0.00 1 1 0 0 0 +( 896 272 272 ) ( 896 272 592 ) ( 1088 272 592 ) we_cemetary/cemtrim2 -128 14 0.00 1 1 0 0 0 +( 992 336 272 ) ( 1008 320 272 ) ( 1000 328 336 ) we_cemetary/cemtrim2 -32 14 0.00 1 1 0 0 0 +( 784 320 272 ) ( 800 336 272 ) ( 792 328 336 ) we_cemetary/cemtrim2 -32 14 0.00 1 1 0 0 0 +} +// brush 120 +{ +( 800 848 272 ) ( 768 848 272 ) ( 768 656 272 ) we_cemetary/cemrunner2 7 -14 -180.00 1 1.000122 0 0 0 +( 768 656 336 ) ( 768 848 336 ) ( 800 848 336 ) we_cemetary/cemtrim2 -154 15 -180.00 1 1 0 0 0 +( 800 656 592 ) ( 800 848 592 ) ( 800 848 272 ) we_cemetary/cemtrim2 -16 14 -180.00 1 -1 0 0 0 +( 736 848 592 ) ( 736 656 592 ) ( 736 656 272 ) we_cemetary/cemtrim2 -16 14 -180.00 1 -1 0 0 0 +( 768 304 336 ) ( 784 320 272 ) ( 752 288 272 ) we_cemetary/cemtrim2 80 14 0.00 1 1 0 0 0 +( 784 880 272 ) ( 800 896 272 ) ( 792 888 336 ) we_cemetary/cemtrim2 176 14 0.00 1 1 0 0 0 +} +// brush 121 +{ +( 784 656 256 ) ( 784 848 256 ) ( 736 848 256 ) we_cemetary/fogtrunk -122 16 -180.00 1 1 0 0 0 +( 736 656 272 ) ( 736 848 272 ) ( 800 848 272 ) we_cemetary/fogtrunk -122 16 -180.00 1 1 0 0 0 +( 784 848 256 ) ( 784 656 256 ) ( 800 656 272 ) we_cemetary/fogtrunk -122 16 -180.00 1 1 0 0 0 +( 736 848 272 ) ( 736 656 272 ) ( 736 656 256 ) we_cemetary/fogtrunk -16 0 -180.00 1 -1 0 0 0 +( 768 304 272 ) ( 784 320 256 ) ( 752 288 256 ) we_cemetary/fogtrunk 80 0 0.00 1 1 0 0 0 +( 784 880 256 ) ( 800 896 256 ) ( 792 888 272 ) we_cemetary/fogtrunk 176 0 0.00 1 1 0 0 0 +} +// brush 122 +{ +( 768 848 0 ) ( 736 848 0 ) ( 736 656 0 ) we_cemetary/cemtrim2 -122 15 -180.00 1 1 0 0 0 +( 736 656 64 ) ( 736 848 64 ) ( 768 848 64 ) we_cemetary/cemtrim2 -122 15 -180.00 1 1 0 0 0 +( 784 288 320 ) ( 784 480 320 ) ( 784 480 0 ) we_cemetary/cemtrim2 -16 0 -180.00 1 -1 0 0 0 +( 736 848 320 ) ( 736 656 320 ) ( 736 656 0 ) we_cemetary/cemtrim2 -16 0 -180.00 1 -1 0 0 0 +( 768 304 64 ) ( 784 320 0 ) ( 752 288 0 ) we_cemetary/cemtrim2 80 0 0.00 1 1 0 0 0 +( 784 880 0 ) ( 800 896 0 ) ( 792 888 64 ) we_cemetary/cemtrim2 176 0 0.00 1 1 0 0 0 +} +// brush 123 +{ +( 768 848 64 ) ( 736 848 64 ) ( 736 656 64 ) we_cemetary/cemstair2 -122 15 -180.00 1 1 0 0 0 +( 736 848 384 ) ( 736 656 384 ) ( 736 656 64 ) we_cemetary/cemstair2 -16 0 -180.00 1 -1 0 0 0 +( 784 656 96 ) ( 776 848 80 ) ( 768 656 64 ) we_cemetary/cemstair2 -16 0 -180.00 1 -1 0 0 0 +( 800 848 256 ) ( 800 656 256 ) ( 736 656 256 ) we_cemetary/cemstair2 -122 15 -180.00 1 1 0 0 0 +( 784 656 208 ) ( 784 848 176 ) ( 784 656 144 ) we_cemetary/cemstair2 -16 0 -180.00 1 -1 0 0 0 +( 768 304 256 ) ( 784 320 64 ) ( 752 288 64 ) we_cemetary/cemstair2 80 0 0.00 1 1 0 0 0 +( 784 880 64 ) ( 800 896 64 ) ( 792 888 256 ) we_cemetary/cemstair2 176 0 0.00 1 1 0 0 0 +} +// brush 124 +{ +( 1056 656 64 ) ( 1056 848 64 ) ( 1024 848 64 ) we_cemetary/cemstair2 102 15 -180.00 1 1 0 0 0 +( 1056 656 64 ) ( 1056 656 384 ) ( 1056 848 384 ) we_cemetary/cemstair2 -16 0 -180.00 1 -1 0 0 0 +( 1024 656 64 ) ( 1016 848 80 ) ( 1008 656 96 ) we_cemetary/cemstair2 -16 0 -180.00 1 -1 0 0 0 +( 1056 656 256 ) ( 992 656 256 ) ( 992 848 256 ) we_cemetary/cemstair2 102 15 -180.00 1 1 0 0 0 +( 1008 656 144 ) ( 1008 848 176 ) ( 1008 656 208 ) we_cemetary/cemstair2 -16 0 -180.00 1 -1 0 0 0 +( 1040 288 64 ) ( 1008 320 64 ) ( 1024 304 256 ) we_cemetary/cemstair2 80 0 0.00 1 1 0 0 0 +( 1000 888 256 ) ( 992 896 64 ) ( 1008 880 64 ) we_cemetary/cemstair2 176 0 0.00 1 1 0 0 0 +} +// brush 125 +{ +( 1056 656 0 ) ( 1056 848 0 ) ( 1024 848 0 ) we_cemetary/cemtrim2 102 15 -180.00 1 1 0 0 0 +( 1024 848 64 ) ( 1056 848 64 ) ( 1056 656 64 ) we_cemetary/cemtrim2 102 15 -180.00 1 1 0 0 0 +( 1008 480 0 ) ( 1008 480 320 ) ( 1008 288 320 ) we_cemetary/cemtrim2 -16 0 -180.00 1 -1 0 0 0 +( 1056 656 0 ) ( 1056 656 320 ) ( 1056 848 320 ) we_cemetary/cemtrim2 -16 0 -180.00 1 -1 0 0 0 +( 1040 288 0 ) ( 1008 320 0 ) ( 1024 304 64 ) we_cemetary/cemtrim2 80 0 0.00 1 1 0 0 0 +( 1000 888 64 ) ( 992 896 0 ) ( 1008 880 0 ) we_cemetary/cemtrim2 176 0 0.00 1 1 0 0 0 +} +// brush 126 +{ +( 1056 848 256 ) ( 1008 848 256 ) ( 1008 656 256 ) we_cemetary/fogtrunk 102 16 -180.00 1 1 0 0 0 +( 992 848 272 ) ( 1056 848 272 ) ( 1056 656 272 ) we_cemetary/fogtrunk 102 16 -180.00 1 1 0 0 0 +( 992 656 272 ) ( 1008 656 256 ) ( 1008 848 256 ) we_cemetary/fogtrunk 102 16 -180.00 1 1 0 0 0 +( 1056 656 256 ) ( 1056 656 272 ) ( 1056 848 272 ) we_cemetary/fogtrunk -16 0 -180.00 1 -1 0 0 0 +( 1040 288 256 ) ( 1008 320 256 ) ( 1024 304 272 ) we_cemetary/fogtrunk 80 0 0.00 1 1 0 0 0 +( 1000 888 272 ) ( 992 896 256 ) ( 1008 880 256 ) we_cemetary/fogtrunk 176 0 0.00 1 1 0 0 0 +} +// brush 127 +{ +( 1024 656 272 ) ( 1024 848 272 ) ( 992 848 272 ) we_cemetary/cemrunner2 -25 17 -180.00 1 1.000122 0 0 0 +( 992 848 336 ) ( 1024 848 336 ) ( 1024 656 336 ) we_cemetary/cemtrim2 70 15 -180.00 1 1 0 0 0 +( 992 848 272 ) ( 992 848 592 ) ( 992 656 592 ) we_cemetary/cemtrim2 -16 14 -180.00 1 -1 0 0 0 +( 1056 656 272 ) ( 1056 656 592 ) ( 1056 848 592 ) we_cemetary/cemtrim2 -16 14 -180.00 1 -1 0 0 0 +( 1040 288 272 ) ( 1008 320 272 ) ( 1024 304 336 ) we_cemetary/cemtrim2 80 14 0.00 1 1 0 0 0 +( 1000 888 336 ) ( 992 896 272 ) ( 1008 880 272 ) we_cemetary/cemtrim2 176 14 0.00 1 1 0 0 0 +} +// brush 128 +{ +( 896 896 272 ) ( 896 864 272 ) ( 1088 864 272 ) we_cemetary/cemrunner2 6 2 90.00 1 1.000122 0 0 0 +( 1088 864 336 ) ( 896 864 336 ) ( 896 896 336 ) we_cemetary/cemtrim2 -26 0 90.00 1 1 0 0 0 +( 1088 896 592 ) ( 896 896 592 ) ( 896 896 272 ) we_cemetary/cemtrim2 128 15 -180.00 1 -1 0 0 0 +( 896 832 592 ) ( 1088 832 592 ) ( 1088 832 272 ) we_cemetary/cemtrim2 128 15 -180.00 1 -1 0 0 0 +( 1136 848 336 ) ( 1120 864 272 ) ( 1152 832 272 ) we_cemetary/cemtrim2 128 15 -180.00 1 -1 0 0 0 +( 1008 880 272 ) ( 992 896 272 ) ( 1000 888 336 ) we_cemetary/cemtrim2 128 15 -180.00 1 -1 0 0 0 +} +// brush 129 +{ +( 1088 880 256 ) ( 896 880 256 ) ( 896 832 256 ) we_cemetary/fogtrunk 6 -127 90.00 1 1 0 0 0 +( 1088 832 272 ) ( 896 832 272 ) ( 896 896 272 ) we_cemetary/fogtrunk 6 -127 90.00 1 1 0 0 0 +( 896 880 256 ) ( 1088 880 256 ) ( 1088 896 272 ) we_cemetary/fogtrunk 6 -127 90.00 1 1 0 0 0 +( 896 832 272 ) ( 1088 832 272 ) ( 1088 832 256 ) we_cemetary/fogtrunk 128 0 -180.00 1 -1 0 0 0 +( 1136 848 272 ) ( 1120 864 256 ) ( 1152 832 256 ) we_cemetary/fogtrunk 128 0 -180.00 1 -1 0 0 0 +( 1008 880 256 ) ( 992 896 256 ) ( 1000 888 272 ) we_cemetary/fogtrunk 128 0 -180.00 1 -1 0 0 0 +} +// brush 130 +{ +( 896 864 0 ) ( 896 832 0 ) ( 1088 832 0 ) we_cemetary/cemtrim2 6 0 90.00 1 1 0 0 0 +( 1088 832 64 ) ( 896 832 64 ) ( 896 864 64 ) we_cemetary/cemtrim2 6 0 90.00 1 1 0 0 0 +( 1152 864 320 ) ( 960 864 320 ) ( 960 864 0 ) we_cemetary/cemtrim2 128 0 -180.00 1 -1 0 0 0 +( 896 832 320 ) ( 1088 832 320 ) ( 1088 832 0 ) we_cemetary/cemtrim2 128 0 -180.00 1 -1 0 0 0 +( 1136 848 64 ) ( 1120 864 0 ) ( 1152 832 0 ) we_cemetary/cemtrim2 128 0 -180.00 1 -1 0 0 0 +( 1008 880 0 ) ( 992 896 0 ) ( 1000 888 64 ) we_cemetary/cemtrim2 128 0 -180.00 1 -1 0 0 0 +} +// brush 131 +{ +( 896 864 64 ) ( 896 832 64 ) ( 1088 832 64 ) we_cemetary/cemstair2 6 0 90.00 1 1 0 0 0 +( 896 832 384 ) ( 1088 832 384 ) ( 1088 832 64 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +( 1088 880 96 ) ( 896 872 80 ) ( 1088 864 64 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +( 896 896 256 ) ( 1088 896 256 ) ( 1088 832 256 ) we_cemetary/cemstair2 6 0 90.00 1 1 0 0 0 +( 1088 880 208 ) ( 896 880 176 ) ( 1088 880 144 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +( 1136 848 256 ) ( 1120 864 64 ) ( 1152 832 64 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +( 1008 880 64 ) ( 992 896 64 ) ( 1000 888 256 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +} +// brush 132 +{ +( 896 864 0 ) ( 896 832 0 ) ( 1088 832 0 ) we_cemetary/cemtrim2 6 0 90.00 1 1 0 0 0 +( 1088 832 64 ) ( 896 832 64 ) ( 896 864 64 ) we_cemetary/cemtrim2 6 0 90.00 1 1 0 0 0 +( 1152 864 320 ) ( 960 864 320 ) ( 960 864 0 ) we_cemetary/cemtrim2 128 0 -180.00 1 -1 0 0 0 +( 896 832 320 ) ( 1088 832 320 ) ( 1088 832 0 ) we_cemetary/cemtrim2 128 0 -180.00 1 -1 0 0 0 +( 640 832 0 ) ( 672 864 0 ) ( 656 848 64 ) we_cemetary/cemtrim2 128 0 -180.00 1 -1 0 0 0 +( 800 896 0 ) ( 784 880 0 ) ( 792 888 64 ) we_cemetary/cemtrim2 128 0 -180.00 1 -1 0 0 0 +} +// brush 133 +{ +( 896 864 64 ) ( 896 832 64 ) ( 1088 832 64 ) we_cemetary/cemstair2 6 0 90.00 1 1 0 0 0 +( 896 832 384 ) ( 1088 832 384 ) ( 1088 832 64 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +( 1088 880 96 ) ( 896 872 80 ) ( 1088 864 64 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +( 896 896 256 ) ( 1088 896 256 ) ( 1088 832 256 ) we_cemetary/cemstair2 6 0 90.00 1 1 0 0 0 +( 1088 880 208 ) ( 896 880 176 ) ( 1088 880 144 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +( 640 832 64 ) ( 672 864 64 ) ( 656 848 256 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +( 800 896 64 ) ( 784 880 64 ) ( 792 888 256 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +} +// brush 134 +{ +( 1088 880 256 ) ( 896 880 256 ) ( 896 832 256 ) we_cemetary/fogtrunk 6 -127 90.00 1 1 0 0 0 +( 1088 832 272 ) ( 896 832 272 ) ( 896 896 272 ) we_cemetary/fogtrunk 6 -127 90.00 1 1 0 0 0 +( 896 880 256 ) ( 1088 880 256 ) ( 1088 896 272 ) we_cemetary/fogtrunk 6 -127 90.00 1 1 0 0 0 +( 896 832 272 ) ( 1088 832 272 ) ( 1088 832 256 ) we_cemetary/fogtrunk 128 0 -180.00 1 -1 0 0 0 +( 640 832 256 ) ( 672 864 256 ) ( 656 848 272 ) we_cemetary/fogtrunk 128 0 -180.00 1 -1 0 0 0 +( 800 896 256 ) ( 784 880 256 ) ( 792 888 272 ) we_cemetary/fogtrunk 128 0 -180.00 1 -1 0 0 0 +} +// brush 135 +{ +( 896 896 272 ) ( 896 864 272 ) ( 1088 864 272 ) we_cemetary/cemrunner2 6 2 90.00 1 1.000122 0 0 0 +( 1088 864 336 ) ( 896 864 336 ) ( 896 896 336 ) we_cemetary/cemtrim2 -26 0 90.00 1 1 0 0 0 +( 1088 896 592 ) ( 896 896 592 ) ( 896 896 272 ) we_cemetary/cemtrim2 128 15 -180.00 1 -1 0 0 0 +( 896 832 592 ) ( 1088 832 592 ) ( 1088 832 272 ) we_cemetary/cemtrim2 128 15 -180.00 1 -1 0 0 0 +( 640 832 272 ) ( 672 864 272 ) ( 656 848 336 ) we_cemetary/cemtrim2 128 15 -180.00 1 -1 0 0 0 +( 800 896 272 ) ( 784 880 272 ) ( 792 888 336 ) we_cemetary/cemtrim2 128 15 -180.00 1 -1 0 0 0 +} +// brush 136 +{ +( 3760 1776 336 ) ( 3648 1776 336 ) ( 3648 1360 336 ) water/waterfloor2 32 -48 0.00 1 1 0 0 0 +( 3648 1360 400 ) ( 3648 1776 400 ) ( 3760 1776 400 ) water/waterfloor2 32 -48 0.00 1 1 0 0 0 +( 3648 1360 400 ) ( 3760 1360 400 ) ( 3760 1360 336 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( 3760 1360 400 ) ( 3760 1776 400 ) ( 3760 1776 336 ) water/waterfloor2 48 -32 0.00 1 1 0 0 0 +( 3760 1776 400 ) ( 3648 1776 400 ) ( 3648 1776 336 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( 3648 1776 400 ) ( 3648 1360 400 ) ( 3648 1360 336 ) water/waterfloor2 48 -32 0.00 1 1 0 0 0 +} +// brush 137 +{ +( 1712 1776 336 ) ( 1600 1776 336 ) ( 1600 1360 336 ) water/waterfloor2 32 -48 0.00 1 1 0 0 0 +( 1600 1360 400 ) ( 1600 1776 400 ) ( 1712 1776 400 ) water/waterfloor2 32 -48 0.00 1 1 0 0 0 +( 1600 1360 400 ) ( 1712 1360 400 ) ( 1712 1360 336 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( 1712 1360 400 ) ( 1712 1776 400 ) ( 1712 1776 336 ) water/waterfloor2 48 -32 0.00 1 1 0 0 0 +( 1712 1776 400 ) ( 1600 1776 400 ) ( 1600 1776 336 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( 1600 1776 400 ) ( 1600 1360 400 ) ( 1600 1360 336 ) water/waterfloor2 48 -32 0.00 1 1 0 0 0 +} +// brush 138 +{ +( -336 1792 336 ) ( -448 1792 336 ) ( -448 1376 336 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( -448 1376 400 ) ( -448 1792 400 ) ( -336 1792 400 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( -448 1376 400 ) ( -336 1376 400 ) ( -336 1376 336 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( -336 1376 400 ) ( -336 1792 400 ) ( -336 1792 336 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( -336 1792 400 ) ( -448 1792 400 ) ( -448 1792 336 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( -448 1792 400 ) ( -448 1376 400 ) ( -448 1376 336 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +} +// brush 139 +{ +( 3744 1632 208 ) ( 3680 1632 208 ) ( 3680 1504 208 ) we_cemetary/cemstair2 -224 16 0.00 1 1 0 0 0 +( 3680 1504 256 ) ( 3680 1632 256 ) ( 3744 1632 256 ) we_cemetary/cemstair2 -224 16 0.00 1 1 0 0 0 +( 3680 1440 256 ) ( 3744 1440 256 ) ( 3744 1440 64 ) we_cemetary/cemstair2 -224 0 0.00 1 1 0 0 0 +( 3760 1504 256 ) ( 3760 1632 256 ) ( 3760 1632 64 ) we_cemetary/cemstair2 16 0 0.00 1 1 0 0 0 +( 3744 1696 256 ) ( 3680 1696 256 ) ( 3680 1696 64 ) we_cemetary/cemstair2 -224 0 0.00 1 1 0 0 0 +( 3664 1632 256 ) ( 3664 1504 256 ) ( 3664 1504 64 ) we_cemetary/cemstair2 16 0 0.00 1 1 0 0 0 +} +// brush 140 +{ +( 3744 1808 272 ) ( 3744 1616 272 ) ( 3776 1616 272 ) we_cemetary/cemrunner2 -64 17 0.00 1 1 0 0 0 +( 3776 1616 336 ) ( 3744 1616 336 ) ( 3744 1808 336 ) we_cemetary/cemtrim2 -223 17 0.00 1 1 0 0 0 +( 3776 1616 272 ) ( 3776 1616 592 ) ( 3776 1808 592 ) we_cemetary/cemtrim2 -16 15 0.00 1 1 0 0 0 +( 3712 1808 272 ) ( 3712 1808 592 ) ( 3712 1616 592 ) we_cemetary/cemtrim2 -16 15 0.00 1 1 0 0 0 +( 3744 1360 336 ) ( 3776 1360 272 ) ( 3712 1360 272 ) we_cemetary/cemtrim2 0 16 -180.00 1 -1 0 0 0 +( 3736 1776 336 ) ( 3696 1776 272 ) ( 3776 1776 272 ) we_cemetary/cemtrim2 0 16 -180.00 1 -1 0 0 0 +} +// brush 141 +{ +( 3712 1616 256 ) ( 3760 1616 256 ) ( 3760 1808 256 ) we_cemetary/fogtrunk -191 16 0.00 1 1 0 0 0 +( 3776 1616 272 ) ( 3712 1616 272 ) ( 3712 1808 272 ) we_cemetary/fogtrunk -191 16 0.00 1 1 0 0 0 +( 3776 1808 272 ) ( 3760 1808 256 ) ( 3760 1616 256 ) we_cemetary/fogtrunk -191 16 0.00 1 1 0 0 0 +( 3712 1808 256 ) ( 3712 1808 272 ) ( 3712 1616 272 ) we_cemetary/fogtrunk -16 0 0.00 1 1 0 0 0 +( 3744 1360 272 ) ( 3776 1360 256 ) ( 3712 1360 256 ) we_cemetary/fogtrunk 0 0 -180.00 1 -1 0 0 0 +( 3736 1776 272 ) ( 3696 1776 256 ) ( 3776 1776 256 ) we_cemetary/fogtrunk 0 0 -180.00 1 -1 0 0 0 +} +// brush 142 +{ +( 3712 1808 0 ) ( 3712 1616 0 ) ( 3744 1616 0 ) we_cemetary/cemtrim2 -191 17 0.00 1 1 0 0 0 +( 3744 1552 64 ) ( 3712 1552 64 ) ( 3712 1744 64 ) we_cemetary/cemtrim2 -191 17 0.00 1 1 0 0 0 +( 3744 1408 0 ) ( 3744 1408 320 ) ( 3744 1600 320 ) we_cemetary/cemtrim2 -16 0 0.00 1 1 0 0 0 +( 3712 1808 0 ) ( 3712 1808 320 ) ( 3712 1616 320 ) we_cemetary/cemtrim2 -16 0 0.00 1 1 0 0 0 +( 3712 1440 64 ) ( 3680 1440 0 ) ( 3744 1440 0 ) we_cemetary/cemtrim2 0 0 -180.00 1 -1 0 0 0 +( 3744 1360 64 ) ( 3776 1360 0 ) ( 3712 1360 0 ) we_cemetary/cemtrim2 0 0 -180.00 1 -1 0 0 0 +} +// brush 143 +{ +( 3712 1744 64 ) ( 3712 1552 64 ) ( 3744 1552 64 ) we_cemetary/cemstair2 -191 17 0.00 1 1 0 0 0 +( 3712 1808 64 ) ( 3712 1808 384 ) ( 3712 1616 384 ) we_cemetary/cemstair2 -16 0 0.00 1 1 0 0 0 +( 3744 1808 64 ) ( 3752 1616 80 ) ( 3760 1808 96 ) we_cemetary/cemstair2 -16 0 0.00 1 1 0 0 0 +( 3712 1808 256 ) ( 3776 1808 256 ) ( 3776 1616 256 ) we_cemetary/cemstair2 -191 17 0.00 1 1 0 0 0 +( 3760 1728 144 ) ( 3760 1536 176 ) ( 3760 1728 208 ) we_cemetary/cemstair2 -16 0 0.00 1 1 0 0 0 +( 3712 1440 256 ) ( 3680 1440 64 ) ( 3744 1440 64 ) we_cemetary/cemstair2 0 0 -180.00 1 -1 0 0 0 +( 3744 1360 256 ) ( 3776 1360 64 ) ( 3712 1360 64 ) we_cemetary/cemstair2 0 0 -180.00 1 -1 0 0 0 +} +// brush 144 +{ +( 3712 2096 64 ) ( 3712 1904 64 ) ( 3744 1904 64 ) we_cemetary/cemstair2 -191 -15 0.00 1 1 0 0 0 +( 3712 2032 64 ) ( 3712 2032 384 ) ( 3712 1840 384 ) we_cemetary/cemstair2 16 0 0.00 1 1 0 0 0 +( 3744 2032 64 ) ( 3752 1840 80 ) ( 3760 2032 96 ) we_cemetary/cemstair2 16 0 0.00 1 1 0 0 0 +( 3712 2032 256 ) ( 3776 2032 256 ) ( 3776 1840 256 ) we_cemetary/cemstair2 -191 -15 0.00 1 1 0 0 0 +( 3760 1936 144 ) ( 3760 1744 176 ) ( 3760 1936 208 ) we_cemetary/cemstair2 16 0 0.00 1 1 0 0 0 +( 3712 1776 256 ) ( 3680 1776 64 ) ( 3744 1776 64 ) we_cemetary/cemstair2 0 0 -180.00 1 -1 0 0 0 +( 3760 1696 256 ) ( 3792 1696 64 ) ( 3728 1696 64 ) we_cemetary/cemstair2 0 0 -180.00 1 -1 0 0 0 +} +// brush 145 +{ +( 3712 2032 0 ) ( 3712 1840 0 ) ( 3744 1840 0 ) we_cemetary/cemtrim2 -191 -15 0.00 1 1 0 0 0 +( 3744 1904 64 ) ( 3712 1904 64 ) ( 3712 2096 64 ) we_cemetary/cemtrim2 -191 -15 0.00 1 1 0 0 0 +( 3744 1808 0 ) ( 3744 1808 320 ) ( 3744 2000 320 ) we_cemetary/cemtrim2 16 0 0.00 1 1 0 0 0 +( 3712 2032 0 ) ( 3712 2032 320 ) ( 3712 1840 320 ) we_cemetary/cemtrim2 16 0 0.00 1 1 0 0 0 +( 3712 1776 64 ) ( 3680 1776 0 ) ( 3744 1776 0 ) we_cemetary/cemtrim2 0 0 -180.00 1 -1 0 0 0 +( 3760 1696 64 ) ( 3792 1696 0 ) ( 3728 1696 0 ) we_cemetary/cemtrim2 0 0 -180.00 1 -1 0 0 0 +} +// brush 146 +{ +( 3728 1504 0 ) ( 3728 1632 0 ) ( 3712 1632 0 ) common/areaportal -29 0 90.00 1 1 805339136 16528 0 +( 3712 1632 208 ) ( 3728 1632 208 ) ( 3728 1504 208 ) common/areaportal -29 0 90.00 1 1 805339136 16528 0 +( 3712 608 208 ) ( 3712 480 208 ) ( 3712 480 0 ) common/areaportal -32 0 0.00 1 1 805339136 16528 0 +( 3712 1440 208 ) ( 3728 1440 208 ) ( 3728 1440 0 ) common/areaportal 0 0 -180.00 1 -1 805339136 16528 0 +( 3713 1441 208 ) ( 3713 1569 208 ) ( 3713 1569 0 ) common/areaportal -32 0 0.00 1 1 805339136 16528 0 +( 3728 1696 208 ) ( 3712 1696 208 ) ( 3712 1696 0 ) common/areaportal 0 0 -180.00 1 -1 805339136 16528 0 +} +// brush 147 +{ +( 3680 1840 0 ) ( 3712 1840 0 ) ( 3712 2032 0 ) we_cemetary/cemtrim2 -127 -15 0.00 1 1 0 0 0 +( 3712 2096 64 ) ( 3712 1904 64 ) ( 3680 1904 64 ) we_cemetary/cemtrim2 -127 -15 0.00 1 1 0 0 0 +( 3680 1936 320 ) ( 3680 1744 320 ) ( 3680 1744 0 ) we_cemetary/cemtrim2 16 0 0.00 1 1 0 0 0 +( 3712 1904 320 ) ( 3712 2096 320 ) ( 3712 2096 0 ) we_cemetary/cemtrim2 16 0 0.00 1 1 0 0 0 +( 3680 1776 0 ) ( 3744 1776 0 ) ( 3712 1776 64 ) we_cemetary/cemtrim2 192 0 -180.00 1 -1 0 0 0 +( 3696 1696 0 ) ( 3632 1696 0 ) ( 3664 1696 64 ) we_cemetary/cemtrim2 192 0 -180.00 1 -1 0 0 0 +} +// brush 148 +{ +( 3680 1904 64 ) ( 3712 1904 64 ) ( 3712 2096 64 ) we_cemetary/cemstair2 -127 -15 0.00 1 1 0 0 0 +( 3712 1904 384 ) ( 3712 2096 384 ) ( 3712 2096 64 ) we_cemetary/cemstair2 16 0 0.00 1 1 0 0 0 +( 3664 2032 96 ) ( 3672 1840 80 ) ( 3680 2032 64 ) we_cemetary/cemstair2 16 0 0.00 1 1 0 0 0 +( 3648 1840 256 ) ( 3648 2032 256 ) ( 3712 2032 256 ) we_cemetary/cemstair2 -127 -15 0.00 1 1 0 0 0 +( 3664 1936 208 ) ( 3664 1744 176 ) ( 3664 1936 144 ) we_cemetary/cemstair2 16 0 0.00 1 1 0 0 0 +( 3680 1776 64 ) ( 3744 1776 64 ) ( 3712 1776 256 ) we_cemetary/cemstair2 192 0 -180.00 1 -1 0 0 0 +( 3696 1696 64 ) ( 3632 1696 64 ) ( 3664 1696 256 ) we_cemetary/cemstair2 192 0 -180.00 1 -1 0 0 0 +} +// brush 149 +{ +( 3680 1552 64 ) ( 3712 1552 64 ) ( 3712 1744 64 ) we_cemetary/cemstair2 -127 17 0.00 1 1 0 0 0 +( 3712 1584 384 ) ( 3712 1776 384 ) ( 3712 1776 64 ) we_cemetary/cemstair2 -16 0 0.00 1 1 0 0 0 +( 3664 1808 96 ) ( 3672 1616 80 ) ( 3680 1808 64 ) we_cemetary/cemstair2 -16 0 0.00 1 1 0 0 0 +( 3648 1616 256 ) ( 3648 1808 256 ) ( 3712 1808 256 ) we_cemetary/cemstair2 -127 17 0.00 1 1 0 0 0 +( 3664 1728 208 ) ( 3664 1536 176 ) ( 3664 1728 144 ) we_cemetary/cemstair2 -16 0 0.00 1 1 0 0 0 +( 3680 1440 64 ) ( 3744 1440 64 ) ( 3712 1440 256 ) we_cemetary/cemstair2 192 0 -180.00 1 -1 0 0 0 +( 3712 1360 64 ) ( 3648 1360 64 ) ( 3680 1360 256 ) we_cemetary/cemstair2 192 0 -180.00 1 -1 0 0 0 +} +// brush 150 +{ +( 3680 1616 0 ) ( 3712 1616 0 ) ( 3712 1808 0 ) we_cemetary/cemtrim2 -127 17 0.00 1 1 0 0 0 +( 3712 1744 64 ) ( 3712 1552 64 ) ( 3680 1552 64 ) we_cemetary/cemtrim2 -127 17 0.00 1 1 0 0 0 +( 3680 1664 320 ) ( 3680 1472 320 ) ( 3680 1472 0 ) we_cemetary/cemtrim2 -16 0 0.00 1 1 0 0 0 +( 3712 1584 320 ) ( 3712 1776 320 ) ( 3712 1776 0 ) we_cemetary/cemtrim2 -16 0 0.00 1 1 0 0 0 +( 3680 1440 0 ) ( 3744 1440 0 ) ( 3712 1440 64 ) we_cemetary/cemtrim2 192 0 -180.00 1 -1 0 0 0 +( 3712 1360 0 ) ( 3648 1360 0 ) ( 3680 1360 64 ) we_cemetary/cemtrim2 192 0 -180.00 1 -1 0 0 0 +} +// brush 151 +{ +( 3664 1808 256 ) ( 3664 1616 256 ) ( 3712 1616 256 ) we_cemetary/fogtrunk -127 16 0.00 1 1 0 0 0 +( 3712 1808 272 ) ( 3712 1616 272 ) ( 3648 1616 272 ) we_cemetary/fogtrunk -127 16 0.00 1 1 0 0 0 +( 3664 1616 256 ) ( 3664 1808 256 ) ( 3648 1808 272 ) we_cemetary/fogtrunk -127 16 0.00 1 1 0 0 0 +( 3712 1616 272 ) ( 3712 1808 272 ) ( 3712 1808 256 ) we_cemetary/fogtrunk -16 0 0.00 1 1 0 0 0 +( 3712 1360 256 ) ( 3648 1360 256 ) ( 3680 1360 272 ) we_cemetary/fogtrunk 192 0 -180.00 1 -1 0 0 0 +( 3648 1776 256 ) ( 3728 1776 256 ) ( 3688 1776 272 ) we_cemetary/fogtrunk 192 0 -180.00 1 -1 0 0 0 +} +// brush 152 +{ +( 3648 1616 272 ) ( 3680 1616 272 ) ( 3680 1808 272 ) we_cemetary/cemrunner2 0 17 0.00 1 1 0 0 0 +( 3680 1808 336 ) ( 3680 1616 336 ) ( 3648 1616 336 ) we_cemetary/cemtrim2 -159 17 0.00 1 1 0 0 0 +( 3648 1808 592 ) ( 3648 1616 592 ) ( 3648 1616 272 ) we_cemetary/cemtrim2 -16 15 0.00 1 1 0 0 0 +( 3712 1616 592 ) ( 3712 1808 592 ) ( 3712 1808 272 ) we_cemetary/cemtrim2 -16 15 0.00 1 1 0 0 0 +( 3712 1360 272 ) ( 3648 1360 272 ) ( 3680 1360 336 ) we_cemetary/cemtrim2 192 16 -180.00 1 -1 0 0 0 +( 3648 1776 272 ) ( 3728 1776 272 ) ( 3688 1776 336 ) we_cemetary/cemtrim2 192 16 -180.00 1 -1 0 0 0 +} +// brush 153 +{ +( 1600 1616 272 ) ( 1632 1616 272 ) ( 1632 1808 272 ) we_cemetary/cemrunner2 0 17 0.00 1 1 0 0 0 +( 1632 1808 336 ) ( 1632 1616 336 ) ( 1600 1616 336 ) we_cemetary/cemtrim2 -159 17 0.00 1 1 0 0 0 +( 1600 1808 592 ) ( 1600 1616 592 ) ( 1600 1616 272 ) we_cemetary/cemtrim2 -16 15 0.00 1 1 0 0 0 +( 1664 1616 592 ) ( 1664 1808 592 ) ( 1664 1808 272 ) we_cemetary/cemtrim2 -16 15 0.00 1 1 0 0 0 +( 1664 1360 272 ) ( 1600 1360 272 ) ( 1632 1360 336 ) we_cemetary/cemtrim2 192 16 -180.00 1 -1 0 0 0 +( 1600 1776 272 ) ( 1680 1776 272 ) ( 1640 1776 336 ) we_cemetary/cemtrim2 192 16 -180.00 1 -1 0 0 0 +} +// brush 154 +{ +( 1616 1808 256 ) ( 1616 1616 256 ) ( 1664 1616 256 ) we_cemetary/fogtrunk -127 16 0.00 1 1 0 0 0 +( 1664 1808 272 ) ( 1664 1616 272 ) ( 1600 1616 272 ) we_cemetary/fogtrunk -127 16 0.00 1 1 0 0 0 +( 1616 1616 256 ) ( 1616 1808 256 ) ( 1600 1808 272 ) we_cemetary/fogtrunk -127 16 0.00 1 1 0 0 0 +( 1664 1616 272 ) ( 1664 1808 272 ) ( 1664 1808 256 ) we_cemetary/fogtrunk -16 0 0.00 1 1 0 0 0 +( 1664 1360 256 ) ( 1600 1360 256 ) ( 1632 1360 272 ) we_cemetary/fogtrunk 192 0 -180.00 1 -1 0 0 0 +( 1600 1776 256 ) ( 1680 1776 256 ) ( 1640 1776 272 ) we_cemetary/fogtrunk 192 0 -180.00 1 -1 0 0 0 +} +// brush 155 +{ +( 1632 1616 0 ) ( 1664 1616 0 ) ( 1664 1808 0 ) we_cemetary/cemtrim2 -127 17 0.00 1 1 0 0 0 +( 1664 1744 64 ) ( 1664 1552 64 ) ( 1632 1552 64 ) we_cemetary/cemtrim2 -127 17 0.00 1 1 0 0 0 +( 1632 1664 320 ) ( 1632 1472 320 ) ( 1632 1472 0 ) we_cemetary/cemtrim2 -16 0 0.00 1 1 0 0 0 +( 1664 1584 320 ) ( 1664 1776 320 ) ( 1664 1776 0 ) we_cemetary/cemtrim2 -16 0 0.00 1 1 0 0 0 +( 1632 1440 0 ) ( 1696 1440 0 ) ( 1664 1440 64 ) we_cemetary/cemtrim2 192 0 -180.00 1 -1 0 0 0 +( 1664 1360 0 ) ( 1600 1360 0 ) ( 1632 1360 64 ) we_cemetary/cemtrim2 192 0 -180.00 1 -1 0 0 0 +} +// brush 156 +{ +( 1632 1552 64 ) ( 1664 1552 64 ) ( 1664 1744 64 ) we_cemetary/cemstair2 -127 17 0.00 1 1 0 0 0 +( 1664 1584 384 ) ( 1664 1776 384 ) ( 1664 1776 64 ) we_cemetary/cemstair2 -16 0 0.00 1 1 0 0 0 +( 1616 1808 96 ) ( 1624 1616 80 ) ( 1632 1808 64 ) we_cemetary/cemstair2 -16 0 0.00 1 1 0 0 0 +( 1600 1616 256 ) ( 1600 1808 256 ) ( 1664 1808 256 ) we_cemetary/cemstair2 -127 17 0.00 1 1 0 0 0 +( 1616 1728 208 ) ( 1616 1536 176 ) ( 1616 1728 144 ) we_cemetary/cemstair2 -16 0 0.00 1 1 0 0 0 +( 1632 1440 64 ) ( 1696 1440 64 ) ( 1664 1440 256 ) we_cemetary/cemstair2 192 0 -180.00 1 -1 0 0 0 +( 1664 1360 64 ) ( 1600 1360 64 ) ( 1632 1360 256 ) we_cemetary/cemstair2 192 0 -180.00 1 -1 0 0 0 +} +// brush 157 +{ +( 1632 1904 64 ) ( 1664 1904 64 ) ( 1664 2096 64 ) we_cemetary/cemstair2 -127 -15 0.00 1 1 0 0 0 +( 1664 1904 384 ) ( 1664 2096 384 ) ( 1664 2096 64 ) we_cemetary/cemstair2 16 0 0.00 1 1 0 0 0 +( 1616 2032 96 ) ( 1624 1840 80 ) ( 1632 2032 64 ) we_cemetary/cemstair2 16 0 0.00 1 1 0 0 0 +( 1600 1840 256 ) ( 1600 2032 256 ) ( 1664 2032 256 ) we_cemetary/cemstair2 -127 -15 0.00 1 1 0 0 0 +( 1616 1936 208 ) ( 1616 1744 176 ) ( 1616 1936 144 ) we_cemetary/cemstair2 16 0 0.00 1 1 0 0 0 +( 1632 1776 64 ) ( 1696 1776 64 ) ( 1664 1776 256 ) we_cemetary/cemstair2 192 0 -180.00 1 -1 0 0 0 +( 1648 1696 64 ) ( 1584 1696 64 ) ( 1616 1696 256 ) we_cemetary/cemstair2 192 0 -180.00 1 -1 0 0 0 +} +// brush 158 +{ +( 1632 1840 0 ) ( 1664 1840 0 ) ( 1664 2032 0 ) we_cemetary/cemtrim2 -127 -15 0.00 1 1 0 0 0 +( 1664 2096 64 ) ( 1664 1904 64 ) ( 1632 1904 64 ) we_cemetary/cemtrim2 -127 -15 0.00 1 1 0 0 0 +( 1632 1936 320 ) ( 1632 1744 320 ) ( 1632 1744 0 ) we_cemetary/cemtrim2 16 0 0.00 1 1 0 0 0 +( 1664 1904 320 ) ( 1664 2096 320 ) ( 1664 2096 0 ) we_cemetary/cemtrim2 16 0 0.00 1 1 0 0 0 +( 1632 1776 0 ) ( 1696 1776 0 ) ( 1664 1776 64 ) we_cemetary/cemtrim2 192 0 -180.00 1 -1 0 0 0 +( 1648 1696 0 ) ( 1584 1696 0 ) ( 1616 1696 64 ) we_cemetary/cemtrim2 192 0 -180.00 1 -1 0 0 0 +} +// brush 159 +{ +( 1680 1504 0 ) ( 1680 1632 0 ) ( 1664 1632 0 ) common/areaportal -30 0 90.00 1 1 805339136 16528 0 +( 1664 1632 208 ) ( 1680 1632 208 ) ( 1680 1504 208 ) common/areaportal -30 0 90.00 1 1 805339136 16528 0 +( 1664 608 208 ) ( 1664 480 208 ) ( 1664 480 0 ) common/areaportal -32 0 0.00 1 1 805339136 16528 0 +( 1664 1440 208 ) ( 1680 1440 208 ) ( 1680 1440 0 ) common/areaportal 0 0 -180.00 1 -1 805339136 16528 0 +( 1665 1441 208 ) ( 1665 1569 208 ) ( 1665 1569 0 ) common/areaportal -32 0 0.00 1 1 805339136 16528 0 +( 1680 1696 208 ) ( 1664 1696 208 ) ( 1664 1696 0 ) common/areaportal 0 0 -180.00 1 -1 805339136 16528 0 +} +// brush 160 +{ +( 1664 2032 0 ) ( 1664 1840 0 ) ( 1696 1840 0 ) we_cemetary/cemtrim2 -191 -15 0.00 1 1 0 0 0 +( 1696 1904 64 ) ( 1664 1904 64 ) ( 1664 2096 64 ) we_cemetary/cemtrim2 -191 -15 0.00 1 1 0 0 0 +( 1696 1808 0 ) ( 1696 1808 320 ) ( 1696 2000 320 ) we_cemetary/cemtrim2 16 0 0.00 1 1 0 0 0 +( 1664 2032 0 ) ( 1664 2032 320 ) ( 1664 1840 320 ) we_cemetary/cemtrim2 16 0 0.00 1 1 0 0 0 +( 1664 1776 64 ) ( 1632 1776 0 ) ( 1696 1776 0 ) we_cemetary/cemtrim2 0 0 -180.00 1 -1 0 0 0 +( 1712 1696 64 ) ( 1744 1696 0 ) ( 1680 1696 0 ) we_cemetary/cemtrim2 0 0 -180.00 1 -1 0 0 0 +} +// brush 161 +{ +( 1664 2096 64 ) ( 1664 1904 64 ) ( 1696 1904 64 ) we_cemetary/cemstair2 -191 -15 0.00 1 1 0 0 0 +( 1664 2032 64 ) ( 1664 2032 384 ) ( 1664 1840 384 ) we_cemetary/cemstair2 16 0 0.00 1 1 0 0 0 +( 1696 2032 64 ) ( 1704 1840 80 ) ( 1712 2032 96 ) we_cemetary/cemstair2 16 0 0.00 1 1 0 0 0 +( 1664 2032 256 ) ( 1728 2032 256 ) ( 1728 1840 256 ) we_cemetary/cemstair2 -191 -15 0.00 1 1 0 0 0 +( 1712 1936 144 ) ( 1712 1744 176 ) ( 1712 1936 208 ) we_cemetary/cemstair2 16 0 0.00 1 1 0 0 0 +( 1664 1776 256 ) ( 1632 1776 64 ) ( 1696 1776 64 ) we_cemetary/cemstair2 0 0 -180.00 1 -1 0 0 0 +( 1712 1696 256 ) ( 1744 1696 64 ) ( 1680 1696 64 ) we_cemetary/cemstair2 0 0 -180.00 1 -1 0 0 0 +} +// brush 162 +{ +( 1664 1744 64 ) ( 1664 1552 64 ) ( 1696 1552 64 ) we_cemetary/cemstair2 -191 17 0.00 1 1 0 0 0 +( 1664 1808 64 ) ( 1664 1808 384 ) ( 1664 1616 384 ) we_cemetary/cemstair2 -16 0 0.00 1 1 0 0 0 +( 1696 1808 64 ) ( 1704 1616 80 ) ( 1712 1808 96 ) we_cemetary/cemstair2 -16 0 0.00 1 1 0 0 0 +( 1664 1808 256 ) ( 1728 1808 256 ) ( 1728 1616 256 ) we_cemetary/cemstair2 -191 17 0.00 1 1 0 0 0 +( 1712 1728 144 ) ( 1712 1536 176 ) ( 1712 1728 208 ) we_cemetary/cemstair2 -16 0 0.00 1 1 0 0 0 +( 1664 1440 256 ) ( 1632 1440 64 ) ( 1696 1440 64 ) we_cemetary/cemstair2 0 0 -180.00 1 -1 0 0 0 +( 1696 1360 256 ) ( 1728 1360 64 ) ( 1664 1360 64 ) we_cemetary/cemstair2 0 0 -180.00 1 -1 0 0 0 +} +// brush 163 +{ +( 1664 1808 0 ) ( 1664 1616 0 ) ( 1696 1616 0 ) we_cemetary/cemtrim2 -191 17 0.00 1 1 0 0 0 +( 1696 1552 64 ) ( 1664 1552 64 ) ( 1664 1744 64 ) we_cemetary/cemtrim2 -191 17 0.00 1 1 0 0 0 +( 1696 1408 0 ) ( 1696 1408 320 ) ( 1696 1600 320 ) we_cemetary/cemtrim2 -16 0 0.00 1 1 0 0 0 +( 1664 1808 0 ) ( 1664 1808 320 ) ( 1664 1616 320 ) we_cemetary/cemtrim2 -16 0 0.00 1 1 0 0 0 +( 1664 1440 64 ) ( 1632 1440 0 ) ( 1696 1440 0 ) we_cemetary/cemtrim2 0 0 -180.00 1 -1 0 0 0 +( 1696 1360 64 ) ( 1728 1360 0 ) ( 1664 1360 0 ) we_cemetary/cemtrim2 0 0 -180.00 1 -1 0 0 0 +} +// brush 164 +{ +( 1664 1616 256 ) ( 1712 1616 256 ) ( 1712 1808 256 ) we_cemetary/fogtrunk -191 16 0.00 1 1 0 0 0 +( 1728 1616 272 ) ( 1664 1616 272 ) ( 1664 1808 272 ) we_cemetary/fogtrunk -191 16 0.00 1 1 0 0 0 +( 1728 1808 272 ) ( 1712 1808 256 ) ( 1712 1616 256 ) we_cemetary/fogtrunk -191 16 0.00 1 1 0 0 0 +( 1664 1808 256 ) ( 1664 1808 272 ) ( 1664 1616 272 ) we_cemetary/fogtrunk -16 0 0.00 1 1 0 0 0 +( 1696 1360 272 ) ( 1728 1360 256 ) ( 1664 1360 256 ) we_cemetary/fogtrunk 0 0 -180.00 1 -1 0 0 0 +( 1688 1776 272 ) ( 1648 1776 256 ) ( 1728 1776 256 ) we_cemetary/fogtrunk 0 0 -180.00 1 -1 0 0 0 +} +// brush 165 +{ +( 1696 1808 272 ) ( 1696 1616 272 ) ( 1728 1616 272 ) we_cemetary/cemrunner2 -64 17 0.00 1 1 0 0 0 +( 1728 1616 336 ) ( 1696 1616 336 ) ( 1696 1808 336 ) we_cemetary/cemtrim2 -223 17 0.00 1 1 0 0 0 +( 1728 1616 272 ) ( 1728 1616 592 ) ( 1728 1808 592 ) we_cemetary/cemtrim2 -16 15 0.00 1 1 0 0 0 +( 1664 1808 272 ) ( 1664 1808 592 ) ( 1664 1616 592 ) we_cemetary/cemtrim2 -16 15 0.00 1 1 0 0 0 +( 1696 1360 336 ) ( 1728 1360 272 ) ( 1664 1360 272 ) we_cemetary/cemtrim2 0 16 -180.00 1 -1 0 0 0 +( 1688 1776 336 ) ( 1648 1776 272 ) ( 1728 1776 272 ) we_cemetary/cemtrim2 0 16 -180.00 1 -1 0 0 0 +} +// brush 166 +{ +( 1696 1632 208 ) ( 1632 1632 208 ) ( 1632 1504 208 ) we_cemetary/cemstair2 -224 16 0.00 1 1 0 0 0 +( 1632 1504 256 ) ( 1632 1632 256 ) ( 1696 1632 256 ) we_cemetary/cemstair2 -224 16 0.00 1 1 0 0 0 +( 1632 1440 256 ) ( 1696 1440 256 ) ( 1696 1440 64 ) we_cemetary/cemstair2 -224 0 0.00 1 1 0 0 0 +( 1712 1504 256 ) ( 1712 1632 256 ) ( 1712 1632 64 ) we_cemetary/cemstair2 16 0 0.00 1 1 0 0 0 +( 1696 1696 256 ) ( 1632 1696 256 ) ( 1632 1696 64 ) we_cemetary/cemstair2 -224 0 0.00 1 1 0 0 0 +( 1616 1632 256 ) ( 1616 1504 256 ) ( 1616 1504 64 ) we_cemetary/cemstair2 16 0 0.00 1 1 0 0 0 +} +// brush 167 +{ +( -352 1632 208 ) ( -416 1632 208 ) ( -416 1504 208 ) we_cemetary/cemstair2 -224 16 0.00 1 1 0 0 0 +( -416 1504 256 ) ( -416 1632 256 ) ( -352 1632 256 ) we_cemetary/cemstair2 -224 16 0.00 1 1 0 0 0 +( -416 1440 256 ) ( -352 1440 256 ) ( -352 1440 64 ) we_cemetary/cemstair2 -224 0 0.00 1 1 0 0 0 +( -336 1504 256 ) ( -336 1632 256 ) ( -336 1632 64 ) we_cemetary/cemstair2 -240 0 0.00 1 1 0 0 0 +( -352 1696 256 ) ( -416 1696 256 ) ( -416 1696 64 ) we_cemetary/cemstair2 -224 0 0.00 1 1 0 0 0 +( -432 1632 256 ) ( -432 1504 256 ) ( -432 1504 64 ) we_cemetary/cemstair2 -240 0 0.00 1 1 0 0 0 +} +// brush 168 +{ +( -352 1808 272 ) ( -352 1616 272 ) ( -320 1616 272 ) we_cemetary/cemrunner2 -64 17 0.00 1 1 0 0 0 +( -320 1616 336 ) ( -352 1616 336 ) ( -352 1808 336 ) we_cemetary/cemtrim2 -223 17 0.00 1 1 0 0 0 +( -320 1616 272 ) ( -320 1616 592 ) ( -320 1808 592 ) we_cemetary/cemtrim2 -16 15 0.00 1 1 0 0 0 +( -384 1808 272 ) ( -384 1808 592 ) ( -384 1616 592 ) we_cemetary/cemtrim2 -16 15 0.00 1 1 0 0 0 +( -352 1360 336 ) ( -320 1360 272 ) ( -384 1360 272 ) we_cemetary/cemtrim2 0 16 -180.00 1 -1 0 0 0 +( -360 1776 336 ) ( -400 1776 272 ) ( -320 1776 272 ) we_cemetary/cemtrim2 0 16 -180.00 1 -1 0 0 0 +} +// brush 169 +{ +( -384 1616 256 ) ( -336 1616 256 ) ( -336 1808 256 ) we_cemetary/fogtrunk -191 16 0.00 1 1 0 0 0 +( -320 1616 272 ) ( -384 1616 272 ) ( -384 1808 272 ) we_cemetary/fogtrunk -191 16 0.00 1 1 0 0 0 +( -320 1808 272 ) ( -336 1808 256 ) ( -336 1616 256 ) we_cemetary/fogtrunk -191 16 0.00 1 1 0 0 0 +( -384 1808 256 ) ( -384 1808 272 ) ( -384 1616 272 ) we_cemetary/fogtrunk -16 0 0.00 1 1 0 0 0 +( -352 1360 272 ) ( -320 1360 256 ) ( -384 1360 256 ) we_cemetary/fogtrunk 0 0 -180.00 1 -1 0 0 0 +( -360 1776 272 ) ( -400 1776 256 ) ( -320 1776 256 ) we_cemetary/fogtrunk 0 0 -180.00 1 -1 0 0 0 +} +// brush 170 +{ +( -384 1808 0 ) ( -384 1616 0 ) ( -352 1616 0 ) we_cemetary/cemtrim2 -191 17 0.00 1 1 0 0 0 +( -352 1552 64 ) ( -384 1552 64 ) ( -384 1744 64 ) we_cemetary/cemtrim2 -191 17 0.00 1 1 0 0 0 +( -352 1408 0 ) ( -352 1408 320 ) ( -352 1600 320 ) we_cemetary/cemtrim2 -16 0 0.00 1 1 0 0 0 +( -384 1808 0 ) ( -384 1808 320 ) ( -384 1616 320 ) we_cemetary/cemtrim2 -16 0 0.00 1 1 0 0 0 +( -384 1440 64 ) ( -416 1440 0 ) ( -352 1440 0 ) we_cemetary/cemtrim2 0 0 -180.00 1 -1 0 0 0 +( -352 1360 64 ) ( -320 1360 0 ) ( -384 1360 0 ) we_cemetary/cemtrim2 0 0 -180.00 1 -1 0 0 0 +} +// brush 171 +{ +( -384 1744 64 ) ( -384 1552 64 ) ( -352 1552 64 ) we_cemetary/cemstair2 -191 17 0.00 1 1 0 0 0 +( -384 1808 64 ) ( -384 1808 384 ) ( -384 1616 384 ) we_cemetary/cemstair2 -16 0 0.00 1 1 0 0 0 +( -352 1808 64 ) ( -344 1616 80 ) ( -336 1808 96 ) we_cemetary/cemstair2 -16 0 0.00 1 1 0 0 0 +( -384 1808 256 ) ( -320 1808 256 ) ( -320 1616 256 ) we_cemetary/cemstair2 -191 17 0.00 1 1 0 0 0 +( -336 1728 144 ) ( -336 1536 176 ) ( -336 1728 208 ) we_cemetary/cemstair2 -16 0 0.00 1 1 0 0 0 +( -384 1440 256 ) ( -416 1440 64 ) ( -352 1440 64 ) we_cemetary/cemstair2 0 0 -180.00 1 -1 0 0 0 +( -352 1360 256 ) ( -320 1360 64 ) ( -384 1360 64 ) we_cemetary/cemstair2 0 0 -180.00 1 -1 0 0 0 +} +// brush 172 +{ +( -384 2096 64 ) ( -384 1904 64 ) ( -352 1904 64 ) we_cemetary/cemstair2 -191 49 0.00 1 1 0 0 0 +( -384 2032 64 ) ( -384 2032 384 ) ( -384 1840 384 ) we_cemetary/cemstair2 -240 0 0.00 1 1 0 0 0 +( -352 2032 64 ) ( -344 1840 80 ) ( -336 2032 96 ) we_cemetary/cemstair2 -240 0 0.00 1 1 0 0 0 +( -384 2032 256 ) ( -320 2032 256 ) ( -320 1840 256 ) we_cemetary/cemstair2 -191 49 0.00 1 1 0 0 0 +( -336 1936 144 ) ( -336 1744 176 ) ( -336 1936 208 ) we_cemetary/cemstair2 -240 0 0.00 1 1 0 0 0 +( -384 1776 256 ) ( -416 1776 64 ) ( -352 1776 64 ) we_cemetary/cemstair2 0 0 -180.00 1 -1 0 0 0 +( -336 1696 256 ) ( -304 1696 64 ) ( -368 1696 64 ) we_cemetary/cemstair2 0 0 -180.00 1 -1 0 0 0 +} +// brush 173 +{ +( -384 2032 0 ) ( -384 1840 0 ) ( -352 1840 0 ) we_cemetary/cemtrim2 -191 49 0.00 1 1 0 0 0 +( -352 1904 64 ) ( -384 1904 64 ) ( -384 2096 64 ) we_cemetary/cemtrim2 -191 49 0.00 1 1 0 0 0 +( -352 1808 0 ) ( -352 1808 320 ) ( -352 2000 320 ) we_cemetary/cemtrim2 -240 0 0.00 1 1 0 0 0 +( -384 2032 0 ) ( -384 2032 320 ) ( -384 1840 320 ) we_cemetary/cemtrim2 -240 0 0.00 1 1 0 0 0 +( -384 1776 64 ) ( -416 1776 0 ) ( -352 1776 0 ) we_cemetary/cemtrim2 0 0 -180.00 1 -1 0 0 0 +( -336 1696 64 ) ( -304 1696 0 ) ( -368 1696 0 ) we_cemetary/cemtrim2 0 0 -180.00 1 -1 0 0 0 +} +// brush 174 +{ +( -368 1504 0 ) ( -368 1632 0 ) ( -384 1632 0 ) common/areaportal -32 0 90.00 1 1 805339136 16528 0 +( -384 1632 208 ) ( -368 1632 208 ) ( -368 1504 208 ) common/areaportal -32 0 90.00 1 1 805339136 16528 0 +( -384 608 208 ) ( -384 480 208 ) ( -384 480 0 ) common/areaportal -32 0 0.00 1 1 805339136 16528 0 +( -384 1440 208 ) ( -368 1440 208 ) ( -368 1440 0 ) common/areaportal 0 0 -180.00 1 -1 805339136 16528 0 +( -383 1441 208 ) ( -383 1569 208 ) ( -383 1569 0 ) common/areaportal -32 0 0.00 1 1 805339136 16528 0 +( -368 1696 208 ) ( -384 1696 208 ) ( -384 1696 0 ) common/areaportal 0 0 -180.00 1 -1 805339136 16528 0 +} +// brush 175 +{ +( -416 1840 0 ) ( -384 1840 0 ) ( -384 2032 0 ) we_cemetary/cemtrim2 -127 49 0.00 1 1 0 0 0 +( -384 2096 64 ) ( -384 1904 64 ) ( -416 1904 64 ) we_cemetary/cemtrim2 -127 49 0.00 1 1 0 0 0 +( -416 1936 320 ) ( -416 1744 320 ) ( -416 1744 0 ) we_cemetary/cemtrim2 -240 0 0.00 1 1 0 0 0 +( -384 1904 320 ) ( -384 2096 320 ) ( -384 2096 0 ) we_cemetary/cemtrim2 -240 0 0.00 1 1 0 0 0 +( -416 1776 0 ) ( -352 1776 0 ) ( -384 1776 64 ) we_cemetary/cemtrim2 192 0 -180.00 1 -1 0 0 0 +( -400 1696 0 ) ( -464 1696 0 ) ( -432 1696 64 ) we_cemetary/cemtrim2 192 0 -180.00 1 -1 0 0 0 +} +// brush 176 +{ +( -416 1904 64 ) ( -384 1904 64 ) ( -384 2096 64 ) we_cemetary/cemstair2 -127 49 0.00 1 1 0 0 0 +( -384 1904 384 ) ( -384 2096 384 ) ( -384 2096 64 ) we_cemetary/cemstair2 -240 0 0.00 1 1 0 0 0 +( -432 2032 96 ) ( -424 1840 80 ) ( -416 2032 64 ) we_cemetary/cemstair2 -240 0 0.00 1 1 0 0 0 +( -448 1840 256 ) ( -448 2032 256 ) ( -384 2032 256 ) we_cemetary/cemstair2 -127 49 0.00 1 1 0 0 0 +( -432 1936 208 ) ( -432 1744 176 ) ( -432 1936 144 ) we_cemetary/cemstair2 -240 0 0.00 1 1 0 0 0 +( -416 1776 64 ) ( -352 1776 64 ) ( -384 1776 256 ) we_cemetary/cemstair2 192 0 -180.00 1 -1 0 0 0 +( -400 1696 64 ) ( -464 1696 64 ) ( -432 1696 256 ) we_cemetary/cemstair2 192 0 -180.00 1 -1 0 0 0 +} +// brush 177 +{ +( -416 1552 64 ) ( -384 1552 64 ) ( -384 1744 64 ) we_cemetary/cemstair2 -127 17 0.00 1 1 0 0 0 +( -384 1584 384 ) ( -384 1776 384 ) ( -384 1776 64 ) we_cemetary/cemstair2 -16 0 0.00 1 1 0 0 0 +( -432 1808 96 ) ( -424 1616 80 ) ( -416 1808 64 ) we_cemetary/cemstair2 -16 0 0.00 1 1 0 0 0 +( -448 1616 256 ) ( -448 1808 256 ) ( -384 1808 256 ) we_cemetary/cemstair2 -127 17 0.00 1 1 0 0 0 +( -432 1728 208 ) ( -432 1536 176 ) ( -432 1728 144 ) we_cemetary/cemstair2 -16 0 0.00 1 1 0 0 0 +( -416 1440 64 ) ( -352 1440 64 ) ( -384 1440 256 ) we_cemetary/cemstair2 192 0 -180.00 1 -1 0 0 0 +( -384 1360 64 ) ( -448 1360 64 ) ( -416 1360 256 ) we_cemetary/cemstair2 192 0 -180.00 1 -1 0 0 0 +} +// brush 178 +{ +( -416 1616 0 ) ( -384 1616 0 ) ( -384 1808 0 ) we_cemetary/cemtrim2 -127 17 0.00 1 1 0 0 0 +( -384 1744 64 ) ( -384 1552 64 ) ( -416 1552 64 ) we_cemetary/cemtrim2 -127 17 0.00 1 1 0 0 0 +( -416 1664 320 ) ( -416 1472 320 ) ( -416 1472 0 ) we_cemetary/cemtrim2 -16 0 0.00 1 1 0 0 0 +( -384 1584 320 ) ( -384 1776 320 ) ( -384 1776 0 ) we_cemetary/cemtrim2 -16 0 0.00 1 1 0 0 0 +( -416 1440 0 ) ( -352 1440 0 ) ( -384 1440 64 ) we_cemetary/cemtrim2 192 0 -180.00 1 -1 0 0 0 +( -384 1360 0 ) ( -448 1360 0 ) ( -416 1360 64 ) we_cemetary/cemtrim2 192 0 -180.00 1 -1 0 0 0 +} +// brush 179 +{ +( -432 1808 256 ) ( -432 1616 256 ) ( -384 1616 256 ) we_cemetary/fogtrunk -127 16 0.00 1 1 0 0 0 +( -384 1808 272 ) ( -384 1616 272 ) ( -448 1616 272 ) we_cemetary/fogtrunk -127 16 0.00 1 1 0 0 0 +( -432 1616 256 ) ( -432 1808 256 ) ( -448 1808 272 ) we_cemetary/fogtrunk -127 16 0.00 1 1 0 0 0 +( -384 1616 272 ) ( -384 1808 272 ) ( -384 1808 256 ) we_cemetary/fogtrunk -16 0 0.00 1 1 0 0 0 +( -384 1360 256 ) ( -448 1360 256 ) ( -416 1360 272 ) we_cemetary/fogtrunk 192 0 -180.00 1 -1 0 0 0 +( -448 1776 256 ) ( -368 1776 256 ) ( -408 1776 272 ) we_cemetary/fogtrunk 192 0 -180.00 1 -1 0 0 0 +} +// brush 180 +{ +( -448 1616 272 ) ( -416 1616 272 ) ( -416 1808 272 ) we_cemetary/cemrunner2 0 17 0.00 1 1 0 0 0 +( -416 1808 336 ) ( -416 1616 336 ) ( -448 1616 336 ) we_cemetary/cemtrim2 -159 17 0.00 1 1 0 0 0 +( -448 1808 592 ) ( -448 1616 592 ) ( -448 1616 272 ) we_cemetary/cemtrim2 -16 15 0.00 1 1 0 0 0 +( -384 1616 592 ) ( -384 1808 592 ) ( -384 1808 272 ) we_cemetary/cemtrim2 -16 15 0.00 1 1 0 0 0 +( -384 1360 272 ) ( -448 1360 272 ) ( -416 1360 336 ) we_cemetary/cemtrim2 192 16 -180.00 1 -1 0 0 0 +( -448 1776 272 ) ( -368 1776 272 ) ( -408 1776 336 ) we_cemetary/cemtrim2 192 16 -180.00 1 -1 0 0 0 +} +// brush 181 +{ +( 5280 1792 0 ) ( 5248 1792 0 ) ( 5248 1344 0 ) we_cemetary/cemtrim2 -96 0 0.00 1 1 0 0 0 +( 5248 1344 64 ) ( 5248 1792 64 ) ( 5280 1792 64 ) we_cemetary/cemtrim2 -96 0 0.00 1 1 0 0 0 +( 5248 1344 0 ) ( 5280 1344 0 ) ( 5280 1344 -32 ) we_cemetary/cemtrim2 -96 0 0.00 1 1 0 0 0 +( 5280 1344 32 ) ( 5280 1792 32 ) ( 5280 1792 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 5280 1792 0 ) ( 5248 1792 0 ) ( 5248 1792 -32 ) we_cemetary/cemtrim2 -96 0 0.00 1 1 0 0 0 +( 5248 1792 64 ) ( 5248 1344 64 ) ( 5248 1344 32 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +} +// brush 182 +{ +( 5280 1792 272 ) ( 5248 1792 272 ) ( 5248 1344 272 ) we_cemetary/cemtrim2 -96 0 0.00 1 1 0 0 0 +( 5248 1344 336 ) ( 5248 1792 336 ) ( 5280 1792 336 ) we_cemetary/cemtrim2 -96 0 0.00 1 1 0 0 0 +( 5248 1344 272 ) ( 5280 1344 272 ) ( 5280 1344 240 ) we_cemetary/cemtrim2 -96 16 0.00 1 1 0 0 0 +( 5280 1344 304 ) ( 5280 1792 304 ) ( 5280 1792 272 ) we_cemetary/cemtrim2 -64 16 0.00 1 1 0 0 0 +( 5280 1792 272 ) ( 5248 1792 272 ) ( 5248 1792 240 ) we_cemetary/cemtrim2 -96 16 0.00 1 1 0 0 0 +( 5248 1792 336 ) ( 5248 1344 336 ) ( 5248 1344 304 ) we_cemetary/cemtrim2 -64 16 0.00 1 1 0 0 0 +} +// brush 183 +{ +( 5280 1792 256 ) ( 5248 1792 256 ) ( 5248 1344 256 ) we_cemetary/fogtrunk -128 96 -90.00 1 1 0 0 0 +( 5248 1352 272 ) ( 5248 1800 272 ) ( 5280 1800 272 ) we_cemetary/fogtrunk -128 96 -90.00 1 1 0 0 0 +( 5248 1344 312 ) ( 5280 1344 312 ) ( 5280 1344 248 ) we_cemetary/fogtrunk -128 96 -90.00 1 1 0 0 0 +( 5280 1352 264 ) ( 5280 1800 264 ) ( 5280 1800 200 ) we_cemetary/fogtrunk -129 64 -90.00 1 1 0 0 0 +( 5280 1792 312 ) ( 5248 1792 312 ) ( 5248 1792 248 ) we_cemetary/fogtrunk -128 96 -90.00 1 1 0 0 0 +( 5248 1792 312 ) ( 5248 1344 312 ) ( 5248 1344 248 ) we_cemetary/fogtrunk -129 64 -90.00 1 1 0 0 0 +} +// brush 184 +{ +( 5280 1776 336 ) ( 5248 1776 336 ) ( 5248 1328 336 ) water/waterfloor2 0 -32 0.00 1 1 0 0 0 +( 5248 1328 400 ) ( 5248 1776 400 ) ( 5280 1776 400 ) water/waterfloor2 0 -32 0.00 1 1 0 0 0 +( 5248 1328 336 ) ( 5280 1328 336 ) ( 5280 1328 304 ) water/waterfloor2 0 -32 0.00 1 1 0 0 0 +( 5280 1328 368 ) ( 5280 1776 368 ) ( 5280 1776 336 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( 5280 1776 336 ) ( 5248 1776 336 ) ( 5248 1776 304 ) water/waterfloor2 0 -32 0.00 1 1 0 0 0 +( 5248 1776 400 ) ( 5248 1328 400 ) ( 5248 1328 368 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +} +// brush 185 +{ +( 5280 1776 64 ) ( 5248 1776 64 ) ( 5248 1376 64 ) we_cemetary/cemfloor -32 0 0.00 1 1 0 0 0 +( 5248 1376 256 ) ( 5248 1776 256 ) ( 5280 1776 256 ) we_cemetary/cemfloor -32 0 0.00 1 1 0 0 0 +( 5248 1360 256 ) ( 5280 1360 256 ) ( 5280 1360 64 ) we_cemetary/cemfloor -32 0 0.00 1 1 0 0 0 +( 5280 1376 256 ) ( 5280 1776 256 ) ( 5280 1776 64 ) we_cemetary/cemfloor 0 0 0.00 1 1 0 0 0 +( 5280 1776 256 ) ( 5248 1776 256 ) ( 5248 1776 64 ) we_cemetary/cemfloor -32 0 0.00 1 1 0 0 0 +( 5248 1760 256 ) ( 5248 1360 256 ) ( 5248 1360 64 ) we_cemetary/cemfloor 0 0 0.00 1 1 0 0 0 +} +// brush 186 +{ +( -2432 1776 336 ) ( -2464 1776 336 ) ( -2464 1328 336 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( -2464 1328 400 ) ( -2464 1776 400 ) ( -2432 1776 400 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( -2464 1328 336 ) ( -2432 1328 336 ) ( -2432 1328 304 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( -2432 1328 368 ) ( -2432 1776 368 ) ( -2432 1776 336 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( -2432 1776 336 ) ( -2464 1776 336 ) ( -2464 1776 304 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +( -2464 1776 400 ) ( -2464 1328 400 ) ( -2464 1328 368 ) water/waterfloor2 32 -32 0.00 1 1 0 0 0 +} +// brush 187 +{ +( -2432 1792 256 ) ( -2464 1792 256 ) ( -2464 1344 256 ) we_cemetary/fogtrunk -129 64 -90.00 1 1 0 0 0 +( -2464 1352 272 ) ( -2464 1800 272 ) ( -2432 1800 272 ) we_cemetary/fogtrunk -129 64 -90.00 1 1 0 0 0 +( -2464 1344 312 ) ( -2432 1344 312 ) ( -2432 1344 248 ) we_cemetary/fogtrunk -129 64 -90.00 1 1 0 0 0 +( -2432 1352 264 ) ( -2432 1800 264 ) ( -2432 1800 200 ) we_cemetary/fogtrunk -129 64 -90.00 1 1 0 0 0 +( -2432 1792 312 ) ( -2464 1792 312 ) ( -2464 1792 248 ) we_cemetary/fogtrunk -129 64 -90.00 1 1 0 0 0 +( -2464 1792 312 ) ( -2464 1344 312 ) ( -2464 1344 248 ) we_cemetary/fogtrunk -129 64 -90.00 1 1 0 0 0 +} +// brush 188 +{ +( -2432 1792 272 ) ( -2464 1792 272 ) ( -2464 1344 272 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( -2464 1344 336 ) ( -2464 1792 336 ) ( -2432 1792 336 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( -2464 1344 272 ) ( -2432 1344 272 ) ( -2432 1344 240 ) we_cemetary/cemtrim2 -64 16 0.00 1 1 0 0 0 +( -2432 1344 304 ) ( -2432 1792 304 ) ( -2432 1792 272 ) we_cemetary/cemtrim2 -64 16 0.00 1 1 0 0 0 +( -2432 1792 272 ) ( -2464 1792 272 ) ( -2464 1792 240 ) we_cemetary/cemtrim2 -64 16 0.00 1 1 0 0 0 +( -2464 1792 336 ) ( -2464 1344 336 ) ( -2464 1344 304 ) we_cemetary/cemtrim2 -64 16 0.00 1 1 0 0 0 +} +// brush 189 +{ +( 1984 1808 0 ) ( 1856 1808 0 ) ( 1856 1792 0 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( 1856 1792 208 ) ( 1856 1808 208 ) ( 1984 1808 208 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( 1856 1792 208 ) ( 1984 1792 208 ) ( 1984 1792 0 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( 1984 1792 208 ) ( 1984 1808 208 ) ( 1984 1808 0 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( 1983 1793 208 ) ( 1855 1793 208 ) ( 1855 1793 0 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( 1856 1808 208 ) ( 1856 1792 208 ) ( 1856 1792 0 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +} +// brush 190 +{ +( 1984 1392 0 ) ( 1856 1392 0 ) ( 1856 1376 0 ) common/areaportal 0 32 0.00 1 1 805339136 16528 0 +( 1856 1376 208 ) ( 1856 1392 208 ) ( 1984 1392 208 ) common/areaportal 0 32 0.00 1 1 805339136 16528 0 +( 1856 1344 208 ) ( 1984 1344 208 ) ( 1984 1344 0 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( 1984 1376 208 ) ( 1984 1392 208 ) ( 1984 1392 0 ) common/areaportal -32 0 0.00 1 1 805339136 16528 0 +( 1983 1345 208 ) ( 1855 1345 208 ) ( 1855 1345 0 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( 1856 1392 208 ) ( 1856 1376 208 ) ( 1856 1376 0 ) common/areaportal -32 0 0.00 1 1 805339136 16528 0 +} +// brush 191 +{ +( 2496 1392 0 ) ( 2368 1392 0 ) ( 2368 1376 0 ) common/areaportal 0 32 0.00 1 1 805339136 16528 0 +( 2368 1376 208 ) ( 2368 1392 208 ) ( 2496 1392 208 ) common/areaportal 0 32 0.00 1 1 805339136 16528 0 +( 2848 1344 208 ) ( 2976 1344 208 ) ( 2976 1344 0 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( 2496 1376 208 ) ( 2496 1392 208 ) ( 2496 1392 0 ) common/areaportal -32 0 0.00 1 1 805339136 16528 0 +( 3103 1345 208 ) ( 2975 1345 208 ) ( 2975 1345 0 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( 2368 1392 208 ) ( 2368 1376 208 ) ( 2368 1376 0 ) common/areaportal -32 0 0.00 1 1 805339136 16528 0 +} +// brush 192 +{ +( 2496 1808 0 ) ( 2368 1808 0 ) ( 2368 1792 0 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( 2368 1792 208 ) ( 2368 1808 208 ) ( 2496 1808 208 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( 3456 1792 208 ) ( 3584 1792 208 ) ( 3584 1792 0 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( 2496 1792 208 ) ( 2496 1808 208 ) ( 2496 1808 0 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( 2495 1793 208 ) ( 2367 1793 208 ) ( 2367 1793 0 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( 2368 1808 208 ) ( 2368 1792 208 ) ( 2368 1792 0 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +} +// brush 193 +{ +( 3520 1808 0 ) ( 3392 1808 0 ) ( 3392 1792 0 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( 3392 1792 208 ) ( 3392 1808 208 ) ( 3520 1808 208 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( 4480 1792 208 ) ( 4608 1792 208 ) ( 4608 1792 0 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( 3520 1792 208 ) ( 3520 1808 208 ) ( 3520 1808 0 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( 3519 1793 208 ) ( 3391 1793 208 ) ( 3391 1793 0 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( 3392 1808 208 ) ( 3392 1792 208 ) ( 3392 1792 0 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +} +// brush 194 +{ +( 3520 1392 0 ) ( 3392 1392 0 ) ( 3392 1376 0 ) common/areaportal 0 32 0.00 1 1 805339136 16528 0 +( 3392 1376 208 ) ( 3392 1392 208 ) ( 3520 1392 208 ) common/areaportal 0 32 0.00 1 1 805339136 16528 0 +( 3872 1344 208 ) ( 4000 1344 208 ) ( 4000 1344 0 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( 3520 1376 208 ) ( 3520 1392 208 ) ( 3520 1392 0 ) common/areaportal -32 0 0.00 1 1 805339136 16528 0 +( 4127 1345 208 ) ( 3999 1345 208 ) ( 3999 1345 0 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( 3392 1392 208 ) ( 3392 1376 208 ) ( 3392 1376 0 ) common/areaportal -32 0 0.00 1 1 805339136 16528 0 +} +// brush 195 +{ +( 3008 1392 0 ) ( 2880 1392 0 ) ( 2880 1376 0 ) common/areaportal 0 32 0.00 1 1 805339136 16528 0 +( 2880 1376 208 ) ( 2880 1392 208 ) ( 3008 1392 208 ) common/areaportal 0 32 0.00 1 1 805339136 16528 0 +( 2880 1344 208 ) ( 3008 1344 208 ) ( 3008 1344 0 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( 3008 1376 208 ) ( 3008 1392 208 ) ( 3008 1392 0 ) common/areaportal -32 0 0.00 1 1 805339136 16528 0 +( 3007 1345 208 ) ( 2879 1345 208 ) ( 2879 1345 0 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( 2880 1392 208 ) ( 2880 1376 208 ) ( 2880 1376 0 ) common/areaportal -32 0 0.00 1 1 805339136 16528 0 +} +// brush 196 +{ +( 3008 1808 0 ) ( 2880 1808 0 ) ( 2880 1792 0 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( 2880 1792 208 ) ( 2880 1808 208 ) ( 3008 1808 208 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( 2880 1792 208 ) ( 3008 1792 208 ) ( 3008 1792 0 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( 3008 1792 208 ) ( 3008 1808 208 ) ( 3008 1808 0 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( 3007 1793 208 ) ( 2879 1793 208 ) ( 2879 1793 0 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( 2880 1808 208 ) ( 2880 1792 208 ) ( 2880 1792 0 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +} +// brush 197 +{ +( 5056 1808 0 ) ( 4928 1808 0 ) ( 4928 1792 0 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( 4928 1792 208 ) ( 4928 1808 208 ) ( 5056 1808 208 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( 4928 1792 208 ) ( 5056 1792 208 ) ( 5056 1792 0 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( 5056 1792 208 ) ( 5056 1808 208 ) ( 5056 1808 0 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( 5055 1793 208 ) ( 4927 1793 208 ) ( 4927 1793 0 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( 4928 1808 208 ) ( 4928 1792 208 ) ( 4928 1792 0 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +} +// brush 198 +{ +( 5056 1392 0 ) ( 4928 1392 0 ) ( 4928 1376 0 ) common/areaportal 0 32 0.00 1 1 805339136 16528 0 +( 4928 1376 208 ) ( 4928 1392 208 ) ( 5056 1392 208 ) common/areaportal 0 32 0.00 1 1 805339136 16528 0 +( 4928 1344 208 ) ( 5056 1344 208 ) ( 5056 1344 0 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( 5056 1376 208 ) ( 5056 1392 208 ) ( 5056 1392 0 ) common/areaportal -32 0 0.00 1 1 805339136 16528 0 +( 5055 1345 208 ) ( 4927 1345 208 ) ( 4927 1345 0 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( 4928 1392 208 ) ( 4928 1376 208 ) ( 4928 1376 0 ) common/areaportal -32 0 0.00 1 1 805339136 16528 0 +} +// brush 199 +{ +( 4544 1808 0 ) ( 4416 1808 0 ) ( 4416 1792 0 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( 4416 1792 208 ) ( 4416 1808 208 ) ( 4544 1808 208 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( 5504 1792 208 ) ( 5632 1792 208 ) ( 5632 1792 0 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( 4544 1792 208 ) ( 4544 1808 208 ) ( 4544 1808 0 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( 4543 1793 208 ) ( 4415 1793 208 ) ( 4415 1793 0 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( 4416 1808 208 ) ( 4416 1792 208 ) ( 4416 1792 0 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +} +// brush 200 +{ +( 4544 1392 0 ) ( 4416 1392 0 ) ( 4416 1376 0 ) common/areaportal 0 32 0.00 1 1 805339136 16528 0 +( 4416 1376 208 ) ( 4416 1392 208 ) ( 4544 1392 208 ) common/areaportal 0 32 0.00 1 1 805339136 16528 0 +( 4896 1344 208 ) ( 5024 1344 208 ) ( 5024 1344 0 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( 4544 1376 208 ) ( 4544 1392 208 ) ( 4544 1392 0 ) common/areaportal -32 0 0.00 1 1 805339136 16528 0 +( 5151 1345 208 ) ( 5023 1345 208 ) ( 5023 1345 0 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( 4416 1392 208 ) ( 4416 1376 208 ) ( 4416 1376 0 ) common/areaportal -32 0 0.00 1 1 805339136 16528 0 +} +// brush 201 +{ +( 4032 1392 0 ) ( 3904 1392 0 ) ( 3904 1376 0 ) common/areaportal 0 32 0.00 1 1 805339136 16528 0 +( 3904 1376 208 ) ( 3904 1392 208 ) ( 4032 1392 208 ) common/areaportal 0 32 0.00 1 1 805339136 16528 0 +( 3904 1344 208 ) ( 4032 1344 208 ) ( 4032 1344 0 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( 4032 1376 208 ) ( 4032 1392 208 ) ( 4032 1392 0 ) common/areaportal -32 0 0.00 1 1 805339136 16528 0 +( 4031 1345 208 ) ( 3903 1345 208 ) ( 3903 1345 0 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( 3904 1392 208 ) ( 3904 1376 208 ) ( 3904 1376 0 ) common/areaportal -32 0 0.00 1 1 805339136 16528 0 +} +// brush 202 +{ +( 4032 1808 0 ) ( 3904 1808 0 ) ( 3904 1792 0 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( 3904 1792 208 ) ( 3904 1808 208 ) ( 4032 1808 208 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( 3904 1792 208 ) ( 4032 1792 208 ) ( 4032 1792 0 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( 4032 1792 208 ) ( 4032 1808 208 ) ( 4032 1808 0 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( 4031 1793 208 ) ( 3903 1793 208 ) ( 3903 1793 0 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( 3904 1808 208 ) ( 3904 1792 208 ) ( 3904 1792 0 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +} +// brush 203 +{ +( -64 1808 0 ) ( -192 1808 0 ) ( -192 1792 0 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( -192 1792 208 ) ( -192 1808 208 ) ( -64 1808 208 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( -192 1792 208 ) ( -64 1792 208 ) ( -64 1792 0 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( -64 1792 208 ) ( -64 1808 208 ) ( -64 1808 0 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( -65 1793 208 ) ( -193 1793 208 ) ( -193 1793 0 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( -192 1808 208 ) ( -192 1792 208 ) ( -192 1792 0 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +} +// brush 204 +{ +( -64 1392 0 ) ( -192 1392 0 ) ( -192 1376 0 ) common/areaportal 0 32 0.00 1 1 805339136 16528 0 +( -192 1376 208 ) ( -192 1392 208 ) ( -64 1392 208 ) common/areaportal 0 32 0.00 1 1 805339136 16528 0 +( -192 1344 208 ) ( -64 1344 208 ) ( -64 1344 0 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( -64 1376 208 ) ( -64 1392 208 ) ( -64 1392 0 ) common/areaportal -32 0 0.00 1 1 805339136 16528 0 +( -65 1345 208 ) ( -193 1345 208 ) ( -193 1345 0 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( -192 1392 208 ) ( -192 1376 208 ) ( -192 1376 0 ) common/areaportal -32 0 0.00 1 1 805339136 16528 0 +} +// brush 205 +{ +( 448 1392 0 ) ( 320 1392 0 ) ( 320 1376 0 ) common/areaportal 0 32 0.00 1 1 805339136 16528 0 +( 320 1376 208 ) ( 320 1392 208 ) ( 448 1392 208 ) common/areaportal 0 32 0.00 1 1 805339136 16528 0 +( 800 1344 208 ) ( 928 1344 208 ) ( 928 1344 0 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( 448 1376 208 ) ( 448 1392 208 ) ( 448 1392 0 ) common/areaportal -32 0 0.00 1 1 805339136 16528 0 +( 1055 1345 208 ) ( 927 1345 208 ) ( 927 1345 0 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( 320 1392 208 ) ( 320 1376 208 ) ( 320 1376 0 ) common/areaportal -32 0 0.00 1 1 805339136 16528 0 +} +// brush 206 +{ +( 448 1808 0 ) ( 320 1808 0 ) ( 320 1792 0 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( 320 1792 208 ) ( 320 1808 208 ) ( 448 1808 208 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( 1408 1792 208 ) ( 1536 1792 208 ) ( 1536 1792 0 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( 448 1792 208 ) ( 448 1808 208 ) ( 448 1808 0 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( 447 1793 208 ) ( 319 1793 208 ) ( 319 1793 0 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( 320 1808 208 ) ( 320 1792 208 ) ( 320 1792 0 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +} +// brush 207 +{ +( 1472 1808 0 ) ( 1344 1808 0 ) ( 1344 1792 0 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( 1344 1792 208 ) ( 1344 1808 208 ) ( 1472 1808 208 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( 2432 1792 208 ) ( 2560 1792 208 ) ( 2560 1792 0 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( 1472 1792 208 ) ( 1472 1808 208 ) ( 1472 1808 0 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( 1471 1793 208 ) ( 1343 1793 208 ) ( 1343 1793 0 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( 1344 1808 208 ) ( 1344 1792 208 ) ( 1344 1792 0 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +} +// brush 208 +{ +( 1472 1392 0 ) ( 1344 1392 0 ) ( 1344 1376 0 ) common/areaportal 0 32 0.00 1 1 805339136 16528 0 +( 1344 1376 208 ) ( 1344 1392 208 ) ( 1472 1392 208 ) common/areaportal 0 32 0.00 1 1 805339136 16528 0 +( 1824 1344 208 ) ( 1952 1344 208 ) ( 1952 1344 0 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( 1472 1376 208 ) ( 1472 1392 208 ) ( 1472 1392 0 ) common/areaportal -32 0 0.00 1 1 805339136 16528 0 +( 2079 1345 208 ) ( 1951 1345 208 ) ( 1951 1345 0 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( 1344 1392 208 ) ( 1344 1376 208 ) ( 1344 1376 0 ) common/areaportal -32 0 0.00 1 1 805339136 16528 0 +} +// brush 209 +{ +( 960 1392 0 ) ( 832 1392 0 ) ( 832 1376 0 ) common/areaportal 0 32 0.00 1 1 805339136 16528 0 +( 832 1376 208 ) ( 832 1392 208 ) ( 960 1392 208 ) common/areaportal 0 32 0.00 1 1 805339136 16528 0 +( 832 1344 208 ) ( 960 1344 208 ) ( 960 1344 0 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( 960 1376 208 ) ( 960 1392 208 ) ( 960 1392 0 ) common/areaportal -32 0 0.00 1 1 805339136 16528 0 +( 959 1345 208 ) ( 831 1345 208 ) ( 831 1345 0 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( 832 1392 208 ) ( 832 1376 208 ) ( 832 1376 0 ) common/areaportal -32 0 0.00 1 1 805339136 16528 0 +} +// brush 210 +{ +( 960 1808 0 ) ( 832 1808 0 ) ( 832 1792 0 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( 832 1792 208 ) ( 832 1808 208 ) ( 960 1808 208 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( 832 1792 208 ) ( 960 1792 208 ) ( 960 1792 0 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( 960 1792 208 ) ( 960 1808 208 ) ( 960 1808 0 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( 959 1793 208 ) ( 831 1793 208 ) ( 831 1793 0 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( 832 1808 208 ) ( 832 1792 208 ) ( 832 1792 0 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +} +// brush 211 +{ +( -1088 1808 0 ) ( -1216 1808 0 ) ( -1216 1792 0 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( -1216 1792 208 ) ( -1216 1808 208 ) ( -1088 1808 208 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( -1216 1792 208 ) ( -1088 1792 208 ) ( -1088 1792 0 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( -1088 1792 208 ) ( -1088 1808 208 ) ( -1088 1808 0 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( -1089 1793 208 ) ( -1217 1793 208 ) ( -1217 1793 0 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( -1216 1808 208 ) ( -1216 1792 208 ) ( -1216 1792 0 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +} +// brush 212 +{ +( -1088 1392 0 ) ( -1216 1392 0 ) ( -1216 1376 0 ) common/areaportal 0 32 0.00 1 1 805339136 16528 0 +( -1216 1376 208 ) ( -1216 1392 208 ) ( -1088 1392 208 ) common/areaportal 0 32 0.00 1 1 805339136 16528 0 +( -1216 1344 208 ) ( -1088 1344 208 ) ( -1088 1344 0 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( -1088 1376 208 ) ( -1088 1392 208 ) ( -1088 1392 0 ) common/areaportal -32 0 0.00 1 1 805339136 16528 0 +( -1089 1345 208 ) ( -1217 1345 208 ) ( -1217 1345 0 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( -1216 1392 208 ) ( -1216 1376 208 ) ( -1216 1376 0 ) common/areaportal -32 0 0.00 1 1 805339136 16528 0 +} +// brush 213 +{ +( -576 1392 0 ) ( -704 1392 0 ) ( -704 1376 0 ) common/areaportal 0 32 0.00 1 1 805339136 16528 0 +( -704 1376 208 ) ( -704 1392 208 ) ( -576 1392 208 ) common/areaportal 0 32 0.00 1 1 805339136 16528 0 +( -224 1344 208 ) ( -96 1344 208 ) ( -96 1344 0 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( -576 1376 208 ) ( -576 1392 208 ) ( -576 1392 0 ) common/areaportal -32 0 0.00 1 1 805339136 16528 0 +( 31 1345 208 ) ( -97 1345 208 ) ( -97 1345 0 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( -704 1392 208 ) ( -704 1376 208 ) ( -704 1376 0 ) common/areaportal -32 0 0.00 1 1 805339136 16528 0 +} +// brush 214 +{ +( -576 1808 0 ) ( -704 1808 0 ) ( -704 1792 0 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( -704 1792 208 ) ( -704 1808 208 ) ( -576 1808 208 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( 384 1792 208 ) ( 512 1792 208 ) ( 512 1792 0 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( -576 1792 208 ) ( -576 1808 208 ) ( -576 1808 0 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( -577 1793 208 ) ( -705 1793 208 ) ( -705 1793 0 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( -704 1808 208 ) ( -704 1792 208 ) ( -704 1792 0 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +} +// brush 215 +{ +( -1600 1808 0 ) ( -1728 1808 0 ) ( -1728 1792 0 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( -1728 1792 208 ) ( -1728 1808 208 ) ( -1600 1808 208 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( -640 1792 208 ) ( -512 1792 208 ) ( -512 1792 0 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( -1600 1792 208 ) ( -1600 1808 208 ) ( -1600 1808 0 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( -1601 1793 208 ) ( -1729 1793 208 ) ( -1729 1793 0 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( -1728 1808 208 ) ( -1728 1792 208 ) ( -1728 1792 0 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +} +// brush 216 +{ +( -1600 1392 0 ) ( -1728 1392 0 ) ( -1728 1376 0 ) common/areaportal 0 32 0.00 1 1 805339136 16528 0 +( -1728 1376 208 ) ( -1728 1392 208 ) ( -1600 1392 208 ) common/areaportal 0 32 0.00 1 1 805339136 16528 0 +( -1248 1344 208 ) ( -1120 1344 208 ) ( -1120 1344 0 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( -1600 1376 208 ) ( -1600 1392 208 ) ( -1600 1392 0 ) common/areaportal -32 0 0.00 1 1 805339136 16528 0 +( -993 1345 208 ) ( -1121 1345 208 ) ( -1121 1345 0 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( -1728 1392 208 ) ( -1728 1376 208 ) ( -1728 1376 0 ) common/areaportal -32 0 0.00 1 1 805339136 16528 0 +} +// brush 217 +{ +( -2112 1392 0 ) ( -2240 1392 0 ) ( -2240 1376 0 ) common/areaportal 0 -32 0.00 1 1 805339136 16528 0 +( -2240 1376 208 ) ( -2240 1392 208 ) ( -2112 1392 208 ) common/areaportal 0 -32 0.00 1 1 805339136 16528 0 +( -2240 1344 208 ) ( -2112 1344 208 ) ( -2112 1344 0 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( -2112 1376 208 ) ( -2112 1392 208 ) ( -2112 1392 0 ) common/areaportal 32 0 0.00 1 1 805339136 16528 0 +( -2113 1345 208 ) ( -2241 1345 208 ) ( -2241 1345 0 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( -2240 1392 208 ) ( -2240 1376 208 ) ( -2240 1376 0 ) common/areaportal 32 0 0.00 1 1 805339136 16528 0 +} +// brush 218 +{ +( -2112 1808 0 ) ( -2240 1808 0 ) ( -2240 1792 0 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( -2240 1792 208 ) ( -2240 1808 208 ) ( -2112 1808 208 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( -2240 1792 208 ) ( -2112 1792 208 ) ( -2112 1792 0 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( -2112 1792 208 ) ( -2112 1808 208 ) ( -2112 1808 0 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( -2113 1793 208 ) ( -2241 1793 208 ) ( -2241 1793 0 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +( -2240 1808 208 ) ( -2240 1792 208 ) ( -2240 1792 0 ) common/areaportal 0 0 0.00 1 1 805339136 16528 0 +} +// brush 219 +{ +( -2176 896 272 ) ( -2176 864 272 ) ( -1984 864 272 ) we_cemetary/cemrunner2 0 0 90.00 1 1.000122 0 0 0 +( -1984 864 336 ) ( -2176 864 336 ) ( -2176 896 336 ) we_cemetary/cemtrim2 -32 0 90.00 1 1 0 0 0 +( -1984 896 592 ) ( -2176 896 592 ) ( -2176 896 272 ) we_cemetary/cemtrim2 128 15 -180.00 1 -1 0 0 0 +( -2176 832 592 ) ( -1984 832 592 ) ( -1984 832 272 ) we_cemetary/cemtrim2 128 15 -180.00 1 -1 0 0 0 +( -2432 832 272 ) ( -2400 864 272 ) ( -2416 848 336 ) we_cemetary/cemtrim2 128 15 -180.00 1 -1 0 0 0 +( -1936 848 336 ) ( -1952 864 272 ) ( -1920 832 272 ) we_cemetary/cemtrim2 128 15 -180.00 1 -1 0 0 0 +} +// brush 220 +{ +( -1984 880 256 ) ( -2176 880 256 ) ( -2176 832 256 ) we_cemetary/fogtrunk 0 -127 90.00 1 1 0 0 0 +( -1984 832 272 ) ( -2176 832 272 ) ( -2176 896 272 ) we_cemetary/fogtrunk 0 -127 90.00 1 1 0 0 0 +( -2176 880 256 ) ( -1984 880 256 ) ( -1984 896 272 ) we_cemetary/fogtrunk 0 -127 90.00 1 1 0 0 0 +( -2176 832 272 ) ( -1984 832 272 ) ( -1984 832 256 ) we_cemetary/fogtrunk 128 0 -180.00 1 -1 0 0 0 +( -2432 832 256 ) ( -2400 864 256 ) ( -2416 848 272 ) we_cemetary/fogtrunk 128 0 -180.00 1 -1 0 0 0 +( -1936 848 272 ) ( -1952 864 256 ) ( -1920 832 256 ) we_cemetary/fogtrunk 128 0 -180.00 1 -1 0 0 0 +} +// brush 221 +{ +( -2176 864 64 ) ( -2176 832 64 ) ( -1984 832 64 ) we_cemetary/cemstair2 0 0 90.00 1 1 0 0 0 +( -2176 832 384 ) ( -1984 832 384 ) ( -1984 832 64 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +( -1984 880 96 ) ( -2176 872 80 ) ( -1984 864 64 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +( -2176 896 256 ) ( -1984 896 256 ) ( -1984 832 256 ) we_cemetary/cemstair2 0 0 90.00 1 1 0 0 0 +( -1984 880 208 ) ( -2176 880 176 ) ( -1984 880 144 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +( -2432 832 64 ) ( -2400 864 64 ) ( -2416 848 256 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +( -1936 848 256 ) ( -1952 864 64 ) ( -1920 832 64 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +} +// brush 222 +{ +( -2176 864 0 ) ( -2176 832 0 ) ( -1984 832 0 ) we_cemetary/cemtrim2 0 0 90.00 1 1 0 0 0 +( -1984 832 64 ) ( -2176 832 64 ) ( -2176 864 64 ) we_cemetary/cemtrim2 0 0 90.00 1 1 0 0 0 +( -1920 864 320 ) ( -2112 864 320 ) ( -2112 864 0 ) we_cemetary/cemtrim2 128 0 -180.00 1 -1 0 0 0 +( -2176 832 320 ) ( -1984 832 320 ) ( -1984 832 0 ) we_cemetary/cemtrim2 128 0 -180.00 1 -1 0 0 0 +( -2432 832 0 ) ( -2400 864 0 ) ( -2416 848 64 ) we_cemetary/cemtrim2 128 0 -180.00 1 -1 0 0 0 +( -1936 848 64 ) ( -1952 864 0 ) ( -1920 832 0 ) we_cemetary/cemtrim2 128 0 -180.00 1 -1 0 0 0 +} +// brush 223 +{ +( -1952 1088 0 ) ( -1920 1088 0 ) ( -1920 1280 0 ) we_cemetary/cemtrim2 191 0 -180.00 1 1 0 0 0 +( -1920 1280 64 ) ( -1920 1088 64 ) ( -1952 1088 64 ) we_cemetary/cemtrim2 191 0 -180.00 1 1 0 0 0 +( -1952 1408 320 ) ( -1952 1216 320 ) ( -1952 1216 0 ) we_cemetary/cemtrim2 0 0 -180.00 1 -1 0 0 0 +( -1920 1088 320 ) ( -1920 1280 320 ) ( -1920 1280 0 ) we_cemetary/cemtrim2 0 0 -180.00 1 -1 0 0 0 +( -1920 832 0 ) ( -1952 864 0 ) ( -1936 848 64 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( -1936 1328 64 ) ( -1952 1312 0 ) ( -1920 1344 0 ) we_cemetary/cemtrim2 -64 0 -180.00 1 -1 0 0 0 +} +// brush 224 +{ +( -1952 1088 64 ) ( -1920 1088 64 ) ( -1920 1280 64 ) we_cemetary/cemstair2 191 0 -180.00 1 1 0 0 0 +( -1920 1088 384 ) ( -1920 1280 384 ) ( -1920 1280 64 ) we_cemetary/cemstair2 0 0 -180.00 1 -1 0 0 0 +( -1968 1280 96 ) ( -1960 1088 80 ) ( -1952 1280 64 ) we_cemetary/cemstair2 0 0 -180.00 1 -1 0 0 0 +( -1984 1088 256 ) ( -1984 1280 256 ) ( -1920 1280 256 ) we_cemetary/cemstair2 191 0 -180.00 1 1 0 0 0 +( -1968 1280 208 ) ( -1968 1088 176 ) ( -1968 1280 144 ) we_cemetary/cemstair2 0 0 -180.00 1 -1 0 0 0 +( -1920 832 64 ) ( -1952 864 64 ) ( -1936 848 256 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -1936 1328 256 ) ( -1952 1312 64 ) ( -1920 1344 64 ) we_cemetary/cemstair2 -64 0 -180.00 1 -1 0 0 0 +} +// brush 225 +{ +( -1968 1280 256 ) ( -1968 1088 256 ) ( -1920 1088 256 ) we_cemetary/fogtrunk 191 0 -180.00 1 1 0 0 0 +( -1920 1280 272 ) ( -1920 1088 272 ) ( -1984 1088 272 ) we_cemetary/fogtrunk 191 0 -180.00 1 1 0 0 0 +( -1968 1088 256 ) ( -1968 1280 256 ) ( -1984 1280 272 ) we_cemetary/fogtrunk 191 0 -180.00 1 1 0 0 0 +( -1920 1088 272 ) ( -1920 1280 272 ) ( -1920 1280 256 ) we_cemetary/fogtrunk 0 0 -180.00 1 -1 0 0 0 +( -1920 832 256 ) ( -1952 864 256 ) ( -1936 848 272 ) we_cemetary/fogtrunk -64 0 0.00 1 1 0 0 0 +( -1936 1328 272 ) ( -1952 1312 256 ) ( -1920 1344 256 ) we_cemetary/fogtrunk -64 0 -180.00 1 -1 0 0 0 +} +// brush 226 +{ +( -1984 1088 272 ) ( -1952 1088 272 ) ( -1952 1280 272 ) we_cemetary/cemrunner2 63 0 -180.00 1 1 0 0 0 +( -1952 1280 336 ) ( -1952 1088 336 ) ( -1984 1088 336 ) we_cemetary/cemtrim2 159 0 -180.00 1 1 0 0 0 +( -1984 1280 592 ) ( -1984 1088 592 ) ( -1984 1088 272 ) we_cemetary/cemtrim2 0 14 -180.00 1 -1 0 0 0 +( -1920 1088 592 ) ( -1920 1280 592 ) ( -1920 1280 272 ) we_cemetary/cemtrim2 0 14 -180.00 1 -1 0 0 0 +( -1920 832 272 ) ( -1952 864 272 ) ( -1936 848 336 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( -1936 1328 336 ) ( -1952 1312 272 ) ( -1920 1344 272 ) we_cemetary/cemtrim2 -64 15 -180.00 1 -1 0 0 0 +} +// brush 227 +{ +( -2176 1280 272 ) ( -2176 1312 272 ) ( -2368 1312 272 ) we_cemetary/cemrunner2 -1 -31 -90.00 1 1 0 0 0 +( -2368 1312 336 ) ( -2176 1312 336 ) ( -2176 1280 336 ) we_cemetary/cemtrim2 95 -63 -90.00 1 1 0 0 0 +( -2368 1280 592 ) ( -2176 1280 592 ) ( -2176 1280 272 ) we_cemetary/cemtrim2 192 15 0.00 1 1 0 0 0 +( -2176 1344 592 ) ( -2368 1344 592 ) ( -2368 1344 272 ) we_cemetary/cemtrim2 192 15 0.00 1 1 0 0 0 +( -1920 1344 272 ) ( -1952 1312 272 ) ( -1936 1328 336 ) we_cemetary/cemtrim2 64 15 0.00 1 1 0 0 0 +( -2416 1328 336 ) ( -2400 1312 272 ) ( -2432 1344 272 ) we_cemetary/cemtrim2 -64 16 0.00 1 1 0 0 0 +} +// brush 228 +{ +( -2368 1296 256 ) ( -2176 1296 256 ) ( -2176 1344 256 ) we_cemetary/fogtrunk 127 -191 -90.00 1 1 0 0 0 +( -2368 1344 272 ) ( -2176 1344 272 ) ( -2176 1280 272 ) we_cemetary/fogtrunk 127 -191 -90.00 1 1 0 0 0 +( -2176 1296 256 ) ( -2368 1296 256 ) ( -2368 1280 272 ) we_cemetary/fogtrunk 127 -191 -90.00 1 1 0 0 0 +( -2176 1344 272 ) ( -2368 1344 272 ) ( -2368 1344 256 ) we_cemetary/fogtrunk 192 0 0.00 1 1 0 0 0 +( -1920 1344 256 ) ( -1952 1312 256 ) ( -1936 1328 272 ) we_cemetary/fogtrunk 64 0 0.00 1 1 0 0 0 +( -2416 1328 272 ) ( -2400 1312 256 ) ( -2432 1344 256 ) we_cemetary/fogtrunk -64 0 0.00 1 1 0 0 0 +} +// brush 229 +{ +( -2400 1280 272 ) ( -2400 1088 272 ) ( -2368 1088 272 ) we_cemetary/cemrunner2 0 0 0.00 1 1 0 0 0 +( -2368 1088 336 ) ( -2400 1088 336 ) ( -2400 1280 336 ) we_cemetary/cemtrim2 224 0 0.00 1 1 0 0 0 +( -2368 1088 272 ) ( -2368 1088 592 ) ( -2368 1280 592 ) we_cemetary/cemtrim2 64 16 0.00 1 1 0 0 0 +( -2432 1280 272 ) ( -2432 1280 592 ) ( -2432 1088 592 ) we_cemetary/cemtrim2 64 16 0.00 1 1 0 0 0 +( -2416 848 336 ) ( -2400 864 272 ) ( -2432 832 272 ) we_cemetary/cemtrim2 64 16 0.00 1 1 0 0 0 +( -2384 1296 336 ) ( -2400 1312 272 ) ( -2368 1280 272 ) we_cemetary/cemtrim2 64 16 0.00 1 1 0 0 0 +} +// brush 230 +{ +( -2432 1088 256 ) ( -2384 1088 256 ) ( -2384 1280 256 ) we_cemetary/fogtrunk 0 -64 0.00 1 1 0 0 0 +( -2368 1088 272 ) ( -2432 1088 272 ) ( -2432 1280 272 ) we_cemetary/fogtrunk 0 -64 0.00 1 1 0 0 0 +( -2368 1280 272 ) ( -2384 1280 256 ) ( -2384 1088 256 ) we_cemetary/fogtrunk 0 -64 0.00 1 1 0 0 0 +( -2432 1280 256 ) ( -2432 1280 272 ) ( -2432 1088 272 ) we_cemetary/fogtrunk 64 0 0.00 1 1 0 0 0 +( -2416 848 272 ) ( -2400 864 256 ) ( -2432 832 256 ) we_cemetary/fogtrunk 64 0 0.00 1 1 0 0 0 +( -2384 1296 272 ) ( -2400 1312 256 ) ( -2368 1280 256 ) we_cemetary/fogtrunk 64 0 0.00 1 1 0 0 0 +} +// brush 231 +{ +( -2432 1280 64 ) ( -2432 1088 64 ) ( -2400 1088 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( -2432 1280 64 ) ( -2432 1280 384 ) ( -2432 1088 384 ) we_cemetary/cemstair2 64 0 0.00 1 1 0 0 0 +( -2400 1280 64 ) ( -2392 1088 80 ) ( -2384 1280 96 ) we_cemetary/cemstair2 64 0 0.00 1 1 0 0 0 +( -2432 1280 256 ) ( -2368 1280 256 ) ( -2368 1088 256 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( -2384 1280 144 ) ( -2384 1088 176 ) ( -2384 1280 208 ) we_cemetary/cemstair2 64 0 0.00 1 1 0 0 0 +( -2416 848 256 ) ( -2400 864 64 ) ( -2432 832 64 ) we_cemetary/cemstair2 64 0 0.00 1 1 0 0 0 +( -2384 1296 256 ) ( -2400 1312 64 ) ( -2368 1280 64 ) we_cemetary/cemstair2 64 0 0.00 1 1 0 0 0 +} +// brush 232 +{ +( -2432 1280 0 ) ( -2432 1088 0 ) ( -2400 1088 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( -2400 1088 64 ) ( -2432 1088 64 ) ( -2432 1280 64 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( -2400 1152 0 ) ( -2400 1152 320 ) ( -2400 1344 320 ) we_cemetary/cemtrim2 64 0 0.00 1 1 0 0 0 +( -2432 1280 0 ) ( -2432 1280 320 ) ( -2432 1088 320 ) we_cemetary/cemtrim2 64 0 0.00 1 1 0 0 0 +( -2416 848 64 ) ( -2400 864 0 ) ( -2432 832 0 ) we_cemetary/cemtrim2 64 0 0.00 1 1 0 0 0 +( -2384 1296 64 ) ( -2400 1312 0 ) ( -2368 1280 0 ) we_cemetary/cemtrim2 64 0 0.00 1 1 0 0 0 +} +// brush 233 +{ +( -2176 1312 0 ) ( -2176 1344 0 ) ( -2368 1344 0 ) we_cemetary/cemtrim2 127 -63 -90.00 1 1 0 0 0 +( -2368 1344 64 ) ( -2176 1344 64 ) ( -2176 1312 64 ) we_cemetary/cemtrim2 127 -63 -90.00 1 1 0 0 0 +( -2496 1312 320 ) ( -2304 1312 320 ) ( -2304 1312 0 ) we_cemetary/cemtrim2 192 0 0.00 1 1 0 0 0 +( -2176 1344 320 ) ( -2368 1344 320 ) ( -2368 1344 0 ) we_cemetary/cemtrim2 192 0 0.00 1 1 0 0 0 +( -2416 1328 64 ) ( -2400 1312 0 ) ( -2432 1344 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( -2240 1344 64 ) ( -2240 1376 0 ) ( -2240 1312 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +} +// brush 234 +{ +( -2176 1312 0 ) ( -2176 1344 0 ) ( -2368 1344 0 ) we_cemetary/cemtrim2 127 -63 -90.00 1 1 0 0 0 +( -2368 1344 64 ) ( -2176 1344 64 ) ( -2176 1312 64 ) we_cemetary/cemtrim2 127 -63 -90.00 1 1 0 0 0 +( -2368 1312 320 ) ( -2176 1312 320 ) ( -2176 1312 0 ) we_cemetary/cemtrim2 192 0 0.00 1 1 0 0 0 +( -2176 1344 320 ) ( -2368 1344 320 ) ( -2368 1344 0 ) we_cemetary/cemtrim2 192 0 0.00 1 1 0 0 0 +( -1920 1344 0 ) ( -1952 1312 0 ) ( -1936 1328 64 ) we_cemetary/cemtrim2 64 0 0.00 1 1 0 0 0 +( -2112 1344 64 ) ( -2112 1312 0 ) ( -2112 1376 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +} +// brush 235 +{ +( -2176 1312 64 ) ( -2176 1344 64 ) ( -2368 1344 64 ) we_cemetary/cemstair2 127 -63 -90.00 1 1 0 0 0 +( -2176 1344 384 ) ( -2368 1344 384 ) ( -2368 1344 64 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +( -2368 1296 96 ) ( -2176 1304 80 ) ( -2368 1312 64 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +( -2176 1280 256 ) ( -2368 1280 256 ) ( -2368 1344 256 ) we_cemetary/cemstair2 127 -63 -90.00 1 1 0 0 0 +( -2368 1296 208 ) ( -2176 1296 176 ) ( -2368 1296 144 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +( -2416 1328 256 ) ( -2400 1312 64 ) ( -2432 1344 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -2240 1344 256 ) ( -2240 1376 64 ) ( -2240 1312 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +} +// brush 236 +{ +( -2176 1312 64 ) ( -2176 1344 64 ) ( -2368 1344 64 ) we_cemetary/cemstair2 127 -63 -90.00 1 1 0 0 0 +( -2176 1344 384 ) ( -2368 1344 384 ) ( -2368 1344 64 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +( -2368 1296 96 ) ( -2176 1304 80 ) ( -2368 1312 64 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +( -2176 1280 256 ) ( -2368 1280 256 ) ( -2368 1344 256 ) we_cemetary/cemstair2 127 -63 -90.00 1 1 0 0 0 +( -2240 1296 208 ) ( -2048 1296 176 ) ( -2240 1296 144 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +( -1920 1344 64 ) ( -1952 1312 64 ) ( -1936 1328 256 ) we_cemetary/cemstair2 64 0 0.00 1 1 0 0 0 +( -2112 1344 256 ) ( -2112 1312 64 ) ( -2112 1376 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +} +// brush 237 +{ +( -2368 1344 64 ) ( -2176 1344 64 ) ( -2176 1376 64 ) we_cemetary/cemstair2 63 -63 -90.00 1 1 0 0 0 +( -2368 1344 64 ) ( -2368 1344 384 ) ( -2176 1344 384 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +( -2368 1376 64 ) ( -2176 1384 80 ) ( -2368 1392 96 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +( -2368 1344 256 ) ( -2368 1408 256 ) ( -2176 1408 256 ) we_cemetary/cemstair2 63 -63 -90.00 1 1 0 0 0 +( -2272 1392 144 ) ( -2080 1392 176 ) ( -2272 1392 208 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +( -2112 1344 256 ) ( -2112 1312 64 ) ( -2112 1376 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( -1920 1376 256 ) ( -1920 1408 64 ) ( -1920 1344 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +} +// brush 238 +{ +( -2368 1344 0 ) ( -2176 1344 0 ) ( -2176 1376 0 ) we_cemetary/cemtrim2 63 -63 -90.00 1 1 0 0 0 +( -2176 1376 64 ) ( -2176 1344 64 ) ( -2368 1344 64 ) we_cemetary/cemtrim2 63 -63 -90.00 1 1 0 0 0 +( -2080 1376 0 ) ( -2080 1376 320 ) ( -2272 1376 320 ) we_cemetary/cemtrim2 192 0 0.00 1 1 0 0 0 +( -2368 1344 0 ) ( -2368 1344 320 ) ( -2176 1344 320 ) we_cemetary/cemtrim2 192 0 0.00 1 1 0 0 0 +( -2112 1344 64 ) ( -2112 1312 0 ) ( -2112 1376 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( -1920 1376 64 ) ( -1920 1408 0 ) ( -1920 1344 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +} +// brush 239 +{ +( -2368 1344 64 ) ( -2176 1344 64 ) ( -2176 1376 64 ) we_cemetary/cemstair2 63 -63 -90.00 1 1 0 0 0 +( -2368 1344 64 ) ( -2368 1344 384 ) ( -2176 1344 384 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -2368 1376 64 ) ( -2176 1384 80 ) ( -2368 1392 96 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -2368 1344 256 ) ( -2368 1408 256 ) ( -2176 1408 256 ) we_cemetary/cemstair2 63 -63 -90.00 1 1 0 0 0 +( -2368 1392 144 ) ( -2176 1392 176 ) ( -2368 1392 208 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -2240 1344 256 ) ( -2240 1376 64 ) ( -2240 1312 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( -2432 1392 256 ) ( -2432 1376 64 ) ( -2432 1408 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +} +// brush 240 +{ +( -2368 1344 0 ) ( -2176 1344 0 ) ( -2176 1376 0 ) we_cemetary/cemtrim2 63 -63 -90.00 1 1 0 0 0 +( -2176 1376 64 ) ( -2176 1344 64 ) ( -2368 1344 64 ) we_cemetary/cemtrim2 63 -63 -90.00 1 1 0 0 0 +( -2368 1376 0 ) ( -2368 1376 320 ) ( -2560 1376 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( -2368 1344 0 ) ( -2368 1344 320 ) ( -2176 1344 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( -2240 1344 64 ) ( -2240 1376 0 ) ( -2240 1312 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( -2432 1392 64 ) ( -2432 1376 0 ) ( -2432 1408 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +} +// brush 241 +{ +( -2176 1344 256 ) ( -2176 1392 256 ) ( -2368 1392 256 ) we_cemetary/fogtrunk 63 64 -90.00 1 1 0 0 0 +( -2176 1408 272 ) ( -2176 1344 272 ) ( -2368 1344 272 ) we_cemetary/fogtrunk 63 64 -90.00 1 1 0 0 0 +( -2368 1408 272 ) ( -2368 1392 256 ) ( -2176 1392 256 ) we_cemetary/fogtrunk 63 64 -90.00 1 1 0 0 0 +( -2368 1344 256 ) ( -2368 1344 272 ) ( -2176 1344 272 ) we_cemetary/fogtrunk -64 0 0.00 1 1 0 0 0 +( -1920 1376 272 ) ( -1920 1408 256 ) ( -1920 1344 256 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +( -2432 1392 272 ) ( -2432 1376 256 ) ( -2432 1408 256 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +} +// brush 242 +{ +( -2368 1376 272 ) ( -2176 1376 272 ) ( -2176 1408 272 ) we_cemetary/cemrunner2 63 -31 -90.00 1 1 0 0 0 +( -2176 1408 336 ) ( -2176 1376 336 ) ( -2368 1376 336 ) we_cemetary/cemtrim2 31 -63 -90.00 1 1 0 0 0 +( -2176 1408 272 ) ( -2176 1408 592 ) ( -2368 1408 592 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( -2368 1344 272 ) ( -2368 1344 592 ) ( -2176 1344 592 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( -1920 1376 336 ) ( -1920 1408 272 ) ( -1920 1344 272 ) we_cemetary/cemtrim2 0 16 0.00 1 1 0 0 0 +( -2432 1392 336 ) ( -2432 1376 272 ) ( -2432 1408 272 ) we_cemetary/cemtrim2 0 16 0.00 1 1 0 0 0 +} +// brush 243 +{ +( -2400 1312 -32 ) ( -2400 864 -32 ) ( -1952 864 -32 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( -1952 864 0 ) ( -2400 864 0 ) ( -2400 1312 0 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( -1952 1376 -64 ) ( -1952 1376 0 ) ( -2400 1376 0 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( -1920 864 -64 ) ( -1920 864 0 ) ( -1920 1312 0 ) we_cemetary/cemtrim5 64 0 0.00 1 1 0 0 0 +( -2400 832 -64 ) ( -2400 832 0 ) ( -1952 832 0 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( -2432 1312 -64 ) ( -2432 1312 0 ) ( -2432 864 0 ) we_cemetary/cemtrim5 64 0 0.00 1 1 0 0 0 +} +// brush 244 +{ +( -2400 1312 336 ) ( -2400 864 336 ) ( -1952 864 336 ) water/waterfloor2 0 -64 0.00 1 1 0 0 0 +( -1952 864 352 ) ( -2400 864 352 ) ( -2400 1312 352 ) water/waterfloor2 0 -64 0.00 1 1 0 0 0 +( -1952 1312 304 ) ( -1952 1312 368 ) ( -2400 1312 368 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +( -1952 864 304 ) ( -1952 864 368 ) ( -1952 1312 368 ) water/waterfloor2 64 0 0.00 1 1 0 0 0 +( -2400 864 304 ) ( -2400 864 368 ) ( -1952 864 368 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +( -2400 1312 304 ) ( -2400 1312 368 ) ( -2400 864 368 ) water/waterfloor2 64 0 0.00 1 1 0 0 0 +} +// brush 245 +{ +( -2240 1392 208 ) ( -2240 1296 208 ) ( -2112 1296 208 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +( -2112 1296 256 ) ( -2240 1296 256 ) ( -2240 1392 256 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +( -2112 1392 64 ) ( -2112 1392 256 ) ( -2240 1392 256 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +( -2112 1296 48 ) ( -2112 1296 240 ) ( -2112 1392 240 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( -2240 1296 48 ) ( -2240 1296 240 ) ( -2112 1296 240 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +( -2240 1392 64 ) ( -2240 1392 256 ) ( -2240 1296 256 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +} +// brush 246 +{ +( -1728 1392 208 ) ( -1728 1296 208 ) ( -1600 1296 208 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -1600 1296 256 ) ( -1728 1296 256 ) ( -1728 1392 256 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -1600 1392 64 ) ( -1600 1392 256 ) ( -1728 1392 256 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -1600 1296 48 ) ( -1600 1296 240 ) ( -1600 1392 240 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( -1728 1296 48 ) ( -1728 1296 240 ) ( -1600 1296 240 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -1728 1392 64 ) ( -1728 1392 256 ) ( -1728 1296 256 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +} +// brush 247 +{ +( -1888 1312 336 ) ( -1888 864 336 ) ( -1440 864 336 ) water/waterfloor2 0 -64 0.00 1 1 0 0 0 +( -1440 864 352 ) ( -1888 864 352 ) ( -1888 1312 352 ) water/waterfloor2 0 -64 0.00 1 1 0 0 0 +( -1440 1312 304 ) ( -1440 1312 368 ) ( -1888 1312 368 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +( -1440 864 304 ) ( -1440 864 368 ) ( -1440 1312 368 ) water/waterfloor2 64 0 0.00 1 1 0 0 0 +( -1888 864 304 ) ( -1888 864 368 ) ( -1440 864 368 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +( -1888 1312 304 ) ( -1888 1312 368 ) ( -1888 864 368 ) water/waterfloor2 64 0 0.00 1 1 0 0 0 +} +// brush 248 +{ +( -1888 1312 -32 ) ( -1888 864 -32 ) ( -1440 864 -32 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( -1440 864 0 ) ( -1888 864 0 ) ( -1888 1312 0 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( -1440 1376 -64 ) ( -1440 1376 0 ) ( -1888 1376 0 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( -1408 864 -64 ) ( -1408 864 0 ) ( -1408 1312 0 ) we_cemetary/cemtrim5 64 0 0.00 1 1 0 0 0 +( -1888 832 -64 ) ( -1888 832 0 ) ( -1440 832 0 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( -1920 1312 -64 ) ( -1920 1312 0 ) ( -1920 864 0 ) we_cemetary/cemtrim5 64 0 0.00 1 1 0 0 0 +} +// brush 249 +{ +( -1856 1376 272 ) ( -1664 1376 272 ) ( -1664 1408 272 ) we_cemetary/cemrunner2 -64 -31 -90.00 1 1 0 0 0 +( -1664 1408 336 ) ( -1664 1376 336 ) ( -1856 1376 336 ) we_cemetary/cemtrim2 31 -63 -90.00 1 1 0 0 0 +( -1664 1408 272 ) ( -1664 1408 592 ) ( -1856 1408 592 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( -1856 1344 272 ) ( -1856 1344 592 ) ( -1664 1344 592 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( -1408 1376 336 ) ( -1408 1408 272 ) ( -1408 1344 272 ) we_cemetary/cemtrim2 0 16 0.00 1 1 0 0 0 +( -1920 1392 336 ) ( -1920 1376 272 ) ( -1920 1408 272 ) we_cemetary/cemtrim2 0 16 0.00 1 1 0 0 0 +} +// brush 250 +{ +( -1664 1344 256 ) ( -1664 1392 256 ) ( -1856 1392 256 ) we_cemetary/fogtrunk 63 64 -90.00 1 1 0 0 0 +( -1664 1408 272 ) ( -1664 1344 272 ) ( -1856 1344 272 ) we_cemetary/fogtrunk 63 64 -90.00 1 1 0 0 0 +( -1856 1408 272 ) ( -1856 1392 256 ) ( -1664 1392 256 ) we_cemetary/fogtrunk 63 64 -90.00 1 1 0 0 0 +( -1856 1344 256 ) ( -1856 1344 272 ) ( -1664 1344 272 ) we_cemetary/fogtrunk -64 0 0.00 1 1 0 0 0 +( -1408 1376 272 ) ( -1408 1408 256 ) ( -1408 1344 256 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +( -1920 1392 272 ) ( -1920 1376 256 ) ( -1920 1408 256 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +} +// brush 251 +{ +( -1856 1344 0 ) ( -1664 1344 0 ) ( -1664 1376 0 ) we_cemetary/cemtrim2 63 -63 -90.00 1 1 0 0 0 +( -1664 1376 64 ) ( -1664 1344 64 ) ( -1856 1344 64 ) we_cemetary/cemtrim2 63 -63 -90.00 1 1 0 0 0 +( -1856 1376 0 ) ( -1856 1376 320 ) ( -2048 1376 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( -1856 1344 0 ) ( -1856 1344 320 ) ( -1664 1344 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( -1728 1344 64 ) ( -1728 1376 0 ) ( -1728 1312 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( -1920 1392 64 ) ( -1920 1376 0 ) ( -1920 1408 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +} +// brush 252 +{ +( -1856 1344 64 ) ( -1664 1344 64 ) ( -1664 1376 64 ) we_cemetary/cemstair2 63 -63 -90.00 1 1 0 0 0 +( -1856 1344 64 ) ( -1856 1344 384 ) ( -1664 1344 384 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -1856 1376 64 ) ( -1664 1384 80 ) ( -1856 1392 96 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -1856 1344 256 ) ( -1856 1408 256 ) ( -1664 1408 256 ) we_cemetary/cemstair2 63 -63 -90.00 1 1 0 0 0 +( -1856 1392 144 ) ( -1664 1392 176 ) ( -1856 1392 208 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -1728 1344 256 ) ( -1728 1376 64 ) ( -1728 1312 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( -1920 1392 256 ) ( -1920 1376 64 ) ( -1920 1408 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +} +// brush 253 +{ +( -1856 1344 0 ) ( -1664 1344 0 ) ( -1664 1376 0 ) we_cemetary/cemtrim2 63 -63 -90.00 1 1 0 0 0 +( -1664 1376 64 ) ( -1664 1344 64 ) ( -1856 1344 64 ) we_cemetary/cemtrim2 63 -63 -90.00 1 1 0 0 0 +( -1568 1376 0 ) ( -1568 1376 320 ) ( -1760 1376 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( -1856 1344 0 ) ( -1856 1344 320 ) ( -1664 1344 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( -1600 1344 64 ) ( -1600 1312 0 ) ( -1600 1376 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( -1408 1376 64 ) ( -1408 1408 0 ) ( -1408 1344 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +} +// brush 254 +{ +( -1856 1344 64 ) ( -1664 1344 64 ) ( -1664 1376 64 ) we_cemetary/cemstair2 63 -63 -90.00 1 1 0 0 0 +( -1856 1344 64 ) ( -1856 1344 384 ) ( -1664 1344 384 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -1856 1376 64 ) ( -1664 1384 80 ) ( -1856 1392 96 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -1856 1344 256 ) ( -1856 1408 256 ) ( -1664 1408 256 ) we_cemetary/cemstair2 63 -63 -90.00 1 1 0 0 0 +( -1760 1392 144 ) ( -1568 1392 176 ) ( -1760 1392 208 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -1600 1344 256 ) ( -1600 1312 64 ) ( -1600 1376 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( -1408 1376 256 ) ( -1408 1408 64 ) ( -1408 1344 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +} +// brush 255 +{ +( -1664 1312 64 ) ( -1664 1344 64 ) ( -1856 1344 64 ) we_cemetary/cemstair2 128 -63 -90.00 1 1 0 0 0 +( -1664 1344 384 ) ( -1856 1344 384 ) ( -1856 1344 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -1856 1296 96 ) ( -1664 1304 80 ) ( -1856 1312 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -1664 1280 256 ) ( -1856 1280 256 ) ( -1856 1344 256 ) we_cemetary/cemstair2 128 -63 -90.00 1 1 0 0 0 +( -1728 1296 208 ) ( -1536 1296 176 ) ( -1728 1296 144 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -1408 1344 64 ) ( -1440 1312 64 ) ( -1424 1328 256 ) we_cemetary/cemstair2 64 0 0.00 1 1 0 0 0 +( -1600 1344 256 ) ( -1600 1312 64 ) ( -1600 1376 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +} +// brush 256 +{ +( -1664 1312 64 ) ( -1664 1344 64 ) ( -1856 1344 64 ) we_cemetary/cemstair2 128 -63 -90.00 1 1 0 0 0 +( -1664 1344 384 ) ( -1856 1344 384 ) ( -1856 1344 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -1856 1296 96 ) ( -1664 1304 80 ) ( -1856 1312 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -1664 1280 256 ) ( -1856 1280 256 ) ( -1856 1344 256 ) we_cemetary/cemstair2 128 -63 -90.00 1 1 0 0 0 +( -1856 1296 208 ) ( -1664 1296 176 ) ( -1856 1296 144 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -1904 1328 256 ) ( -1888 1312 64 ) ( -1920 1344 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -1728 1344 256 ) ( -1728 1376 64 ) ( -1728 1312 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +} +// brush 257 +{ +( -1664 1312 0 ) ( -1664 1344 0 ) ( -1856 1344 0 ) we_cemetary/cemtrim2 128 -63 -90.00 1 1 0 0 0 +( -1856 1344 64 ) ( -1664 1344 64 ) ( -1664 1312 64 ) we_cemetary/cemtrim2 128 -63 -90.00 1 1 0 0 0 +( -1856 1312 320 ) ( -1664 1312 320 ) ( -1664 1312 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( -1664 1344 320 ) ( -1856 1344 320 ) ( -1856 1344 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( -1408 1344 0 ) ( -1440 1312 0 ) ( -1424 1328 64 ) we_cemetary/cemtrim2 64 0 0.00 1 1 0 0 0 +( -1600 1344 64 ) ( -1600 1312 0 ) ( -1600 1376 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +} +// brush 258 +{ +( -1664 1312 0 ) ( -1664 1344 0 ) ( -1856 1344 0 ) we_cemetary/cemtrim2 128 -63 -90.00 1 1 0 0 0 +( -1856 1344 64 ) ( -1664 1344 64 ) ( -1664 1312 64 ) we_cemetary/cemtrim2 128 -63 -90.00 1 1 0 0 0 +( -1984 1312 320 ) ( -1792 1312 320 ) ( -1792 1312 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( -1664 1344 320 ) ( -1856 1344 320 ) ( -1856 1344 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( -1904 1328 64 ) ( -1888 1312 0 ) ( -1920 1344 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( -1728 1344 64 ) ( -1728 1376 0 ) ( -1728 1312 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +} +// brush 259 +{ +( -1920 1280 0 ) ( -1920 1088 0 ) ( -1888 1088 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( -1888 1088 64 ) ( -1920 1088 64 ) ( -1920 1280 64 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( -1888 1152 0 ) ( -1888 1152 320 ) ( -1888 1344 320 ) we_cemetary/cemtrim2 64 0 0.00 1 1 0 0 0 +( -1920 1280 0 ) ( -1920 1280 320 ) ( -1920 1088 320 ) we_cemetary/cemtrim2 64 0 0.00 1 1 0 0 0 +( -1904 848 64 ) ( -1888 864 0 ) ( -1920 832 0 ) we_cemetary/cemtrim2 64 0 0.00 1 1 0 0 0 +( -1872 1296 64 ) ( -1888 1312 0 ) ( -1856 1280 0 ) we_cemetary/cemtrim2 64 0 0.00 1 1 0 0 0 +} +// brush 260 +{ +( -1920 1280 64 ) ( -1920 1088 64 ) ( -1888 1088 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( -1920 1280 64 ) ( -1920 1280 384 ) ( -1920 1088 384 ) we_cemetary/cemstair2 64 0 0.00 1 1 0 0 0 +( -1888 1280 64 ) ( -1880 1088 80 ) ( -1872 1280 96 ) we_cemetary/cemstair2 64 0 0.00 1 1 0 0 0 +( -1920 1280 256 ) ( -1856 1280 256 ) ( -1856 1088 256 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( -1872 1280 144 ) ( -1872 1088 176 ) ( -1872 1280 208 ) we_cemetary/cemstair2 64 0 0.00 1 1 0 0 0 +( -1904 848 256 ) ( -1888 864 64 ) ( -1920 832 64 ) we_cemetary/cemstair2 64 0 0.00 1 1 0 0 0 +( -1872 1296 256 ) ( -1888 1312 64 ) ( -1856 1280 64 ) we_cemetary/cemstair2 64 0 0.00 1 1 0 0 0 +} +// brush 261 +{ +( -1920 1088 256 ) ( -1872 1088 256 ) ( -1872 1280 256 ) we_cemetary/fogtrunk 0 -64 0.00 1 1 0 0 0 +( -1856 1088 272 ) ( -1920 1088 272 ) ( -1920 1280 272 ) we_cemetary/fogtrunk 0 -64 0.00 1 1 0 0 0 +( -1856 1280 272 ) ( -1872 1280 256 ) ( -1872 1088 256 ) we_cemetary/fogtrunk 0 -64 0.00 1 1 0 0 0 +( -1920 1280 256 ) ( -1920 1280 272 ) ( -1920 1088 272 ) we_cemetary/fogtrunk 64 0 0.00 1 1 0 0 0 +( -1904 848 272 ) ( -1888 864 256 ) ( -1920 832 256 ) we_cemetary/fogtrunk 64 0 0.00 1 1 0 0 0 +( -1872 1296 272 ) ( -1888 1312 256 ) ( -1856 1280 256 ) we_cemetary/fogtrunk 64 0 0.00 1 1 0 0 0 +} +// brush 262 +{ +( -1888 1280 272 ) ( -1888 1088 272 ) ( -1856 1088 272 ) we_cemetary/cemrunner2 0 0 0.00 1 1 0 0 0 +( -1856 1088 336 ) ( -1888 1088 336 ) ( -1888 1280 336 ) we_cemetary/cemtrim2 -32 0 0.00 1 1 0 0 0 +( -1856 1088 272 ) ( -1856 1088 592 ) ( -1856 1280 592 ) we_cemetary/cemtrim2 64 16 0.00 1 1 0 0 0 +( -1920 1280 272 ) ( -1920 1280 592 ) ( -1920 1088 592 ) we_cemetary/cemtrim2 64 16 0.00 1 1 0 0 0 +( -1904 848 336 ) ( -1888 864 272 ) ( -1920 832 272 ) we_cemetary/cemtrim2 64 16 0.00 1 1 0 0 0 +( -1872 1296 336 ) ( -1888 1312 272 ) ( -1856 1280 272 ) we_cemetary/cemtrim2 64 16 0.00 1 1 0 0 0 +} +// brush 263 +{ +( -1856 1296 256 ) ( -1664 1296 256 ) ( -1664 1344 256 ) we_cemetary/fogtrunk 128 64 -90.00 1 1 0 0 0 +( -1856 1344 272 ) ( -1664 1344 272 ) ( -1664 1280 272 ) we_cemetary/fogtrunk 128 64 -90.00 1 1 0 0 0 +( -1664 1296 256 ) ( -1856 1296 256 ) ( -1856 1280 272 ) we_cemetary/fogtrunk 128 64 -90.00 1 1 0 0 0 +( -1664 1344 272 ) ( -1856 1344 272 ) ( -1856 1344 256 ) we_cemetary/fogtrunk -64 0 0.00 1 1 0 0 0 +( -1408 1344 256 ) ( -1440 1312 256 ) ( -1424 1328 272 ) we_cemetary/fogtrunk 64 0 0.00 1 1 0 0 0 +( -1904 1328 272 ) ( -1888 1312 256 ) ( -1920 1344 256 ) we_cemetary/fogtrunk -64 0 0.00 1 1 0 0 0 +} +// brush 264 +{ +( -1664 1280 272 ) ( -1664 1312 272 ) ( -1856 1312 272 ) we_cemetary/cemrunner2 0 -31 -90.00 1 1 0 0 0 +( -1856 1312 336 ) ( -1664 1312 336 ) ( -1664 1280 336 ) we_cemetary/cemtrim2 95 -63 -90.00 1 1 0 0 0 +( -1856 1280 592 ) ( -1664 1280 592 ) ( -1664 1280 272 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( -1664 1344 592 ) ( -1856 1344 592 ) ( -1856 1344 272 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( -1408 1344 272 ) ( -1440 1312 272 ) ( -1424 1328 336 ) we_cemetary/cemtrim2 64 15 0.00 1 1 0 0 0 +( -1904 1328 336 ) ( -1888 1312 272 ) ( -1920 1344 272 ) we_cemetary/cemtrim2 -64 16 0.00 1 1 0 0 0 +} +// brush 265 +{ +( -1472 1088 272 ) ( -1440 1088 272 ) ( -1440 1280 272 ) we_cemetary/cemrunner2 63 0 -180.00 1 1 0 0 0 +( -1440 1280 336 ) ( -1440 1088 336 ) ( -1472 1088 336 ) we_cemetary/cemtrim2 159 0 -180.00 1 1 0 0 0 +( -1472 1280 592 ) ( -1472 1088 592 ) ( -1472 1088 272 ) we_cemetary/cemtrim2 0 14 -180.00 1 -1 0 0 0 +( -1408 1088 592 ) ( -1408 1280 592 ) ( -1408 1280 272 ) we_cemetary/cemtrim2 0 14 -180.00 1 -1 0 0 0 +( -1408 832 272 ) ( -1440 864 272 ) ( -1424 848 336 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( -1424 1328 336 ) ( -1440 1312 272 ) ( -1408 1344 272 ) we_cemetary/cemtrim2 -64 15 -180.00 1 -1 0 0 0 +} +// brush 266 +{ +( -1456 1280 256 ) ( -1456 1088 256 ) ( -1408 1088 256 ) we_cemetary/fogtrunk 191 0 -180.00 1 1 0 0 0 +( -1408 1280 272 ) ( -1408 1088 272 ) ( -1472 1088 272 ) we_cemetary/fogtrunk 191 0 -180.00 1 1 0 0 0 +( -1456 1088 256 ) ( -1456 1280 256 ) ( -1472 1280 272 ) we_cemetary/fogtrunk 191 0 -180.00 1 1 0 0 0 +( -1408 1088 272 ) ( -1408 1280 272 ) ( -1408 1280 256 ) we_cemetary/fogtrunk 0 0 -180.00 1 -1 0 0 0 +( -1408 832 256 ) ( -1440 864 256 ) ( -1424 848 272 ) we_cemetary/fogtrunk -64 0 0.00 1 1 0 0 0 +( -1424 1328 272 ) ( -1440 1312 256 ) ( -1408 1344 256 ) we_cemetary/fogtrunk -64 0 -180.00 1 -1 0 0 0 +} +// brush 267 +{ +( -1440 1088 64 ) ( -1408 1088 64 ) ( -1408 1280 64 ) we_cemetary/cemstair2 191 0 -180.00 1 1 0 0 0 +( -1408 1088 384 ) ( -1408 1280 384 ) ( -1408 1280 64 ) we_cemetary/cemstair2 0 0 -180.00 1 -1 0 0 0 +( -1456 1280 96 ) ( -1448 1088 80 ) ( -1440 1280 64 ) we_cemetary/cemstair2 0 0 -180.00 1 -1 0 0 0 +( -1472 1088 256 ) ( -1472 1280 256 ) ( -1408 1280 256 ) we_cemetary/cemstair2 191 0 -180.00 1 1 0 0 0 +( -1456 1280 208 ) ( -1456 1088 176 ) ( -1456 1280 144 ) we_cemetary/cemstair2 0 0 -180.00 1 -1 0 0 0 +( -1408 832 64 ) ( -1440 864 64 ) ( -1424 848 256 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -1424 1328 256 ) ( -1440 1312 64 ) ( -1408 1344 64 ) we_cemetary/cemstair2 -64 0 -180.00 1 -1 0 0 0 +} +// brush 268 +{ +( -1440 1088 0 ) ( -1408 1088 0 ) ( -1408 1280 0 ) we_cemetary/cemtrim2 191 0 -180.00 1 1 0 0 0 +( -1408 1280 64 ) ( -1408 1088 64 ) ( -1440 1088 64 ) we_cemetary/cemtrim2 191 0 -180.00 1 1 0 0 0 +( -1440 1408 320 ) ( -1440 1216 320 ) ( -1440 1216 0 ) we_cemetary/cemtrim2 0 0 -180.00 1 -1 0 0 0 +( -1408 1088 320 ) ( -1408 1280 320 ) ( -1408 1280 0 ) we_cemetary/cemtrim2 0 0 -180.00 1 -1 0 0 0 +( -1408 832 0 ) ( -1440 864 0 ) ( -1424 848 64 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( -1424 1328 64 ) ( -1440 1312 0 ) ( -1408 1344 0 ) we_cemetary/cemtrim2 -64 0 -180.00 1 -1 0 0 0 +} +// brush 269 +{ +( -1664 864 0 ) ( -1664 832 0 ) ( -1472 832 0 ) we_cemetary/cemtrim2 1 0 90.00 1 1 0 0 0 +( -1472 832 64 ) ( -1664 832 64 ) ( -1664 864 64 ) we_cemetary/cemtrim2 1 0 90.00 1 1 0 0 0 +( -1408 864 320 ) ( -1600 864 320 ) ( -1600 864 0 ) we_cemetary/cemtrim2 128 0 -180.00 1 -1 0 0 0 +( -1664 832 320 ) ( -1472 832 320 ) ( -1472 832 0 ) we_cemetary/cemtrim2 128 0 -180.00 1 -1 0 0 0 +( -1920 832 0 ) ( -1888 864 0 ) ( -1904 848 64 ) we_cemetary/cemtrim2 128 0 -180.00 1 -1 0 0 0 +( -1424 848 64 ) ( -1440 864 0 ) ( -1408 832 0 ) we_cemetary/cemtrim2 128 0 -180.00 1 -1 0 0 0 +} +// brush 270 +{ +( -1664 864 64 ) ( -1664 832 64 ) ( -1472 832 64 ) we_cemetary/cemstair2 1 0 90.00 1 1 0 0 0 +( -1664 832 384 ) ( -1472 832 384 ) ( -1472 832 64 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +( -1472 880 96 ) ( -1664 872 80 ) ( -1472 864 64 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +( -1664 896 256 ) ( -1472 896 256 ) ( -1472 832 256 ) we_cemetary/cemstair2 1 0 90.00 1 1 0 0 0 +( -1472 880 208 ) ( -1664 880 176 ) ( -1472 880 144 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +( -1920 832 64 ) ( -1888 864 64 ) ( -1904 848 256 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +( -1424 848 256 ) ( -1440 864 64 ) ( -1408 832 64 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +} +// brush 271 +{ +( -1472 880 256 ) ( -1664 880 256 ) ( -1664 832 256 ) we_cemetary/fogtrunk 1 -127 90.00 1 1 0 0 0 +( -1472 832 272 ) ( -1664 832 272 ) ( -1664 896 272 ) we_cemetary/fogtrunk 1 -127 90.00 1 1 0 0 0 +( -1664 880 256 ) ( -1472 880 256 ) ( -1472 896 272 ) we_cemetary/fogtrunk 1 -127 90.00 1 1 0 0 0 +( -1664 832 272 ) ( -1472 832 272 ) ( -1472 832 256 ) we_cemetary/fogtrunk 128 0 -180.00 1 -1 0 0 0 +( -1920 832 256 ) ( -1888 864 256 ) ( -1904 848 272 ) we_cemetary/fogtrunk 128 0 -180.00 1 -1 0 0 0 +( -1424 848 272 ) ( -1440 864 256 ) ( -1408 832 256 ) we_cemetary/fogtrunk 128 0 -180.00 1 -1 0 0 0 +} +// brush 272 +{ +( -1664 896 272 ) ( -1664 864 272 ) ( -1472 864 272 ) we_cemetary/cemrunner2 1 0 90.00 1 1.000122 0 0 0 +( -1472 864 336 ) ( -1664 864 336 ) ( -1664 896 336 ) we_cemetary/cemtrim2 -31 0 90.00 1 1 0 0 0 +( -1472 896 592 ) ( -1664 896 592 ) ( -1664 896 272 ) we_cemetary/cemtrim2 128 15 -180.00 1 -1 0 0 0 +( -1664 832 592 ) ( -1472 832 592 ) ( -1472 832 272 ) we_cemetary/cemtrim2 128 15 -180.00 1 -1 0 0 0 +( -1920 832 272 ) ( -1888 864 272 ) ( -1904 848 336 ) we_cemetary/cemtrim2 128 15 -180.00 1 -1 0 0 0 +( -1424 848 336 ) ( -1440 864 272 ) ( -1408 832 272 ) we_cemetary/cemtrim2 128 15 -180.00 1 -1 0 0 0 +} +// brush 273 +{ +( -1152 896 272 ) ( -1152 864 272 ) ( -960 864 272 ) we_cemetary/cemrunner2 2 0 90.00 1 1.000122 0 0 0 +( -960 864 336 ) ( -1152 864 336 ) ( -1152 896 336 ) we_cemetary/cemtrim2 -30 0 90.00 1 1 0 0 0 +( -960 896 592 ) ( -1152 896 592 ) ( -1152 896 272 ) we_cemetary/cemtrim2 128 15 -180.00 1 -1 0 0 0 +( -1152 832 592 ) ( -960 832 592 ) ( -960 832 272 ) we_cemetary/cemtrim2 128 15 -180.00 1 -1 0 0 0 +( -1408 832 272 ) ( -1376 864 272 ) ( -1392 848 336 ) we_cemetary/cemtrim2 128 15 -180.00 1 -1 0 0 0 +( -912 848 336 ) ( -928 864 272 ) ( -896 832 272 ) we_cemetary/cemtrim2 128 15 -180.00 1 -1 0 0 0 +} +// brush 274 +{ +( -960 880 256 ) ( -1152 880 256 ) ( -1152 832 256 ) we_cemetary/fogtrunk 2 -127 90.00 1 1 0 0 0 +( -960 832 272 ) ( -1152 832 272 ) ( -1152 896 272 ) we_cemetary/fogtrunk 2 -127 90.00 1 1 0 0 0 +( -1152 880 256 ) ( -960 880 256 ) ( -960 896 272 ) we_cemetary/fogtrunk 2 -127 90.00 1 1 0 0 0 +( -1152 832 272 ) ( -960 832 272 ) ( -960 832 256 ) we_cemetary/fogtrunk 128 0 -180.00 1 -1 0 0 0 +( -1408 832 256 ) ( -1376 864 256 ) ( -1392 848 272 ) we_cemetary/fogtrunk 128 0 -180.00 1 -1 0 0 0 +( -912 848 272 ) ( -928 864 256 ) ( -896 832 256 ) we_cemetary/fogtrunk 128 0 -180.00 1 -1 0 0 0 +} +// brush 275 +{ +( -1152 864 64 ) ( -1152 832 64 ) ( -960 832 64 ) we_cemetary/cemstair2 2 0 90.00 1 1 0 0 0 +( -1152 832 384 ) ( -960 832 384 ) ( -960 832 64 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +( -960 880 96 ) ( -1152 872 80 ) ( -960 864 64 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +( -1152 896 256 ) ( -960 896 256 ) ( -960 832 256 ) we_cemetary/cemstair2 2 0 90.00 1 1 0 0 0 +( -960 880 208 ) ( -1152 880 176 ) ( -960 880 144 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +( -1408 832 64 ) ( -1376 864 64 ) ( -1392 848 256 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +( -912 848 256 ) ( -928 864 64 ) ( -896 832 64 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +} +// brush 276 +{ +( -1152 864 0 ) ( -1152 832 0 ) ( -960 832 0 ) we_cemetary/cemtrim2 2 0 90.00 1 1 0 0 0 +( -960 832 64 ) ( -1152 832 64 ) ( -1152 864 64 ) we_cemetary/cemtrim2 2 0 90.00 1 1 0 0 0 +( -896 864 320 ) ( -1088 864 320 ) ( -1088 864 0 ) we_cemetary/cemtrim2 128 0 -180.00 1 -1 0 0 0 +( -1152 832 320 ) ( -960 832 320 ) ( -960 832 0 ) we_cemetary/cemtrim2 128 0 -180.00 1 -1 0 0 0 +( -1408 832 0 ) ( -1376 864 0 ) ( -1392 848 64 ) we_cemetary/cemtrim2 128 0 -180.00 1 -1 0 0 0 +( -912 848 64 ) ( -928 864 0 ) ( -896 832 0 ) we_cemetary/cemtrim2 128 0 -180.00 1 -1 0 0 0 +} +// brush 277 +{ +( -928 1088 0 ) ( -896 1088 0 ) ( -896 1280 0 ) we_cemetary/cemtrim2 191 0 -180.00 1 1 0 0 0 +( -896 1280 64 ) ( -896 1088 64 ) ( -928 1088 64 ) we_cemetary/cemtrim2 191 0 -180.00 1 1 0 0 0 +( -928 1408 320 ) ( -928 1216 320 ) ( -928 1216 0 ) we_cemetary/cemtrim2 0 0 -180.00 1 -1 0 0 0 +( -896 1088 320 ) ( -896 1280 320 ) ( -896 1280 0 ) we_cemetary/cemtrim2 0 0 -180.00 1 -1 0 0 0 +( -896 832 0 ) ( -928 864 0 ) ( -912 848 64 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( -912 1328 64 ) ( -928 1312 0 ) ( -896 1344 0 ) we_cemetary/cemtrim2 -64 0 -180.00 1 -1 0 0 0 +} +// brush 278 +{ +( -928 1088 64 ) ( -896 1088 64 ) ( -896 1280 64 ) we_cemetary/cemstair2 191 0 -180.00 1 1 0 0 0 +( -896 1088 384 ) ( -896 1280 384 ) ( -896 1280 64 ) we_cemetary/cemstair2 0 0 -180.00 1 -1 0 0 0 +( -944 1280 96 ) ( -936 1088 80 ) ( -928 1280 64 ) we_cemetary/cemstair2 0 0 -180.00 1 -1 0 0 0 +( -960 1088 256 ) ( -960 1280 256 ) ( -896 1280 256 ) we_cemetary/cemstair2 191 0 -180.00 1 1 0 0 0 +( -944 1280 208 ) ( -944 1088 176 ) ( -944 1280 144 ) we_cemetary/cemstair2 0 0 -180.00 1 -1 0 0 0 +( -896 832 64 ) ( -928 864 64 ) ( -912 848 256 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -912 1328 256 ) ( -928 1312 64 ) ( -896 1344 64 ) we_cemetary/cemstair2 -64 0 -180.00 1 -1 0 0 0 +} +// brush 279 +{ +( -944 1280 256 ) ( -944 1088 256 ) ( -896 1088 256 ) we_cemetary/fogtrunk 191 0 -180.00 1 1 0 0 0 +( -896 1280 272 ) ( -896 1088 272 ) ( -960 1088 272 ) we_cemetary/fogtrunk 191 0 -180.00 1 1 0 0 0 +( -944 1088 256 ) ( -944 1280 256 ) ( -960 1280 272 ) we_cemetary/fogtrunk 191 0 -180.00 1 1 0 0 0 +( -896 1088 272 ) ( -896 1280 272 ) ( -896 1280 256 ) we_cemetary/fogtrunk 0 0 -180.00 1 -1 0 0 0 +( -896 832 256 ) ( -928 864 256 ) ( -912 848 272 ) we_cemetary/fogtrunk -64 0 0.00 1 1 0 0 0 +( -912 1328 272 ) ( -928 1312 256 ) ( -896 1344 256 ) we_cemetary/fogtrunk -64 0 -180.00 1 -1 0 0 0 +} +// brush 280 +{ +( -960 1088 272 ) ( -928 1088 272 ) ( -928 1280 272 ) we_cemetary/cemrunner2 63 0 -180.00 1 1 0 0 0 +( -928 1280 336 ) ( -928 1088 336 ) ( -960 1088 336 ) we_cemetary/cemtrim2 159 0 -180.00 1 1 0 0 0 +( -960 1280 592 ) ( -960 1088 592 ) ( -960 1088 272 ) we_cemetary/cemtrim2 0 14 -180.00 1 -1 0 0 0 +( -896 1088 592 ) ( -896 1280 592 ) ( -896 1280 272 ) we_cemetary/cemtrim2 0 14 -180.00 1 -1 0 0 0 +( -896 832 272 ) ( -928 864 272 ) ( -912 848 336 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( -912 1328 336 ) ( -928 1312 272 ) ( -896 1344 272 ) we_cemetary/cemtrim2 -64 15 -180.00 1 -1 0 0 0 +} +// brush 281 +{ +( -1152 1280 272 ) ( -1152 1312 272 ) ( -1344 1312 272 ) we_cemetary/cemrunner2 1 -31 -90.00 1 1 0 0 0 +( -1344 1312 336 ) ( -1152 1312 336 ) ( -1152 1280 336 ) we_cemetary/cemtrim2 96 -63 -90.00 1 1 0 0 0 +( -1344 1280 592 ) ( -1152 1280 592 ) ( -1152 1280 272 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( -1152 1344 592 ) ( -1344 1344 592 ) ( -1344 1344 272 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( -896 1344 272 ) ( -928 1312 272 ) ( -912 1328 336 ) we_cemetary/cemtrim2 64 15 0.00 1 1 0 0 0 +( -1392 1328 336 ) ( -1376 1312 272 ) ( -1408 1344 272 ) we_cemetary/cemtrim2 -64 16 0.00 1 1 0 0 0 +} +// brush 282 +{ +( -1344 1296 256 ) ( -1152 1296 256 ) ( -1152 1344 256 ) we_cemetary/fogtrunk -127 64 -90.00 1 1 0 0 0 +( -1344 1344 272 ) ( -1152 1344 272 ) ( -1152 1280 272 ) we_cemetary/fogtrunk -127 64 -90.00 1 1 0 0 0 +( -1152 1296 256 ) ( -1344 1296 256 ) ( -1344 1280 272 ) we_cemetary/fogtrunk -127 64 -90.00 1 1 0 0 0 +( -1152 1344 272 ) ( -1344 1344 272 ) ( -1344 1344 256 ) we_cemetary/fogtrunk -64 0 0.00 1 1 0 0 0 +( -896 1344 256 ) ( -928 1312 256 ) ( -912 1328 272 ) we_cemetary/fogtrunk 64 0 0.00 1 1 0 0 0 +( -1392 1328 272 ) ( -1376 1312 256 ) ( -1408 1344 256 ) we_cemetary/fogtrunk -64 0 0.00 1 1 0 0 0 +} +// brush 283 +{ +( -1376 1280 272 ) ( -1376 1088 272 ) ( -1344 1088 272 ) we_cemetary/cemrunner2 0 0 0.00 1 1 0 0 0 +( -1344 1088 336 ) ( -1376 1088 336 ) ( -1376 1280 336 ) we_cemetary/cemtrim2 -32 0 0.00 1 1 0 0 0 +( -1344 1088 272 ) ( -1344 1088 592 ) ( -1344 1280 592 ) we_cemetary/cemtrim2 64 16 0.00 1 1 0 0 0 +( -1408 1280 272 ) ( -1408 1280 592 ) ( -1408 1088 592 ) we_cemetary/cemtrim2 64 16 0.00 1 1 0 0 0 +( -1392 848 336 ) ( -1376 864 272 ) ( -1408 832 272 ) we_cemetary/cemtrim2 64 16 0.00 1 1 0 0 0 +( -1360 1296 336 ) ( -1376 1312 272 ) ( -1344 1280 272 ) we_cemetary/cemtrim2 64 16 0.00 1 1 0 0 0 +} +// brush 284 +{ +( -1408 1088 256 ) ( -1360 1088 256 ) ( -1360 1280 256 ) we_cemetary/fogtrunk 0 -64 0.00 1 1 0 0 0 +( -1344 1088 272 ) ( -1408 1088 272 ) ( -1408 1280 272 ) we_cemetary/fogtrunk 0 -64 0.00 1 1 0 0 0 +( -1344 1280 272 ) ( -1360 1280 256 ) ( -1360 1088 256 ) we_cemetary/fogtrunk 0 -64 0.00 1 1 0 0 0 +( -1408 1280 256 ) ( -1408 1280 272 ) ( -1408 1088 272 ) we_cemetary/fogtrunk 64 0 0.00 1 1 0 0 0 +( -1392 848 272 ) ( -1376 864 256 ) ( -1408 832 256 ) we_cemetary/fogtrunk 64 0 0.00 1 1 0 0 0 +( -1360 1296 272 ) ( -1376 1312 256 ) ( -1344 1280 256 ) we_cemetary/fogtrunk 64 0 0.00 1 1 0 0 0 +} +// brush 285 +{ +( -1408 1280 64 ) ( -1408 1088 64 ) ( -1376 1088 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( -1408 1280 64 ) ( -1408 1280 384 ) ( -1408 1088 384 ) we_cemetary/cemstair2 64 0 0.00 1 1 0 0 0 +( -1376 1280 64 ) ( -1368 1088 80 ) ( -1360 1280 96 ) we_cemetary/cemstair2 64 0 0.00 1 1 0 0 0 +( -1408 1280 256 ) ( -1344 1280 256 ) ( -1344 1088 256 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( -1360 1280 144 ) ( -1360 1088 176 ) ( -1360 1280 208 ) we_cemetary/cemstair2 64 0 0.00 1 1 0 0 0 +( -1392 848 256 ) ( -1376 864 64 ) ( -1408 832 64 ) we_cemetary/cemstair2 64 0 0.00 1 1 0 0 0 +( -1360 1296 256 ) ( -1376 1312 64 ) ( -1344 1280 64 ) we_cemetary/cemstair2 64 0 0.00 1 1 0 0 0 +} +// brush 286 +{ +( -1408 1280 0 ) ( -1408 1088 0 ) ( -1376 1088 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( -1376 1088 64 ) ( -1408 1088 64 ) ( -1408 1280 64 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( -1376 1152 0 ) ( -1376 1152 320 ) ( -1376 1344 320 ) we_cemetary/cemtrim2 64 0 0.00 1 1 0 0 0 +( -1408 1280 0 ) ( -1408 1280 320 ) ( -1408 1088 320 ) we_cemetary/cemtrim2 64 0 0.00 1 1 0 0 0 +( -1392 848 64 ) ( -1376 864 0 ) ( -1408 832 0 ) we_cemetary/cemtrim2 64 0 0.00 1 1 0 0 0 +( -1360 1296 64 ) ( -1376 1312 0 ) ( -1344 1280 0 ) we_cemetary/cemtrim2 64 0 0.00 1 1 0 0 0 +} +// brush 287 +{ +( -1152 1312 0 ) ( -1152 1344 0 ) ( -1344 1344 0 ) we_cemetary/cemtrim2 -127 -63 -90.00 1 1 0 0 0 +( -1344 1344 64 ) ( -1152 1344 64 ) ( -1152 1312 64 ) we_cemetary/cemtrim2 -127 -63 -90.00 1 1 0 0 0 +( -1472 1312 320 ) ( -1280 1312 320 ) ( -1280 1312 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( -1152 1344 320 ) ( -1344 1344 320 ) ( -1344 1344 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( -1392 1328 64 ) ( -1376 1312 0 ) ( -1408 1344 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( -1216 1344 64 ) ( -1216 1376 0 ) ( -1216 1312 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +} +// brush 288 +{ +( -1152 1312 0 ) ( -1152 1344 0 ) ( -1344 1344 0 ) we_cemetary/cemtrim2 -127 -63 -90.00 1 1 0 0 0 +( -1344 1344 64 ) ( -1152 1344 64 ) ( -1152 1312 64 ) we_cemetary/cemtrim2 -127 -63 -90.00 1 1 0 0 0 +( -1344 1312 320 ) ( -1152 1312 320 ) ( -1152 1312 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( -1152 1344 320 ) ( -1344 1344 320 ) ( -1344 1344 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( -896 1344 0 ) ( -928 1312 0 ) ( -912 1328 64 ) we_cemetary/cemtrim2 64 0 0.00 1 1 0 0 0 +( -1088 1344 64 ) ( -1088 1312 0 ) ( -1088 1376 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +} +// brush 289 +{ +( -1152 1312 64 ) ( -1152 1344 64 ) ( -1344 1344 64 ) we_cemetary/cemstair2 -127 -63 -90.00 1 1 0 0 0 +( -1152 1344 384 ) ( -1344 1344 384 ) ( -1344 1344 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -1344 1296 96 ) ( -1152 1304 80 ) ( -1344 1312 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -1152 1280 256 ) ( -1344 1280 256 ) ( -1344 1344 256 ) we_cemetary/cemstair2 -127 -63 -90.00 1 1 0 0 0 +( -1344 1296 208 ) ( -1152 1296 176 ) ( -1344 1296 144 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -1392 1328 256 ) ( -1376 1312 64 ) ( -1408 1344 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -1216 1344 256 ) ( -1216 1376 64 ) ( -1216 1312 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +} +// brush 290 +{ +( -1152 1312 64 ) ( -1152 1344 64 ) ( -1344 1344 64 ) we_cemetary/cemstair2 -127 -63 -90.00 1 1 0 0 0 +( -1152 1344 384 ) ( -1344 1344 384 ) ( -1344 1344 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -1344 1296 96 ) ( -1152 1304 80 ) ( -1344 1312 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -1152 1280 256 ) ( -1344 1280 256 ) ( -1344 1344 256 ) we_cemetary/cemstair2 -127 -63 -90.00 1 1 0 0 0 +( -1216 1296 208 ) ( -1024 1296 176 ) ( -1216 1296 144 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -896 1344 64 ) ( -928 1312 64 ) ( -912 1328 256 ) we_cemetary/cemstair2 64 0 0.00 1 1 0 0 0 +( -1088 1344 256 ) ( -1088 1312 64 ) ( -1088 1376 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +} +// brush 291 +{ +( -1344 1344 64 ) ( -1152 1344 64 ) ( -1152 1376 64 ) we_cemetary/cemstair2 64 -63 -90.00 1 1 0 0 0 +( -1344 1344 64 ) ( -1344 1344 384 ) ( -1152 1344 384 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -1344 1376 64 ) ( -1152 1384 80 ) ( -1344 1392 96 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -1344 1344 256 ) ( -1344 1408 256 ) ( -1152 1408 256 ) we_cemetary/cemstair2 64 -63 -90.00 1 1 0 0 0 +( -1248 1392 144 ) ( -1056 1392 176 ) ( -1248 1392 208 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -1088 1344 256 ) ( -1088 1312 64 ) ( -1088 1376 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( -896 1376 256 ) ( -896 1408 64 ) ( -896 1344 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +} +// brush 292 +{ +( -1344 1344 0 ) ( -1152 1344 0 ) ( -1152 1376 0 ) we_cemetary/cemtrim2 64 -63 -90.00 1 1 0 0 0 +( -1152 1376 64 ) ( -1152 1344 64 ) ( -1344 1344 64 ) we_cemetary/cemtrim2 64 -63 -90.00 1 1 0 0 0 +( -1056 1376 0 ) ( -1056 1376 320 ) ( -1248 1376 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( -1344 1344 0 ) ( -1344 1344 320 ) ( -1152 1344 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( -1088 1344 64 ) ( -1088 1312 0 ) ( -1088 1376 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( -896 1376 64 ) ( -896 1408 0 ) ( -896 1344 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +} +// brush 293 +{ +( -1344 1344 64 ) ( -1152 1344 64 ) ( -1152 1376 64 ) we_cemetary/cemstair2 64 -63 -90.00 1 1 0 0 0 +( -1344 1344 64 ) ( -1344 1344 384 ) ( -1152 1344 384 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -1344 1376 64 ) ( -1152 1384 80 ) ( -1344 1392 96 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -1344 1344 256 ) ( -1344 1408 256 ) ( -1152 1408 256 ) we_cemetary/cemstair2 64 -63 -90.00 1 1 0 0 0 +( -1344 1392 144 ) ( -1152 1392 176 ) ( -1344 1392 208 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -1216 1344 256 ) ( -1216 1376 64 ) ( -1216 1312 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( -1408 1392 256 ) ( -1408 1376 64 ) ( -1408 1408 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +} +// brush 294 +{ +( -1344 1344 0 ) ( -1152 1344 0 ) ( -1152 1376 0 ) we_cemetary/cemtrim2 64 -63 -90.00 1 1 0 0 0 +( -1152 1376 64 ) ( -1152 1344 64 ) ( -1344 1344 64 ) we_cemetary/cemtrim2 64 -63 -90.00 1 1 0 0 0 +( -1344 1376 0 ) ( -1344 1376 320 ) ( -1536 1376 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( -1344 1344 0 ) ( -1344 1344 320 ) ( -1152 1344 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( -1216 1344 64 ) ( -1216 1376 0 ) ( -1216 1312 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( -1408 1392 64 ) ( -1408 1376 0 ) ( -1408 1408 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +} +// brush 295 +{ +( -1152 1344 256 ) ( -1152 1392 256 ) ( -1344 1392 256 ) we_cemetary/fogtrunk 64 64 -90.00 1 1 0 0 0 +( -1152 1408 272 ) ( -1152 1344 272 ) ( -1344 1344 272 ) we_cemetary/fogtrunk 64 64 -90.00 1 1 0 0 0 +( -1344 1408 272 ) ( -1344 1392 256 ) ( -1152 1392 256 ) we_cemetary/fogtrunk 64 64 -90.00 1 1 0 0 0 +( -1344 1344 256 ) ( -1344 1344 272 ) ( -1152 1344 272 ) we_cemetary/fogtrunk -64 0 0.00 1 1 0 0 0 +( -896 1376 272 ) ( -896 1408 256 ) ( -896 1344 256 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +( -1408 1392 272 ) ( -1408 1376 256 ) ( -1408 1408 256 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +} +// brush 296 +{ +( -1344 1376 272 ) ( -1152 1376 272 ) ( -1152 1408 272 ) we_cemetary/cemrunner2 -64 -31 -90.00 1 1 0 0 0 +( -1152 1408 336 ) ( -1152 1376 336 ) ( -1344 1376 336 ) we_cemetary/cemtrim2 32 -63 -90.00 1 1 0 0 0 +( -1152 1408 272 ) ( -1152 1408 592 ) ( -1344 1408 592 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( -1344 1344 272 ) ( -1344 1344 592 ) ( -1152 1344 592 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( -896 1376 336 ) ( -896 1408 272 ) ( -896 1344 272 ) we_cemetary/cemtrim2 0 16 0.00 1 1 0 0 0 +( -1408 1392 336 ) ( -1408 1376 272 ) ( -1408 1408 272 ) we_cemetary/cemtrim2 0 16 0.00 1 1 0 0 0 +} +// brush 297 +{ +( -1376 1312 -32 ) ( -1376 864 -32 ) ( -928 864 -32 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( -928 864 0 ) ( -1376 864 0 ) ( -1376 1312 0 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( -928 1376 -64 ) ( -928 1376 0 ) ( -1376 1376 0 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( -896 864 -64 ) ( -896 864 0 ) ( -896 1312 0 ) we_cemetary/cemtrim5 64 0 0.00 1 1 0 0 0 +( -1376 832 -64 ) ( -1376 832 0 ) ( -928 832 0 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( -1408 1312 -64 ) ( -1408 1312 0 ) ( -1408 864 0 ) we_cemetary/cemtrim5 64 0 0.00 1 1 0 0 0 +} +// brush 298 +{ +( -1376 1312 336 ) ( -1376 864 336 ) ( -928 864 336 ) water/waterfloor2 0 -64 0.00 1 1 0 0 0 +( -928 864 352 ) ( -1376 864 352 ) ( -1376 1312 352 ) water/waterfloor2 0 -64 0.00 1 1 0 0 0 +( -928 1312 304 ) ( -928 1312 368 ) ( -1376 1312 368 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +( -928 864 304 ) ( -928 864 368 ) ( -928 1312 368 ) water/waterfloor2 64 0 0.00 1 1 0 0 0 +( -1376 864 304 ) ( -1376 864 368 ) ( -928 864 368 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +( -1376 1312 304 ) ( -1376 1312 368 ) ( -1376 864 368 ) water/waterfloor2 64 0 0.00 1 1 0 0 0 +} +// brush 299 +{ +( -1216 1392 208 ) ( -1216 1296 208 ) ( -1088 1296 208 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -1088 1296 256 ) ( -1216 1296 256 ) ( -1216 1392 256 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -1088 1392 64 ) ( -1088 1392 256 ) ( -1216 1392 256 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -1088 1296 48 ) ( -1088 1296 240 ) ( -1088 1392 240 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( -1216 1296 48 ) ( -1216 1296 240 ) ( -1088 1296 240 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -1216 1392 64 ) ( -1216 1392 256 ) ( -1216 1296 256 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +} +// brush 300 +{ +( -704 1392 208 ) ( -704 1296 208 ) ( -576 1296 208 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -576 1296 256 ) ( -704 1296 256 ) ( -704 1392 256 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -576 1392 64 ) ( -576 1392 256 ) ( -704 1392 256 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -576 1296 48 ) ( -576 1296 240 ) ( -576 1392 240 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( -704 1296 48 ) ( -704 1296 240 ) ( -576 1296 240 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -704 1392 64 ) ( -704 1392 256 ) ( -704 1296 256 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +} +// brush 301 +{ +( -864 1312 336 ) ( -864 864 336 ) ( -416 864 336 ) water/waterfloor2 0 -64 0.00 1 1 0 0 0 +( -416 864 352 ) ( -864 864 352 ) ( -864 1312 352 ) water/waterfloor2 0 -64 0.00 1 1 0 0 0 +( -416 1312 304 ) ( -416 1312 368 ) ( -864 1312 368 ) water/waterfloor2 0 -64 0.00 1 1 0 0 0 +( -416 864 304 ) ( -416 864 368 ) ( -416 1312 368 ) water/waterfloor2 0 -64 0.00 1 1 0 0 0 +( -864 864 304 ) ( -864 864 368 ) ( -416 864 368 ) water/waterfloor2 0 -64 0.00 1 1 0 0 0 +( -864 1312 304 ) ( -864 1312 368 ) ( -864 864 368 ) water/waterfloor2 0 -64 0.00 1 1 0 0 0 +} +// brush 302 +{ +( -864 1312 -32 ) ( -864 864 -32 ) ( -416 864 -32 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( -416 864 0 ) ( -864 864 0 ) ( -864 1312 0 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( -416 1376 -64 ) ( -416 1376 0 ) ( -864 1376 0 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( -384 864 -64 ) ( -384 864 0 ) ( -384 1312 0 ) we_cemetary/cemtrim5 64 0 0.00 1 1 0 0 0 +( -864 832 -64 ) ( -864 832 0 ) ( -416 832 0 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( -896 1312 -64 ) ( -896 1312 0 ) ( -896 864 0 ) we_cemetary/cemtrim5 64 0 0.00 1 1 0 0 0 +} +// brush 303 +{ +( -832 1376 272 ) ( -640 1376 272 ) ( -640 1408 272 ) we_cemetary/cemrunner2 -64 -31 -90.00 1 1 0 0 0 +( -640 1408 336 ) ( -640 1376 336 ) ( -832 1376 336 ) we_cemetary/cemtrim2 33 -63 -90.00 1 1 0 0 0 +( -640 1408 272 ) ( -640 1408 592 ) ( -832 1408 592 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( -832 1344 272 ) ( -832 1344 592 ) ( -640 1344 592 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( -384 1376 336 ) ( -384 1408 272 ) ( -384 1344 272 ) we_cemetary/cemtrim2 0 16 0.00 1 1 0 0 0 +( -896 1392 336 ) ( -896 1376 272 ) ( -896 1408 272 ) we_cemetary/cemtrim2 0 16 0.00 1 1 0 0 0 +} +// brush 304 +{ +( -640 1344 256 ) ( -640 1392 256 ) ( -832 1392 256 ) we_cemetary/fogtrunk 65 64 -90.00 1 1 0 0 0 +( -640 1408 272 ) ( -640 1344 272 ) ( -832 1344 272 ) we_cemetary/fogtrunk 65 64 -90.00 1 1 0 0 0 +( -832 1408 272 ) ( -832 1392 256 ) ( -640 1392 256 ) we_cemetary/fogtrunk 65 64 -90.00 1 1 0 0 0 +( -832 1344 256 ) ( -832 1344 272 ) ( -640 1344 272 ) we_cemetary/fogtrunk -64 0 0.00 1 1 0 0 0 +( -384 1376 272 ) ( -384 1408 256 ) ( -384 1344 256 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +( -896 1392 272 ) ( -896 1376 256 ) ( -896 1408 256 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +} +// brush 305 +{ +( -832 1344 0 ) ( -640 1344 0 ) ( -640 1376 0 ) we_cemetary/cemtrim2 65 -63 -90.00 1 1 0 0 0 +( -640 1376 64 ) ( -640 1344 64 ) ( -832 1344 64 ) we_cemetary/cemtrim2 65 -63 -90.00 1 1 0 0 0 +( -832 1376 0 ) ( -832 1376 320 ) ( -1024 1376 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( -832 1344 0 ) ( -832 1344 320 ) ( -640 1344 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( -704 1344 64 ) ( -704 1376 0 ) ( -704 1312 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( -896 1392 64 ) ( -896 1376 0 ) ( -896 1408 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +} +// brush 306 +{ +( -832 1344 64 ) ( -640 1344 64 ) ( -640 1376 64 ) we_cemetary/cemstair2 65 -63 -90.00 1 1 0 0 0 +( -832 1344 64 ) ( -832 1344 384 ) ( -640 1344 384 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -832 1376 64 ) ( -640 1384 80 ) ( -832 1392 96 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -832 1344 256 ) ( -832 1408 256 ) ( -640 1408 256 ) we_cemetary/cemstair2 65 -63 -90.00 1 1 0 0 0 +( -832 1392 144 ) ( -640 1392 176 ) ( -832 1392 208 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -704 1344 256 ) ( -704 1376 64 ) ( -704 1312 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( -896 1392 256 ) ( -896 1376 64 ) ( -896 1408 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +} +// brush 307 +{ +( -832 1344 0 ) ( -640 1344 0 ) ( -640 1376 0 ) we_cemetary/cemtrim2 65 -63 -90.00 1 1 0 0 0 +( -640 1376 64 ) ( -640 1344 64 ) ( -832 1344 64 ) we_cemetary/cemtrim2 65 -63 -90.00 1 1 0 0 0 +( -544 1376 0 ) ( -544 1376 320 ) ( -736 1376 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( -832 1344 0 ) ( -832 1344 320 ) ( -640 1344 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( -576 1344 64 ) ( -576 1312 0 ) ( -576 1376 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( -384 1376 64 ) ( -384 1408 0 ) ( -384 1344 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +} +// brush 308 +{ +( -832 1344 64 ) ( -640 1344 64 ) ( -640 1376 64 ) we_cemetary/cemstair2 65 -63 -90.00 1 1 0 0 0 +( -832 1344 64 ) ( -832 1344 384 ) ( -640 1344 384 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -832 1376 64 ) ( -640 1384 80 ) ( -832 1392 96 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -832 1344 256 ) ( -832 1408 256 ) ( -640 1408 256 ) we_cemetary/cemstair2 65 -63 -90.00 1 1 0 0 0 +( -736 1392 144 ) ( -544 1392 176 ) ( -736 1392 208 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -576 1344 256 ) ( -576 1312 64 ) ( -576 1376 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( -384 1376 256 ) ( -384 1408 64 ) ( -384 1344 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +} +// brush 309 +{ +( -640 1312 64 ) ( -640 1344 64 ) ( -832 1344 64 ) we_cemetary/cemstair2 -126 -63 -90.00 1 1 0 0 0 +( -640 1344 384 ) ( -832 1344 384 ) ( -832 1344 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -832 1296 96 ) ( -640 1304 80 ) ( -832 1312 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -640 1280 256 ) ( -832 1280 256 ) ( -832 1344 256 ) we_cemetary/cemstair2 -126 -63 -90.00 1 1 0 0 0 +( -704 1296 208 ) ( -512 1296 176 ) ( -704 1296 144 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -384 1344 64 ) ( -416 1312 64 ) ( -400 1328 256 ) we_cemetary/cemstair2 64 0 0.00 1 1 0 0 0 +( -576 1344 256 ) ( -576 1312 64 ) ( -576 1376 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +} +// brush 310 +{ +( -640 1312 64 ) ( -640 1344 64 ) ( -832 1344 64 ) we_cemetary/cemstair2 -126 -63 -90.00 1 1 0 0 0 +( -640 1344 384 ) ( -832 1344 384 ) ( -832 1344 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -832 1296 96 ) ( -640 1304 80 ) ( -832 1312 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -640 1280 256 ) ( -832 1280 256 ) ( -832 1344 256 ) we_cemetary/cemstair2 -126 -63 -90.00 1 1 0 0 0 +( -832 1296 208 ) ( -640 1296 176 ) ( -832 1296 144 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -880 1328 256 ) ( -864 1312 64 ) ( -896 1344 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -704 1344 256 ) ( -704 1376 64 ) ( -704 1312 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +} +// brush 311 +{ +( -640 1312 0 ) ( -640 1344 0 ) ( -832 1344 0 ) we_cemetary/cemtrim2 -126 -63 -90.00 1 1 0 0 0 +( -832 1344 64 ) ( -640 1344 64 ) ( -640 1312 64 ) we_cemetary/cemtrim2 -126 -63 -90.00 1 1 0 0 0 +( -832 1312 320 ) ( -640 1312 320 ) ( -640 1312 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( -640 1344 320 ) ( -832 1344 320 ) ( -832 1344 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( -384 1344 0 ) ( -416 1312 0 ) ( -400 1328 64 ) we_cemetary/cemtrim2 64 0 0.00 1 1 0 0 0 +( -576 1344 64 ) ( -576 1312 0 ) ( -576 1376 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +} +// brush 312 +{ +( -640 1312 0 ) ( -640 1344 0 ) ( -832 1344 0 ) we_cemetary/cemtrim2 -126 -63 -90.00 1 1 0 0 0 +( -832 1344 64 ) ( -640 1344 64 ) ( -640 1312 64 ) we_cemetary/cemtrim2 -126 -63 -90.00 1 1 0 0 0 +( -960 1312 320 ) ( -768 1312 320 ) ( -768 1312 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( -640 1344 320 ) ( -832 1344 320 ) ( -832 1344 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( -880 1328 64 ) ( -864 1312 0 ) ( -896 1344 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( -704 1344 64 ) ( -704 1376 0 ) ( -704 1312 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +} +// brush 313 +{ +( -896 1280 0 ) ( -896 1088 0 ) ( -864 1088 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( -864 1088 64 ) ( -896 1088 64 ) ( -896 1280 64 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( -864 1152 0 ) ( -864 1152 320 ) ( -864 1344 320 ) we_cemetary/cemtrim2 64 0 0.00 1 1 0 0 0 +( -896 1280 0 ) ( -896 1280 320 ) ( -896 1088 320 ) we_cemetary/cemtrim2 64 0 0.00 1 1 0 0 0 +( -880 848 64 ) ( -864 864 0 ) ( -896 832 0 ) we_cemetary/cemtrim2 64 0 0.00 1 1 0 0 0 +( -848 1296 64 ) ( -864 1312 0 ) ( -832 1280 0 ) we_cemetary/cemtrim2 64 0 0.00 1 1 0 0 0 +} +// brush 314 +{ +( -896 1280 64 ) ( -896 1088 64 ) ( -864 1088 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( -896 1280 64 ) ( -896 1280 384 ) ( -896 1088 384 ) we_cemetary/cemstair2 64 0 0.00 1 1 0 0 0 +( -864 1280 64 ) ( -856 1088 80 ) ( -848 1280 96 ) we_cemetary/cemstair2 64 0 0.00 1 1 0 0 0 +( -896 1280 256 ) ( -832 1280 256 ) ( -832 1088 256 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( -848 1280 144 ) ( -848 1088 176 ) ( -848 1280 208 ) we_cemetary/cemstair2 64 0 0.00 1 1 0 0 0 +( -880 848 256 ) ( -864 864 64 ) ( -896 832 64 ) we_cemetary/cemstair2 64 0 0.00 1 1 0 0 0 +( -848 1296 256 ) ( -864 1312 64 ) ( -832 1280 64 ) we_cemetary/cemstair2 64 0 0.00 1 1 0 0 0 +} +// brush 315 +{ +( -896 1088 256 ) ( -848 1088 256 ) ( -848 1280 256 ) we_cemetary/fogtrunk 0 -64 0.00 1 1 0 0 0 +( -832 1088 272 ) ( -896 1088 272 ) ( -896 1280 272 ) we_cemetary/fogtrunk 0 -64 0.00 1 1 0 0 0 +( -832 1280 272 ) ( -848 1280 256 ) ( -848 1088 256 ) we_cemetary/fogtrunk 0 -64 0.00 1 1 0 0 0 +( -896 1280 256 ) ( -896 1280 272 ) ( -896 1088 272 ) we_cemetary/fogtrunk 64 0 0.00 1 1 0 0 0 +( -880 848 272 ) ( -864 864 256 ) ( -896 832 256 ) we_cemetary/fogtrunk 64 0 0.00 1 1 0 0 0 +( -848 1296 272 ) ( -864 1312 256 ) ( -832 1280 256 ) we_cemetary/fogtrunk 64 0 0.00 1 1 0 0 0 +} +// brush 316 +{ +( -864 1280 272 ) ( -864 1088 272 ) ( -832 1088 272 ) we_cemetary/cemrunner2 0 0 0.00 1 1 0 0 0 +( -832 1088 336 ) ( -864 1088 336 ) ( -864 1280 336 ) we_cemetary/cemtrim2 -32 0 0.00 1 1 0 0 0 +( -832 1088 272 ) ( -832 1088 592 ) ( -832 1280 592 ) we_cemetary/cemtrim2 64 16 0.00 1 1 0 0 0 +( -896 1280 272 ) ( -896 1280 592 ) ( -896 1088 592 ) we_cemetary/cemtrim2 64 16 0.00 1 1 0 0 0 +( -880 848 336 ) ( -864 864 272 ) ( -896 832 272 ) we_cemetary/cemtrim2 64 16 0.00 1 1 0 0 0 +( -848 1296 336 ) ( -864 1312 272 ) ( -832 1280 272 ) we_cemetary/cemtrim2 64 16 0.00 1 1 0 0 0 +} +// brush 317 +{ +( -832 1296 256 ) ( -640 1296 256 ) ( -640 1344 256 ) we_cemetary/fogtrunk -126 64 -90.00 1 1 0 0 0 +( -832 1344 272 ) ( -640 1344 272 ) ( -640 1280 272 ) we_cemetary/fogtrunk -126 64 -90.00 1 1 0 0 0 +( -640 1296 256 ) ( -832 1296 256 ) ( -832 1280 272 ) we_cemetary/fogtrunk -126 64 -90.00 1 1 0 0 0 +( -640 1344 272 ) ( -832 1344 272 ) ( -832 1344 256 ) we_cemetary/fogtrunk -64 0 0.00 1 1 0 0 0 +( -384 1344 256 ) ( -416 1312 256 ) ( -400 1328 272 ) we_cemetary/fogtrunk 64 0 0.00 1 1 0 0 0 +( -880 1328 272 ) ( -864 1312 256 ) ( -896 1344 256 ) we_cemetary/fogtrunk -64 0 0.00 1 1 0 0 0 +} +// brush 318 +{ +( -640 1280 272 ) ( -640 1312 272 ) ( -832 1312 272 ) we_cemetary/cemrunner2 2 -31 -90.00 1 1 0 0 0 +( -832 1312 336 ) ( -640 1312 336 ) ( -640 1280 336 ) we_cemetary/cemtrim2 97 -63 -90.00 1 1 0 0 0 +( -832 1280 592 ) ( -640 1280 592 ) ( -640 1280 272 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( -640 1344 592 ) ( -832 1344 592 ) ( -832 1344 272 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( -384 1344 272 ) ( -416 1312 272 ) ( -400 1328 336 ) we_cemetary/cemtrim2 64 15 0.00 1 1 0 0 0 +( -880 1328 336 ) ( -864 1312 272 ) ( -896 1344 272 ) we_cemetary/cemtrim2 -64 16 0.00 1 1 0 0 0 +} +// brush 319 +{ +( -448 1088 272 ) ( -416 1088 272 ) ( -416 1280 272 ) we_cemetary/cemrunner2 63 0 -180.00 1 1 0 0 0 +( -416 1280 336 ) ( -416 1088 336 ) ( -448 1088 336 ) we_cemetary/cemtrim2 159 0 -180.00 1 1 0 0 0 +( -448 1280 592 ) ( -448 1088 592 ) ( -448 1088 272 ) we_cemetary/cemtrim2 0 14 -180.00 1 -1 0 0 0 +( -384 1088 592 ) ( -384 1280 592 ) ( -384 1280 272 ) we_cemetary/cemtrim2 0 14 -180.00 1 -1 0 0 0 +( -384 832 272 ) ( -416 864 272 ) ( -400 848 336 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( -400 1328 336 ) ( -416 1312 272 ) ( -384 1344 272 ) we_cemetary/cemtrim2 -64 15 -180.00 1 -1 0 0 0 +} +// brush 320 +{ +( -432 1280 256 ) ( -432 1088 256 ) ( -384 1088 256 ) we_cemetary/fogtrunk 191 0 -180.00 1 1 0 0 0 +( -384 1280 272 ) ( -384 1088 272 ) ( -448 1088 272 ) we_cemetary/fogtrunk 191 0 -180.00 1 1 0 0 0 +( -432 1088 256 ) ( -432 1280 256 ) ( -448 1280 272 ) we_cemetary/fogtrunk 191 0 -180.00 1 1 0 0 0 +( -384 1088 272 ) ( -384 1280 272 ) ( -384 1280 256 ) we_cemetary/fogtrunk 0 0 -180.00 1 -1 0 0 0 +( -384 832 256 ) ( -416 864 256 ) ( -400 848 272 ) we_cemetary/fogtrunk -64 0 0.00 1 1 0 0 0 +( -400 1328 272 ) ( -416 1312 256 ) ( -384 1344 256 ) we_cemetary/fogtrunk -64 0 -180.00 1 -1 0 0 0 +} +// brush 321 +{ +( -416 1088 64 ) ( -384 1088 64 ) ( -384 1280 64 ) we_cemetary/cemstair2 191 0 -180.00 1 1 0 0 0 +( -384 1088 384 ) ( -384 1280 384 ) ( -384 1280 64 ) we_cemetary/cemstair2 0 0 -180.00 1 -1 0 0 0 +( -432 1280 96 ) ( -424 1088 80 ) ( -416 1280 64 ) we_cemetary/cemstair2 0 0 -180.00 1 -1 0 0 0 +( -448 1088 256 ) ( -448 1280 256 ) ( -384 1280 256 ) we_cemetary/cemstair2 191 0 -180.00 1 1 0 0 0 +( -432 1280 208 ) ( -432 1088 176 ) ( -432 1280 144 ) we_cemetary/cemstair2 0 0 -180.00 1 -1 0 0 0 +( -384 832 64 ) ( -416 864 64 ) ( -400 848 256 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -400 1328 256 ) ( -416 1312 64 ) ( -384 1344 64 ) we_cemetary/cemstair2 -64 0 -180.00 1 -1 0 0 0 +} +// brush 322 +{ +( -416 1088 0 ) ( -384 1088 0 ) ( -384 1280 0 ) we_cemetary/cemtrim2 191 0 -180.00 1 1 0 0 0 +( -384 1280 64 ) ( -384 1088 64 ) ( -416 1088 64 ) we_cemetary/cemtrim2 191 0 -180.00 1 1 0 0 0 +( -416 1408 320 ) ( -416 1216 320 ) ( -416 1216 0 ) we_cemetary/cemtrim2 0 0 -180.00 1 -1 0 0 0 +( -384 1088 320 ) ( -384 1280 320 ) ( -384 1280 0 ) we_cemetary/cemtrim2 0 0 -180.00 1 -1 0 0 0 +( -384 832 0 ) ( -416 864 0 ) ( -400 848 64 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( -400 1328 64 ) ( -416 1312 0 ) ( -384 1344 0 ) we_cemetary/cemtrim2 -64 0 -180.00 1 -1 0 0 0 +} +// brush 323 +{ +( -640 864 0 ) ( -640 832 0 ) ( -448 832 0 ) we_cemetary/cemtrim2 3 0 90.00 1 1 0 0 0 +( -448 832 64 ) ( -640 832 64 ) ( -640 864 64 ) we_cemetary/cemtrim2 3 0 90.00 1 1 0 0 0 +( -384 864 320 ) ( -576 864 320 ) ( -576 864 0 ) we_cemetary/cemtrim2 128 0 -180.00 1 -1 0 0 0 +( -640 832 320 ) ( -448 832 320 ) ( -448 832 0 ) we_cemetary/cemtrim2 128 0 -180.00 1 -1 0 0 0 +( -896 832 0 ) ( -864 864 0 ) ( -880 848 64 ) we_cemetary/cemtrim2 128 0 -180.00 1 -1 0 0 0 +( -400 848 64 ) ( -416 864 0 ) ( -384 832 0 ) we_cemetary/cemtrim2 128 0 -180.00 1 -1 0 0 0 +} +// brush 324 +{ +( -640 864 64 ) ( -640 832 64 ) ( -448 832 64 ) we_cemetary/cemstair2 3 0 90.00 1 1 0 0 0 +( -640 832 384 ) ( -448 832 384 ) ( -448 832 64 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +( -448 880 96 ) ( -640 872 80 ) ( -448 864 64 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +( -640 896 256 ) ( -448 896 256 ) ( -448 832 256 ) we_cemetary/cemstair2 3 0 90.00 1 1 0 0 0 +( -448 880 208 ) ( -640 880 176 ) ( -448 880 144 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +( -896 832 64 ) ( -864 864 64 ) ( -880 848 256 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +( -400 848 256 ) ( -416 864 64 ) ( -384 832 64 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +} +// brush 325 +{ +( -448 880 256 ) ( -640 880 256 ) ( -640 832 256 ) we_cemetary/fogtrunk 3 -127 90.00 1 1 0 0 0 +( -448 832 272 ) ( -640 832 272 ) ( -640 896 272 ) we_cemetary/fogtrunk 3 -127 90.00 1 1 0 0 0 +( -640 880 256 ) ( -448 880 256 ) ( -448 896 272 ) we_cemetary/fogtrunk 3 -127 90.00 1 1 0 0 0 +( -640 832 272 ) ( -448 832 272 ) ( -448 832 256 ) we_cemetary/fogtrunk 128 0 -180.00 1 -1 0 0 0 +( -896 832 256 ) ( -864 864 256 ) ( -880 848 272 ) we_cemetary/fogtrunk 128 0 -180.00 1 -1 0 0 0 +( -400 848 272 ) ( -416 864 256 ) ( -384 832 256 ) we_cemetary/fogtrunk 128 0 -180.00 1 -1 0 0 0 +} +// brush 326 +{ +( -640 896 272 ) ( -640 864 272 ) ( -448 864 272 ) we_cemetary/cemrunner2 3 1 90.00 1 1.000122 0 0 0 +( -448 864 336 ) ( -640 864 336 ) ( -640 896 336 ) we_cemetary/cemtrim2 -29 0 90.00 1 1 0 0 0 +( -448 896 592 ) ( -640 896 592 ) ( -640 896 272 ) we_cemetary/cemtrim2 128 15 -180.00 1 -1 0 0 0 +( -640 832 592 ) ( -448 832 592 ) ( -448 832 272 ) we_cemetary/cemtrim2 128 15 -180.00 1 -1 0 0 0 +( -896 832 272 ) ( -864 864 272 ) ( -880 848 336 ) we_cemetary/cemtrim2 128 15 -180.00 1 -1 0 0 0 +( -400 848 336 ) ( -416 864 272 ) ( -384 832 272 ) we_cemetary/cemtrim2 128 15 -180.00 1 -1 0 0 0 +} +// brush 327 +{ +( -128 896 272 ) ( -128 864 272 ) ( 64 864 272 ) we_cemetary/cemrunner2 4 1 90.00 1 1.000122 0 0 0 +( 64 864 336 ) ( -128 864 336 ) ( -128 896 336 ) we_cemetary/cemtrim2 -28 0 90.00 1 1 0 0 0 +( 64 896 592 ) ( -128 896 592 ) ( -128 896 272 ) we_cemetary/cemtrim2 128 15 -180.00 1 -1 0 0 0 +( -128 832 592 ) ( 64 832 592 ) ( 64 832 272 ) we_cemetary/cemtrim2 128 15 -180.00 1 -1 0 0 0 +( -384 832 272 ) ( -352 864 272 ) ( -368 848 336 ) we_cemetary/cemtrim2 128 15 -180.00 1 -1 0 0 0 +( 112 848 336 ) ( 96 864 272 ) ( 128 832 272 ) we_cemetary/cemtrim2 128 15 -180.00 1 -1 0 0 0 +} +// brush 328 +{ +( 64 880 256 ) ( -128 880 256 ) ( -128 832 256 ) we_cemetary/fogtrunk 4 -127 90.00 1 1 0 0 0 +( 64 832 272 ) ( -128 832 272 ) ( -128 896 272 ) we_cemetary/fogtrunk 4 -127 90.00 1 1 0 0 0 +( -128 880 256 ) ( 64 880 256 ) ( 64 896 272 ) we_cemetary/fogtrunk 4 -127 90.00 1 1 0 0 0 +( -128 832 272 ) ( 64 832 272 ) ( 64 832 256 ) we_cemetary/fogtrunk 128 0 -180.00 1 -1 0 0 0 +( -384 832 256 ) ( -352 864 256 ) ( -368 848 272 ) we_cemetary/fogtrunk 128 0 -180.00 1 -1 0 0 0 +( 112 848 272 ) ( 96 864 256 ) ( 128 832 256 ) we_cemetary/fogtrunk 128 0 -180.00 1 -1 0 0 0 +} +// brush 329 +{ +( -128 864 64 ) ( -128 832 64 ) ( 64 832 64 ) we_cemetary/cemstair2 4 0 90.00 1 1 0 0 0 +( -128 832 384 ) ( 64 832 384 ) ( 64 832 64 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +( 64 880 96 ) ( -128 872 80 ) ( 64 864 64 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +( -128 896 256 ) ( 64 896 256 ) ( 64 832 256 ) we_cemetary/cemstair2 4 0 90.00 1 1 0 0 0 +( 64 880 208 ) ( -128 880 176 ) ( 64 880 144 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +( -384 832 64 ) ( -352 864 64 ) ( -368 848 256 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +( 112 848 256 ) ( 96 864 64 ) ( 128 832 64 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +} +// brush 330 +{ +( -128 864 0 ) ( -128 832 0 ) ( 64 832 0 ) we_cemetary/cemtrim2 4 0 90.00 1 1 0 0 0 +( 64 832 64 ) ( -128 832 64 ) ( -128 864 64 ) we_cemetary/cemtrim2 4 0 90.00 1 1 0 0 0 +( 128 864 320 ) ( -64 864 320 ) ( -64 864 0 ) we_cemetary/cemtrim2 128 0 -180.00 1 -1 0 0 0 +( -128 832 320 ) ( 64 832 320 ) ( 64 832 0 ) we_cemetary/cemtrim2 128 0 -180.00 1 -1 0 0 0 +( -384 832 0 ) ( -352 864 0 ) ( -368 848 64 ) we_cemetary/cemtrim2 128 0 -180.00 1 -1 0 0 0 +( 112 848 64 ) ( 96 864 0 ) ( 128 832 0 ) we_cemetary/cemtrim2 128 0 -180.00 1 -1 0 0 0 +} +// brush 331 +{ +( 96 1088 0 ) ( 128 1088 0 ) ( 128 1280 0 ) we_cemetary/cemtrim2 191 0 -180.00 1 1 0 0 0 +( 128 1280 64 ) ( 128 1088 64 ) ( 96 1088 64 ) we_cemetary/cemtrim2 191 0 -180.00 1 1 0 0 0 +( 96 1408 320 ) ( 96 1216 320 ) ( 96 1216 0 ) we_cemetary/cemtrim2 0 0 -180.00 1 -1 0 0 0 +( 128 1088 320 ) ( 128 1280 320 ) ( 128 1280 0 ) we_cemetary/cemtrim2 0 0 -180.00 1 -1 0 0 0 +( 128 832 0 ) ( 96 864 0 ) ( 112 848 64 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 112 1328 64 ) ( 96 1312 0 ) ( 128 1344 0 ) we_cemetary/cemtrim2 -64 0 -180.00 1 -1 0 0 0 +} +// brush 332 +{ +( 96 1088 64 ) ( 128 1088 64 ) ( 128 1280 64 ) we_cemetary/cemstair2 191 0 -180.00 1 1 0 0 0 +( 128 1088 384 ) ( 128 1280 384 ) ( 128 1280 64 ) we_cemetary/cemstair2 0 0 -180.00 1 -1 0 0 0 +( 80 1280 96 ) ( 88 1088 80 ) ( 96 1280 64 ) we_cemetary/cemstair2 0 0 -180.00 1 -1 0 0 0 +( 64 1088 256 ) ( 64 1280 256 ) ( 128 1280 256 ) we_cemetary/cemstair2 191 0 -180.00 1 1 0 0 0 +( 80 1280 208 ) ( 80 1088 176 ) ( 80 1280 144 ) we_cemetary/cemstair2 0 0 -180.00 1 -1 0 0 0 +( 128 832 64 ) ( 96 864 64 ) ( 112 848 256 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 112 1328 256 ) ( 96 1312 64 ) ( 128 1344 64 ) we_cemetary/cemstair2 -64 0 -180.00 1 -1 0 0 0 +} +// brush 333 +{ +( 80 1280 256 ) ( 80 1088 256 ) ( 128 1088 256 ) we_cemetary/fogtrunk 191 0 -180.00 1 1 0 0 0 +( 128 1280 272 ) ( 128 1088 272 ) ( 64 1088 272 ) we_cemetary/fogtrunk 191 0 -180.00 1 1 0 0 0 +( 80 1088 256 ) ( 80 1280 256 ) ( 64 1280 272 ) we_cemetary/fogtrunk 191 0 -180.00 1 1 0 0 0 +( 128 1088 272 ) ( 128 1280 272 ) ( 128 1280 256 ) we_cemetary/fogtrunk 0 0 -180.00 1 -1 0 0 0 +( 128 832 256 ) ( 96 864 256 ) ( 112 848 272 ) we_cemetary/fogtrunk -64 0 0.00 1 1 0 0 0 +( 112 1328 272 ) ( 96 1312 256 ) ( 128 1344 256 ) we_cemetary/fogtrunk -64 0 -180.00 1 -1 0 0 0 +} +// brush 334 +{ +( 64 1088 272 ) ( 96 1088 272 ) ( 96 1280 272 ) we_cemetary/cemrunner2 63 0 -180.00 1 1 0 0 0 +( 96 1280 336 ) ( 96 1088 336 ) ( 64 1088 336 ) we_cemetary/cemtrim2 159 0 -180.00 1 1 0 0 0 +( 64 1280 592 ) ( 64 1088 592 ) ( 64 1088 272 ) we_cemetary/cemtrim2 0 14 -180.00 1 -1 0 0 0 +( 128 1088 592 ) ( 128 1280 592 ) ( 128 1280 272 ) we_cemetary/cemtrim2 0 14 -180.00 1 -1 0 0 0 +( 128 832 272 ) ( 96 864 272 ) ( 112 848 336 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( 112 1328 336 ) ( 96 1312 272 ) ( 128 1344 272 ) we_cemetary/cemtrim2 -64 15 -180.00 1 -1 0 0 0 +} +// brush 335 +{ +( -128 1280 272 ) ( -128 1312 272 ) ( -320 1312 272 ) we_cemetary/cemrunner2 3 -31 -90.00 1 1 0 0 0 +( -320 1312 336 ) ( -128 1312 336 ) ( -128 1280 336 ) we_cemetary/cemtrim2 98 -63 -90.00 1 1 0 0 0 +( -320 1280 592 ) ( -128 1280 592 ) ( -128 1280 272 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( -128 1344 592 ) ( -320 1344 592 ) ( -320 1344 272 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( 128 1344 272 ) ( 96 1312 272 ) ( 112 1328 336 ) we_cemetary/cemtrim2 64 15 0.00 1 1 0 0 0 +( -368 1328 336 ) ( -352 1312 272 ) ( -384 1344 272 ) we_cemetary/cemtrim2 -64 16 0.00 1 1 0 0 0 +} +// brush 336 +{ +( -320 1296 256 ) ( -128 1296 256 ) ( -128 1344 256 ) we_cemetary/fogtrunk -125 64 -90.00 1 1 0 0 0 +( -320 1344 272 ) ( -128 1344 272 ) ( -128 1280 272 ) we_cemetary/fogtrunk -125 64 -90.00 1 1 0 0 0 +( -128 1296 256 ) ( -320 1296 256 ) ( -320 1280 272 ) we_cemetary/fogtrunk -125 64 -90.00 1 1 0 0 0 +( -128 1344 272 ) ( -320 1344 272 ) ( -320 1344 256 ) we_cemetary/fogtrunk -64 0 0.00 1 1 0 0 0 +( 128 1344 256 ) ( 96 1312 256 ) ( 112 1328 272 ) we_cemetary/fogtrunk 64 0 0.00 1 1 0 0 0 +( -368 1328 272 ) ( -352 1312 256 ) ( -384 1344 256 ) we_cemetary/fogtrunk -64 0 0.00 1 1 0 0 0 +} +// brush 337 +{ +( -352 1280 272 ) ( -352 1088 272 ) ( -320 1088 272 ) we_cemetary/cemrunner2 0 0 0.00 1 1 0 0 0 +( -320 1088 336 ) ( -352 1088 336 ) ( -352 1280 336 ) we_cemetary/cemtrim2 -32 0 0.00 1 1 0 0 0 +( -320 1088 272 ) ( -320 1088 592 ) ( -320 1280 592 ) we_cemetary/cemtrim2 64 16 0.00 1 1 0 0 0 +( -384 1280 272 ) ( -384 1280 592 ) ( -384 1088 592 ) we_cemetary/cemtrim2 64 16 0.00 1 1 0 0 0 +( -368 848 336 ) ( -352 864 272 ) ( -384 832 272 ) we_cemetary/cemtrim2 64 16 0.00 1 1 0 0 0 +( -336 1296 336 ) ( -352 1312 272 ) ( -320 1280 272 ) we_cemetary/cemtrim2 64 16 0.00 1 1 0 0 0 +} +// brush 338 +{ +( -384 1088 256 ) ( -336 1088 256 ) ( -336 1280 256 ) we_cemetary/fogtrunk 0 -64 0.00 1 1 0 0 0 +( -320 1088 272 ) ( -384 1088 272 ) ( -384 1280 272 ) we_cemetary/fogtrunk 0 -64 0.00 1 1 0 0 0 +( -320 1280 272 ) ( -336 1280 256 ) ( -336 1088 256 ) we_cemetary/fogtrunk 0 -64 0.00 1 1 0 0 0 +( -384 1280 256 ) ( -384 1280 272 ) ( -384 1088 272 ) we_cemetary/fogtrunk 64 0 0.00 1 1 0 0 0 +( -368 848 272 ) ( -352 864 256 ) ( -384 832 256 ) we_cemetary/fogtrunk 64 0 0.00 1 1 0 0 0 +( -336 1296 272 ) ( -352 1312 256 ) ( -320 1280 256 ) we_cemetary/fogtrunk 64 0 0.00 1 1 0 0 0 +} +// brush 339 +{ +( -384 1280 64 ) ( -384 1088 64 ) ( -352 1088 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( -384 1280 64 ) ( -384 1280 384 ) ( -384 1088 384 ) we_cemetary/cemstair2 64 0 0.00 1 1 0 0 0 +( -352 1280 64 ) ( -344 1088 80 ) ( -336 1280 96 ) we_cemetary/cemstair2 64 0 0.00 1 1 0 0 0 +( -384 1280 256 ) ( -320 1280 256 ) ( -320 1088 256 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( -336 1280 144 ) ( -336 1088 176 ) ( -336 1280 208 ) we_cemetary/cemstair2 64 0 0.00 1 1 0 0 0 +( -368 848 256 ) ( -352 864 64 ) ( -384 832 64 ) we_cemetary/cemstair2 64 0 0.00 1 1 0 0 0 +( -336 1296 256 ) ( -352 1312 64 ) ( -320 1280 64 ) we_cemetary/cemstair2 64 0 0.00 1 1 0 0 0 +} +// brush 340 +{ +( -384 1280 0 ) ( -384 1088 0 ) ( -352 1088 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( -352 1088 64 ) ( -384 1088 64 ) ( -384 1280 64 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( -352 1152 0 ) ( -352 1152 320 ) ( -352 1344 320 ) we_cemetary/cemtrim2 64 0 0.00 1 1 0 0 0 +( -384 1280 0 ) ( -384 1280 320 ) ( -384 1088 320 ) we_cemetary/cemtrim2 64 0 0.00 1 1 0 0 0 +( -368 848 64 ) ( -352 864 0 ) ( -384 832 0 ) we_cemetary/cemtrim2 64 0 0.00 1 1 0 0 0 +( -336 1296 64 ) ( -352 1312 0 ) ( -320 1280 0 ) we_cemetary/cemtrim2 64 0 0.00 1 1 0 0 0 +} +// brush 341 +{ +( -128 1312 0 ) ( -128 1344 0 ) ( -320 1344 0 ) we_cemetary/cemtrim2 -125 -63 -90.00 1 1 0 0 0 +( -320 1344 64 ) ( -128 1344 64 ) ( -128 1312 64 ) we_cemetary/cemtrim2 -125 -63 -90.00 1 1 0 0 0 +( -448 1312 320 ) ( -256 1312 320 ) ( -256 1312 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( -128 1344 320 ) ( -320 1344 320 ) ( -320 1344 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( -368 1328 64 ) ( -352 1312 0 ) ( -384 1344 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( -192 1344 64 ) ( -192 1376 0 ) ( -192 1312 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +} +// brush 342 +{ +( -128 1312 0 ) ( -128 1344 0 ) ( -320 1344 0 ) we_cemetary/cemtrim2 -125 -63 -90.00 1 1 0 0 0 +( -320 1344 64 ) ( -128 1344 64 ) ( -128 1312 64 ) we_cemetary/cemtrim2 -125 -63 -90.00 1 1 0 0 0 +( -320 1312 320 ) ( -128 1312 320 ) ( -128 1312 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( -128 1344 320 ) ( -320 1344 320 ) ( -320 1344 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 128 1344 0 ) ( 96 1312 0 ) ( 112 1328 64 ) we_cemetary/cemtrim2 64 0 0.00 1 1 0 0 0 +( -64 1344 64 ) ( -64 1312 0 ) ( -64 1376 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +} +// brush 343 +{ +( -128 1312 64 ) ( -128 1344 64 ) ( -320 1344 64 ) we_cemetary/cemstair2 -125 -63 -90.00 1 1 0 0 0 +( -128 1344 384 ) ( -320 1344 384 ) ( -320 1344 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -320 1296 96 ) ( -128 1304 80 ) ( -320 1312 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -128 1280 256 ) ( -320 1280 256 ) ( -320 1344 256 ) we_cemetary/cemstair2 -125 -63 -90.00 1 1 0 0 0 +( -320 1296 208 ) ( -128 1296 176 ) ( -320 1296 144 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -368 1328 256 ) ( -352 1312 64 ) ( -384 1344 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -192 1344 256 ) ( -192 1376 64 ) ( -192 1312 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +} +// brush 344 +{ +( -128 1312 64 ) ( -128 1344 64 ) ( -320 1344 64 ) we_cemetary/cemstair2 -125 -63 -90.00 1 1 0 0 0 +( -128 1344 384 ) ( -320 1344 384 ) ( -320 1344 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -320 1296 96 ) ( -128 1304 80 ) ( -320 1312 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -128 1280 256 ) ( -320 1280 256 ) ( -320 1344 256 ) we_cemetary/cemstair2 -125 -63 -90.00 1 1 0 0 0 +( -192 1296 208 ) ( 0 1296 176 ) ( -192 1296 144 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 128 1344 64 ) ( 96 1312 64 ) ( 112 1328 256 ) we_cemetary/cemstair2 64 0 0.00 1 1 0 0 0 +( -64 1344 256 ) ( -64 1312 64 ) ( -64 1376 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +} +// brush 345 +{ +( -320 1344 64 ) ( -128 1344 64 ) ( -128 1376 64 ) we_cemetary/cemstair2 66 -63 -90.00 1 1 0 0 0 +( -320 1344 64 ) ( -320 1344 384 ) ( -128 1344 384 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -320 1376 64 ) ( -128 1384 80 ) ( -320 1392 96 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -320 1344 256 ) ( -320 1408 256 ) ( -128 1408 256 ) we_cemetary/cemstair2 66 -63 -90.00 1 1 0 0 0 +( -224 1392 144 ) ( -32 1392 176 ) ( -224 1392 208 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -64 1344 256 ) ( -64 1312 64 ) ( -64 1376 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 128 1376 256 ) ( 128 1408 64 ) ( 128 1344 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +} +// brush 346 +{ +( -320 1344 0 ) ( -128 1344 0 ) ( -128 1376 0 ) we_cemetary/cemtrim2 66 -63 -90.00 1 1 0 0 0 +( -128 1376 64 ) ( -128 1344 64 ) ( -320 1344 64 ) we_cemetary/cemtrim2 66 -63 -90.00 1 1 0 0 0 +( -32 1376 0 ) ( -32 1376 320 ) ( -224 1376 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( -320 1344 0 ) ( -320 1344 320 ) ( -128 1344 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( -64 1344 64 ) ( -64 1312 0 ) ( -64 1376 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( 128 1376 64 ) ( 128 1408 0 ) ( 128 1344 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +} +// brush 347 +{ +( -320 1344 64 ) ( -128 1344 64 ) ( -128 1376 64 ) we_cemetary/cemstair2 66 -63 -90.00 1 1 0 0 0 +( -320 1344 64 ) ( -320 1344 384 ) ( -128 1344 384 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -320 1376 64 ) ( -128 1384 80 ) ( -320 1392 96 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -320 1344 256 ) ( -320 1408 256 ) ( -128 1408 256 ) we_cemetary/cemstair2 66 -63 -90.00 1 1 0 0 0 +( -320 1392 144 ) ( -128 1392 176 ) ( -320 1392 208 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -192 1344 256 ) ( -192 1376 64 ) ( -192 1312 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( -384 1392 256 ) ( -384 1376 64 ) ( -384 1408 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +} +// brush 348 +{ +( -320 1344 0 ) ( -128 1344 0 ) ( -128 1376 0 ) we_cemetary/cemtrim2 66 -63 -90.00 1 1 0 0 0 +( -128 1376 64 ) ( -128 1344 64 ) ( -320 1344 64 ) we_cemetary/cemtrim2 66 -63 -90.00 1 1 0 0 0 +( -320 1376 0 ) ( -320 1376 320 ) ( -512 1376 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( -320 1344 0 ) ( -320 1344 320 ) ( -128 1344 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( -192 1344 64 ) ( -192 1376 0 ) ( -192 1312 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( -384 1392 64 ) ( -384 1376 0 ) ( -384 1408 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +} +// brush 349 +{ +( -128 1344 256 ) ( -128 1392 256 ) ( -320 1392 256 ) we_cemetary/fogtrunk 66 64 -90.00 1 1 0 0 0 +( -128 1408 272 ) ( -128 1344 272 ) ( -320 1344 272 ) we_cemetary/fogtrunk 66 64 -90.00 1 1 0 0 0 +( -320 1408 272 ) ( -320 1392 256 ) ( -128 1392 256 ) we_cemetary/fogtrunk 66 64 -90.00 1 1 0 0 0 +( -320 1344 256 ) ( -320 1344 272 ) ( -128 1344 272 ) we_cemetary/fogtrunk -64 0 0.00 1 1 0 0 0 +( 128 1376 272 ) ( 128 1408 256 ) ( 128 1344 256 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +( -384 1392 272 ) ( -384 1376 256 ) ( -384 1408 256 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +} +// brush 350 +{ +( -320 1376 272 ) ( -128 1376 272 ) ( -128 1408 272 ) we_cemetary/cemrunner2 -64 -31 -90.00 1 1 0 0 0 +( -128 1408 336 ) ( -128 1376 336 ) ( -320 1376 336 ) we_cemetary/cemtrim2 34 -63 -90.00 1 1 0 0 0 +( -128 1408 272 ) ( -128 1408 592 ) ( -320 1408 592 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( -320 1344 272 ) ( -320 1344 592 ) ( -128 1344 592 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( 128 1376 336 ) ( 128 1408 272 ) ( 128 1344 272 ) we_cemetary/cemtrim2 0 16 0.00 1 1 0 0 0 +( -384 1392 336 ) ( -384 1376 272 ) ( -384 1408 272 ) we_cemetary/cemtrim2 0 16 0.00 1 1 0 0 0 +} +// brush 351 +{ +( -352 1312 -32 ) ( -352 864 -32 ) ( 96 864 -32 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 96 864 0 ) ( -352 864 0 ) ( -352 1312 0 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 96 1376 -64 ) ( 96 1376 0 ) ( -352 1376 0 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 128 864 -64 ) ( 128 864 0 ) ( 128 1312 0 ) we_cemetary/cemtrim5 64 0 0.00 1 1 0 0 0 +( -352 832 -64 ) ( -352 832 0 ) ( 96 832 0 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( -384 1312 -64 ) ( -384 1312 0 ) ( -384 864 0 ) we_cemetary/cemtrim5 64 0 0.00 1 1 0 0 0 +} +// brush 352 +{ +( -352 1312 336 ) ( -352 864 336 ) ( 96 864 336 ) water/waterfloor2 0 -64 0.00 1 1 0 0 0 +( 96 864 352 ) ( -352 864 352 ) ( -352 1312 352 ) water/waterfloor2 0 -64 0.00 1 1 0 0 0 +( 96 1312 304 ) ( 96 1312 368 ) ( -352 1312 368 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +( 96 864 304 ) ( 96 864 368 ) ( 96 1312 368 ) water/waterfloor2 64 0 0.00 1 1 0 0 0 +( -352 864 304 ) ( -352 864 368 ) ( 96 864 368 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +( -352 1312 304 ) ( -352 1312 368 ) ( -352 864 368 ) water/waterfloor2 64 0 0.00 1 1 0 0 0 +} +// brush 353 +{ +( -192 1392 208 ) ( -192 1296 208 ) ( -64 1296 208 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -64 1296 256 ) ( -192 1296 256 ) ( -192 1392 256 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -64 1392 64 ) ( -64 1392 256 ) ( -192 1392 256 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -64 1296 48 ) ( -64 1296 240 ) ( -64 1392 240 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( -192 1296 48 ) ( -192 1296 240 ) ( -64 1296 240 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -192 1392 64 ) ( -192 1392 256 ) ( -192 1296 256 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +} +// brush 354 +{ +( 320 1392 208 ) ( 320 1296 208 ) ( 448 1296 208 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 448 1296 256 ) ( 320 1296 256 ) ( 320 1392 256 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 448 1392 64 ) ( 448 1392 256 ) ( 320 1392 256 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 448 1296 48 ) ( 448 1296 240 ) ( 448 1392 240 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 320 1296 48 ) ( 320 1296 240 ) ( 448 1296 240 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 320 1392 64 ) ( 320 1392 256 ) ( 320 1296 256 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +} +// brush 355 +{ +( 160 1312 336 ) ( 160 864 336 ) ( 608 864 336 ) water/waterfloor2 0 -64 0.00 1 1 0 0 0 +( 608 864 352 ) ( 160 864 352 ) ( 160 1312 352 ) water/waterfloor2 0 -64 0.00 1 1 0 0 0 +( 608 1312 304 ) ( 608 1312 368 ) ( 160 1312 368 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +( 608 864 304 ) ( 608 864 368 ) ( 608 1312 368 ) water/waterfloor2 64 0 0.00 1 1 0 0 0 +( 160 864 304 ) ( 160 864 368 ) ( 608 864 368 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +( 160 1312 304 ) ( 160 1312 368 ) ( 160 864 368 ) water/waterfloor2 64 0 0.00 1 1 0 0 0 +} +// brush 356 +{ +( 160 1312 -32 ) ( 160 864 -32 ) ( 608 864 -32 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 608 864 0 ) ( 160 864 0 ) ( 160 1312 0 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 608 1376 -64 ) ( 608 1376 0 ) ( 160 1376 0 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 640 864 -64 ) ( 640 864 0 ) ( 640 1312 0 ) we_cemetary/cemtrim5 64 0 0.00 1 1 0 0 0 +( 160 832 -64 ) ( 160 832 0 ) ( 608 832 0 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 128 1312 -64 ) ( 128 1312 0 ) ( 128 864 0 ) we_cemetary/cemtrim5 64 0 0.00 1 1 0 0 0 +} +// brush 357 +{ +( 192 1376 272 ) ( 384 1376 272 ) ( 384 1408 272 ) we_cemetary/cemrunner2 -64 -31 -90.00 1 1 0 0 0 +( 384 1408 336 ) ( 384 1376 336 ) ( 192 1376 336 ) we_cemetary/cemtrim2 35 -63 -90.00 1 1 0 0 0 +( 384 1408 272 ) ( 384 1408 592 ) ( 192 1408 592 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( 192 1344 272 ) ( 192 1344 592 ) ( 384 1344 592 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( 640 1376 336 ) ( 640 1408 272 ) ( 640 1344 272 ) we_cemetary/cemtrim2 0 16 0.00 1 1 0 0 0 +( 128 1392 336 ) ( 128 1376 272 ) ( 128 1408 272 ) we_cemetary/cemtrim2 0 16 0.00 1 1 0 0 0 +} +// brush 358 +{ +( 384 1344 256 ) ( 384 1392 256 ) ( 192 1392 256 ) we_cemetary/fogtrunk 67 64 -90.00 1 1 0 0 0 +( 384 1408 272 ) ( 384 1344 272 ) ( 192 1344 272 ) we_cemetary/fogtrunk 67 64 -90.00 1 1 0 0 0 +( 192 1408 272 ) ( 192 1392 256 ) ( 384 1392 256 ) we_cemetary/fogtrunk 67 64 -90.00 1 1 0 0 0 +( 192 1344 256 ) ( 192 1344 272 ) ( 384 1344 272 ) we_cemetary/fogtrunk -64 0 0.00 1 1 0 0 0 +( 640 1376 272 ) ( 640 1408 256 ) ( 640 1344 256 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +( 128 1392 272 ) ( 128 1376 256 ) ( 128 1408 256 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +} +// brush 359 +{ +( 192 1344 0 ) ( 384 1344 0 ) ( 384 1376 0 ) we_cemetary/cemtrim2 67 -63 -90.00 1 1 0 0 0 +( 384 1376 64 ) ( 384 1344 64 ) ( 192 1344 64 ) we_cemetary/cemtrim2 67 -63 -90.00 1 1 0 0 0 +( 192 1376 0 ) ( 192 1376 320 ) ( 0 1376 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 192 1344 0 ) ( 192 1344 320 ) ( 384 1344 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 320 1344 64 ) ( 320 1376 0 ) ( 320 1312 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( 128 1392 64 ) ( 128 1376 0 ) ( 128 1408 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +} +// brush 360 +{ +( 192 1344 64 ) ( 384 1344 64 ) ( 384 1376 64 ) we_cemetary/cemstair2 67 -63 -90.00 1 1 0 0 0 +( 192 1344 64 ) ( 192 1344 384 ) ( 384 1344 384 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 192 1376 64 ) ( 384 1384 80 ) ( 192 1392 96 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 192 1344 256 ) ( 192 1408 256 ) ( 384 1408 256 ) we_cemetary/cemstair2 67 -63 -90.00 1 1 0 0 0 +( 192 1392 144 ) ( 384 1392 176 ) ( 192 1392 208 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 320 1344 256 ) ( 320 1376 64 ) ( 320 1312 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 128 1392 256 ) ( 128 1376 64 ) ( 128 1408 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +} +// brush 361 +{ +( 192 1344 0 ) ( 384 1344 0 ) ( 384 1376 0 ) we_cemetary/cemtrim2 67 -63 -90.00 1 1 0 0 0 +( 384 1376 64 ) ( 384 1344 64 ) ( 192 1344 64 ) we_cemetary/cemtrim2 67 -63 -90.00 1 1 0 0 0 +( 480 1376 0 ) ( 480 1376 320 ) ( 288 1376 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 192 1344 0 ) ( 192 1344 320 ) ( 384 1344 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 448 1344 64 ) ( 448 1312 0 ) ( 448 1376 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( 640 1376 64 ) ( 640 1408 0 ) ( 640 1344 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +} +// brush 362 +{ +( 192 1344 64 ) ( 384 1344 64 ) ( 384 1376 64 ) we_cemetary/cemstair2 67 -63 -90.00 1 1 0 0 0 +( 192 1344 64 ) ( 192 1344 384 ) ( 384 1344 384 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 192 1376 64 ) ( 384 1384 80 ) ( 192 1392 96 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 192 1344 256 ) ( 192 1408 256 ) ( 384 1408 256 ) we_cemetary/cemstair2 67 -63 -90.00 1 1 0 0 0 +( 288 1392 144 ) ( 480 1392 176 ) ( 288 1392 208 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 448 1344 256 ) ( 448 1312 64 ) ( 448 1376 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 640 1376 256 ) ( 640 1408 64 ) ( 640 1344 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +} +// brush 363 +{ +( 384 1312 64 ) ( 384 1344 64 ) ( 192 1344 64 ) we_cemetary/cemstair2 -124 -63 -90.00 1 1 0 0 0 +( 384 1344 384 ) ( 192 1344 384 ) ( 192 1344 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 192 1296 96 ) ( 384 1304 80 ) ( 192 1312 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 384 1280 256 ) ( 192 1280 256 ) ( 192 1344 256 ) we_cemetary/cemstair2 -124 -63 -90.00 1 1 0 0 0 +( 320 1296 208 ) ( 512 1296 176 ) ( 320 1296 144 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 640 1344 64 ) ( 608 1312 64 ) ( 624 1328 256 ) we_cemetary/cemstair2 64 0 0.00 1 1 0 0 0 +( 448 1344 256 ) ( 448 1312 64 ) ( 448 1376 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +} +// brush 364 +{ +( 384 1312 64 ) ( 384 1344 64 ) ( 192 1344 64 ) we_cemetary/cemstair2 -124 -63 -90.00 1 1 0 0 0 +( 384 1344 384 ) ( 192 1344 384 ) ( 192 1344 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 192 1296 96 ) ( 384 1304 80 ) ( 192 1312 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 384 1280 256 ) ( 192 1280 256 ) ( 192 1344 256 ) we_cemetary/cemstair2 -124 -63 -90.00 1 1 0 0 0 +( 192 1296 208 ) ( 384 1296 176 ) ( 192 1296 144 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 144 1328 256 ) ( 160 1312 64 ) ( 128 1344 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 320 1344 256 ) ( 320 1376 64 ) ( 320 1312 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +} +// brush 365 +{ +( 384 1312 0 ) ( 384 1344 0 ) ( 192 1344 0 ) we_cemetary/cemtrim2 -124 -63 -90.00 1 1 0 0 0 +( 192 1344 64 ) ( 384 1344 64 ) ( 384 1312 64 ) we_cemetary/cemtrim2 -124 -63 -90.00 1 1 0 0 0 +( 192 1312 320 ) ( 384 1312 320 ) ( 384 1312 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 384 1344 320 ) ( 192 1344 320 ) ( 192 1344 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 640 1344 0 ) ( 608 1312 0 ) ( 624 1328 64 ) we_cemetary/cemtrim2 64 0 0.00 1 1 0 0 0 +( 448 1344 64 ) ( 448 1312 0 ) ( 448 1376 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +} +// brush 366 +{ +( 384 1312 0 ) ( 384 1344 0 ) ( 192 1344 0 ) we_cemetary/cemtrim2 -124 -63 -90.00 1 1 0 0 0 +( 192 1344 64 ) ( 384 1344 64 ) ( 384 1312 64 ) we_cemetary/cemtrim2 -124 -63 -90.00 1 1 0 0 0 +( 64 1312 320 ) ( 256 1312 320 ) ( 256 1312 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 384 1344 320 ) ( 192 1344 320 ) ( 192 1344 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 144 1328 64 ) ( 160 1312 0 ) ( 128 1344 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 320 1344 64 ) ( 320 1376 0 ) ( 320 1312 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +} +// brush 367 +{ +( 128 1280 0 ) ( 128 1088 0 ) ( 160 1088 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( 160 1088 64 ) ( 128 1088 64 ) ( 128 1280 64 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( 160 1152 0 ) ( 160 1152 320 ) ( 160 1344 320 ) we_cemetary/cemtrim2 64 0 0.00 1 1 0 0 0 +( 128 1280 0 ) ( 128 1280 320 ) ( 128 1088 320 ) we_cemetary/cemtrim2 64 0 0.00 1 1 0 0 0 +( 144 848 64 ) ( 160 864 0 ) ( 128 832 0 ) we_cemetary/cemtrim2 64 0 0.00 1 1 0 0 0 +( 176 1296 64 ) ( 160 1312 0 ) ( 192 1280 0 ) we_cemetary/cemtrim2 64 0 0.00 1 1 0 0 0 +} +// brush 368 +{ +( 128 1280 64 ) ( 128 1088 64 ) ( 160 1088 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 128 1280 64 ) ( 128 1280 384 ) ( 128 1088 384 ) we_cemetary/cemstair2 64 0 0.00 1 1 0 0 0 +( 160 1280 64 ) ( 168 1088 80 ) ( 176 1280 96 ) we_cemetary/cemstair2 64 0 0.00 1 1 0 0 0 +( 128 1280 256 ) ( 192 1280 256 ) ( 192 1088 256 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 176 1280 144 ) ( 176 1088 176 ) ( 176 1280 208 ) we_cemetary/cemstair2 64 0 0.00 1 1 0 0 0 +( 144 848 256 ) ( 160 864 64 ) ( 128 832 64 ) we_cemetary/cemstair2 64 0 0.00 1 1 0 0 0 +( 176 1296 256 ) ( 160 1312 64 ) ( 192 1280 64 ) we_cemetary/cemstair2 64 0 0.00 1 1 0 0 0 +} +// brush 369 +{ +( 128 1088 256 ) ( 176 1088 256 ) ( 176 1280 256 ) we_cemetary/fogtrunk 0 -64 0.00 1 1 0 0 0 +( 192 1088 272 ) ( 128 1088 272 ) ( 128 1280 272 ) we_cemetary/fogtrunk 0 -64 0.00 1 1 0 0 0 +( 192 1280 272 ) ( 176 1280 256 ) ( 176 1088 256 ) we_cemetary/fogtrunk 0 -64 0.00 1 1 0 0 0 +( 128 1280 256 ) ( 128 1280 272 ) ( 128 1088 272 ) we_cemetary/fogtrunk 64 0 0.00 1 1 0 0 0 +( 144 848 272 ) ( 160 864 256 ) ( 128 832 256 ) we_cemetary/fogtrunk 64 0 0.00 1 1 0 0 0 +( 176 1296 272 ) ( 160 1312 256 ) ( 192 1280 256 ) we_cemetary/fogtrunk 64 0 0.00 1 1 0 0 0 +} +// brush 370 +{ +( 160 1280 272 ) ( 160 1088 272 ) ( 192 1088 272 ) we_cemetary/cemrunner2 0 0 0.00 1 1 0 0 0 +( 192 1088 336 ) ( 160 1088 336 ) ( 160 1280 336 ) we_cemetary/cemtrim2 -32 0 0.00 1 1 0 0 0 +( 192 1088 272 ) ( 192 1088 592 ) ( 192 1280 592 ) we_cemetary/cemtrim2 64 16 0.00 1 1 0 0 0 +( 128 1280 272 ) ( 128 1280 592 ) ( 128 1088 592 ) we_cemetary/cemtrim2 64 16 0.00 1 1 0 0 0 +( 144 848 336 ) ( 160 864 272 ) ( 128 832 272 ) we_cemetary/cemtrim2 64 16 0.00 1 1 0 0 0 +( 176 1296 336 ) ( 160 1312 272 ) ( 192 1280 272 ) we_cemetary/cemtrim2 64 16 0.00 1 1 0 0 0 +} +// brush 371 +{ +( 192 1296 256 ) ( 384 1296 256 ) ( 384 1344 256 ) we_cemetary/fogtrunk -124 64 -90.00 1 1 0 0 0 +( 192 1344 272 ) ( 384 1344 272 ) ( 384 1280 272 ) we_cemetary/fogtrunk -124 64 -90.00 1 1 0 0 0 +( 384 1296 256 ) ( 192 1296 256 ) ( 192 1280 272 ) we_cemetary/fogtrunk -124 64 -90.00 1 1 0 0 0 +( 384 1344 272 ) ( 192 1344 272 ) ( 192 1344 256 ) we_cemetary/fogtrunk -64 0 0.00 1 1 0 0 0 +( 640 1344 256 ) ( 608 1312 256 ) ( 624 1328 272 ) we_cemetary/fogtrunk 64 0 0.00 1 1 0 0 0 +( 144 1328 272 ) ( 160 1312 256 ) ( 128 1344 256 ) we_cemetary/fogtrunk -64 0 0.00 1 1 0 0 0 +} +// brush 372 +{ +( 384 1280 272 ) ( 384 1312 272 ) ( 192 1312 272 ) we_cemetary/cemrunner2 4 -31 -90.00 1 1 0 0 0 +( 192 1312 336 ) ( 384 1312 336 ) ( 384 1280 336 ) we_cemetary/cemtrim2 99 -63 -90.00 1 1 0 0 0 +( 192 1280 592 ) ( 384 1280 592 ) ( 384 1280 272 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( 384 1344 592 ) ( 192 1344 592 ) ( 192 1344 272 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( 640 1344 272 ) ( 608 1312 272 ) ( 624 1328 336 ) we_cemetary/cemtrim2 64 15 0.00 1 1 0 0 0 +( 144 1328 336 ) ( 160 1312 272 ) ( 128 1344 272 ) we_cemetary/cemtrim2 -64 16 0.00 1 1 0 0 0 +} +// brush 373 +{ +( 576 1088 272 ) ( 608 1088 272 ) ( 608 1280 272 ) we_cemetary/cemrunner2 63 0 -180.00 1 1 0 0 0 +( 608 1280 336 ) ( 608 1088 336 ) ( 576 1088 336 ) we_cemetary/cemtrim2 159 0 -180.00 1 1 0 0 0 +( 576 1280 592 ) ( 576 1088 592 ) ( 576 1088 272 ) we_cemetary/cemtrim2 0 14 -180.00 1 -1 0 0 0 +( 640 1088 592 ) ( 640 1280 592 ) ( 640 1280 272 ) we_cemetary/cemtrim2 0 14 -180.00 1 -1 0 0 0 +( 640 832 272 ) ( 608 864 272 ) ( 624 848 336 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( 624 1328 336 ) ( 608 1312 272 ) ( 640 1344 272 ) we_cemetary/cemtrim2 -64 15 -180.00 1 -1 0 0 0 +} +// brush 374 +{ +( 592 1280 256 ) ( 592 1088 256 ) ( 640 1088 256 ) we_cemetary/fogtrunk 191 0 -180.00 1 1 0 0 0 +( 640 1280 272 ) ( 640 1088 272 ) ( 576 1088 272 ) we_cemetary/fogtrunk 191 0 -180.00 1 1 0 0 0 +( 592 1088 256 ) ( 592 1280 256 ) ( 576 1280 272 ) we_cemetary/fogtrunk 191 0 -180.00 1 1 0 0 0 +( 640 1088 272 ) ( 640 1280 272 ) ( 640 1280 256 ) we_cemetary/fogtrunk 0 0 -180.00 1 -1 0 0 0 +( 640 832 256 ) ( 608 864 256 ) ( 624 848 272 ) we_cemetary/fogtrunk -64 0 0.00 1 1 0 0 0 +( 624 1328 272 ) ( 608 1312 256 ) ( 640 1344 256 ) we_cemetary/fogtrunk -64 0 -180.00 1 -1 0 0 0 +} +// brush 375 +{ +( 608 1088 64 ) ( 640 1088 64 ) ( 640 1280 64 ) we_cemetary/cemstair2 191 0 -180.00 1 1 0 0 0 +( 640 1088 384 ) ( 640 1280 384 ) ( 640 1280 64 ) we_cemetary/cemstair2 0 0 -180.00 1 -1 0 0 0 +( 592 1280 96 ) ( 600 1088 80 ) ( 608 1280 64 ) we_cemetary/cemstair2 0 0 -180.00 1 -1 0 0 0 +( 576 1088 256 ) ( 576 1280 256 ) ( 640 1280 256 ) we_cemetary/cemstair2 191 0 -180.00 1 1 0 0 0 +( 592 1280 208 ) ( 592 1088 176 ) ( 592 1280 144 ) we_cemetary/cemstair2 0 0 -180.00 1 -1 0 0 0 +( 640 832 64 ) ( 608 864 64 ) ( 624 848 256 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 624 1328 256 ) ( 608 1312 64 ) ( 640 1344 64 ) we_cemetary/cemstair2 -64 0 -180.00 1 -1 0 0 0 +} +// brush 376 +{ +( 608 1088 0 ) ( 640 1088 0 ) ( 640 1280 0 ) we_cemetary/cemtrim2 191 0 -180.00 1 1 0 0 0 +( 640 1280 64 ) ( 640 1088 64 ) ( 608 1088 64 ) we_cemetary/cemtrim2 191 0 -180.00 1 1 0 0 0 +( 608 1408 320 ) ( 608 1216 320 ) ( 608 1216 0 ) we_cemetary/cemtrim2 0 0 -180.00 1 -1 0 0 0 +( 640 1088 320 ) ( 640 1280 320 ) ( 640 1280 0 ) we_cemetary/cemtrim2 0 0 -180.00 1 -1 0 0 0 +( 640 832 0 ) ( 608 864 0 ) ( 624 848 64 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 624 1328 64 ) ( 608 1312 0 ) ( 640 1344 0 ) we_cemetary/cemtrim2 -64 0 -180.00 1 -1 0 0 0 +} +// brush 377 +{ +( 384 864 0 ) ( 384 832 0 ) ( 576 832 0 ) we_cemetary/cemtrim2 5 0 90.00 1 1 0 0 0 +( 576 832 64 ) ( 384 832 64 ) ( 384 864 64 ) we_cemetary/cemtrim2 5 0 90.00 1 1 0 0 0 +( 640 864 320 ) ( 448 864 320 ) ( 448 864 0 ) we_cemetary/cemtrim2 128 0 -180.00 1 -1 0 0 0 +( 384 832 320 ) ( 576 832 320 ) ( 576 832 0 ) we_cemetary/cemtrim2 128 0 -180.00 1 -1 0 0 0 +( 128 832 0 ) ( 160 864 0 ) ( 144 848 64 ) we_cemetary/cemtrim2 128 0 -180.00 1 -1 0 0 0 +( 624 848 64 ) ( 608 864 0 ) ( 640 832 0 ) we_cemetary/cemtrim2 128 0 -180.00 1 -1 0 0 0 +} +// brush 378 +{ +( 384 864 64 ) ( 384 832 64 ) ( 576 832 64 ) we_cemetary/cemstair2 5 0 90.00 1 1 0 0 0 +( 384 832 384 ) ( 576 832 384 ) ( 576 832 64 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +( 576 880 96 ) ( 384 872 80 ) ( 576 864 64 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +( 384 896 256 ) ( 576 896 256 ) ( 576 832 256 ) we_cemetary/cemstair2 5 0 90.00 1 1 0 0 0 +( 576 880 208 ) ( 384 880 176 ) ( 576 880 144 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +( 128 832 64 ) ( 160 864 64 ) ( 144 848 256 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +( 624 848 256 ) ( 608 864 64 ) ( 640 832 64 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +} +// brush 379 +{ +( 576 880 256 ) ( 384 880 256 ) ( 384 832 256 ) we_cemetary/fogtrunk 5 -127 90.00 1 1 0 0 0 +( 576 832 272 ) ( 384 832 272 ) ( 384 896 272 ) we_cemetary/fogtrunk 5 -127 90.00 1 1 0 0 0 +( 384 880 256 ) ( 576 880 256 ) ( 576 896 272 ) we_cemetary/fogtrunk 5 -127 90.00 1 1 0 0 0 +( 384 832 272 ) ( 576 832 272 ) ( 576 832 256 ) we_cemetary/fogtrunk 128 0 -180.00 1 -1 0 0 0 +( 128 832 256 ) ( 160 864 256 ) ( 144 848 272 ) we_cemetary/fogtrunk 128 0 -180.00 1 -1 0 0 0 +( 624 848 272 ) ( 608 864 256 ) ( 640 832 256 ) we_cemetary/fogtrunk 128 0 -180.00 1 -1 0 0 0 +} +// brush 380 +{ +( 384 896 272 ) ( 384 864 272 ) ( 576 864 272 ) we_cemetary/cemrunner2 5 1 90.00 1 1.000122 0 0 0 +( 576 864 336 ) ( 384 864 336 ) ( 384 896 336 ) we_cemetary/cemtrim2 -27 0 90.00 1 1 0 0 0 +( 576 896 592 ) ( 384 896 592 ) ( 384 896 272 ) we_cemetary/cemtrim2 128 15 -180.00 1 -1 0 0 0 +( 384 832 592 ) ( 576 832 592 ) ( 576 832 272 ) we_cemetary/cemtrim2 128 15 -180.00 1 -1 0 0 0 +( 128 832 272 ) ( 160 864 272 ) ( 144 848 336 ) we_cemetary/cemtrim2 128 15 -180.00 1 -1 0 0 0 +( 624 848 336 ) ( 608 864 272 ) ( 640 832 272 ) we_cemetary/cemtrim2 128 15 -180.00 1 -1 0 0 0 +} +// brush 381 +{ +( 1120 1088 0 ) ( 1152 1088 0 ) ( 1152 1280 0 ) we_cemetary/cemtrim2 191 0 -180.00 1 1 0 0 0 +( 1152 1280 64 ) ( 1152 1088 64 ) ( 1120 1088 64 ) we_cemetary/cemtrim2 191 0 -180.00 1 1 0 0 0 +( 1120 1408 320 ) ( 1120 1216 320 ) ( 1120 1216 0 ) we_cemetary/cemtrim2 0 0 -180.00 1 -1 0 0 0 +( 1152 1088 320 ) ( 1152 1280 320 ) ( 1152 1280 0 ) we_cemetary/cemtrim2 0 0 -180.00 1 -1 0 0 0 +( 1152 832 0 ) ( 1120 864 0 ) ( 1136 848 64 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 1136 1328 64 ) ( 1120 1312 0 ) ( 1152 1344 0 ) we_cemetary/cemtrim2 -64 0 -180.00 1 -1 0 0 0 +} +// brush 382 +{ +( 1120 1088 64 ) ( 1152 1088 64 ) ( 1152 1280 64 ) we_cemetary/cemstair2 191 0 -180.00 1 1 0 0 0 +( 1152 1088 384 ) ( 1152 1280 384 ) ( 1152 1280 64 ) we_cemetary/cemstair2 0 0 -180.00 1 -1 0 0 0 +( 1104 1280 96 ) ( 1112 1088 80 ) ( 1120 1280 64 ) we_cemetary/cemstair2 0 0 -180.00 1 -1 0 0 0 +( 1088 1088 256 ) ( 1088 1280 256 ) ( 1152 1280 256 ) we_cemetary/cemstair2 191 0 -180.00 1 1 0 0 0 +( 1104 1280 208 ) ( 1104 1088 176 ) ( 1104 1280 144 ) we_cemetary/cemstair2 0 0 -180.00 1 -1 0 0 0 +( 1152 832 64 ) ( 1120 864 64 ) ( 1136 848 256 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 1136 1328 256 ) ( 1120 1312 64 ) ( 1152 1344 64 ) we_cemetary/cemstair2 -64 0 -180.00 1 -1 0 0 0 +} +// brush 383 +{ +( 1104 1280 256 ) ( 1104 1088 256 ) ( 1152 1088 256 ) we_cemetary/fogtrunk 191 0 -180.00 1 1 0 0 0 +( 1152 1280 272 ) ( 1152 1088 272 ) ( 1088 1088 272 ) we_cemetary/fogtrunk 191 0 -180.00 1 1 0 0 0 +( 1104 1088 256 ) ( 1104 1280 256 ) ( 1088 1280 272 ) we_cemetary/fogtrunk 191 0 -180.00 1 1 0 0 0 +( 1152 1088 272 ) ( 1152 1280 272 ) ( 1152 1280 256 ) we_cemetary/fogtrunk 0 0 -180.00 1 -1 0 0 0 +( 1152 832 256 ) ( 1120 864 256 ) ( 1136 848 272 ) we_cemetary/fogtrunk -64 0 0.00 1 1 0 0 0 +( 1136 1328 272 ) ( 1120 1312 256 ) ( 1152 1344 256 ) we_cemetary/fogtrunk -64 0 -180.00 1 -1 0 0 0 +} +// brush 384 +{ +( 1088 1088 272 ) ( 1120 1088 272 ) ( 1120 1280 272 ) we_cemetary/cemrunner2 63 0 -180.00 1 1 0 0 0 +( 1120 1280 336 ) ( 1120 1088 336 ) ( 1088 1088 336 ) we_cemetary/cemtrim2 159 0 -180.00 1 1 0 0 0 +( 1088 1280 592 ) ( 1088 1088 592 ) ( 1088 1088 272 ) we_cemetary/cemtrim2 0 14 -180.00 1 -1 0 0 0 +( 1152 1088 592 ) ( 1152 1280 592 ) ( 1152 1280 272 ) we_cemetary/cemtrim2 0 14 -180.00 1 -1 0 0 0 +( 1152 832 272 ) ( 1120 864 272 ) ( 1136 848 336 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( 1136 1328 336 ) ( 1120 1312 272 ) ( 1152 1344 272 ) we_cemetary/cemtrim2 -64 15 -180.00 1 -1 0 0 0 +} +// brush 385 +{ +( 896 1280 272 ) ( 896 1312 272 ) ( 704 1312 272 ) we_cemetary/cemrunner2 5 0 -90.00 1 1 0 0 0 +( 704 1312 336 ) ( 896 1312 336 ) ( 896 1280 336 ) we_cemetary/cemtrim2 99 0 -90.00 1 1 0 0 0 +( 704 1280 592 ) ( 896 1280 592 ) ( 896 1280 272 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( 896 1344 592 ) ( 704 1344 592 ) ( 704 1344 272 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( 1152 1344 272 ) ( 1120 1312 272 ) ( 1136 1328 336 ) we_cemetary/cemtrim2 64 15 0.00 1 1 0 0 0 +( 656 1328 336 ) ( 672 1312 272 ) ( 640 1344 272 ) we_cemetary/cemtrim2 -64 16 0.00 1 1 0 0 0 +} +// brush 386 +{ +( 704 1296 256 ) ( 896 1296 256 ) ( 896 1344 256 ) we_cemetary/fogtrunk -123 63 -90.00 1 1 0 0 0 +( 704 1344 272 ) ( 896 1344 272 ) ( 896 1280 272 ) we_cemetary/fogtrunk -123 63 -90.00 1 1 0 0 0 +( 896 1296 256 ) ( 704 1296 256 ) ( 704 1280 272 ) we_cemetary/fogtrunk -123 63 -90.00 1 1 0 0 0 +( 896 1344 272 ) ( 704 1344 272 ) ( 704 1344 256 ) we_cemetary/fogtrunk -64 0 0.00 1 1 0 0 0 +( 1152 1344 256 ) ( 1120 1312 256 ) ( 1136 1328 272 ) we_cemetary/fogtrunk 64 0 0.00 1 1 0 0 0 +( 656 1328 272 ) ( 672 1312 256 ) ( 640 1344 256 ) we_cemetary/fogtrunk -64 0 0.00 1 1 0 0 0 +} +// brush 387 +{ +( 672 1280 272 ) ( 672 1088 272 ) ( 704 1088 272 ) we_cemetary/cemrunner2 0 0 0.00 1 1 0 0 0 +( 704 1088 336 ) ( 672 1088 336 ) ( 672 1280 336 ) we_cemetary/cemtrim2 -32 0 0.00 1 1 0 0 0 +( 704 1088 272 ) ( 704 1088 592 ) ( 704 1280 592 ) we_cemetary/cemtrim2 64 16 0.00 1 1 0 0 0 +( 640 1280 272 ) ( 640 1280 592 ) ( 640 1088 592 ) we_cemetary/cemtrim2 64 16 0.00 1 1 0 0 0 +( 656 848 336 ) ( 672 864 272 ) ( 640 832 272 ) we_cemetary/cemtrim2 64 16 0.00 1 1 0 0 0 +( 688 1296 336 ) ( 672 1312 272 ) ( 704 1280 272 ) we_cemetary/cemtrim2 64 16 0.00 1 1 0 0 0 +} +// brush 388 +{ +( 640 1088 256 ) ( 688 1088 256 ) ( 688 1280 256 ) we_cemetary/fogtrunk 0 -64 0.00 1 1 0 0 0 +( 704 1088 272 ) ( 640 1088 272 ) ( 640 1280 272 ) we_cemetary/fogtrunk 0 -64 0.00 1 1 0 0 0 +( 704 1280 272 ) ( 688 1280 256 ) ( 688 1088 256 ) we_cemetary/fogtrunk 0 -64 0.00 1 1 0 0 0 +( 640 1280 256 ) ( 640 1280 272 ) ( 640 1088 272 ) we_cemetary/fogtrunk 64 0 0.00 1 1 0 0 0 +( 656 848 272 ) ( 672 864 256 ) ( 640 832 256 ) we_cemetary/fogtrunk 64 0 0.00 1 1 0 0 0 +( 688 1296 272 ) ( 672 1312 256 ) ( 704 1280 256 ) we_cemetary/fogtrunk 64 0 0.00 1 1 0 0 0 +} +// brush 389 +{ +( 640 1280 64 ) ( 640 1088 64 ) ( 672 1088 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 640 1280 64 ) ( 640 1280 384 ) ( 640 1088 384 ) we_cemetary/cemstair2 64 0 0.00 1 1 0 0 0 +( 672 1280 64 ) ( 680 1088 80 ) ( 688 1280 96 ) we_cemetary/cemstair2 64 0 0.00 1 1 0 0 0 +( 640 1280 256 ) ( 704 1280 256 ) ( 704 1088 256 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 688 1280 144 ) ( 688 1088 176 ) ( 688 1280 208 ) we_cemetary/cemstair2 64 0 0.00 1 1 0 0 0 +( 656 848 256 ) ( 672 864 64 ) ( 640 832 64 ) we_cemetary/cemstair2 64 0 0.00 1 1 0 0 0 +( 688 1296 256 ) ( 672 1312 64 ) ( 704 1280 64 ) we_cemetary/cemstair2 64 0 0.00 1 1 0 0 0 +} +// brush 390 +{ +( 640 1280 0 ) ( 640 1088 0 ) ( 672 1088 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( 672 1088 64 ) ( 640 1088 64 ) ( 640 1280 64 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( 672 1152 0 ) ( 672 1152 320 ) ( 672 1344 320 ) we_cemetary/cemtrim2 64 0 0.00 1 1 0 0 0 +( 640 1280 0 ) ( 640 1280 320 ) ( 640 1088 320 ) we_cemetary/cemtrim2 64 0 0.00 1 1 0 0 0 +( 656 848 64 ) ( 672 864 0 ) ( 640 832 0 ) we_cemetary/cemtrim2 64 0 0.00 1 1 0 0 0 +( 688 1296 64 ) ( 672 1312 0 ) ( 704 1280 0 ) we_cemetary/cemtrim2 64 0 0.00 1 1 0 0 0 +} +// brush 391 +{ +( 896 1312 0 ) ( 896 1344 0 ) ( 704 1344 0 ) we_cemetary/cemtrim2 -123 0 -90.00 1 1 0 0 0 +( 704 1344 64 ) ( 896 1344 64 ) ( 896 1312 64 ) we_cemetary/cemtrim2 -123 0 -90.00 1 1 0 0 0 +( 576 1312 320 ) ( 768 1312 320 ) ( 768 1312 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 896 1344 320 ) ( 704 1344 320 ) ( 704 1344 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 656 1328 64 ) ( 672 1312 0 ) ( 640 1344 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 832 1344 64 ) ( 832 1376 0 ) ( 832 1312 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +} +// brush 392 +{ +( 896 1312 0 ) ( 896 1344 0 ) ( 704 1344 0 ) we_cemetary/cemtrim2 -123 0 -90.00 1 1 0 0 0 +( 704 1344 64 ) ( 896 1344 64 ) ( 896 1312 64 ) we_cemetary/cemtrim2 -123 0 -90.00 1 1 0 0 0 +( 704 1312 320 ) ( 896 1312 320 ) ( 896 1312 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 896 1344 320 ) ( 704 1344 320 ) ( 704 1344 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 1152 1344 0 ) ( 1120 1312 0 ) ( 1136 1328 64 ) we_cemetary/cemtrim2 64 0 0.00 1 1 0 0 0 +( 960 1344 64 ) ( 960 1312 0 ) ( 960 1376 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +} +// brush 393 +{ +( 896 1312 64 ) ( 896 1344 64 ) ( 704 1344 64 ) we_cemetary/cemstair2 -123 0 -90.00 1 1 0 0 0 +( 896 1344 384 ) ( 704 1344 384 ) ( 704 1344 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 704 1296 96 ) ( 896 1304 80 ) ( 704 1312 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 896 1280 256 ) ( 704 1280 256 ) ( 704 1344 256 ) we_cemetary/cemstair2 -123 0 -90.00 1 1 0 0 0 +( 704 1296 208 ) ( 896 1296 176 ) ( 704 1296 144 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 656 1328 256 ) ( 672 1312 64 ) ( 640 1344 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 832 1344 256 ) ( 832 1376 64 ) ( 832 1312 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +} +// brush 394 +{ +( 896 1312 64 ) ( 896 1344 64 ) ( 704 1344 64 ) we_cemetary/cemstair2 -123 0 -90.00 1 1 0 0 0 +( 896 1344 384 ) ( 704 1344 384 ) ( 704 1344 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 704 1296 96 ) ( 896 1304 80 ) ( 704 1312 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 896 1280 256 ) ( 704 1280 256 ) ( 704 1344 256 ) we_cemetary/cemstair2 -123 0 -90.00 1 1 0 0 0 +( 832 1296 208 ) ( 1024 1296 176 ) ( 832 1296 144 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 1152 1344 64 ) ( 1120 1312 64 ) ( 1136 1328 256 ) we_cemetary/cemstair2 64 0 0.00 1 1 0 0 0 +( 960 1344 256 ) ( 960 1312 64 ) ( 960 1376 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +} +// brush 395 +{ +( 704 1344 64 ) ( 896 1344 64 ) ( 896 1376 64 ) we_cemetary/cemstair2 67 0 -90.00 1 1 0 0 0 +( 704 1344 64 ) ( 704 1344 384 ) ( 896 1344 384 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 704 1376 64 ) ( 896 1384 80 ) ( 704 1392 96 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 704 1344 256 ) ( 704 1408 256 ) ( 896 1408 256 ) we_cemetary/cemstair2 67 0 -90.00 1 1 0 0 0 +( 800 1392 144 ) ( 992 1392 176 ) ( 800 1392 208 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 960 1344 256 ) ( 960 1312 64 ) ( 960 1376 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 1152 1376 256 ) ( 1152 1408 64 ) ( 1152 1344 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +} +// brush 396 +{ +( 704 1344 0 ) ( 896 1344 0 ) ( 896 1376 0 ) we_cemetary/cemtrim2 67 0 -90.00 1 1 0 0 0 +( 896 1376 64 ) ( 896 1344 64 ) ( 704 1344 64 ) we_cemetary/cemtrim2 67 0 -90.00 1 1 0 0 0 +( 992 1376 0 ) ( 992 1376 320 ) ( 800 1376 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 704 1344 0 ) ( 704 1344 320 ) ( 896 1344 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 960 1344 64 ) ( 960 1312 0 ) ( 960 1376 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( 1152 1376 64 ) ( 1152 1408 0 ) ( 1152 1344 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +} +// brush 397 +{ +( 704 1344 64 ) ( 896 1344 64 ) ( 896 1376 64 ) we_cemetary/cemstair2 67 0 -90.00 1 1 0 0 0 +( 704 1344 64 ) ( 704 1344 384 ) ( 896 1344 384 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 704 1376 64 ) ( 896 1384 80 ) ( 704 1392 96 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 704 1344 256 ) ( 704 1408 256 ) ( 896 1408 256 ) we_cemetary/cemstair2 67 0 -90.00 1 1 0 0 0 +( 704 1392 144 ) ( 896 1392 176 ) ( 704 1392 208 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 832 1344 256 ) ( 832 1376 64 ) ( 832 1312 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 640 1392 256 ) ( 640 1376 64 ) ( 640 1408 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +} +// brush 398 +{ +( 704 1344 0 ) ( 896 1344 0 ) ( 896 1376 0 ) we_cemetary/cemtrim2 67 0 -90.00 1 1 0 0 0 +( 896 1376 64 ) ( 896 1344 64 ) ( 704 1344 64 ) we_cemetary/cemtrim2 67 0 -90.00 1 1 0 0 0 +( 704 1376 0 ) ( 704 1376 320 ) ( 512 1376 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 704 1344 0 ) ( 704 1344 320 ) ( 896 1344 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 832 1344 64 ) ( 832 1376 0 ) ( 832 1312 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( 640 1392 64 ) ( 640 1376 0 ) ( 640 1408 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +} +// brush 399 +{ +( 896 1344 256 ) ( 896 1392 256 ) ( 704 1392 256 ) we_cemetary/fogtrunk 67 63 -90.00 1 1 0 0 0 +( 896 1408 272 ) ( 896 1344 272 ) ( 704 1344 272 ) we_cemetary/fogtrunk 67 63 -90.00 1 1 0 0 0 +( 704 1408 272 ) ( 704 1392 256 ) ( 896 1392 256 ) we_cemetary/fogtrunk 67 63 -90.00 1 1 0 0 0 +( 704 1344 256 ) ( 704 1344 272 ) ( 896 1344 272 ) we_cemetary/fogtrunk -64 0 0.00 1 1 0 0 0 +( 1152 1376 272 ) ( 1152 1408 256 ) ( 1152 1344 256 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +( 640 1392 272 ) ( 640 1376 256 ) ( 640 1408 256 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +} +// brush 400 +{ +( 704 1376 272 ) ( 896 1376 272 ) ( 896 1408 272 ) we_cemetary/cemrunner2 -64 0 -90.00 1 1 0 0 0 +( 896 1408 336 ) ( 896 1376 336 ) ( 704 1376 336 ) we_cemetary/cemtrim2 35 0 -90.00 1 1 0 0 0 +( 896 1408 272 ) ( 896 1408 592 ) ( 704 1408 592 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( 704 1344 272 ) ( 704 1344 592 ) ( 896 1344 592 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( 1152 1376 336 ) ( 1152 1408 272 ) ( 1152 1344 272 ) we_cemetary/cemtrim2 0 16 0.00 1 1 0 0 0 +( 640 1392 336 ) ( 640 1376 272 ) ( 640 1408 272 ) we_cemetary/cemtrim2 0 16 0.00 1 1 0 0 0 +} +// brush 401 +{ +( 672 1312 -32 ) ( 672 864 -32 ) ( 1120 864 -32 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 1120 864 0 ) ( 672 864 0 ) ( 672 1312 0 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 1120 1376 -64 ) ( 1120 1376 0 ) ( 672 1376 0 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 1152 864 -64 ) ( 1152 864 0 ) ( 1152 1312 0 ) we_cemetary/cemtrim5 64 0 0.00 1 1 0 0 0 +( 672 832 -64 ) ( 672 832 0 ) ( 1120 832 0 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 640 1312 -64 ) ( 640 1312 0 ) ( 640 864 0 ) we_cemetary/cemtrim5 64 0 0.00 1 1 0 0 0 +} +// brush 402 +{ +( 672 1312 336 ) ( 672 864 336 ) ( 1120 864 336 ) water/waterfloor2 0 -64 0.00 1 1 0 0 0 +( 1120 864 352 ) ( 672 864 352 ) ( 672 1312 352 ) water/waterfloor2 0 -64 0.00 1 1 0 0 0 +( 1120 1312 304 ) ( 1120 1312 368 ) ( 672 1312 368 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +( 1120 864 304 ) ( 1120 864 368 ) ( 1120 1312 368 ) water/waterfloor2 64 0 0.00 1 1 0 0 0 +( 672 864 304 ) ( 672 864 368 ) ( 1120 864 368 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +( 672 1312 304 ) ( 672 1312 368 ) ( 672 864 368 ) water/waterfloor2 64 0 0.00 1 1 0 0 0 +} +// brush 403 +{ +( 832 1392 208 ) ( 832 1296 208 ) ( 960 1296 208 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 960 1296 256 ) ( 832 1296 256 ) ( 832 1392 256 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 960 1392 64 ) ( 960 1392 256 ) ( 832 1392 256 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 960 1296 48 ) ( 960 1296 240 ) ( 960 1392 240 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 832 1296 48 ) ( 832 1296 240 ) ( 960 1296 240 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 832 1392 64 ) ( 832 1392 256 ) ( 832 1296 256 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +} +// brush 404 +{ +( 1344 1392 208 ) ( 1344 1296 208 ) ( 1472 1296 208 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 1472 1296 256 ) ( 1344 1296 256 ) ( 1344 1392 256 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 1472 1392 64 ) ( 1472 1392 256 ) ( 1344 1392 256 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 1472 1296 48 ) ( 1472 1296 240 ) ( 1472 1392 240 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 1344 1296 48 ) ( 1344 1296 240 ) ( 1472 1296 240 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 1344 1392 64 ) ( 1344 1392 256 ) ( 1344 1296 256 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +} +// brush 405 +{ +( 1184 1312 336 ) ( 1184 864 336 ) ( 1632 864 336 ) water/waterfloor2 0 -64 0.00 1 1 0 0 0 +( 1632 864 352 ) ( 1184 864 352 ) ( 1184 1312 352 ) water/waterfloor2 0 -64 0.00 1 1 0 0 0 +( 1632 1312 304 ) ( 1632 1312 368 ) ( 1184 1312 368 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +( 1632 864 304 ) ( 1632 864 368 ) ( 1632 1312 368 ) water/waterfloor2 64 0 0.00 1 1 0 0 0 +( 1184 864 304 ) ( 1184 864 368 ) ( 1632 864 368 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +( 1184 1312 304 ) ( 1184 1312 368 ) ( 1184 864 368 ) water/waterfloor2 64 0 0.00 1 1 0 0 0 +} +// brush 406 +{ +( 1184 1312 -32 ) ( 1184 864 -32 ) ( 1632 864 -32 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 1632 864 0 ) ( 1184 864 0 ) ( 1184 1312 0 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 1632 1376 -64 ) ( 1632 1376 0 ) ( 1184 1376 0 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 1664 864 -64 ) ( 1664 864 0 ) ( 1664 1312 0 ) we_cemetary/cemtrim5 64 0 0.00 1 1 0 0 0 +( 1184 832 -64 ) ( 1184 832 0 ) ( 1632 832 0 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 1152 1312 -64 ) ( 1152 1312 0 ) ( 1152 864 0 ) we_cemetary/cemtrim5 64 0 0.00 1 1 0 0 0 +} +// brush 407 +{ +( 1216 1376 272 ) ( 1408 1376 272 ) ( 1408 1408 272 ) we_cemetary/cemrunner2 -64 0 -90.00 1 1 0 0 0 +( 1408 1408 336 ) ( 1408 1376 336 ) ( 1216 1376 336 ) we_cemetary/cemtrim2 36 0 -90.00 1 1 0 0 0 +( 1408 1408 272 ) ( 1408 1408 592 ) ( 1216 1408 592 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( 1216 1344 272 ) ( 1216 1344 592 ) ( 1408 1344 592 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( 1664 1376 336 ) ( 1664 1408 272 ) ( 1664 1344 272 ) we_cemetary/cemtrim2 0 16 0.00 1 1 0 0 0 +( 1152 1392 336 ) ( 1152 1376 272 ) ( 1152 1408 272 ) we_cemetary/cemtrim2 0 16 0.00 1 1 0 0 0 +} +// brush 408 +{ +( 1408 1344 256 ) ( 1408 1392 256 ) ( 1216 1392 256 ) we_cemetary/fogtrunk 68 63 -90.00 1 1 0 0 0 +( 1408 1408 272 ) ( 1408 1344 272 ) ( 1216 1344 272 ) we_cemetary/fogtrunk 68 63 -90.00 1 1 0 0 0 +( 1216 1408 272 ) ( 1216 1392 256 ) ( 1408 1392 256 ) we_cemetary/fogtrunk 68 63 -90.00 1 1 0 0 0 +( 1216 1344 256 ) ( 1216 1344 272 ) ( 1408 1344 272 ) we_cemetary/fogtrunk -64 0 0.00 1 1 0 0 0 +( 1664 1376 272 ) ( 1664 1408 256 ) ( 1664 1344 256 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +( 1152 1392 272 ) ( 1152 1376 256 ) ( 1152 1408 256 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +} +// brush 409 +{ +( 1216 1344 0 ) ( 1408 1344 0 ) ( 1408 1376 0 ) we_cemetary/cemtrim2 68 0 -90.00 1 1 0 0 0 +( 1408 1376 64 ) ( 1408 1344 64 ) ( 1216 1344 64 ) we_cemetary/cemtrim2 68 0 -90.00 1 1 0 0 0 +( 1216 1376 0 ) ( 1216 1376 320 ) ( 1024 1376 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 1216 1344 0 ) ( 1216 1344 320 ) ( 1408 1344 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 1344 1344 64 ) ( 1344 1376 0 ) ( 1344 1312 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( 1152 1392 64 ) ( 1152 1376 0 ) ( 1152 1408 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +} +// brush 410 +{ +( 1216 1344 64 ) ( 1408 1344 64 ) ( 1408 1376 64 ) we_cemetary/cemstair2 68 0 -90.00 1 1 0 0 0 +( 1216 1344 64 ) ( 1216 1344 384 ) ( 1408 1344 384 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 1216 1376 64 ) ( 1408 1384 80 ) ( 1216 1392 96 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 1216 1344 256 ) ( 1216 1408 256 ) ( 1408 1408 256 ) we_cemetary/cemstair2 68 0 -90.00 1 1 0 0 0 +( 1216 1392 144 ) ( 1408 1392 176 ) ( 1216 1392 208 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 1344 1344 256 ) ( 1344 1376 64 ) ( 1344 1312 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 1152 1392 256 ) ( 1152 1376 64 ) ( 1152 1408 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +} +// brush 411 +{ +( 1216 1344 0 ) ( 1408 1344 0 ) ( 1408 1376 0 ) we_cemetary/cemtrim2 68 0 -90.00 1 1 0 0 0 +( 1408 1376 64 ) ( 1408 1344 64 ) ( 1216 1344 64 ) we_cemetary/cemtrim2 68 0 -90.00 1 1 0 0 0 +( 1504 1376 0 ) ( 1504 1376 320 ) ( 1312 1376 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 1216 1344 0 ) ( 1216 1344 320 ) ( 1408 1344 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 1472 1344 64 ) ( 1472 1312 0 ) ( 1472 1376 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( 1664 1376 64 ) ( 1664 1408 0 ) ( 1664 1344 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +} +// brush 412 +{ +( 1216 1344 64 ) ( 1408 1344 64 ) ( 1408 1376 64 ) we_cemetary/cemstair2 68 0 -90.00 1 1 0 0 0 +( 1216 1344 64 ) ( 1216 1344 384 ) ( 1408 1344 384 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 1216 1376 64 ) ( 1408 1384 80 ) ( 1216 1392 96 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 1216 1344 256 ) ( 1216 1408 256 ) ( 1408 1408 256 ) we_cemetary/cemstair2 68 0 -90.00 1 1 0 0 0 +( 1312 1392 144 ) ( 1504 1392 176 ) ( 1312 1392 208 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 1472 1344 256 ) ( 1472 1312 64 ) ( 1472 1376 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 1664 1376 256 ) ( 1664 1408 64 ) ( 1664 1344 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +} +// brush 413 +{ +( 1408 1312 64 ) ( 1408 1344 64 ) ( 1216 1344 64 ) we_cemetary/cemstair2 -122 0 -90.00 1 1 0 0 0 +( 1408 1344 384 ) ( 1216 1344 384 ) ( 1216 1344 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 1216 1296 96 ) ( 1408 1304 80 ) ( 1216 1312 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 1408 1280 256 ) ( 1216 1280 256 ) ( 1216 1344 256 ) we_cemetary/cemstair2 -122 0 -90.00 1 1 0 0 0 +( 1344 1296 208 ) ( 1536 1296 176 ) ( 1344 1296 144 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 1664 1344 64 ) ( 1632 1312 64 ) ( 1648 1328 256 ) we_cemetary/cemstair2 64 0 0.00 1 1 0 0 0 +( 1472 1344 256 ) ( 1472 1312 64 ) ( 1472 1376 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +} +// brush 414 +{ +( 1408 1312 64 ) ( 1408 1344 64 ) ( 1216 1344 64 ) we_cemetary/cemstair2 -122 0 -90.00 1 1 0 0 0 +( 1408 1344 384 ) ( 1216 1344 384 ) ( 1216 1344 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 1216 1296 96 ) ( 1408 1304 80 ) ( 1216 1312 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 1408 1280 256 ) ( 1216 1280 256 ) ( 1216 1344 256 ) we_cemetary/cemstair2 -122 0 -90.00 1 1 0 0 0 +( 1216 1296 208 ) ( 1408 1296 176 ) ( 1216 1296 144 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 1168 1328 256 ) ( 1184 1312 64 ) ( 1152 1344 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 1344 1344 256 ) ( 1344 1376 64 ) ( 1344 1312 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +} +// brush 415 +{ +( 1408 1312 0 ) ( 1408 1344 0 ) ( 1216 1344 0 ) we_cemetary/cemtrim2 -122 0 -90.00 1 1 0 0 0 +( 1216 1344 64 ) ( 1408 1344 64 ) ( 1408 1312 64 ) we_cemetary/cemtrim2 -122 0 -90.00 1 1 0 0 0 +( 1216 1312 320 ) ( 1408 1312 320 ) ( 1408 1312 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 1408 1344 320 ) ( 1216 1344 320 ) ( 1216 1344 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 1664 1344 0 ) ( 1632 1312 0 ) ( 1648 1328 64 ) we_cemetary/cemtrim2 64 0 0.00 1 1 0 0 0 +( 1472 1344 64 ) ( 1472 1312 0 ) ( 1472 1376 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +} +// brush 416 +{ +( 1408 1312 0 ) ( 1408 1344 0 ) ( 1216 1344 0 ) we_cemetary/cemtrim2 -122 0 -90.00 1 1 0 0 0 +( 1216 1344 64 ) ( 1408 1344 64 ) ( 1408 1312 64 ) we_cemetary/cemtrim2 -122 0 -90.00 1 1 0 0 0 +( 1088 1312 320 ) ( 1280 1312 320 ) ( 1280 1312 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 1408 1344 320 ) ( 1216 1344 320 ) ( 1216 1344 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 1168 1328 64 ) ( 1184 1312 0 ) ( 1152 1344 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 1344 1344 64 ) ( 1344 1376 0 ) ( 1344 1312 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +} +// brush 417 +{ +( 1152 1280 0 ) ( 1152 1088 0 ) ( 1184 1088 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( 1184 1088 64 ) ( 1152 1088 64 ) ( 1152 1280 64 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( 1184 1152 0 ) ( 1184 1152 320 ) ( 1184 1344 320 ) we_cemetary/cemtrim2 64 0 0.00 1 1 0 0 0 +( 1152 1280 0 ) ( 1152 1280 320 ) ( 1152 1088 320 ) we_cemetary/cemtrim2 64 0 0.00 1 1 0 0 0 +( 1168 848 64 ) ( 1184 864 0 ) ( 1152 832 0 ) we_cemetary/cemtrim2 64 0 0.00 1 1 0 0 0 +( 1200 1296 64 ) ( 1184 1312 0 ) ( 1216 1280 0 ) we_cemetary/cemtrim2 64 0 0.00 1 1 0 0 0 +} +// brush 418 +{ +( 1152 1280 64 ) ( 1152 1088 64 ) ( 1184 1088 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 1152 1280 64 ) ( 1152 1280 384 ) ( 1152 1088 384 ) we_cemetary/cemstair2 64 0 0.00 1 1 0 0 0 +( 1184 1280 64 ) ( 1192 1088 80 ) ( 1200 1280 96 ) we_cemetary/cemstair2 64 0 0.00 1 1 0 0 0 +( 1152 1280 256 ) ( 1216 1280 256 ) ( 1216 1088 256 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 1200 1280 144 ) ( 1200 1088 176 ) ( 1200 1280 208 ) we_cemetary/cemstair2 64 0 0.00 1 1 0 0 0 +( 1168 848 256 ) ( 1184 864 64 ) ( 1152 832 64 ) we_cemetary/cemstair2 64 0 0.00 1 1 0 0 0 +( 1200 1296 256 ) ( 1184 1312 64 ) ( 1216 1280 64 ) we_cemetary/cemstair2 64 0 0.00 1 1 0 0 0 +} +// brush 419 +{ +( 1152 1088 256 ) ( 1200 1088 256 ) ( 1200 1280 256 ) we_cemetary/fogtrunk 0 -64 0.00 1 1 0 0 0 +( 1216 1088 272 ) ( 1152 1088 272 ) ( 1152 1280 272 ) we_cemetary/fogtrunk 0 -64 0.00 1 1 0 0 0 +( 1216 1280 272 ) ( 1200 1280 256 ) ( 1200 1088 256 ) we_cemetary/fogtrunk 0 -64 0.00 1 1 0 0 0 +( 1152 1280 256 ) ( 1152 1280 272 ) ( 1152 1088 272 ) we_cemetary/fogtrunk 64 0 0.00 1 1 0 0 0 +( 1168 848 272 ) ( 1184 864 256 ) ( 1152 832 256 ) we_cemetary/fogtrunk 64 0 0.00 1 1 0 0 0 +( 1200 1296 272 ) ( 1184 1312 256 ) ( 1216 1280 256 ) we_cemetary/fogtrunk 64 0 0.00 1 1 0 0 0 +} +// brush 420 +{ +( 1184 1280 272 ) ( 1184 1088 272 ) ( 1216 1088 272 ) we_cemetary/cemrunner2 0 0 0.00 1 1 0 0 0 +( 1216 1088 336 ) ( 1184 1088 336 ) ( 1184 1280 336 ) we_cemetary/cemtrim2 -32 0 0.00 1 1 0 0 0 +( 1216 1088 272 ) ( 1216 1088 592 ) ( 1216 1280 592 ) we_cemetary/cemtrim2 64 16 0.00 1 1 0 0 0 +( 1152 1280 272 ) ( 1152 1280 592 ) ( 1152 1088 592 ) we_cemetary/cemtrim2 64 16 0.00 1 1 0 0 0 +( 1168 848 336 ) ( 1184 864 272 ) ( 1152 832 272 ) we_cemetary/cemtrim2 64 16 0.00 1 1 0 0 0 +( 1200 1296 336 ) ( 1184 1312 272 ) ( 1216 1280 272 ) we_cemetary/cemtrim2 64 16 0.00 1 1 0 0 0 +} +// brush 421 +{ +( 1216 1296 256 ) ( 1408 1296 256 ) ( 1408 1344 256 ) we_cemetary/fogtrunk -122 63 -90.00 1 1 0 0 0 +( 1216 1344 272 ) ( 1408 1344 272 ) ( 1408 1280 272 ) we_cemetary/fogtrunk -122 63 -90.00 1 1 0 0 0 +( 1408 1296 256 ) ( 1216 1296 256 ) ( 1216 1280 272 ) we_cemetary/fogtrunk -122 63 -90.00 1 1 0 0 0 +( 1408 1344 272 ) ( 1216 1344 272 ) ( 1216 1344 256 ) we_cemetary/fogtrunk -64 0 0.00 1 1 0 0 0 +( 1664 1344 256 ) ( 1632 1312 256 ) ( 1648 1328 272 ) we_cemetary/fogtrunk 64 0 0.00 1 1 0 0 0 +( 1168 1328 272 ) ( 1184 1312 256 ) ( 1152 1344 256 ) we_cemetary/fogtrunk -64 0 0.00 1 1 0 0 0 +} +// brush 422 +{ +( 1408 1280 272 ) ( 1408 1312 272 ) ( 1216 1312 272 ) we_cemetary/cemrunner2 6 0 -90.00 1 1 0 0 0 +( 1216 1312 336 ) ( 1408 1312 336 ) ( 1408 1280 336 ) we_cemetary/cemtrim2 100 0 -90.00 1 1 0 0 0 +( 1216 1280 592 ) ( 1408 1280 592 ) ( 1408 1280 272 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( 1408 1344 592 ) ( 1216 1344 592 ) ( 1216 1344 272 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( 1664 1344 272 ) ( 1632 1312 272 ) ( 1648 1328 336 ) we_cemetary/cemtrim2 64 15 0.00 1 1 0 0 0 +( 1168 1328 336 ) ( 1184 1312 272 ) ( 1152 1344 272 ) we_cemetary/cemtrim2 -64 16 0.00 1 1 0 0 0 +} +// brush 423 +{ +( 1600 1088 272 ) ( 1632 1088 272 ) ( 1632 1280 272 ) we_cemetary/cemrunner2 63 0 -180.00 1 1 0 0 0 +( 1632 1280 336 ) ( 1632 1088 336 ) ( 1600 1088 336 ) we_cemetary/cemtrim2 159 0 -180.00 1 1 0 0 0 +( 1600 1280 592 ) ( 1600 1088 592 ) ( 1600 1088 272 ) we_cemetary/cemtrim2 0 14 -180.00 1 -1 0 0 0 +( 1664 1088 592 ) ( 1664 1280 592 ) ( 1664 1280 272 ) we_cemetary/cemtrim2 0 14 -180.00 1 -1 0 0 0 +( 1664 832 272 ) ( 1632 864 272 ) ( 1648 848 336 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( 1648 1328 336 ) ( 1632 1312 272 ) ( 1664 1344 272 ) we_cemetary/cemtrim2 -64 15 -180.00 1 -1 0 0 0 +} +// brush 424 +{ +( 1616 1280 256 ) ( 1616 1088 256 ) ( 1664 1088 256 ) we_cemetary/fogtrunk 191 0 -180.00 1 1 0 0 0 +( 1664 1280 272 ) ( 1664 1088 272 ) ( 1600 1088 272 ) we_cemetary/fogtrunk 191 0 -180.00 1 1 0 0 0 +( 1616 1088 256 ) ( 1616 1280 256 ) ( 1600 1280 272 ) we_cemetary/fogtrunk 191 0 -180.00 1 1 0 0 0 +( 1664 1088 272 ) ( 1664 1280 272 ) ( 1664 1280 256 ) we_cemetary/fogtrunk 0 0 -180.00 1 -1 0 0 0 +( 1664 832 256 ) ( 1632 864 256 ) ( 1648 848 272 ) we_cemetary/fogtrunk -64 0 0.00 1 1 0 0 0 +( 1648 1328 272 ) ( 1632 1312 256 ) ( 1664 1344 256 ) we_cemetary/fogtrunk -64 0 -180.00 1 -1 0 0 0 +} +// brush 425 +{ +( 1632 1088 64 ) ( 1664 1088 64 ) ( 1664 1280 64 ) we_cemetary/cemstair2 191 0 -180.00 1 1 0 0 0 +( 1664 1088 384 ) ( 1664 1280 384 ) ( 1664 1280 64 ) we_cemetary/cemstair2 0 0 -180.00 1 -1 0 0 0 +( 1616 1280 96 ) ( 1624 1088 80 ) ( 1632 1280 64 ) we_cemetary/cemstair2 0 0 -180.00 1 -1 0 0 0 +( 1600 1088 256 ) ( 1600 1280 256 ) ( 1664 1280 256 ) we_cemetary/cemstair2 191 0 -180.00 1 1 0 0 0 +( 1616 1280 208 ) ( 1616 1088 176 ) ( 1616 1280 144 ) we_cemetary/cemstair2 0 0 -180.00 1 -1 0 0 0 +( 1664 832 64 ) ( 1632 864 64 ) ( 1648 848 256 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 1648 1328 256 ) ( 1632 1312 64 ) ( 1664 1344 64 ) we_cemetary/cemstair2 -64 0 -180.00 1 -1 0 0 0 +} +// brush 426 +{ +( 1632 1088 0 ) ( 1664 1088 0 ) ( 1664 1280 0 ) we_cemetary/cemtrim2 191 0 -180.00 1 1 0 0 0 +( 1664 1280 64 ) ( 1664 1088 64 ) ( 1632 1088 64 ) we_cemetary/cemtrim2 191 0 -180.00 1 1 0 0 0 +( 1632 1408 320 ) ( 1632 1216 320 ) ( 1632 1216 0 ) we_cemetary/cemtrim2 0 0 -180.00 1 -1 0 0 0 +( 1664 1088 320 ) ( 1664 1280 320 ) ( 1664 1280 0 ) we_cemetary/cemtrim2 0 0 -180.00 1 -1 0 0 0 +( 1664 832 0 ) ( 1632 864 0 ) ( 1648 848 64 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 1648 1328 64 ) ( 1632 1312 0 ) ( 1664 1344 0 ) we_cemetary/cemtrim2 -64 0 -180.00 1 -1 0 0 0 +} +// brush 427 +{ +( 1408 864 0 ) ( 1408 832 0 ) ( 1600 832 0 ) we_cemetary/cemtrim2 7 0 90.00 1 1 0 0 0 +( 1600 832 64 ) ( 1408 832 64 ) ( 1408 864 64 ) we_cemetary/cemtrim2 7 0 90.00 1 1 0 0 0 +( 1664 864 320 ) ( 1472 864 320 ) ( 1472 864 0 ) we_cemetary/cemtrim2 128 0 -180.00 1 -1 0 0 0 +( 1408 832 320 ) ( 1600 832 320 ) ( 1600 832 0 ) we_cemetary/cemtrim2 128 0 -180.00 1 -1 0 0 0 +( 1152 832 0 ) ( 1184 864 0 ) ( 1168 848 64 ) we_cemetary/cemtrim2 128 0 -180.00 1 -1 0 0 0 +( 1648 848 64 ) ( 1632 864 0 ) ( 1664 832 0 ) we_cemetary/cemtrim2 128 0 -180.00 1 -1 0 0 0 +} +// brush 428 +{ +( 1408 864 64 ) ( 1408 832 64 ) ( 1600 832 64 ) we_cemetary/cemstair2 7 0 90.00 1 1 0 0 0 +( 1408 832 384 ) ( 1600 832 384 ) ( 1600 832 64 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +( 1600 880 96 ) ( 1408 872 80 ) ( 1600 864 64 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +( 1408 896 256 ) ( 1600 896 256 ) ( 1600 832 256 ) we_cemetary/cemstair2 7 0 90.00 1 1 0 0 0 +( 1600 880 208 ) ( 1408 880 176 ) ( 1600 880 144 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +( 1152 832 64 ) ( 1184 864 64 ) ( 1168 848 256 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +( 1648 848 256 ) ( 1632 864 64 ) ( 1664 832 64 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +} +// brush 429 +{ +( 1600 880 256 ) ( 1408 880 256 ) ( 1408 832 256 ) we_cemetary/fogtrunk 7 -127 90.00 1 1 0 0 0 +( 1600 832 272 ) ( 1408 832 272 ) ( 1408 896 272 ) we_cemetary/fogtrunk 7 -127 90.00 1 1 0 0 0 +( 1408 880 256 ) ( 1600 880 256 ) ( 1600 896 272 ) we_cemetary/fogtrunk 7 -127 90.00 1 1 0 0 0 +( 1408 832 272 ) ( 1600 832 272 ) ( 1600 832 256 ) we_cemetary/fogtrunk 128 0 -180.00 1 -1 0 0 0 +( 1152 832 256 ) ( 1184 864 256 ) ( 1168 848 272 ) we_cemetary/fogtrunk 128 0 -180.00 1 -1 0 0 0 +( 1648 848 272 ) ( 1632 864 256 ) ( 1664 832 256 ) we_cemetary/fogtrunk 128 0 -180.00 1 -1 0 0 0 +} +// brush 430 +{ +( 1408 896 272 ) ( 1408 864 272 ) ( 1600 864 272 ) we_cemetary/cemrunner2 7 3 90.00 1 1.000122 0 0 0 +( 1600 864 336 ) ( 1408 864 336 ) ( 1408 896 336 ) we_cemetary/cemtrim2 -25 0 90.00 1 1 0 0 0 +( 1600 896 592 ) ( 1408 896 592 ) ( 1408 896 272 ) we_cemetary/cemtrim2 128 15 -180.00 1 -1 0 0 0 +( 1408 832 592 ) ( 1600 832 592 ) ( 1600 832 272 ) we_cemetary/cemtrim2 128 15 -180.00 1 -1 0 0 0 +( 1152 832 272 ) ( 1184 864 272 ) ( 1168 848 336 ) we_cemetary/cemtrim2 128 15 -180.00 1 -1 0 0 0 +( 1648 848 336 ) ( 1632 864 272 ) ( 1664 832 272 ) we_cemetary/cemtrim2 128 15 -180.00 1 -1 0 0 0 +} +// brush 431 +{ +( 1920 896 272 ) ( 1920 864 272 ) ( 2112 864 272 ) we_cemetary/cemrunner2 8 3 90.00 1 1.000122 0 0 0 +( 2112 864 336 ) ( 1920 864 336 ) ( 1920 896 336 ) we_cemetary/cemtrim2 -24 0 90.00 1 1 0 0 0 +( 2112 896 592 ) ( 1920 896 592 ) ( 1920 896 272 ) we_cemetary/cemtrim2 128 15 -180.00 1 -1 0 0 0 +( 1920 832 592 ) ( 2112 832 592 ) ( 2112 832 272 ) we_cemetary/cemtrim2 128 15 -180.00 1 -1 0 0 0 +( 1664 832 272 ) ( 1696 864 272 ) ( 1680 848 336 ) we_cemetary/cemtrim2 128 15 -180.00 1 -1 0 0 0 +( 2160 848 336 ) ( 2144 864 272 ) ( 2176 832 272 ) we_cemetary/cemtrim2 128 15 -180.00 1 -1 0 0 0 +} +// brush 432 +{ +( 2112 880 256 ) ( 1920 880 256 ) ( 1920 832 256 ) we_cemetary/fogtrunk 8 -127 90.00 1 1 0 0 0 +( 2112 832 272 ) ( 1920 832 272 ) ( 1920 896 272 ) we_cemetary/fogtrunk 8 -127 90.00 1 1 0 0 0 +( 1920 880 256 ) ( 2112 880 256 ) ( 2112 896 272 ) we_cemetary/fogtrunk 8 -127 90.00 1 1 0 0 0 +( 1920 832 272 ) ( 2112 832 272 ) ( 2112 832 256 ) we_cemetary/fogtrunk 128 0 -180.00 1 -1 0 0 0 +( 1664 832 256 ) ( 1696 864 256 ) ( 1680 848 272 ) we_cemetary/fogtrunk 128 0 -180.00 1 -1 0 0 0 +( 2160 848 272 ) ( 2144 864 256 ) ( 2176 832 256 ) we_cemetary/fogtrunk 128 0 -180.00 1 -1 0 0 0 +} +// brush 433 +{ +( 1920 864 64 ) ( 1920 832 64 ) ( 2112 832 64 ) we_cemetary/cemstair2 8 0 90.00 1 1 0 0 0 +( 1920 832 384 ) ( 2112 832 384 ) ( 2112 832 64 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +( 2112 880 96 ) ( 1920 872 80 ) ( 2112 864 64 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +( 1920 896 256 ) ( 2112 896 256 ) ( 2112 832 256 ) we_cemetary/cemstair2 8 0 90.00 1 1 0 0 0 +( 2112 880 208 ) ( 1920 880 176 ) ( 2112 880 144 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +( 1664 832 64 ) ( 1696 864 64 ) ( 1680 848 256 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +( 2160 848 256 ) ( 2144 864 64 ) ( 2176 832 64 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +} +// brush 434 +{ +( 1920 864 0 ) ( 1920 832 0 ) ( 2112 832 0 ) we_cemetary/cemtrim2 8 0 90.00 1 1 0 0 0 +( 2112 832 64 ) ( 1920 832 64 ) ( 1920 864 64 ) we_cemetary/cemtrim2 8 0 90.00 1 1 0 0 0 +( 2176 864 320 ) ( 1984 864 320 ) ( 1984 864 0 ) we_cemetary/cemtrim2 128 0 -180.00 1 -1 0 0 0 +( 1920 832 320 ) ( 2112 832 320 ) ( 2112 832 0 ) we_cemetary/cemtrim2 128 0 -180.00 1 -1 0 0 0 +( 1664 832 0 ) ( 1696 864 0 ) ( 1680 848 64 ) we_cemetary/cemtrim2 128 0 -180.00 1 -1 0 0 0 +( 2160 848 64 ) ( 2144 864 0 ) ( 2176 832 0 ) we_cemetary/cemtrim2 128 0 -180.00 1 -1 0 0 0 +} +// brush 435 +{ +( 2144 1088 0 ) ( 2176 1088 0 ) ( 2176 1280 0 ) we_cemetary/cemtrim2 -64 0 -180.00 1 1 0 0 0 +( 2176 1280 64 ) ( 2176 1088 64 ) ( 2144 1088 64 ) we_cemetary/cemtrim2 -64 0 -180.00 1 1 0 0 0 +( 2144 1408 320 ) ( 2144 1216 320 ) ( 2144 1216 0 ) we_cemetary/cemtrim2 0 0 -180.00 1 -1 0 0 0 +( 2176 1088 320 ) ( 2176 1280 320 ) ( 2176 1280 0 ) we_cemetary/cemtrim2 0 0 -180.00 1 -1 0 0 0 +( 2176 832 0 ) ( 2144 864 0 ) ( 2160 848 64 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 2160 1328 64 ) ( 2144 1312 0 ) ( 2176 1344 0 ) we_cemetary/cemtrim2 -64 0 -180.00 1 -1 0 0 0 +} +// brush 436 +{ +( 2144 1088 64 ) ( 2176 1088 64 ) ( 2176 1280 64 ) we_cemetary/cemstair2 -64 0 -180.00 1 1 0 0 0 +( 2176 1088 384 ) ( 2176 1280 384 ) ( 2176 1280 64 ) we_cemetary/cemstair2 0 0 -180.00 1 -1 0 0 0 +( 2128 1280 96 ) ( 2136 1088 80 ) ( 2144 1280 64 ) we_cemetary/cemstair2 0 0 -180.00 1 -1 0 0 0 +( 2112 1088 256 ) ( 2112 1280 256 ) ( 2176 1280 256 ) we_cemetary/cemstair2 -64 0 -180.00 1 1 0 0 0 +( 2128 1280 208 ) ( 2128 1088 176 ) ( 2128 1280 144 ) we_cemetary/cemstair2 0 0 -180.00 1 -1 0 0 0 +( 2176 832 64 ) ( 2144 864 64 ) ( 2160 848 256 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 2160 1328 256 ) ( 2144 1312 64 ) ( 2176 1344 64 ) we_cemetary/cemstair2 -64 0 -180.00 1 -1 0 0 0 +} +// brush 437 +{ +( 2128 1280 256 ) ( 2128 1088 256 ) ( 2176 1088 256 ) we_cemetary/fogtrunk -64 0 -180.00 1 1 0 0 0 +( 2176 1280 272 ) ( 2176 1088 272 ) ( 2112 1088 272 ) we_cemetary/fogtrunk -64 0 -180.00 1 1 0 0 0 +( 2128 1088 256 ) ( 2128 1280 256 ) ( 2112 1280 272 ) we_cemetary/fogtrunk -64 0 -180.00 1 1 0 0 0 +( 2176 1088 272 ) ( 2176 1280 272 ) ( 2176 1280 256 ) we_cemetary/fogtrunk 0 0 -180.00 1 -1 0 0 0 +( 2176 832 256 ) ( 2144 864 256 ) ( 2160 848 272 ) we_cemetary/fogtrunk -64 0 0.00 1 1 0 0 0 +( 2160 1328 272 ) ( 2144 1312 256 ) ( 2176 1344 256 ) we_cemetary/fogtrunk -64 0 -180.00 1 -1 0 0 0 +} +// brush 438 +{ +( 2112 1088 272 ) ( 2144 1088 272 ) ( 2144 1280 272 ) we_cemetary/cemrunner2 -64 0 -180.00 1 1 0 0 0 +( 2144 1280 336 ) ( 2144 1088 336 ) ( 2112 1088 336 ) we_cemetary/cemtrim2 159 0 -180.00 1 1 0 0 0 +( 2112 1280 592 ) ( 2112 1088 592 ) ( 2112 1088 272 ) we_cemetary/cemtrim2 0 14 -180.00 1 -1 0 0 0 +( 2176 1088 592 ) ( 2176 1280 592 ) ( 2176 1280 272 ) we_cemetary/cemtrim2 0 14 -180.00 1 -1 0 0 0 +( 2176 832 272 ) ( 2144 864 272 ) ( 2160 848 336 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( 2160 1328 336 ) ( 2144 1312 272 ) ( 2176 1344 272 ) we_cemetary/cemtrim2 -64 15 -180.00 1 -1 0 0 0 +} +// brush 439 +{ +( 1920 1280 272 ) ( 1920 1312 272 ) ( 1728 1312 272 ) we_cemetary/cemrunner2 7 0 -90.00 1 1 0 0 0 +( 1728 1312 336 ) ( 1920 1312 336 ) ( 1920 1280 336 ) we_cemetary/cemtrim2 101 0 -90.00 1 1 0 0 0 +( 1728 1280 592 ) ( 1920 1280 592 ) ( 1920 1280 272 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( 1920 1344 592 ) ( 1728 1344 592 ) ( 1728 1344 272 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( 2176 1344 272 ) ( 2144 1312 272 ) ( 2160 1328 336 ) we_cemetary/cemtrim2 64 15 0.00 1 1 0 0 0 +( 1680 1328 336 ) ( 1696 1312 272 ) ( 1664 1344 272 ) we_cemetary/cemtrim2 -64 16 0.00 1 1 0 0 0 +} +// brush 440 +{ +( 1728 1296 256 ) ( 1920 1296 256 ) ( 1920 1344 256 ) we_cemetary/fogtrunk -121 63 -90.00 1 1 0 0 0 +( 1728 1344 272 ) ( 1920 1344 272 ) ( 1920 1280 272 ) we_cemetary/fogtrunk -121 63 -90.00 1 1 0 0 0 +( 1920 1296 256 ) ( 1728 1296 256 ) ( 1728 1280 272 ) we_cemetary/fogtrunk -121 63 -90.00 1 1 0 0 0 +( 1920 1344 272 ) ( 1728 1344 272 ) ( 1728 1344 256 ) we_cemetary/fogtrunk -64 0 0.00 1 1 0 0 0 +( 2176 1344 256 ) ( 2144 1312 256 ) ( 2160 1328 272 ) we_cemetary/fogtrunk 64 0 0.00 1 1 0 0 0 +( 1680 1328 272 ) ( 1696 1312 256 ) ( 1664 1344 256 ) we_cemetary/fogtrunk -64 0 0.00 1 1 0 0 0 +} +// brush 441 +{ +( 1696 1280 272 ) ( 1696 1088 272 ) ( 1728 1088 272 ) we_cemetary/cemrunner2 0 0 0.00 1 1 0 0 0 +( 1728 1088 336 ) ( 1696 1088 336 ) ( 1696 1280 336 ) we_cemetary/cemtrim2 -32 0 0.00 1 1 0 0 0 +( 1728 1088 272 ) ( 1728 1088 592 ) ( 1728 1280 592 ) we_cemetary/cemtrim2 64 16 0.00 1 1 0 0 0 +( 1664 1280 272 ) ( 1664 1280 592 ) ( 1664 1088 592 ) we_cemetary/cemtrim2 64 16 0.00 1 1 0 0 0 +( 1680 848 336 ) ( 1696 864 272 ) ( 1664 832 272 ) we_cemetary/cemtrim2 64 16 0.00 1 1 0 0 0 +( 1712 1296 336 ) ( 1696 1312 272 ) ( 1728 1280 272 ) we_cemetary/cemtrim2 64 16 0.00 1 1 0 0 0 +} +// brush 442 +{ +( 1664 1088 256 ) ( 1712 1088 256 ) ( 1712 1280 256 ) we_cemetary/fogtrunk 0 -64 0.00 1 1 0 0 0 +( 1728 1088 272 ) ( 1664 1088 272 ) ( 1664 1280 272 ) we_cemetary/fogtrunk 0 -64 0.00 1 1 0 0 0 +( 1728 1280 272 ) ( 1712 1280 256 ) ( 1712 1088 256 ) we_cemetary/fogtrunk 0 -64 0.00 1 1 0 0 0 +( 1664 1280 256 ) ( 1664 1280 272 ) ( 1664 1088 272 ) we_cemetary/fogtrunk 64 0 0.00 1 1 0 0 0 +( 1680 848 272 ) ( 1696 864 256 ) ( 1664 832 256 ) we_cemetary/fogtrunk 64 0 0.00 1 1 0 0 0 +( 1712 1296 272 ) ( 1696 1312 256 ) ( 1728 1280 256 ) we_cemetary/fogtrunk 64 0 0.00 1 1 0 0 0 +} +// brush 443 +{ +( 1664 1280 64 ) ( 1664 1088 64 ) ( 1696 1088 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 1664 1280 64 ) ( 1664 1280 384 ) ( 1664 1088 384 ) we_cemetary/cemstair2 64 0 0.00 1 1 0 0 0 +( 1696 1280 64 ) ( 1704 1088 80 ) ( 1712 1280 96 ) we_cemetary/cemstair2 64 0 0.00 1 1 0 0 0 +( 1664 1280 256 ) ( 1728 1280 256 ) ( 1728 1088 256 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 1712 1280 144 ) ( 1712 1088 176 ) ( 1712 1280 208 ) we_cemetary/cemstair2 64 0 0.00 1 1 0 0 0 +( 1680 848 256 ) ( 1696 864 64 ) ( 1664 832 64 ) we_cemetary/cemstair2 64 0 0.00 1 1 0 0 0 +( 1712 1296 256 ) ( 1696 1312 64 ) ( 1728 1280 64 ) we_cemetary/cemstair2 64 0 0.00 1 1 0 0 0 +} +// brush 444 +{ +( 1664 1280 0 ) ( 1664 1088 0 ) ( 1696 1088 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( 1696 1088 64 ) ( 1664 1088 64 ) ( 1664 1280 64 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( 1696 1152 0 ) ( 1696 1152 320 ) ( 1696 1344 320 ) we_cemetary/cemtrim2 64 0 0.00 1 1 0 0 0 +( 1664 1280 0 ) ( 1664 1280 320 ) ( 1664 1088 320 ) we_cemetary/cemtrim2 64 0 0.00 1 1 0 0 0 +( 1680 848 64 ) ( 1696 864 0 ) ( 1664 832 0 ) we_cemetary/cemtrim2 64 0 0.00 1 1 0 0 0 +( 1712 1296 64 ) ( 1696 1312 0 ) ( 1728 1280 0 ) we_cemetary/cemtrim2 64 0 0.00 1 1 0 0 0 +} +// brush 445 +{ +( 1920 1312 0 ) ( 1920 1344 0 ) ( 1728 1344 0 ) we_cemetary/cemtrim2 -121 0 -90.00 1 1 0 0 0 +( 1728 1344 64 ) ( 1920 1344 64 ) ( 1920 1312 64 ) we_cemetary/cemtrim2 -121 0 -90.00 1 1 0 0 0 +( 1600 1312 320 ) ( 1792 1312 320 ) ( 1792 1312 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 1920 1344 320 ) ( 1728 1344 320 ) ( 1728 1344 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 1680 1328 64 ) ( 1696 1312 0 ) ( 1664 1344 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 1856 1344 64 ) ( 1856 1376 0 ) ( 1856 1312 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +} +// brush 446 +{ +( 1920 1312 0 ) ( 1920 1344 0 ) ( 1728 1344 0 ) we_cemetary/cemtrim2 -121 0 -90.00 1 1 0 0 0 +( 1728 1344 64 ) ( 1920 1344 64 ) ( 1920 1312 64 ) we_cemetary/cemtrim2 -121 0 -90.00 1 1 0 0 0 +( 1728 1312 320 ) ( 1920 1312 320 ) ( 1920 1312 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 1920 1344 320 ) ( 1728 1344 320 ) ( 1728 1344 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 2176 1344 0 ) ( 2144 1312 0 ) ( 2160 1328 64 ) we_cemetary/cemtrim2 64 0 0.00 1 1 0 0 0 +( 1984 1344 64 ) ( 1984 1312 0 ) ( 1984 1376 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +} +// brush 447 +{ +( 1920 1312 64 ) ( 1920 1344 64 ) ( 1728 1344 64 ) we_cemetary/cemstair2 -121 0 -90.00 1 1 0 0 0 +( 1920 1344 384 ) ( 1728 1344 384 ) ( 1728 1344 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 1728 1296 96 ) ( 1920 1304 80 ) ( 1728 1312 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 1920 1280 256 ) ( 1728 1280 256 ) ( 1728 1344 256 ) we_cemetary/cemstair2 -121 0 -90.00 1 1 0 0 0 +( 1728 1296 208 ) ( 1920 1296 176 ) ( 1728 1296 144 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 1680 1328 256 ) ( 1696 1312 64 ) ( 1664 1344 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 1856 1344 256 ) ( 1856 1376 64 ) ( 1856 1312 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +} +// brush 448 +{ +( 1920 1312 64 ) ( 1920 1344 64 ) ( 1728 1344 64 ) we_cemetary/cemstair2 -121 0 -90.00 1 1 0 0 0 +( 1920 1344 384 ) ( 1728 1344 384 ) ( 1728 1344 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 1728 1296 96 ) ( 1920 1304 80 ) ( 1728 1312 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 1920 1280 256 ) ( 1728 1280 256 ) ( 1728 1344 256 ) we_cemetary/cemstair2 -121 0 -90.00 1 1 0 0 0 +( 1856 1296 208 ) ( 2048 1296 176 ) ( 1856 1296 144 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 2176 1344 64 ) ( 2144 1312 64 ) ( 2160 1328 256 ) we_cemetary/cemstair2 64 0 0.00 1 1 0 0 0 +( 1984 1344 256 ) ( 1984 1312 64 ) ( 1984 1376 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +} +// brush 449 +{ +( 1728 1344 64 ) ( 1920 1344 64 ) ( 1920 1376 64 ) we_cemetary/cemstair2 69 0 -90.00 1 1 0 0 0 +( 1728 1344 64 ) ( 1728 1344 384 ) ( 1920 1344 384 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 1728 1376 64 ) ( 1920 1384 80 ) ( 1728 1392 96 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 1728 1344 256 ) ( 1728 1408 256 ) ( 1920 1408 256 ) we_cemetary/cemstair2 69 0 -90.00 1 1 0 0 0 +( 1824 1392 144 ) ( 2016 1392 176 ) ( 1824 1392 208 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 1984 1344 256 ) ( 1984 1312 64 ) ( 1984 1376 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 2176 1376 256 ) ( 2176 1408 64 ) ( 2176 1344 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +} +// brush 450 +{ +( 1728 1344 0 ) ( 1920 1344 0 ) ( 1920 1376 0 ) we_cemetary/cemtrim2 69 0 -90.00 1 1 0 0 0 +( 1920 1376 64 ) ( 1920 1344 64 ) ( 1728 1344 64 ) we_cemetary/cemtrim2 69 0 -90.00 1 1 0 0 0 +( 2016 1376 0 ) ( 2016 1376 320 ) ( 1824 1376 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 1728 1344 0 ) ( 1728 1344 320 ) ( 1920 1344 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 1984 1344 64 ) ( 1984 1312 0 ) ( 1984 1376 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( 2176 1376 64 ) ( 2176 1408 0 ) ( 2176 1344 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +} +// brush 451 +{ +( 1728 1344 64 ) ( 1920 1344 64 ) ( 1920 1376 64 ) we_cemetary/cemstair2 69 0 -90.00 1 1 0 0 0 +( 1728 1344 64 ) ( 1728 1344 384 ) ( 1920 1344 384 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 1728 1376 64 ) ( 1920 1384 80 ) ( 1728 1392 96 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 1728 1344 256 ) ( 1728 1408 256 ) ( 1920 1408 256 ) we_cemetary/cemstair2 69 0 -90.00 1 1 0 0 0 +( 1728 1392 144 ) ( 1920 1392 176 ) ( 1728 1392 208 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 1856 1344 256 ) ( 1856 1376 64 ) ( 1856 1312 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 1664 1392 256 ) ( 1664 1376 64 ) ( 1664 1408 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +} +// brush 452 +{ +( 1728 1344 0 ) ( 1920 1344 0 ) ( 1920 1376 0 ) we_cemetary/cemtrim2 69 0 -90.00 1 1 0 0 0 +( 1920 1376 64 ) ( 1920 1344 64 ) ( 1728 1344 64 ) we_cemetary/cemtrim2 69 0 -90.00 1 1 0 0 0 +( 1728 1376 0 ) ( 1728 1376 320 ) ( 1536 1376 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 1728 1344 0 ) ( 1728 1344 320 ) ( 1920 1344 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 1856 1344 64 ) ( 1856 1376 0 ) ( 1856 1312 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( 1664 1392 64 ) ( 1664 1376 0 ) ( 1664 1408 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +} +// brush 453 +{ +( 1920 1344 256 ) ( 1920 1392 256 ) ( 1728 1392 256 ) we_cemetary/fogtrunk 69 63 -90.00 1 1 0 0 0 +( 1920 1408 272 ) ( 1920 1344 272 ) ( 1728 1344 272 ) we_cemetary/fogtrunk 69 63 -90.00 1 1 0 0 0 +( 1728 1408 272 ) ( 1728 1392 256 ) ( 1920 1392 256 ) we_cemetary/fogtrunk 69 63 -90.00 1 1 0 0 0 +( 1728 1344 256 ) ( 1728 1344 272 ) ( 1920 1344 272 ) we_cemetary/fogtrunk -64 0 0.00 1 1 0 0 0 +( 2176 1376 272 ) ( 2176 1408 256 ) ( 2176 1344 256 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +( 1664 1392 272 ) ( 1664 1376 256 ) ( 1664 1408 256 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +} +// brush 454 +{ +( 1728 1376 272 ) ( 1920 1376 272 ) ( 1920 1408 272 ) we_cemetary/cemrunner2 -64 0 -90.00 1 1 0 0 0 +( 1920 1408 336 ) ( 1920 1376 336 ) ( 1728 1376 336 ) we_cemetary/cemtrim2 37 0 -90.00 1 1 0 0 0 +( 1920 1408 272 ) ( 1920 1408 592 ) ( 1728 1408 592 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( 1728 1344 272 ) ( 1728 1344 592 ) ( 1920 1344 592 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( 2176 1376 336 ) ( 2176 1408 272 ) ( 2176 1344 272 ) we_cemetary/cemtrim2 0 16 0.00 1 1 0 0 0 +( 1664 1392 336 ) ( 1664 1376 272 ) ( 1664 1408 272 ) we_cemetary/cemtrim2 0 16 0.00 1 1 0 0 0 +} +// brush 455 +{ +( 1696 1312 -32 ) ( 1696 864 -32 ) ( 2144 864 -32 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 2144 864 0 ) ( 1696 864 0 ) ( 1696 1312 0 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 2144 1376 -64 ) ( 2144 1376 0 ) ( 1696 1376 0 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 2176 864 -64 ) ( 2176 864 0 ) ( 2176 1312 0 ) we_cemetary/cemtrim5 64 0 0.00 1 1 0 0 0 +( 1696 832 -64 ) ( 1696 832 0 ) ( 2144 832 0 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 1664 1312 -64 ) ( 1664 1312 0 ) ( 1664 864 0 ) we_cemetary/cemtrim5 64 0 0.00 1 1 0 0 0 +} +// brush 456 +{ +( 1696 1312 336 ) ( 1696 864 336 ) ( 2144 864 336 ) water/waterfloor2 0 -64 0.00 1 1 0 0 0 +( 2144 864 352 ) ( 1696 864 352 ) ( 1696 1312 352 ) water/waterfloor2 0 -64 0.00 1 1 0 0 0 +( 2144 1312 304 ) ( 2144 1312 368 ) ( 1696 1312 368 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +( 2144 864 304 ) ( 2144 864 368 ) ( 2144 1312 368 ) water/waterfloor2 64 0 0.00 1 1 0 0 0 +( 1696 864 304 ) ( 1696 864 368 ) ( 2144 864 368 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +( 1696 1312 304 ) ( 1696 1312 368 ) ( 1696 864 368 ) water/waterfloor2 64 0 0.00 1 1 0 0 0 +} +// brush 457 +{ +( 1856 1392 208 ) ( 1856 1296 208 ) ( 1984 1296 208 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 1984 1296 256 ) ( 1856 1296 256 ) ( 1856 1392 256 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 1984 1392 64 ) ( 1984 1392 256 ) ( 1856 1392 256 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 1984 1296 48 ) ( 1984 1296 240 ) ( 1984 1392 240 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 1856 1296 48 ) ( 1856 1296 240 ) ( 1984 1296 240 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 1856 1392 64 ) ( 1856 1392 256 ) ( 1856 1296 256 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +} +// brush 458 +{ +( 2368 1392 208 ) ( 2368 1296 208 ) ( 2496 1296 208 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 2496 1296 256 ) ( 2368 1296 256 ) ( 2368 1392 256 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 2496 1392 64 ) ( 2496 1392 256 ) ( 2368 1392 256 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 2496 1296 48 ) ( 2496 1296 240 ) ( 2496 1392 240 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 2368 1296 48 ) ( 2368 1296 240 ) ( 2496 1296 240 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 2368 1392 64 ) ( 2368 1392 256 ) ( 2368 1296 256 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +} +// brush 459 +{ +( 2208 1312 336 ) ( 2208 864 336 ) ( 2656 864 336 ) water/waterfloor2 0 -64 0.00 1 1 0 0 0 +( 2656 864 352 ) ( 2208 864 352 ) ( 2208 1312 352 ) water/waterfloor2 0 -64 0.00 1 1 0 0 0 +( 2656 1312 304 ) ( 2656 1312 368 ) ( 2208 1312 368 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +( 2656 864 304 ) ( 2656 864 368 ) ( 2656 1312 368 ) water/waterfloor2 64 0 0.00 1 1 0 0 0 +( 2208 864 304 ) ( 2208 864 368 ) ( 2656 864 368 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +( 2208 1312 304 ) ( 2208 1312 368 ) ( 2208 864 368 ) water/waterfloor2 64 0 0.00 1 1 0 0 0 +} +// brush 460 +{ +( 2208 1312 -32 ) ( 2208 864 -32 ) ( 2656 864 -32 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 2656 864 0 ) ( 2208 864 0 ) ( 2208 1312 0 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 2656 1376 -64 ) ( 2656 1376 0 ) ( 2208 1376 0 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 2688 864 -64 ) ( 2688 864 0 ) ( 2688 1312 0 ) we_cemetary/cemtrim5 64 0 0.00 1 1 0 0 0 +( 2208 832 -64 ) ( 2208 832 0 ) ( 2656 832 0 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 2176 1312 -64 ) ( 2176 1312 0 ) ( 2176 864 0 ) we_cemetary/cemtrim5 64 0 0.00 1 1 0 0 0 +} +// brush 461 +{ +( 2240 1376 272 ) ( 2432 1376 272 ) ( 2432 1408 272 ) we_cemetary/cemrunner2 -64 0 -90.00 1 1 0 0 0 +( 2432 1408 336 ) ( 2432 1376 336 ) ( 2240 1376 336 ) we_cemetary/cemtrim2 38 0 -90.00 1 1 0 0 0 +( 2432 1408 272 ) ( 2432 1408 592 ) ( 2240 1408 592 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( 2240 1344 272 ) ( 2240 1344 592 ) ( 2432 1344 592 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( 2688 1376 336 ) ( 2688 1408 272 ) ( 2688 1344 272 ) we_cemetary/cemtrim2 0 16 0.00 1 1 0 0 0 +( 2176 1392 336 ) ( 2176 1376 272 ) ( 2176 1408 272 ) we_cemetary/cemtrim2 0 16 0.00 1 1 0 0 0 +} +// brush 462 +{ +( 2432 1344 256 ) ( 2432 1392 256 ) ( 2240 1392 256 ) we_cemetary/fogtrunk 70 63 -90.00 1 1 0 0 0 +( 2432 1408 272 ) ( 2432 1344 272 ) ( 2240 1344 272 ) we_cemetary/fogtrunk 70 63 -90.00 1 1 0 0 0 +( 2240 1408 272 ) ( 2240 1392 256 ) ( 2432 1392 256 ) we_cemetary/fogtrunk 70 63 -90.00 1 1 0 0 0 +( 2240 1344 256 ) ( 2240 1344 272 ) ( 2432 1344 272 ) we_cemetary/fogtrunk -64 0 0.00 1 1 0 0 0 +( 2688 1376 272 ) ( 2688 1408 256 ) ( 2688 1344 256 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +( 2176 1392 272 ) ( 2176 1376 256 ) ( 2176 1408 256 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +} +// brush 463 +{ +( 2240 1344 0 ) ( 2432 1344 0 ) ( 2432 1376 0 ) we_cemetary/cemtrim2 70 0 -90.00 1 1 0 0 0 +( 2432 1376 64 ) ( 2432 1344 64 ) ( 2240 1344 64 ) we_cemetary/cemtrim2 70 0 -90.00 1 1 0 0 0 +( 2240 1376 0 ) ( 2240 1376 320 ) ( 2048 1376 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 2240 1344 0 ) ( 2240 1344 320 ) ( 2432 1344 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 2368 1344 64 ) ( 2368 1376 0 ) ( 2368 1312 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( 2176 1392 64 ) ( 2176 1376 0 ) ( 2176 1408 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +} +// brush 464 +{ +( 2240 1344 64 ) ( 2432 1344 64 ) ( 2432 1376 64 ) we_cemetary/cemstair2 70 0 -90.00 1 1 0 0 0 +( 2240 1344 64 ) ( 2240 1344 384 ) ( 2432 1344 384 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 2240 1376 64 ) ( 2432 1384 80 ) ( 2240 1392 96 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 2240 1344 256 ) ( 2240 1408 256 ) ( 2432 1408 256 ) we_cemetary/cemstair2 70 0 -90.00 1 1 0 0 0 +( 2240 1392 144 ) ( 2432 1392 176 ) ( 2240 1392 208 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 2368 1344 256 ) ( 2368 1376 64 ) ( 2368 1312 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 2176 1392 256 ) ( 2176 1376 64 ) ( 2176 1408 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +} +// brush 465 +{ +( 2240 1344 0 ) ( 2432 1344 0 ) ( 2432 1376 0 ) we_cemetary/cemtrim2 70 0 -90.00 1 1 0 0 0 +( 2432 1376 64 ) ( 2432 1344 64 ) ( 2240 1344 64 ) we_cemetary/cemtrim2 70 0 -90.00 1 1 0 0 0 +( 2528 1376 0 ) ( 2528 1376 320 ) ( 2336 1376 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 2240 1344 0 ) ( 2240 1344 320 ) ( 2432 1344 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 2496 1344 64 ) ( 2496 1312 0 ) ( 2496 1376 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( 2688 1376 64 ) ( 2688 1408 0 ) ( 2688 1344 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +} +// brush 466 +{ +( 2240 1344 64 ) ( 2432 1344 64 ) ( 2432 1376 64 ) we_cemetary/cemstair2 70 0 -90.00 1 1 0 0 0 +( 2240 1344 64 ) ( 2240 1344 384 ) ( 2432 1344 384 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 2240 1376 64 ) ( 2432 1384 80 ) ( 2240 1392 96 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 2240 1344 256 ) ( 2240 1408 256 ) ( 2432 1408 256 ) we_cemetary/cemstair2 70 0 -90.00 1 1 0 0 0 +( 2336 1392 144 ) ( 2528 1392 176 ) ( 2336 1392 208 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 2496 1344 256 ) ( 2496 1312 64 ) ( 2496 1376 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 2688 1376 256 ) ( 2688 1408 64 ) ( 2688 1344 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +} +// brush 467 +{ +( 2432 1312 64 ) ( 2432 1344 64 ) ( 2240 1344 64 ) we_cemetary/cemstair2 -120 0 -90.00 1 1 0 0 0 +( 2432 1344 384 ) ( 2240 1344 384 ) ( 2240 1344 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 2240 1296 96 ) ( 2432 1304 80 ) ( 2240 1312 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 2432 1280 256 ) ( 2240 1280 256 ) ( 2240 1344 256 ) we_cemetary/cemstair2 -120 0 -90.00 1 1 0 0 0 +( 2368 1296 208 ) ( 2560 1296 176 ) ( 2368 1296 144 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 2688 1344 64 ) ( 2656 1312 64 ) ( 2672 1328 256 ) we_cemetary/cemstair2 64 0 0.00 1 1 0 0 0 +( 2496 1344 256 ) ( 2496 1312 64 ) ( 2496 1376 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +} +// brush 468 +{ +( 2432 1312 64 ) ( 2432 1344 64 ) ( 2240 1344 64 ) we_cemetary/cemstair2 -120 0 -90.00 1 1 0 0 0 +( 2432 1344 384 ) ( 2240 1344 384 ) ( 2240 1344 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 2240 1296 96 ) ( 2432 1304 80 ) ( 2240 1312 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 2432 1280 256 ) ( 2240 1280 256 ) ( 2240 1344 256 ) we_cemetary/cemstair2 -120 0 -90.00 1 1 0 0 0 +( 2240 1296 208 ) ( 2432 1296 176 ) ( 2240 1296 144 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 2192 1328 256 ) ( 2208 1312 64 ) ( 2176 1344 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 2368 1344 256 ) ( 2368 1376 64 ) ( 2368 1312 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +} +// brush 469 +{ +( 2432 1312 0 ) ( 2432 1344 0 ) ( 2240 1344 0 ) we_cemetary/cemtrim2 -120 0 -90.00 1 1 0 0 0 +( 2240 1344 64 ) ( 2432 1344 64 ) ( 2432 1312 64 ) we_cemetary/cemtrim2 -120 0 -90.00 1 1 0 0 0 +( 2240 1312 320 ) ( 2432 1312 320 ) ( 2432 1312 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 2432 1344 320 ) ( 2240 1344 320 ) ( 2240 1344 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 2688 1344 0 ) ( 2656 1312 0 ) ( 2672 1328 64 ) we_cemetary/cemtrim2 64 0 0.00 1 1 0 0 0 +( 2496 1344 64 ) ( 2496 1312 0 ) ( 2496 1376 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +} +// brush 470 +{ +( 2432 1312 0 ) ( 2432 1344 0 ) ( 2240 1344 0 ) we_cemetary/cemtrim2 -120 0 -90.00 1 1 0 0 0 +( 2240 1344 64 ) ( 2432 1344 64 ) ( 2432 1312 64 ) we_cemetary/cemtrim2 -120 0 -90.00 1 1 0 0 0 +( 2112 1312 320 ) ( 2304 1312 320 ) ( 2304 1312 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 2432 1344 320 ) ( 2240 1344 320 ) ( 2240 1344 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 2192 1328 64 ) ( 2208 1312 0 ) ( 2176 1344 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 2368 1344 64 ) ( 2368 1376 0 ) ( 2368 1312 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +} +// brush 471 +{ +( 2176 1280 0 ) ( 2176 1088 0 ) ( 2208 1088 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( 2208 1088 64 ) ( 2176 1088 64 ) ( 2176 1280 64 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( 2208 1152 0 ) ( 2208 1152 320 ) ( 2208 1344 320 ) we_cemetary/cemtrim2 64 0 0.00 1 1 0 0 0 +( 2176 1280 0 ) ( 2176 1280 320 ) ( 2176 1088 320 ) we_cemetary/cemtrim2 64 0 0.00 1 1 0 0 0 +( 2192 848 64 ) ( 2208 864 0 ) ( 2176 832 0 ) we_cemetary/cemtrim2 64 0 0.00 1 1 0 0 0 +( 2224 1296 64 ) ( 2208 1312 0 ) ( 2240 1280 0 ) we_cemetary/cemtrim2 64 0 0.00 1 1 0 0 0 +} +// brush 472 +{ +( 2176 1280 64 ) ( 2176 1088 64 ) ( 2208 1088 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 2176 1280 64 ) ( 2176 1280 384 ) ( 2176 1088 384 ) we_cemetary/cemstair2 64 0 0.00 1 1 0 0 0 +( 2208 1280 64 ) ( 2216 1088 80 ) ( 2224 1280 96 ) we_cemetary/cemstair2 64 0 0.00 1 1 0 0 0 +( 2176 1280 256 ) ( 2240 1280 256 ) ( 2240 1088 256 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 2224 1280 144 ) ( 2224 1088 176 ) ( 2224 1280 208 ) we_cemetary/cemstair2 64 0 0.00 1 1 0 0 0 +( 2192 848 256 ) ( 2208 864 64 ) ( 2176 832 64 ) we_cemetary/cemstair2 64 0 0.00 1 1 0 0 0 +( 2224 1296 256 ) ( 2208 1312 64 ) ( 2240 1280 64 ) we_cemetary/cemstair2 64 0 0.00 1 1 0 0 0 +} +// brush 473 +{ +( 2176 1088 256 ) ( 2224 1088 256 ) ( 2224 1280 256 ) we_cemetary/fogtrunk 0 -64 0.00 1 1 0 0 0 +( 2240 1088 272 ) ( 2176 1088 272 ) ( 2176 1280 272 ) we_cemetary/fogtrunk 0 -64 0.00 1 1 0 0 0 +( 2240 1280 272 ) ( 2224 1280 256 ) ( 2224 1088 256 ) we_cemetary/fogtrunk 0 -64 0.00 1 1 0 0 0 +( 2176 1280 256 ) ( 2176 1280 272 ) ( 2176 1088 272 ) we_cemetary/fogtrunk 64 0 0.00 1 1 0 0 0 +( 2192 848 272 ) ( 2208 864 256 ) ( 2176 832 256 ) we_cemetary/fogtrunk 64 0 0.00 1 1 0 0 0 +( 2224 1296 272 ) ( 2208 1312 256 ) ( 2240 1280 256 ) we_cemetary/fogtrunk 64 0 0.00 1 1 0 0 0 +} +// brush 474 +{ +( 2208 1280 272 ) ( 2208 1088 272 ) ( 2240 1088 272 ) we_cemetary/cemrunner2 0 0 0.00 1 1 0 0 0 +( 2240 1088 336 ) ( 2208 1088 336 ) ( 2208 1280 336 ) we_cemetary/cemtrim2 -32 0 0.00 1 1 0 0 0 +( 2240 1088 272 ) ( 2240 1088 592 ) ( 2240 1280 592 ) we_cemetary/cemtrim2 64 16 0.00 1 1 0 0 0 +( 2176 1280 272 ) ( 2176 1280 592 ) ( 2176 1088 592 ) we_cemetary/cemtrim2 64 16 0.00 1 1 0 0 0 +( 2192 848 336 ) ( 2208 864 272 ) ( 2176 832 272 ) we_cemetary/cemtrim2 64 16 0.00 1 1 0 0 0 +( 2224 1296 336 ) ( 2208 1312 272 ) ( 2240 1280 272 ) we_cemetary/cemtrim2 64 16 0.00 1 1 0 0 0 +} +// brush 475 +{ +( 2240 1296 256 ) ( 2432 1296 256 ) ( 2432 1344 256 ) we_cemetary/fogtrunk -120 63 -90.00 1 1 0 0 0 +( 2240 1344 272 ) ( 2432 1344 272 ) ( 2432 1280 272 ) we_cemetary/fogtrunk -120 63 -90.00 1 1 0 0 0 +( 2432 1296 256 ) ( 2240 1296 256 ) ( 2240 1280 272 ) we_cemetary/fogtrunk -120 63 -90.00 1 1 0 0 0 +( 2432 1344 272 ) ( 2240 1344 272 ) ( 2240 1344 256 ) we_cemetary/fogtrunk -64 0 0.00 1 1 0 0 0 +( 2688 1344 256 ) ( 2656 1312 256 ) ( 2672 1328 272 ) we_cemetary/fogtrunk 64 0 0.00 1 1 0 0 0 +( 2192 1328 272 ) ( 2208 1312 256 ) ( 2176 1344 256 ) we_cemetary/fogtrunk -64 0 0.00 1 1 0 0 0 +} +// brush 476 +{ +( 2432 1280 272 ) ( 2432 1312 272 ) ( 2240 1312 272 ) we_cemetary/cemrunner2 8 0 -90.00 1 1 0 0 0 +( 2240 1312 336 ) ( 2432 1312 336 ) ( 2432 1280 336 ) we_cemetary/cemtrim2 102 0 -90.00 1 1 0 0 0 +( 2240 1280 592 ) ( 2432 1280 592 ) ( 2432 1280 272 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( 2432 1344 592 ) ( 2240 1344 592 ) ( 2240 1344 272 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( 2688 1344 272 ) ( 2656 1312 272 ) ( 2672 1328 336 ) we_cemetary/cemtrim2 64 15 0.00 1 1 0 0 0 +( 2192 1328 336 ) ( 2208 1312 272 ) ( 2176 1344 272 ) we_cemetary/cemtrim2 -64 16 0.00 1 1 0 0 0 +} +// brush 477 +{ +( 2624 1088 272 ) ( 2656 1088 272 ) ( 2656 1280 272 ) we_cemetary/cemrunner2 63 0 -180.00 1 1 0 0 0 +( 2656 1280 336 ) ( 2656 1088 336 ) ( 2624 1088 336 ) we_cemetary/cemtrim2 159 0 -180.00 1 1 0 0 0 +( 2624 1280 592 ) ( 2624 1088 592 ) ( 2624 1088 272 ) we_cemetary/cemtrim2 0 14 -180.00 1 -1 0 0 0 +( 2688 1088 592 ) ( 2688 1280 592 ) ( 2688 1280 272 ) we_cemetary/cemtrim2 0 14 -180.00 1 -1 0 0 0 +( 2688 832 272 ) ( 2656 864 272 ) ( 2672 848 336 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( 2672 1328 336 ) ( 2656 1312 272 ) ( 2688 1344 272 ) we_cemetary/cemtrim2 -64 15 -180.00 1 -1 0 0 0 +} +// brush 478 +{ +( 2640 1280 256 ) ( 2640 1088 256 ) ( 2688 1088 256 ) we_cemetary/fogtrunk 191 0 -180.00 1 1 0 0 0 +( 2688 1280 272 ) ( 2688 1088 272 ) ( 2624 1088 272 ) we_cemetary/fogtrunk 191 0 -180.00 1 1 0 0 0 +( 2640 1088 256 ) ( 2640 1280 256 ) ( 2624 1280 272 ) we_cemetary/fogtrunk 191 0 -180.00 1 1 0 0 0 +( 2688 1088 272 ) ( 2688 1280 272 ) ( 2688 1280 256 ) we_cemetary/fogtrunk 0 0 -180.00 1 -1 0 0 0 +( 2688 832 256 ) ( 2656 864 256 ) ( 2672 848 272 ) we_cemetary/fogtrunk -64 0 0.00 1 1 0 0 0 +( 2672 1328 272 ) ( 2656 1312 256 ) ( 2688 1344 256 ) we_cemetary/fogtrunk -64 0 -180.00 1 -1 0 0 0 +} +// brush 479 +{ +( 2656 1088 64 ) ( 2688 1088 64 ) ( 2688 1280 64 ) we_cemetary/cemstair2 191 0 -180.00 1 1 0 0 0 +( 2688 1088 384 ) ( 2688 1280 384 ) ( 2688 1280 64 ) we_cemetary/cemstair2 0 0 -180.00 1 -1 0 0 0 +( 2640 1280 96 ) ( 2648 1088 80 ) ( 2656 1280 64 ) we_cemetary/cemstair2 0 0 -180.00 1 -1 0 0 0 +( 2624 1088 256 ) ( 2624 1280 256 ) ( 2688 1280 256 ) we_cemetary/cemstair2 191 0 -180.00 1 1 0 0 0 +( 2640 1280 208 ) ( 2640 1088 176 ) ( 2640 1280 144 ) we_cemetary/cemstair2 0 0 -180.00 1 -1 0 0 0 +( 2688 832 64 ) ( 2656 864 64 ) ( 2672 848 256 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 2672 1328 256 ) ( 2656 1312 64 ) ( 2688 1344 64 ) we_cemetary/cemstair2 -64 0 -180.00 1 -1 0 0 0 +} +// brush 480 +{ +( 2656 1088 0 ) ( 2688 1088 0 ) ( 2688 1280 0 ) we_cemetary/cemtrim2 191 0 -180.00 1 1 0 0 0 +( 2688 1280 64 ) ( 2688 1088 64 ) ( 2656 1088 64 ) we_cemetary/cemtrim2 191 0 -180.00 1 1 0 0 0 +( 2656 1408 320 ) ( 2656 1216 320 ) ( 2656 1216 0 ) we_cemetary/cemtrim2 0 0 -180.00 1 -1 0 0 0 +( 2688 1088 320 ) ( 2688 1280 320 ) ( 2688 1280 0 ) we_cemetary/cemtrim2 0 0 -180.00 1 -1 0 0 0 +( 2688 832 0 ) ( 2656 864 0 ) ( 2672 848 64 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 2672 1328 64 ) ( 2656 1312 0 ) ( 2688 1344 0 ) we_cemetary/cemtrim2 -64 0 -180.00 1 -1 0 0 0 +} +// brush 481 +{ +( 2432 864 0 ) ( 2432 832 0 ) ( 2624 832 0 ) we_cemetary/cemtrim2 9 0 90.00 1 1 0 0 0 +( 2624 832 64 ) ( 2432 832 64 ) ( 2432 864 64 ) we_cemetary/cemtrim2 9 0 90.00 1 1 0 0 0 +( 2688 864 320 ) ( 2496 864 320 ) ( 2496 864 0 ) we_cemetary/cemtrim2 128 0 -180.00 1 -1 0 0 0 +( 2432 832 320 ) ( 2624 832 320 ) ( 2624 832 0 ) we_cemetary/cemtrim2 128 0 -180.00 1 -1 0 0 0 +( 2176 832 0 ) ( 2208 864 0 ) ( 2192 848 64 ) we_cemetary/cemtrim2 128 0 -180.00 1 -1 0 0 0 +( 2672 848 64 ) ( 2656 864 0 ) ( 2688 832 0 ) we_cemetary/cemtrim2 128 0 -180.00 1 -1 0 0 0 +} +// brush 482 +{ +( 2432 864 64 ) ( 2432 832 64 ) ( 2624 832 64 ) we_cemetary/cemstair2 9 0 90.00 1 1 0 0 0 +( 2432 832 384 ) ( 2624 832 384 ) ( 2624 832 64 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +( 2624 880 96 ) ( 2432 872 80 ) ( 2624 864 64 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +( 2432 896 256 ) ( 2624 896 256 ) ( 2624 832 256 ) we_cemetary/cemstair2 9 0 90.00 1 1 0 0 0 +( 2624 880 208 ) ( 2432 880 176 ) ( 2624 880 144 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +( 2176 832 64 ) ( 2208 864 64 ) ( 2192 848 256 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +( 2672 848 256 ) ( 2656 864 64 ) ( 2688 832 64 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +} +// brush 483 +{ +( 2624 880 256 ) ( 2432 880 256 ) ( 2432 832 256 ) we_cemetary/fogtrunk 9 -127 90.00 1 1 0 0 0 +( 2624 832 272 ) ( 2432 832 272 ) ( 2432 896 272 ) we_cemetary/fogtrunk 9 -127 90.00 1 1 0 0 0 +( 2432 880 256 ) ( 2624 880 256 ) ( 2624 896 272 ) we_cemetary/fogtrunk 9 -127 90.00 1 1 0 0 0 +( 2432 832 272 ) ( 2624 832 272 ) ( 2624 832 256 ) we_cemetary/fogtrunk 128 0 -180.00 1 -1 0 0 0 +( 2176 832 256 ) ( 2208 864 256 ) ( 2192 848 272 ) we_cemetary/fogtrunk 128 0 -180.00 1 -1 0 0 0 +( 2672 848 272 ) ( 2656 864 256 ) ( 2688 832 256 ) we_cemetary/fogtrunk 128 0 -180.00 1 -1 0 0 0 +} +// brush 484 +{ +( 2432 896 272 ) ( 2432 864 272 ) ( 2624 864 272 ) we_cemetary/cemrunner2 9 4 90.00 1 1.000122 0 0 0 +( 2624 864 336 ) ( 2432 864 336 ) ( 2432 896 336 ) we_cemetary/cemtrim2 -23 0 90.00 1 1 0 0 0 +( 2624 896 592 ) ( 2432 896 592 ) ( 2432 896 272 ) we_cemetary/cemtrim2 128 15 -180.00 1 -1 0 0 0 +( 2432 832 592 ) ( 2624 832 592 ) ( 2624 832 272 ) we_cemetary/cemtrim2 128 15 -180.00 1 -1 0 0 0 +( 2176 832 272 ) ( 2208 864 272 ) ( 2192 848 336 ) we_cemetary/cemtrim2 128 15 -180.00 1 -1 0 0 0 +( 2672 848 336 ) ( 2656 864 272 ) ( 2688 832 272 ) we_cemetary/cemtrim2 128 15 -180.00 1 -1 0 0 0 +} +// brush 485 +{ +( 2944 896 272 ) ( 2944 864 272 ) ( 3136 864 272 ) we_cemetary/cemrunner2 10 4 90.00 1 1.000122 0 0 0 +( 3136 864 336 ) ( 2944 864 336 ) ( 2944 896 336 ) we_cemetary/cemtrim2 -22 0 90.00 1 1 0 0 0 +( 3136 896 592 ) ( 2944 896 592 ) ( 2944 896 272 ) we_cemetary/cemtrim2 128 15 -180.00 1 -1 0 0 0 +( 2944 832 592 ) ( 3136 832 592 ) ( 3136 832 272 ) we_cemetary/cemtrim2 128 15 -180.00 1 -1 0 0 0 +( 2688 832 272 ) ( 2720 864 272 ) ( 2704 848 336 ) we_cemetary/cemtrim2 128 15 -180.00 1 -1 0 0 0 +( 3184 848 336 ) ( 3168 864 272 ) ( 3200 832 272 ) we_cemetary/cemtrim2 128 15 -180.00 1 -1 0 0 0 +} +// brush 486 +{ +( 3136 880 256 ) ( 2944 880 256 ) ( 2944 832 256 ) we_cemetary/fogtrunk 10 -127 90.00 1 1 0 0 0 +( 3136 832 272 ) ( 2944 832 272 ) ( 2944 896 272 ) we_cemetary/fogtrunk 10 -127 90.00 1 1 0 0 0 +( 2944 880 256 ) ( 3136 880 256 ) ( 3136 896 272 ) we_cemetary/fogtrunk 10 -127 90.00 1 1 0 0 0 +( 2944 832 272 ) ( 3136 832 272 ) ( 3136 832 256 ) we_cemetary/fogtrunk 128 0 -180.00 1 -1 0 0 0 +( 2688 832 256 ) ( 2720 864 256 ) ( 2704 848 272 ) we_cemetary/fogtrunk 128 0 -180.00 1 -1 0 0 0 +( 3184 848 272 ) ( 3168 864 256 ) ( 3200 832 256 ) we_cemetary/fogtrunk 128 0 -180.00 1 -1 0 0 0 +} +// brush 487 +{ +( 2944 864 64 ) ( 2944 832 64 ) ( 3136 832 64 ) we_cemetary/cemstair2 10 0 90.00 1 1 0 0 0 +( 2944 832 384 ) ( 3136 832 384 ) ( 3136 832 64 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +( 3136 880 96 ) ( 2944 872 80 ) ( 3136 864 64 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +( 2944 896 256 ) ( 3136 896 256 ) ( 3136 832 256 ) we_cemetary/cemstair2 10 0 90.00 1 1 0 0 0 +( 3136 880 208 ) ( 2944 880 176 ) ( 3136 880 144 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +( 2688 832 64 ) ( 2720 864 64 ) ( 2704 848 256 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +( 3184 848 256 ) ( 3168 864 64 ) ( 3200 832 64 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +} +// brush 488 +{ +( 2944 864 0 ) ( 2944 832 0 ) ( 3136 832 0 ) we_cemetary/cemtrim2 10 0 90.00 1 1 0 0 0 +( 3136 832 64 ) ( 2944 832 64 ) ( 2944 864 64 ) we_cemetary/cemtrim2 10 0 90.00 1 1 0 0 0 +( 3200 864 320 ) ( 3008 864 320 ) ( 3008 864 0 ) we_cemetary/cemtrim2 128 0 -180.00 1 -1 0 0 0 +( 2944 832 320 ) ( 3136 832 320 ) ( 3136 832 0 ) we_cemetary/cemtrim2 128 0 -180.00 1 -1 0 0 0 +( 2688 832 0 ) ( 2720 864 0 ) ( 2704 848 64 ) we_cemetary/cemtrim2 128 0 -180.00 1 -1 0 0 0 +( 3184 848 64 ) ( 3168 864 0 ) ( 3200 832 0 ) we_cemetary/cemtrim2 128 0 -180.00 1 -1 0 0 0 +} +// brush 489 +{ +( 3168 1088 0 ) ( 3200 1088 0 ) ( 3200 1280 0 ) we_cemetary/cemtrim2 191 0 -180.00 1 1 0 0 0 +( 3200 1280 64 ) ( 3200 1088 64 ) ( 3168 1088 64 ) we_cemetary/cemtrim2 191 0 -180.00 1 1 0 0 0 +( 3168 1408 320 ) ( 3168 1216 320 ) ( 3168 1216 0 ) we_cemetary/cemtrim2 0 0 -180.00 1 -1 0 0 0 +( 3200 1088 320 ) ( 3200 1280 320 ) ( 3200 1280 0 ) we_cemetary/cemtrim2 0 0 -180.00 1 -1 0 0 0 +( 3200 832 0 ) ( 3168 864 0 ) ( 3184 848 64 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 3184 1328 64 ) ( 3168 1312 0 ) ( 3200 1344 0 ) we_cemetary/cemtrim2 -64 0 -180.00 1 -1 0 0 0 +} +// brush 490 +{ +( 3168 1088 64 ) ( 3200 1088 64 ) ( 3200 1280 64 ) we_cemetary/cemstair2 191 0 -180.00 1 1 0 0 0 +( 3200 1088 384 ) ( 3200 1280 384 ) ( 3200 1280 64 ) we_cemetary/cemstair2 0 0 -180.00 1 -1 0 0 0 +( 3152 1280 96 ) ( 3160 1088 80 ) ( 3168 1280 64 ) we_cemetary/cemstair2 0 0 -180.00 1 -1 0 0 0 +( 3136 1088 256 ) ( 3136 1280 256 ) ( 3200 1280 256 ) we_cemetary/cemstair2 191 0 -180.00 1 1 0 0 0 +( 3152 1280 208 ) ( 3152 1088 176 ) ( 3152 1280 144 ) we_cemetary/cemstair2 0 0 -180.00 1 -1 0 0 0 +( 3200 832 64 ) ( 3168 864 64 ) ( 3184 848 256 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 3184 1328 256 ) ( 3168 1312 64 ) ( 3200 1344 64 ) we_cemetary/cemstair2 -64 0 -180.00 1 -1 0 0 0 +} +// brush 491 +{ +( 3152 1280 256 ) ( 3152 1088 256 ) ( 3200 1088 256 ) we_cemetary/fogtrunk 191 0 -180.00 1 1 0 0 0 +( 3200 1280 272 ) ( 3200 1088 272 ) ( 3136 1088 272 ) we_cemetary/fogtrunk 191 0 -180.00 1 1 0 0 0 +( 3152 1088 256 ) ( 3152 1280 256 ) ( 3136 1280 272 ) we_cemetary/fogtrunk 191 0 -180.00 1 1 0 0 0 +( 3200 1088 272 ) ( 3200 1280 272 ) ( 3200 1280 256 ) we_cemetary/fogtrunk 0 0 -180.00 1 -1 0 0 0 +( 3200 832 256 ) ( 3168 864 256 ) ( 3184 848 272 ) we_cemetary/fogtrunk -64 0 0.00 1 1 0 0 0 +( 3184 1328 272 ) ( 3168 1312 256 ) ( 3200 1344 256 ) we_cemetary/fogtrunk -64 0 -180.00 1 -1 0 0 0 +} +// brush 492 +{ +( 3136 1088 272 ) ( 3168 1088 272 ) ( 3168 1280 272 ) we_cemetary/cemrunner2 63 0 -180.00 1 1 0 0 0 +( 3168 1280 336 ) ( 3168 1088 336 ) ( 3136 1088 336 ) we_cemetary/cemtrim2 159 0 -180.00 1 1 0 0 0 +( 3136 1280 592 ) ( 3136 1088 592 ) ( 3136 1088 272 ) we_cemetary/cemtrim2 0 14 -180.00 1 -1 0 0 0 +( 3200 1088 592 ) ( 3200 1280 592 ) ( 3200 1280 272 ) we_cemetary/cemtrim2 0 14 -180.00 1 -1 0 0 0 +( 3200 832 272 ) ( 3168 864 272 ) ( 3184 848 336 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( 3184 1328 336 ) ( 3168 1312 272 ) ( 3200 1344 272 ) we_cemetary/cemtrim2 -64 15 -180.00 1 -1 0 0 0 +} +// brush 493 +{ +( 2944 1280 272 ) ( 2944 1312 272 ) ( 2752 1312 272 ) we_cemetary/cemrunner2 9 0 -90.00 1 1 0 0 0 +( 2752 1312 336 ) ( 2944 1312 336 ) ( 2944 1280 336 ) we_cemetary/cemtrim2 103 0 -90.00 1 1 0 0 0 +( 2752 1280 592 ) ( 2944 1280 592 ) ( 2944 1280 272 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( 2944 1344 592 ) ( 2752 1344 592 ) ( 2752 1344 272 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( 3200 1344 272 ) ( 3168 1312 272 ) ( 3184 1328 336 ) we_cemetary/cemtrim2 64 15 0.00 1 1 0 0 0 +( 2704 1328 336 ) ( 2720 1312 272 ) ( 2688 1344 272 ) we_cemetary/cemtrim2 -64 16 0.00 1 1 0 0 0 +} +// brush 494 +{ +( 2752 1296 256 ) ( 2944 1296 256 ) ( 2944 1344 256 ) we_cemetary/fogtrunk -119 63 -90.00 1 1 0 0 0 +( 2752 1344 272 ) ( 2944 1344 272 ) ( 2944 1280 272 ) we_cemetary/fogtrunk -119 63 -90.00 1 1 0 0 0 +( 2944 1296 256 ) ( 2752 1296 256 ) ( 2752 1280 272 ) we_cemetary/fogtrunk -119 63 -90.00 1 1 0 0 0 +( 2944 1344 272 ) ( 2752 1344 272 ) ( 2752 1344 256 ) we_cemetary/fogtrunk -64 0 0.00 1 1 0 0 0 +( 3200 1344 256 ) ( 3168 1312 256 ) ( 3184 1328 272 ) we_cemetary/fogtrunk 64 0 0.00 1 1 0 0 0 +( 2704 1328 272 ) ( 2720 1312 256 ) ( 2688 1344 256 ) we_cemetary/fogtrunk -64 0 0.00 1 1 0 0 0 +} +// brush 495 +{ +( 2720 1280 272 ) ( 2720 1088 272 ) ( 2752 1088 272 ) we_cemetary/cemrunner2 0 0 0.00 1 1 0 0 0 +( 2752 1088 336 ) ( 2720 1088 336 ) ( 2720 1280 336 ) we_cemetary/cemtrim2 -32 0 0.00 1 1 0 0 0 +( 2752 1088 272 ) ( 2752 1088 592 ) ( 2752 1280 592 ) we_cemetary/cemtrim2 64 16 0.00 1 1 0 0 0 +( 2688 1280 272 ) ( 2688 1280 592 ) ( 2688 1088 592 ) we_cemetary/cemtrim2 64 16 0.00 1 1 0 0 0 +( 2704 848 336 ) ( 2720 864 272 ) ( 2688 832 272 ) we_cemetary/cemtrim2 64 16 0.00 1 1 0 0 0 +( 2736 1296 336 ) ( 2720 1312 272 ) ( 2752 1280 272 ) we_cemetary/cemtrim2 64 16 0.00 1 1 0 0 0 +} +// brush 496 +{ +( 2688 1088 256 ) ( 2736 1088 256 ) ( 2736 1280 256 ) we_cemetary/fogtrunk 0 -64 0.00 1 1 0 0 0 +( 2752 1088 272 ) ( 2688 1088 272 ) ( 2688 1280 272 ) we_cemetary/fogtrunk 0 -64 0.00 1 1 0 0 0 +( 2752 1280 272 ) ( 2736 1280 256 ) ( 2736 1088 256 ) we_cemetary/fogtrunk 0 -64 0.00 1 1 0 0 0 +( 2688 1280 256 ) ( 2688 1280 272 ) ( 2688 1088 272 ) we_cemetary/fogtrunk 64 0 0.00 1 1 0 0 0 +( 2704 848 272 ) ( 2720 864 256 ) ( 2688 832 256 ) we_cemetary/fogtrunk 64 0 0.00 1 1 0 0 0 +( 2736 1296 272 ) ( 2720 1312 256 ) ( 2752 1280 256 ) we_cemetary/fogtrunk 64 0 0.00 1 1 0 0 0 +} +// brush 497 +{ +( 2688 1280 64 ) ( 2688 1088 64 ) ( 2720 1088 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 2688 1280 64 ) ( 2688 1280 384 ) ( 2688 1088 384 ) we_cemetary/cemstair2 64 0 0.00 1 1 0 0 0 +( 2720 1280 64 ) ( 2728 1088 80 ) ( 2736 1280 96 ) we_cemetary/cemstair2 64 0 0.00 1 1 0 0 0 +( 2688 1280 256 ) ( 2752 1280 256 ) ( 2752 1088 256 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 2736 1280 144 ) ( 2736 1088 176 ) ( 2736 1280 208 ) we_cemetary/cemstair2 64 0 0.00 1 1 0 0 0 +( 2704 848 256 ) ( 2720 864 64 ) ( 2688 832 64 ) we_cemetary/cemstair2 64 0 0.00 1 1 0 0 0 +( 2736 1296 256 ) ( 2720 1312 64 ) ( 2752 1280 64 ) we_cemetary/cemstair2 64 0 0.00 1 1 0 0 0 +} +// brush 498 +{ +( 2688 1280 0 ) ( 2688 1088 0 ) ( 2720 1088 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( 2720 1088 64 ) ( 2688 1088 64 ) ( 2688 1280 64 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( 2720 1152 0 ) ( 2720 1152 320 ) ( 2720 1344 320 ) we_cemetary/cemtrim2 64 0 0.00 1 1 0 0 0 +( 2688 1280 0 ) ( 2688 1280 320 ) ( 2688 1088 320 ) we_cemetary/cemtrim2 64 0 0.00 1 1 0 0 0 +( 2704 848 64 ) ( 2720 864 0 ) ( 2688 832 0 ) we_cemetary/cemtrim2 64 0 0.00 1 1 0 0 0 +( 2736 1296 64 ) ( 2720 1312 0 ) ( 2752 1280 0 ) we_cemetary/cemtrim2 64 0 0.00 1 1 0 0 0 +} +// brush 499 +{ +( 2944 1312 0 ) ( 2944 1344 0 ) ( 2752 1344 0 ) we_cemetary/cemtrim2 -119 0 -90.00 1 1 0 0 0 +( 2752 1344 64 ) ( 2944 1344 64 ) ( 2944 1312 64 ) we_cemetary/cemtrim2 -119 0 -90.00 1 1 0 0 0 +( 2624 1312 320 ) ( 2816 1312 320 ) ( 2816 1312 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 2944 1344 320 ) ( 2752 1344 320 ) ( 2752 1344 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 2704 1328 64 ) ( 2720 1312 0 ) ( 2688 1344 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 2880 1344 64 ) ( 2880 1376 0 ) ( 2880 1312 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +} +// brush 500 +{ +( 2944 1312 0 ) ( 2944 1344 0 ) ( 2752 1344 0 ) we_cemetary/cemtrim2 -119 0 -90.00 1 1 0 0 0 +( 2752 1344 64 ) ( 2944 1344 64 ) ( 2944 1312 64 ) we_cemetary/cemtrim2 -119 0 -90.00 1 1 0 0 0 +( 2752 1312 320 ) ( 2944 1312 320 ) ( 2944 1312 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 2944 1344 320 ) ( 2752 1344 320 ) ( 2752 1344 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 3200 1344 0 ) ( 3168 1312 0 ) ( 3184 1328 64 ) we_cemetary/cemtrim2 64 0 0.00 1 1 0 0 0 +( 3008 1344 64 ) ( 3008 1312 0 ) ( 3008 1376 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +} +// brush 501 +{ +( 2944 1312 64 ) ( 2944 1344 64 ) ( 2752 1344 64 ) we_cemetary/cemstair2 -119 0 -90.00 1 1 0 0 0 +( 2944 1344 384 ) ( 2752 1344 384 ) ( 2752 1344 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 2752 1296 96 ) ( 2944 1304 80 ) ( 2752 1312 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 2944 1280 256 ) ( 2752 1280 256 ) ( 2752 1344 256 ) we_cemetary/cemstair2 -119 0 -90.00 1 1 0 0 0 +( 2752 1296 208 ) ( 2944 1296 176 ) ( 2752 1296 144 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 2704 1328 256 ) ( 2720 1312 64 ) ( 2688 1344 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 2880 1344 256 ) ( 2880 1376 64 ) ( 2880 1312 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +} +// brush 502 +{ +( 2944 1312 64 ) ( 2944 1344 64 ) ( 2752 1344 64 ) we_cemetary/cemstair2 -119 0 -90.00 1 1 0 0 0 +( 2944 1344 384 ) ( 2752 1344 384 ) ( 2752 1344 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 2752 1296 96 ) ( 2944 1304 80 ) ( 2752 1312 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 2944 1280 256 ) ( 2752 1280 256 ) ( 2752 1344 256 ) we_cemetary/cemstair2 -119 0 -90.00 1 1 0 0 0 +( 2880 1296 208 ) ( 3072 1296 176 ) ( 2880 1296 144 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 3200 1344 64 ) ( 3168 1312 64 ) ( 3184 1328 256 ) we_cemetary/cemstair2 64 0 0.00 1 1 0 0 0 +( 3008 1344 256 ) ( 3008 1312 64 ) ( 3008 1376 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +} +// brush 503 +{ +( 2752 1344 64 ) ( 2944 1344 64 ) ( 2944 1376 64 ) we_cemetary/cemstair2 71 0 -90.00 1 1 0 0 0 +( 2752 1344 64 ) ( 2752 1344 384 ) ( 2944 1344 384 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 2752 1376 64 ) ( 2944 1384 80 ) ( 2752 1392 96 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 2752 1344 256 ) ( 2752 1408 256 ) ( 2944 1408 256 ) we_cemetary/cemstair2 71 0 -90.00 1 1 0 0 0 +( 2848 1392 144 ) ( 3040 1392 176 ) ( 2848 1392 208 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 3008 1344 256 ) ( 3008 1312 64 ) ( 3008 1376 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 3200 1376 256 ) ( 3200 1408 64 ) ( 3200 1344 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +} +// brush 504 +{ +( 2752 1344 0 ) ( 2944 1344 0 ) ( 2944 1376 0 ) we_cemetary/cemtrim2 71 0 -90.00 1 1 0 0 0 +( 2944 1376 64 ) ( 2944 1344 64 ) ( 2752 1344 64 ) we_cemetary/cemtrim2 71 0 -90.00 1 1 0 0 0 +( 3040 1376 0 ) ( 3040 1376 320 ) ( 2848 1376 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 2752 1344 0 ) ( 2752 1344 320 ) ( 2944 1344 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 3008 1344 64 ) ( 3008 1312 0 ) ( 3008 1376 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( 3200 1376 64 ) ( 3200 1408 0 ) ( 3200 1344 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +} +// brush 505 +{ +( 2752 1344 64 ) ( 2944 1344 64 ) ( 2944 1376 64 ) we_cemetary/cemstair2 71 0 -90.00 1 1 0 0 0 +( 2752 1344 64 ) ( 2752 1344 384 ) ( 2944 1344 384 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 2752 1376 64 ) ( 2944 1384 80 ) ( 2752 1392 96 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 2752 1344 256 ) ( 2752 1408 256 ) ( 2944 1408 256 ) we_cemetary/cemstair2 71 0 -90.00 1 1 0 0 0 +( 2752 1392 144 ) ( 2944 1392 176 ) ( 2752 1392 208 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 2880 1344 256 ) ( 2880 1376 64 ) ( 2880 1312 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 2688 1392 256 ) ( 2688 1376 64 ) ( 2688 1408 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +} +// brush 506 +{ +( 2752 1344 0 ) ( 2944 1344 0 ) ( 2944 1376 0 ) we_cemetary/cemtrim2 71 0 -90.00 1 1 0 0 0 +( 2944 1376 64 ) ( 2944 1344 64 ) ( 2752 1344 64 ) we_cemetary/cemtrim2 71 0 -90.00 1 1 0 0 0 +( 2752 1376 0 ) ( 2752 1376 320 ) ( 2560 1376 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 2752 1344 0 ) ( 2752 1344 320 ) ( 2944 1344 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 2880 1344 64 ) ( 2880 1376 0 ) ( 2880 1312 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( 2688 1392 64 ) ( 2688 1376 0 ) ( 2688 1408 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +} +// brush 507 +{ +( 2944 1344 256 ) ( 2944 1392 256 ) ( 2752 1392 256 ) we_cemetary/fogtrunk 71 63 -90.00 1 1 0 0 0 +( 2944 1408 272 ) ( 2944 1344 272 ) ( 2752 1344 272 ) we_cemetary/fogtrunk 71 63 -90.00 1 1 0 0 0 +( 2752 1408 272 ) ( 2752 1392 256 ) ( 2944 1392 256 ) we_cemetary/fogtrunk 71 63 -90.00 1 1 0 0 0 +( 2752 1344 256 ) ( 2752 1344 272 ) ( 2944 1344 272 ) we_cemetary/fogtrunk -64 0 0.00 1 1 0 0 0 +( 3200 1376 272 ) ( 3200 1408 256 ) ( 3200 1344 256 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +( 2688 1392 272 ) ( 2688 1376 256 ) ( 2688 1408 256 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +} +// brush 508 +{ +( 2752 1376 272 ) ( 2944 1376 272 ) ( 2944 1408 272 ) we_cemetary/cemrunner2 -64 0 -90.00 1 1 0 0 0 +( 2944 1408 336 ) ( 2944 1376 336 ) ( 2752 1376 336 ) we_cemetary/cemtrim2 39 0 -90.00 1 1 0 0 0 +( 2944 1408 272 ) ( 2944 1408 592 ) ( 2752 1408 592 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( 2752 1344 272 ) ( 2752 1344 592 ) ( 2944 1344 592 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( 3200 1376 336 ) ( 3200 1408 272 ) ( 3200 1344 272 ) we_cemetary/cemtrim2 0 16 0.00 1 1 0 0 0 +( 2688 1392 336 ) ( 2688 1376 272 ) ( 2688 1408 272 ) we_cemetary/cemtrim2 0 16 0.00 1 1 0 0 0 +} +// brush 509 +{ +( 2720 1312 -32 ) ( 2720 864 -32 ) ( 3168 864 -32 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 3168 864 0 ) ( 2720 864 0 ) ( 2720 1312 0 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 3168 1376 -64 ) ( 3168 1376 0 ) ( 2720 1376 0 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 3200 864 -64 ) ( 3200 864 0 ) ( 3200 1312 0 ) we_cemetary/cemtrim5 64 0 0.00 1 1 0 0 0 +( 2720 832 -64 ) ( 2720 832 0 ) ( 3168 832 0 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 2688 1312 -64 ) ( 2688 1312 0 ) ( 2688 864 0 ) we_cemetary/cemtrim5 64 0 0.00 1 1 0 0 0 +} +// brush 510 +{ +( 2720 1312 336 ) ( 2720 864 336 ) ( 3168 864 336 ) water/waterfloor2 0 -64 0.00 1 1 0 0 0 +( 3168 864 352 ) ( 2720 864 352 ) ( 2720 1312 352 ) water/waterfloor2 0 -64 0.00 1 1 0 0 0 +( 3168 1312 304 ) ( 3168 1312 368 ) ( 2720 1312 368 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +( 3168 864 304 ) ( 3168 864 368 ) ( 3168 1312 368 ) water/waterfloor2 64 0 0.00 1 1 0 0 0 +( 2720 864 304 ) ( 2720 864 368 ) ( 3168 864 368 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +( 2720 1312 304 ) ( 2720 1312 368 ) ( 2720 864 368 ) water/waterfloor2 64 0 0.00 1 1 0 0 0 +} +// brush 511 +{ +( 2880 1392 208 ) ( 2880 1296 208 ) ( 3008 1296 208 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 3008 1296 256 ) ( 2880 1296 256 ) ( 2880 1392 256 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 3008 1392 64 ) ( 3008 1392 256 ) ( 2880 1392 256 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 3008 1296 48 ) ( 3008 1296 240 ) ( 3008 1392 240 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 2880 1296 48 ) ( 2880 1296 240 ) ( 3008 1296 240 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 2880 1392 64 ) ( 2880 1392 256 ) ( 2880 1296 256 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +} +// brush 512 +{ +( 3392 1392 208 ) ( 3392 1296 208 ) ( 3520 1296 208 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 3520 1296 256 ) ( 3392 1296 256 ) ( 3392 1392 256 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 3520 1392 64 ) ( 3520 1392 256 ) ( 3392 1392 256 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 3520 1296 48 ) ( 3520 1296 240 ) ( 3520 1392 240 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 3392 1296 48 ) ( 3392 1296 240 ) ( 3520 1296 240 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 3392 1392 64 ) ( 3392 1392 256 ) ( 3392 1296 256 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +} +// brush 513 +{ +( 3232 1312 336 ) ( 3232 864 336 ) ( 3680 864 336 ) water/waterfloor2 0 -64 0.00 1 1 0 0 0 +( 3680 864 352 ) ( 3232 864 352 ) ( 3232 1312 352 ) water/waterfloor2 0 -64 0.00 1 1 0 0 0 +( 3680 1312 304 ) ( 3680 1312 368 ) ( 3232 1312 368 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +( 3680 864 304 ) ( 3680 864 368 ) ( 3680 1312 368 ) water/waterfloor2 64 0 0.00 1 1 0 0 0 +( 3232 864 304 ) ( 3232 864 368 ) ( 3680 864 368 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +( 3232 1312 304 ) ( 3232 1312 368 ) ( 3232 864 368 ) water/waterfloor2 64 0 0.00 1 1 0 0 0 +} +// brush 514 +{ +( 3232 1312 -32 ) ( 3232 864 -32 ) ( 3680 864 -32 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 3680 864 0 ) ( 3232 864 0 ) ( 3232 1312 0 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 3680 1376 -64 ) ( 3680 1376 0 ) ( 3232 1376 0 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 3712 864 -64 ) ( 3712 864 0 ) ( 3712 1312 0 ) we_cemetary/cemtrim5 64 0 0.00 1 1 0 0 0 +( 3232 832 -64 ) ( 3232 832 0 ) ( 3680 832 0 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 3200 1312 -64 ) ( 3200 1312 0 ) ( 3200 864 0 ) we_cemetary/cemtrim5 64 0 0.00 1 1 0 0 0 +} +// brush 515 +{ +( 3264 1376 272 ) ( 3456 1376 272 ) ( 3456 1408 272 ) we_cemetary/cemrunner2 -64 0 -90.00 1 1 0 0 0 +( 3456 1408 336 ) ( 3456 1376 336 ) ( 3264 1376 336 ) we_cemetary/cemtrim2 39 0 -90.00 1 1 0 0 0 +( 3456 1408 272 ) ( 3456 1408 592 ) ( 3264 1408 592 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( 3264 1344 272 ) ( 3264 1344 592 ) ( 3456 1344 592 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( 3712 1376 336 ) ( 3712 1408 272 ) ( 3712 1344 272 ) we_cemetary/cemtrim2 0 16 0.00 1 1 0 0 0 +( 3200 1392 336 ) ( 3200 1376 272 ) ( 3200 1408 272 ) we_cemetary/cemtrim2 0 16 0.00 1 1 0 0 0 +} +// brush 516 +{ +( 3456 1344 256 ) ( 3456 1392 256 ) ( 3264 1392 256 ) we_cemetary/fogtrunk 71 63 -90.00 1 1 0 0 0 +( 3456 1408 272 ) ( 3456 1344 272 ) ( 3264 1344 272 ) we_cemetary/fogtrunk 71 63 -90.00 1 1 0 0 0 +( 3264 1408 272 ) ( 3264 1392 256 ) ( 3456 1392 256 ) we_cemetary/fogtrunk 71 63 -90.00 1 1 0 0 0 +( 3264 1344 256 ) ( 3264 1344 272 ) ( 3456 1344 272 ) we_cemetary/fogtrunk -64 0 0.00 1 1 0 0 0 +( 3712 1376 272 ) ( 3712 1408 256 ) ( 3712 1344 256 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +( 3200 1392 272 ) ( 3200 1376 256 ) ( 3200 1408 256 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +} +// brush 517 +{ +( 3264 1344 0 ) ( 3456 1344 0 ) ( 3456 1376 0 ) we_cemetary/cemtrim2 71 0 -90.00 1 1 0 0 0 +( 3456 1376 64 ) ( 3456 1344 64 ) ( 3264 1344 64 ) we_cemetary/cemtrim2 71 0 -90.00 1 1 0 0 0 +( 3264 1376 0 ) ( 3264 1376 320 ) ( 3072 1376 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 3264 1344 0 ) ( 3264 1344 320 ) ( 3456 1344 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 3392 1344 64 ) ( 3392 1376 0 ) ( 3392 1312 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( 3200 1392 64 ) ( 3200 1376 0 ) ( 3200 1408 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +} +// brush 518 +{ +( 3264 1344 64 ) ( 3456 1344 64 ) ( 3456 1376 64 ) we_cemetary/cemstair2 71 0 -90.00 1 1 0 0 0 +( 3264 1344 64 ) ( 3264 1344 384 ) ( 3456 1344 384 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 3264 1376 64 ) ( 3456 1384 80 ) ( 3264 1392 96 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 3264 1344 256 ) ( 3264 1408 256 ) ( 3456 1408 256 ) we_cemetary/cemstair2 71 0 -90.00 1 1 0 0 0 +( 3264 1392 144 ) ( 3456 1392 176 ) ( 3264 1392 208 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 3392 1344 256 ) ( 3392 1376 64 ) ( 3392 1312 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 3200 1392 256 ) ( 3200 1376 64 ) ( 3200 1408 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +} +// brush 519 +{ +( 3264 1344 0 ) ( 3456 1344 0 ) ( 3456 1376 0 ) we_cemetary/cemtrim2 71 0 -90.00 1 1 0 0 0 +( 3456 1376 64 ) ( 3456 1344 64 ) ( 3264 1344 64 ) we_cemetary/cemtrim2 71 0 -90.00 1 1 0 0 0 +( 3552 1376 0 ) ( 3552 1376 320 ) ( 3360 1376 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 3264 1344 0 ) ( 3264 1344 320 ) ( 3456 1344 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 3520 1344 64 ) ( 3520 1312 0 ) ( 3520 1376 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( 3712 1376 64 ) ( 3712 1408 0 ) ( 3712 1344 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +} +// brush 520 +{ +( 3264 1344 64 ) ( 3456 1344 64 ) ( 3456 1376 64 ) we_cemetary/cemstair2 71 0 -90.00 1 1 0 0 0 +( 3264 1344 64 ) ( 3264 1344 384 ) ( 3456 1344 384 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 3264 1376 64 ) ( 3456 1384 80 ) ( 3264 1392 96 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 3264 1344 256 ) ( 3264 1408 256 ) ( 3456 1408 256 ) we_cemetary/cemstair2 71 0 -90.00 1 1 0 0 0 +( 3360 1392 144 ) ( 3552 1392 176 ) ( 3360 1392 208 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 3520 1344 256 ) ( 3520 1312 64 ) ( 3520 1376 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 3712 1376 256 ) ( 3712 1408 64 ) ( 3712 1344 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +} +// brush 521 +{ +( 3456 1312 64 ) ( 3456 1344 64 ) ( 3264 1344 64 ) we_cemetary/cemstair2 -118 0 -90.00 1 1 0 0 0 +( 3456 1344 384 ) ( 3264 1344 384 ) ( 3264 1344 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 3264 1296 96 ) ( 3456 1304 80 ) ( 3264 1312 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 3456 1280 256 ) ( 3264 1280 256 ) ( 3264 1344 256 ) we_cemetary/cemstair2 -118 0 -90.00 1 1 0 0 0 +( 3392 1296 208 ) ( 3584 1296 176 ) ( 3392 1296 144 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 3712 1344 64 ) ( 3680 1312 64 ) ( 3696 1328 256 ) we_cemetary/cemstair2 64 0 0.00 1 1 0 0 0 +( 3520 1344 256 ) ( 3520 1312 64 ) ( 3520 1376 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +} +// brush 522 +{ +( 3456 1312 64 ) ( 3456 1344 64 ) ( 3264 1344 64 ) we_cemetary/cemstair2 -118 0 -90.00 1 1 0 0 0 +( 3456 1344 384 ) ( 3264 1344 384 ) ( 3264 1344 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 3264 1296 96 ) ( 3456 1304 80 ) ( 3264 1312 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 3456 1280 256 ) ( 3264 1280 256 ) ( 3264 1344 256 ) we_cemetary/cemstair2 -118 0 -90.00 1 1 0 0 0 +( 3264 1296 208 ) ( 3456 1296 176 ) ( 3264 1296 144 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 3216 1328 256 ) ( 3232 1312 64 ) ( 3200 1344 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 3392 1344 256 ) ( 3392 1376 64 ) ( 3392 1312 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +} +// brush 523 +{ +( 3456 1312 0 ) ( 3456 1344 0 ) ( 3264 1344 0 ) we_cemetary/cemtrim2 -118 0 -90.00 1 1 0 0 0 +( 3264 1344 64 ) ( 3456 1344 64 ) ( 3456 1312 64 ) we_cemetary/cemtrim2 -118 0 -90.00 1 1 0 0 0 +( 3264 1312 320 ) ( 3456 1312 320 ) ( 3456 1312 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 3456 1344 320 ) ( 3264 1344 320 ) ( 3264 1344 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 3712 1344 0 ) ( 3680 1312 0 ) ( 3696 1328 64 ) we_cemetary/cemtrim2 64 0 0.00 1 1 0 0 0 +( 3520 1344 64 ) ( 3520 1312 0 ) ( 3520 1376 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +} +// brush 524 +{ +( 3456 1312 0 ) ( 3456 1344 0 ) ( 3264 1344 0 ) we_cemetary/cemtrim2 -118 0 -90.00 1 1 0 0 0 +( 3264 1344 64 ) ( 3456 1344 64 ) ( 3456 1312 64 ) we_cemetary/cemtrim2 -118 0 -90.00 1 1 0 0 0 +( 3136 1312 320 ) ( 3328 1312 320 ) ( 3328 1312 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 3456 1344 320 ) ( 3264 1344 320 ) ( 3264 1344 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 3216 1328 64 ) ( 3232 1312 0 ) ( 3200 1344 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 3392 1344 64 ) ( 3392 1376 0 ) ( 3392 1312 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +} +// brush 525 +{ +( 3200 1280 0 ) ( 3200 1088 0 ) ( 3232 1088 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( 3232 1088 64 ) ( 3200 1088 64 ) ( 3200 1280 64 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( 3232 1152 0 ) ( 3232 1152 320 ) ( 3232 1344 320 ) we_cemetary/cemtrim2 64 0 0.00 1 1 0 0 0 +( 3200 1280 0 ) ( 3200 1280 320 ) ( 3200 1088 320 ) we_cemetary/cemtrim2 64 0 0.00 1 1 0 0 0 +( 3216 848 64 ) ( 3232 864 0 ) ( 3200 832 0 ) we_cemetary/cemtrim2 64 0 0.00 1 1 0 0 0 +( 3248 1296 64 ) ( 3232 1312 0 ) ( 3264 1280 0 ) we_cemetary/cemtrim2 64 0 0.00 1 1 0 0 0 +} +// brush 526 +{ +( 3200 1280 64 ) ( 3200 1088 64 ) ( 3232 1088 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 3200 1280 64 ) ( 3200 1280 384 ) ( 3200 1088 384 ) we_cemetary/cemstair2 64 0 0.00 1 1 0 0 0 +( 3232 1280 64 ) ( 3240 1088 80 ) ( 3248 1280 96 ) we_cemetary/cemstair2 64 0 0.00 1 1 0 0 0 +( 3200 1280 256 ) ( 3264 1280 256 ) ( 3264 1088 256 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 3248 1280 144 ) ( 3248 1088 176 ) ( 3248 1280 208 ) we_cemetary/cemstair2 64 0 0.00 1 1 0 0 0 +( 3216 848 256 ) ( 3232 864 64 ) ( 3200 832 64 ) we_cemetary/cemstair2 64 0 0.00 1 1 0 0 0 +( 3248 1296 256 ) ( 3232 1312 64 ) ( 3264 1280 64 ) we_cemetary/cemstair2 64 0 0.00 1 1 0 0 0 +} +// brush 527 +{ +( 3200 1088 256 ) ( 3248 1088 256 ) ( 3248 1280 256 ) we_cemetary/fogtrunk 0 -64 0.00 1 1 0 0 0 +( 3264 1088 272 ) ( 3200 1088 272 ) ( 3200 1280 272 ) we_cemetary/fogtrunk 0 -64 0.00 1 1 0 0 0 +( 3264 1280 272 ) ( 3248 1280 256 ) ( 3248 1088 256 ) we_cemetary/fogtrunk 0 -64 0.00 1 1 0 0 0 +( 3200 1280 256 ) ( 3200 1280 272 ) ( 3200 1088 272 ) we_cemetary/fogtrunk 64 0 0.00 1 1 0 0 0 +( 3216 848 272 ) ( 3232 864 256 ) ( 3200 832 256 ) we_cemetary/fogtrunk 64 0 0.00 1 1 0 0 0 +( 3248 1296 272 ) ( 3232 1312 256 ) ( 3264 1280 256 ) we_cemetary/fogtrunk 64 0 0.00 1 1 0 0 0 +} +// brush 528 +{ +( 3232 1280 272 ) ( 3232 1088 272 ) ( 3264 1088 272 ) we_cemetary/cemrunner2 0 0 0.00 1 1 0 0 0 +( 3264 1088 336 ) ( 3232 1088 336 ) ( 3232 1280 336 ) we_cemetary/cemtrim2 -32 0 0.00 1 1 0 0 0 +( 3264 1088 272 ) ( 3264 1088 592 ) ( 3264 1280 592 ) we_cemetary/cemtrim2 64 16 0.00 1 1 0 0 0 +( 3200 1280 272 ) ( 3200 1280 592 ) ( 3200 1088 592 ) we_cemetary/cemtrim2 64 16 0.00 1 1 0 0 0 +( 3216 848 336 ) ( 3232 864 272 ) ( 3200 832 272 ) we_cemetary/cemtrim2 64 16 0.00 1 1 0 0 0 +( 3248 1296 336 ) ( 3232 1312 272 ) ( 3264 1280 272 ) we_cemetary/cemtrim2 64 16 0.00 1 1 0 0 0 +} +// brush 529 +{ +( 3264 1296 256 ) ( 3456 1296 256 ) ( 3456 1344 256 ) we_cemetary/fogtrunk -118 63 -90.00 1 1 0 0 0 +( 3264 1344 272 ) ( 3456 1344 272 ) ( 3456 1280 272 ) we_cemetary/fogtrunk -118 63 -90.00 1 1 0 0 0 +( 3456 1296 256 ) ( 3264 1296 256 ) ( 3264 1280 272 ) we_cemetary/fogtrunk -118 63 -90.00 1 1 0 0 0 +( 3456 1344 272 ) ( 3264 1344 272 ) ( 3264 1344 256 ) we_cemetary/fogtrunk -64 0 0.00 1 1 0 0 0 +( 3712 1344 256 ) ( 3680 1312 256 ) ( 3696 1328 272 ) we_cemetary/fogtrunk 64 0 0.00 1 1 0 0 0 +( 3216 1328 272 ) ( 3232 1312 256 ) ( 3200 1344 256 ) we_cemetary/fogtrunk -64 0 0.00 1 1 0 0 0 +} +// brush 530 +{ +( 3456 1280 272 ) ( 3456 1312 272 ) ( 3264 1312 272 ) we_cemetary/cemrunner2 10 0 -90.00 1 1 0 0 0 +( 3264 1312 336 ) ( 3456 1312 336 ) ( 3456 1280 336 ) we_cemetary/cemtrim2 104 0 -90.00 1 1 0 0 0 +( 3264 1280 592 ) ( 3456 1280 592 ) ( 3456 1280 272 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( 3456 1344 592 ) ( 3264 1344 592 ) ( 3264 1344 272 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( 3712 1344 272 ) ( 3680 1312 272 ) ( 3696 1328 336 ) we_cemetary/cemtrim2 64 15 0.00 1 1 0 0 0 +( 3216 1328 336 ) ( 3232 1312 272 ) ( 3200 1344 272 ) we_cemetary/cemtrim2 -64 16 0.00 1 1 0 0 0 +} +// brush 531 +{ +( 3648 1088 272 ) ( 3680 1088 272 ) ( 3680 1280 272 ) we_cemetary/cemrunner2 62 0 -180.00 1 1 0 0 0 +( 3680 1280 336 ) ( 3680 1088 336 ) ( 3648 1088 336 ) we_cemetary/cemtrim2 159 0 -180.00 1 1 0 0 0 +( 3648 1280 592 ) ( 3648 1088 592 ) ( 3648 1088 272 ) we_cemetary/cemtrim2 0 13 -180.00 1 -1 0 0 0 +( 3712 1088 592 ) ( 3712 1280 592 ) ( 3712 1280 272 ) we_cemetary/cemtrim2 0 13 -180.00 1 -1 0 0 0 +( 3712 832 272 ) ( 3680 864 272 ) ( 3696 848 336 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( 3696 1328 336 ) ( 3680 1312 272 ) ( 3712 1344 272 ) we_cemetary/cemtrim2 -64 14 -180.00 1 -1 0 0 0 +} +// brush 532 +{ +( 3664 1280 256 ) ( 3664 1088 256 ) ( 3712 1088 256 ) we_cemetary/fogtrunk 191 0 -180.00 1 1 0 0 0 +( 3712 1280 272 ) ( 3712 1088 272 ) ( 3648 1088 272 ) we_cemetary/fogtrunk 191 0 -180.00 1 1 0 0 0 +( 3664 1088 256 ) ( 3664 1280 256 ) ( 3648 1280 272 ) we_cemetary/fogtrunk 191 0 -180.00 1 1 0 0 0 +( 3712 1088 272 ) ( 3712 1280 272 ) ( 3712 1280 256 ) we_cemetary/fogtrunk 0 0 -180.00 1 -1 0 0 0 +( 3712 832 256 ) ( 3680 864 256 ) ( 3696 848 272 ) we_cemetary/fogtrunk -64 0 0.00 1 1 0 0 0 +( 3696 1328 272 ) ( 3680 1312 256 ) ( 3712 1344 256 ) we_cemetary/fogtrunk -64 0 -180.00 1 -1 0 0 0 +} +// brush 533 +{ +( 3680 1088 64 ) ( 3712 1088 64 ) ( 3712 1280 64 ) we_cemetary/cemstair2 191 0 -180.00 1 1 0 0 0 +( 3712 1088 384 ) ( 3712 1280 384 ) ( 3712 1280 64 ) we_cemetary/cemstair2 0 0 -180.00 1 -1 0 0 0 +( 3664 1280 96 ) ( 3672 1088 80 ) ( 3680 1280 64 ) we_cemetary/cemstair2 0 0 -180.00 1 -1 0 0 0 +( 3648 1088 256 ) ( 3648 1280 256 ) ( 3712 1280 256 ) we_cemetary/cemstair2 191 0 -180.00 1 1 0 0 0 +( 3664 1280 208 ) ( 3664 1088 176 ) ( 3664 1280 144 ) we_cemetary/cemstair2 0 0 -180.00 1 -1 0 0 0 +( 3712 832 64 ) ( 3680 864 64 ) ( 3696 848 256 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 3696 1328 256 ) ( 3680 1312 64 ) ( 3712 1344 64 ) we_cemetary/cemstair2 -64 0 -180.00 1 -1 0 0 0 +} +// brush 534 +{ +( 3680 1088 0 ) ( 3712 1088 0 ) ( 3712 1280 0 ) we_cemetary/cemtrim2 191 0 -180.00 1 1 0 0 0 +( 3712 1280 64 ) ( 3712 1088 64 ) ( 3680 1088 64 ) we_cemetary/cemtrim2 191 0 -180.00 1 1 0 0 0 +( 3680 1408 320 ) ( 3680 1216 320 ) ( 3680 1216 0 ) we_cemetary/cemtrim2 0 0 -180.00 1 -1 0 0 0 +( 3712 1088 320 ) ( 3712 1280 320 ) ( 3712 1280 0 ) we_cemetary/cemtrim2 0 0 -180.00 1 -1 0 0 0 +( 3712 832 0 ) ( 3680 864 0 ) ( 3696 848 64 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 3696 1328 64 ) ( 3680 1312 0 ) ( 3712 1344 0 ) we_cemetary/cemtrim2 -64 0 -180.00 1 -1 0 0 0 +} +// brush 535 +{ +( 3456 864 0 ) ( 3456 832 0 ) ( 3648 832 0 ) we_cemetary/cemtrim2 11 0 90.00 1 1 0 0 0 +( 3648 832 64 ) ( 3456 832 64 ) ( 3456 864 64 ) we_cemetary/cemtrim2 11 0 90.00 1 1 0 0 0 +( 3712 864 320 ) ( 3520 864 320 ) ( 3520 864 0 ) we_cemetary/cemtrim2 128 0 -180.00 1 -1 0 0 0 +( 3456 832 320 ) ( 3648 832 320 ) ( 3648 832 0 ) we_cemetary/cemtrim2 128 0 -180.00 1 -1 0 0 0 +( 3200 832 0 ) ( 3232 864 0 ) ( 3216 848 64 ) we_cemetary/cemtrim2 128 0 -180.00 1 -1 0 0 0 +( 3696 848 64 ) ( 3680 864 0 ) ( 3712 832 0 ) we_cemetary/cemtrim2 128 0 -180.00 1 -1 0 0 0 +} +// brush 536 +{ +( 3456 864 64 ) ( 3456 832 64 ) ( 3648 832 64 ) we_cemetary/cemstair2 11 0 90.00 1 1 0 0 0 +( 3456 832 384 ) ( 3648 832 384 ) ( 3648 832 64 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +( 3648 880 96 ) ( 3456 872 80 ) ( 3648 864 64 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +( 3456 896 256 ) ( 3648 896 256 ) ( 3648 832 256 ) we_cemetary/cemstair2 11 0 90.00 1 1 0 0 0 +( 3648 880 208 ) ( 3456 880 176 ) ( 3648 880 144 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +( 3200 832 64 ) ( 3232 864 64 ) ( 3216 848 256 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +( 3696 848 256 ) ( 3680 864 64 ) ( 3712 832 64 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +} +// brush 537 +{ +( 3648 880 256 ) ( 3456 880 256 ) ( 3456 832 256 ) we_cemetary/fogtrunk 11 -127 90.00 1 1 0 0 0 +( 3648 832 272 ) ( 3456 832 272 ) ( 3456 896 272 ) we_cemetary/fogtrunk 11 -127 90.00 1 1 0 0 0 +( 3456 880 256 ) ( 3648 880 256 ) ( 3648 896 272 ) we_cemetary/fogtrunk 11 -127 90.00 1 1 0 0 0 +( 3456 832 272 ) ( 3648 832 272 ) ( 3648 832 256 ) we_cemetary/fogtrunk 128 0 -180.00 1 -1 0 0 0 +( 3200 832 256 ) ( 3232 864 256 ) ( 3216 848 272 ) we_cemetary/fogtrunk 128 0 -180.00 1 -1 0 0 0 +( 3696 848 272 ) ( 3680 864 256 ) ( 3712 832 256 ) we_cemetary/fogtrunk 128 0 -180.00 1 -1 0 0 0 +} +// brush 538 +{ +( 3456 896 272 ) ( 3456 864 272 ) ( 3648 864 272 ) we_cemetary/cemrunner2 11 5 90.00 1 1.000122 0 0 0 +( 3648 864 336 ) ( 3456 864 336 ) ( 3456 896 336 ) we_cemetary/cemtrim2 -21 0 90.00 1 1 0 0 0 +( 3648 896 592 ) ( 3456 896 592 ) ( 3456 896 272 ) we_cemetary/cemtrim2 128 15 -180.00 1 -1 0 0 0 +( 3456 832 592 ) ( 3648 832 592 ) ( 3648 832 272 ) we_cemetary/cemtrim2 128 15 -180.00 1 -1 0 0 0 +( 3200 832 272 ) ( 3232 864 272 ) ( 3216 848 336 ) we_cemetary/cemtrim2 128 14 -180.00 1 -1 0 0 0 +( 3696 848 336 ) ( 3680 864 272 ) ( 3712 832 272 ) we_cemetary/cemtrim2 128 14 -180.00 1 -1 0 0 0 +} +// brush 539 +{ +( 3968 896 272 ) ( 3968 864 272 ) ( 4160 864 272 ) we_cemetary/cemrunner2 12 5 90.00 1 1.000122 0 0 0 +( 4160 864 336 ) ( 3968 864 336 ) ( 3968 896 336 ) we_cemetary/cemtrim2 -20 0 90.00 1 1 0 0 0 +( 4160 896 592 ) ( 3968 896 592 ) ( 3968 896 272 ) we_cemetary/cemtrim2 128 15 -180.00 1 -1 0 0 0 +( 3968 832 592 ) ( 4160 832 592 ) ( 4160 832 272 ) we_cemetary/cemtrim2 128 15 -180.00 1 -1 0 0 0 +( 3712 832 272 ) ( 3744 864 272 ) ( 3728 848 336 ) we_cemetary/cemtrim2 128 14 -180.00 1 -1 0 0 0 +( 4208 848 336 ) ( 4192 864 272 ) ( 4224 832 272 ) we_cemetary/cemtrim2 128 14 -180.00 1 -1 0 0 0 +} +// brush 540 +{ +( 4160 880 256 ) ( 3968 880 256 ) ( 3968 832 256 ) we_cemetary/fogtrunk 12 -127 90.00 1 1 0 0 0 +( 4160 832 272 ) ( 3968 832 272 ) ( 3968 896 272 ) we_cemetary/fogtrunk 12 -127 90.00 1 1 0 0 0 +( 3968 880 256 ) ( 4160 880 256 ) ( 4160 896 272 ) we_cemetary/fogtrunk 12 -127 90.00 1 1 0 0 0 +( 3968 832 272 ) ( 4160 832 272 ) ( 4160 832 256 ) we_cemetary/fogtrunk 128 0 -180.00 1 -1 0 0 0 +( 3712 832 256 ) ( 3744 864 256 ) ( 3728 848 272 ) we_cemetary/fogtrunk 128 0 -180.00 1 -1 0 0 0 +( 4208 848 272 ) ( 4192 864 256 ) ( 4224 832 256 ) we_cemetary/fogtrunk 128 0 -180.00 1 -1 0 0 0 +} +// brush 541 +{ +( 3968 864 64 ) ( 3968 832 64 ) ( 4160 832 64 ) we_cemetary/cemstair2 12 0 90.00 1 1 0 0 0 +( 3968 832 384 ) ( 4160 832 384 ) ( 4160 832 64 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +( 4160 880 96 ) ( 3968 872 80 ) ( 4160 864 64 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +( 3968 896 256 ) ( 4160 896 256 ) ( 4160 832 256 ) we_cemetary/cemstair2 12 0 90.00 1 1 0 0 0 +( 4160 880 208 ) ( 3968 880 176 ) ( 4160 880 144 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +( 3712 832 64 ) ( 3744 864 64 ) ( 3728 848 256 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +( 4208 848 256 ) ( 4192 864 64 ) ( 4224 832 64 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +} +// brush 542 +{ +( 3968 864 0 ) ( 3968 832 0 ) ( 4160 832 0 ) we_cemetary/cemtrim2 12 0 90.00 1 1 0 0 0 +( 4160 832 64 ) ( 3968 832 64 ) ( 3968 864 64 ) we_cemetary/cemtrim2 12 0 90.00 1 1 0 0 0 +( 4224 864 320 ) ( 4032 864 320 ) ( 4032 864 0 ) we_cemetary/cemtrim2 128 0 -180.00 1 -1 0 0 0 +( 3968 832 320 ) ( 4160 832 320 ) ( 4160 832 0 ) we_cemetary/cemtrim2 128 0 -180.00 1 -1 0 0 0 +( 3712 832 0 ) ( 3744 864 0 ) ( 3728 848 64 ) we_cemetary/cemtrim2 128 0 -180.00 1 -1 0 0 0 +( 4208 848 64 ) ( 4192 864 0 ) ( 4224 832 0 ) we_cemetary/cemtrim2 128 0 -180.00 1 -1 0 0 0 +} +// brush 543 +{ +( 4192 1088 0 ) ( 4224 1088 0 ) ( 4224 1280 0 ) we_cemetary/cemtrim2 -64 0 -180.00 1 1 0 0 0 +( 4224 1280 64 ) ( 4224 1088 64 ) ( 4192 1088 64 ) we_cemetary/cemtrim2 -64 0 -180.00 1 1 0 0 0 +( 4192 1408 320 ) ( 4192 1216 320 ) ( 4192 1216 0 ) we_cemetary/cemtrim2 0 0 -180.00 1 -1 0 0 0 +( 4224 1088 320 ) ( 4224 1280 320 ) ( 4224 1280 0 ) we_cemetary/cemtrim2 0 0 -180.00 1 -1 0 0 0 +( 4224 832 0 ) ( 4192 864 0 ) ( 4208 848 64 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 4208 1328 64 ) ( 4192 1312 0 ) ( 4224 1344 0 ) we_cemetary/cemtrim2 -64 0 -180.00 1 -1 0 0 0 +} +// brush 544 +{ +( 4192 1088 64 ) ( 4224 1088 64 ) ( 4224 1280 64 ) we_cemetary/cemstair2 -64 0 -180.00 1 1 0 0 0 +( 4224 1088 384 ) ( 4224 1280 384 ) ( 4224 1280 64 ) we_cemetary/cemstair2 0 0 -180.00 1 -1 0 0 0 +( 4176 1280 96 ) ( 4184 1088 80 ) ( 4192 1280 64 ) we_cemetary/cemstair2 0 0 -180.00 1 -1 0 0 0 +( 4160 1088 256 ) ( 4160 1280 256 ) ( 4224 1280 256 ) we_cemetary/cemstair2 -64 0 -180.00 1 1 0 0 0 +( 4176 1280 208 ) ( 4176 1088 176 ) ( 4176 1280 144 ) we_cemetary/cemstair2 0 0 -180.00 1 -1 0 0 0 +( 4224 832 64 ) ( 4192 864 64 ) ( 4208 848 256 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 4208 1328 256 ) ( 4192 1312 64 ) ( 4224 1344 64 ) we_cemetary/cemstair2 -64 0 -180.00 1 -1 0 0 0 +} +// brush 545 +{ +( 4176 1280 256 ) ( 4176 1088 256 ) ( 4224 1088 256 ) we_cemetary/fogtrunk -64 0 -180.00 1 1 0 0 0 +( 4224 1280 272 ) ( 4224 1088 272 ) ( 4160 1088 272 ) we_cemetary/fogtrunk -64 0 -180.00 1 1 0 0 0 +( 4176 1088 256 ) ( 4176 1280 256 ) ( 4160 1280 272 ) we_cemetary/fogtrunk -64 0 -180.00 1 1 0 0 0 +( 4224 1088 272 ) ( 4224 1280 272 ) ( 4224 1280 256 ) we_cemetary/fogtrunk 0 0 -180.00 1 -1 0 0 0 +( 4224 832 256 ) ( 4192 864 256 ) ( 4208 848 272 ) we_cemetary/fogtrunk -64 0 0.00 1 1 0 0 0 +( 4208 1328 272 ) ( 4192 1312 256 ) ( 4224 1344 256 ) we_cemetary/fogtrunk -64 0 -180.00 1 -1 0 0 0 +} +// brush 546 +{ +( 4160 1088 272 ) ( 4192 1088 272 ) ( 4192 1280 272 ) we_cemetary/cemrunner2 -65 0 -180.00 1 1 0 0 0 +( 4192 1280 336 ) ( 4192 1088 336 ) ( 4160 1088 336 ) we_cemetary/cemtrim2 -96 0 -180.00 1 1 0 0 0 +( 4160 1280 592 ) ( 4160 1088 592 ) ( 4160 1088 272 ) we_cemetary/cemtrim2 0 13 -180.00 1 -1 0 0 0 +( 4224 1088 592 ) ( 4224 1280 592 ) ( 4224 1280 272 ) we_cemetary/cemtrim2 0 13 -180.00 1 -1 0 0 0 +( 4224 832 272 ) ( 4192 864 272 ) ( 4208 848 336 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( 4208 1328 336 ) ( 4192 1312 272 ) ( 4224 1344 272 ) we_cemetary/cemtrim2 -64 14 -180.00 1 -1 0 0 0 +} +// brush 547 +{ +( 3968 1280 272 ) ( 3968 1312 272 ) ( 3776 1312 272 ) we_cemetary/cemrunner2 11 0 -90.00 1 1 0 0 0 +( 3776 1312 336 ) ( 3968 1312 336 ) ( 3968 1280 336 ) we_cemetary/cemtrim2 105 0 -90.00 1 1 0 0 0 +( 3776 1280 592 ) ( 3968 1280 592 ) ( 3968 1280 272 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( 3968 1344 592 ) ( 3776 1344 592 ) ( 3776 1344 272 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( 4224 1344 272 ) ( 4192 1312 272 ) ( 4208 1328 336 ) we_cemetary/cemtrim2 64 15 0.00 1 1 0 0 0 +( 3728 1328 336 ) ( 3744 1312 272 ) ( 3712 1344 272 ) we_cemetary/cemtrim2 -64 16 0.00 1 1 0 0 0 +} +// brush 548 +{ +( 3776 1296 256 ) ( 3968 1296 256 ) ( 3968 1344 256 ) we_cemetary/fogtrunk -117 63 -90.00 1 1 0 0 0 +( 3776 1344 272 ) ( 3968 1344 272 ) ( 3968 1280 272 ) we_cemetary/fogtrunk -117 63 -90.00 1 1 0 0 0 +( 3968 1296 256 ) ( 3776 1296 256 ) ( 3776 1280 272 ) we_cemetary/fogtrunk -117 63 -90.00 1 1 0 0 0 +( 3968 1344 272 ) ( 3776 1344 272 ) ( 3776 1344 256 ) we_cemetary/fogtrunk -64 0 0.00 1 1 0 0 0 +( 4224 1344 256 ) ( 4192 1312 256 ) ( 4208 1328 272 ) we_cemetary/fogtrunk 64 0 0.00 1 1 0 0 0 +( 3728 1328 272 ) ( 3744 1312 256 ) ( 3712 1344 256 ) we_cemetary/fogtrunk -64 0 0.00 1 1 0 0 0 +} +// brush 549 +{ +( 3744 1280 272 ) ( 3744 1088 272 ) ( 3776 1088 272 ) we_cemetary/cemrunner2 0 0 0.00 1 1 0 0 0 +( 3776 1088 336 ) ( 3744 1088 336 ) ( 3744 1280 336 ) we_cemetary/cemtrim2 -32 0 0.00 1 1 0 0 0 +( 3776 1088 272 ) ( 3776 1088 592 ) ( 3776 1280 592 ) we_cemetary/cemtrim2 64 16 0.00 1 1 0 0 0 +( 3712 1280 272 ) ( 3712 1280 592 ) ( 3712 1088 592 ) we_cemetary/cemtrim2 64 16 0.00 1 1 0 0 0 +( 3728 848 336 ) ( 3744 864 272 ) ( 3712 832 272 ) we_cemetary/cemtrim2 64 16 0.00 1 1 0 0 0 +( 3760 1296 336 ) ( 3744 1312 272 ) ( 3776 1280 272 ) we_cemetary/cemtrim2 64 16 0.00 1 1 0 0 0 +} +// brush 550 +{ +( 3712 1088 256 ) ( 3760 1088 256 ) ( 3760 1280 256 ) we_cemetary/fogtrunk 0 -64 0.00 1 1 0 0 0 +( 3776 1088 272 ) ( 3712 1088 272 ) ( 3712 1280 272 ) we_cemetary/fogtrunk 0 -64 0.00 1 1 0 0 0 +( 3776 1280 272 ) ( 3760 1280 256 ) ( 3760 1088 256 ) we_cemetary/fogtrunk 0 -64 0.00 1 1 0 0 0 +( 3712 1280 256 ) ( 3712 1280 272 ) ( 3712 1088 272 ) we_cemetary/fogtrunk 64 0 0.00 1 1 0 0 0 +( 3728 848 272 ) ( 3744 864 256 ) ( 3712 832 256 ) we_cemetary/fogtrunk 64 0 0.00 1 1 0 0 0 +( 3760 1296 272 ) ( 3744 1312 256 ) ( 3776 1280 256 ) we_cemetary/fogtrunk 64 0 0.00 1 1 0 0 0 +} +// brush 551 +{ +( 3712 1280 64 ) ( 3712 1088 64 ) ( 3744 1088 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 3712 1280 64 ) ( 3712 1280 384 ) ( 3712 1088 384 ) we_cemetary/cemstair2 64 0 0.00 1 1 0 0 0 +( 3744 1280 64 ) ( 3752 1088 80 ) ( 3760 1280 96 ) we_cemetary/cemstair2 64 0 0.00 1 1 0 0 0 +( 3712 1280 256 ) ( 3776 1280 256 ) ( 3776 1088 256 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 3760 1280 144 ) ( 3760 1088 176 ) ( 3760 1280 208 ) we_cemetary/cemstair2 64 0 0.00 1 1 0 0 0 +( 3728 848 256 ) ( 3744 864 64 ) ( 3712 832 64 ) we_cemetary/cemstair2 64 0 0.00 1 1 0 0 0 +( 3760 1296 256 ) ( 3744 1312 64 ) ( 3776 1280 64 ) we_cemetary/cemstair2 64 0 0.00 1 1 0 0 0 +} +// brush 552 +{ +( 3712 1280 0 ) ( 3712 1088 0 ) ( 3744 1088 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( 3744 1088 64 ) ( 3712 1088 64 ) ( 3712 1280 64 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( 3744 1152 0 ) ( 3744 1152 320 ) ( 3744 1344 320 ) we_cemetary/cemtrim2 64 0 0.00 1 1 0 0 0 +( 3712 1280 0 ) ( 3712 1280 320 ) ( 3712 1088 320 ) we_cemetary/cemtrim2 64 0 0.00 1 1 0 0 0 +( 3728 848 64 ) ( 3744 864 0 ) ( 3712 832 0 ) we_cemetary/cemtrim2 64 0 0.00 1 1 0 0 0 +( 3760 1296 64 ) ( 3744 1312 0 ) ( 3776 1280 0 ) we_cemetary/cemtrim2 64 0 0.00 1 1 0 0 0 +} +// brush 553 +{ +( 3968 1312 0 ) ( 3968 1344 0 ) ( 3776 1344 0 ) we_cemetary/cemtrim2 -117 0 -90.00 1 1 0 0 0 +( 3776 1344 64 ) ( 3968 1344 64 ) ( 3968 1312 64 ) we_cemetary/cemtrim2 -117 0 -90.00 1 1 0 0 0 +( 3648 1312 320 ) ( 3840 1312 320 ) ( 3840 1312 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 3968 1344 320 ) ( 3776 1344 320 ) ( 3776 1344 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 3728 1328 64 ) ( 3744 1312 0 ) ( 3712 1344 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 3904 1344 64 ) ( 3904 1376 0 ) ( 3904 1312 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +} +// brush 554 +{ +( 3968 1312 0 ) ( 3968 1344 0 ) ( 3776 1344 0 ) we_cemetary/cemtrim2 -117 0 -90.00 1 1 0 0 0 +( 3776 1344 64 ) ( 3968 1344 64 ) ( 3968 1312 64 ) we_cemetary/cemtrim2 -117 0 -90.00 1 1 0 0 0 +( 3776 1312 320 ) ( 3968 1312 320 ) ( 3968 1312 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 3968 1344 320 ) ( 3776 1344 320 ) ( 3776 1344 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 4224 1344 0 ) ( 4192 1312 0 ) ( 4208 1328 64 ) we_cemetary/cemtrim2 64 0 0.00 1 1 0 0 0 +( 4032 1344 64 ) ( 4032 1312 0 ) ( 4032 1376 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +} +// brush 555 +{ +( 3968 1312 64 ) ( 3968 1344 64 ) ( 3776 1344 64 ) we_cemetary/cemstair2 -117 0 -90.00 1 1 0 0 0 +( 3968 1344 384 ) ( 3776 1344 384 ) ( 3776 1344 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 3776 1296 96 ) ( 3968 1304 80 ) ( 3776 1312 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 3968 1280 256 ) ( 3776 1280 256 ) ( 3776 1344 256 ) we_cemetary/cemstair2 -117 0 -90.00 1 1 0 0 0 +( 3776 1296 208 ) ( 3968 1296 176 ) ( 3776 1296 144 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 3728 1328 256 ) ( 3744 1312 64 ) ( 3712 1344 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 3904 1344 256 ) ( 3904 1376 64 ) ( 3904 1312 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +} +// brush 556 +{ +( 3968 1312 64 ) ( 3968 1344 64 ) ( 3776 1344 64 ) we_cemetary/cemstair2 -117 0 -90.00 1 1 0 0 0 +( 3968 1344 384 ) ( 3776 1344 384 ) ( 3776 1344 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 3776 1296 96 ) ( 3968 1304 80 ) ( 3776 1312 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 3968 1280 256 ) ( 3776 1280 256 ) ( 3776 1344 256 ) we_cemetary/cemstair2 -117 0 -90.00 1 1 0 0 0 +( 3904 1296 208 ) ( 4096 1296 176 ) ( 3904 1296 144 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 4224 1344 64 ) ( 4192 1312 64 ) ( 4208 1328 256 ) we_cemetary/cemstair2 64 0 0.00 1 1 0 0 0 +( 4032 1344 256 ) ( 4032 1312 64 ) ( 4032 1376 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +} +// brush 557 +{ +( 3776 1344 64 ) ( 3968 1344 64 ) ( 3968 1376 64 ) we_cemetary/cemstair2 72 0 -90.00 1 1 0 0 0 +( 3776 1344 64 ) ( 3776 1344 384 ) ( 3968 1344 384 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 3776 1376 64 ) ( 3968 1384 80 ) ( 3776 1392 96 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 3776 1344 256 ) ( 3776 1408 256 ) ( 3968 1408 256 ) we_cemetary/cemstair2 72 0 -90.00 1 1 0 0 0 +( 3872 1392 144 ) ( 4064 1392 176 ) ( 3872 1392 208 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 4032 1344 256 ) ( 4032 1312 64 ) ( 4032 1376 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 4224 1376 256 ) ( 4224 1408 64 ) ( 4224 1344 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +} +// brush 558 +{ +( 3776 1344 0 ) ( 3968 1344 0 ) ( 3968 1376 0 ) we_cemetary/cemtrim2 72 0 -90.00 1 1 0 0 0 +( 3968 1376 64 ) ( 3968 1344 64 ) ( 3776 1344 64 ) we_cemetary/cemtrim2 72 0 -90.00 1 1 0 0 0 +( 4064 1376 0 ) ( 4064 1376 320 ) ( 3872 1376 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 3776 1344 0 ) ( 3776 1344 320 ) ( 3968 1344 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 4032 1344 64 ) ( 4032 1312 0 ) ( 4032 1376 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( 4224 1376 64 ) ( 4224 1408 0 ) ( 4224 1344 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +} +// brush 559 +{ +( 3776 1344 64 ) ( 3968 1344 64 ) ( 3968 1376 64 ) we_cemetary/cemstair2 72 0 -90.00 1 1 0 0 0 +( 3776 1344 64 ) ( 3776 1344 384 ) ( 3968 1344 384 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 3776 1376 64 ) ( 3968 1384 80 ) ( 3776 1392 96 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 3776 1344 256 ) ( 3776 1408 256 ) ( 3968 1408 256 ) we_cemetary/cemstair2 72 0 -90.00 1 1 0 0 0 +( 3776 1392 144 ) ( 3968 1392 176 ) ( 3776 1392 208 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 3904 1344 256 ) ( 3904 1376 64 ) ( 3904 1312 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 3712 1392 256 ) ( 3712 1376 64 ) ( 3712 1408 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +} +// brush 560 +{ +( 3776 1344 0 ) ( 3968 1344 0 ) ( 3968 1376 0 ) we_cemetary/cemtrim2 72 0 -90.00 1 1 0 0 0 +( 3968 1376 64 ) ( 3968 1344 64 ) ( 3776 1344 64 ) we_cemetary/cemtrim2 72 0 -90.00 1 1 0 0 0 +( 3776 1376 0 ) ( 3776 1376 320 ) ( 3584 1376 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 3776 1344 0 ) ( 3776 1344 320 ) ( 3968 1344 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 3904 1344 64 ) ( 3904 1376 0 ) ( 3904 1312 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( 3712 1392 64 ) ( 3712 1376 0 ) ( 3712 1408 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +} +// brush 561 +{ +( 3968 1344 256 ) ( 3968 1392 256 ) ( 3776 1392 256 ) we_cemetary/fogtrunk 72 63 -90.00 1 1 0 0 0 +( 3968 1408 272 ) ( 3968 1344 272 ) ( 3776 1344 272 ) we_cemetary/fogtrunk 72 63 -90.00 1 1 0 0 0 +( 3776 1408 272 ) ( 3776 1392 256 ) ( 3968 1392 256 ) we_cemetary/fogtrunk 72 63 -90.00 1 1 0 0 0 +( 3776 1344 256 ) ( 3776 1344 272 ) ( 3968 1344 272 ) we_cemetary/fogtrunk -64 0 0.00 1 1 0 0 0 +( 4224 1376 272 ) ( 4224 1408 256 ) ( 4224 1344 256 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +( 3712 1392 272 ) ( 3712 1376 256 ) ( 3712 1408 256 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +} +// brush 562 +{ +( 3776 1376 272 ) ( 3968 1376 272 ) ( 3968 1408 272 ) we_cemetary/cemrunner2 -64 0 -90.00 1 1 0 0 0 +( 3968 1408 336 ) ( 3968 1376 336 ) ( 3776 1376 336 ) we_cemetary/cemtrim2 40 0 -90.00 1 1 0 0 0 +( 3968 1408 272 ) ( 3968 1408 592 ) ( 3776 1408 592 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( 3776 1344 272 ) ( 3776 1344 592 ) ( 3968 1344 592 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( 4224 1376 336 ) ( 4224 1408 272 ) ( 4224 1344 272 ) we_cemetary/cemtrim2 0 16 0.00 1 1 0 0 0 +( 3712 1392 336 ) ( 3712 1376 272 ) ( 3712 1408 272 ) we_cemetary/cemtrim2 0 16 0.00 1 1 0 0 0 +} +// brush 563 +{ +( 3744 1312 -32 ) ( 3744 864 -32 ) ( 4192 864 -32 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 4192 864 0 ) ( 3744 864 0 ) ( 3744 1312 0 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 4192 1376 -64 ) ( 4192 1376 0 ) ( 3744 1376 0 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 4224 864 -64 ) ( 4224 864 0 ) ( 4224 1312 0 ) we_cemetary/cemtrim5 64 0 0.00 1 1 0 0 0 +( 3744 832 -64 ) ( 3744 832 0 ) ( 4192 832 0 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 3712 1312 -64 ) ( 3712 1312 0 ) ( 3712 864 0 ) we_cemetary/cemtrim5 64 0 0.00 1 1 0 0 0 +} +// brush 564 +{ +( 3744 1312 336 ) ( 3744 864 336 ) ( 4192 864 336 ) water/waterfloor2 0 -64 0.00 1 1 0 0 0 +( 4192 864 352 ) ( 3744 864 352 ) ( 3744 1312 352 ) water/waterfloor2 0 -64 0.00 1 1 0 0 0 +( 4192 1312 304 ) ( 4192 1312 368 ) ( 3744 1312 368 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +( 4192 864 304 ) ( 4192 864 368 ) ( 4192 1312 368 ) water/waterfloor2 64 0 0.00 1 1 0 0 0 +( 3744 864 304 ) ( 3744 864 368 ) ( 4192 864 368 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +( 3744 1312 304 ) ( 3744 1312 368 ) ( 3744 864 368 ) water/waterfloor2 64 0 0.00 1 1 0 0 0 +} +// brush 565 +{ +( 3904 1392 208 ) ( 3904 1296 208 ) ( 4032 1296 208 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 4032 1296 256 ) ( 3904 1296 256 ) ( 3904 1392 256 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 4032 1392 64 ) ( 4032 1392 256 ) ( 3904 1392 256 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 4032 1296 48 ) ( 4032 1296 240 ) ( 4032 1392 240 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 3904 1296 48 ) ( 3904 1296 240 ) ( 4032 1296 240 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 3904 1392 64 ) ( 3904 1392 256 ) ( 3904 1296 256 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +} +// brush 566 +{ +( 4416 1392 208 ) ( 4416 1296 208 ) ( 4544 1296 208 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 4544 1296 256 ) ( 4416 1296 256 ) ( 4416 1392 256 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 4544 1392 64 ) ( 4544 1392 256 ) ( 4416 1392 256 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 4544 1296 48 ) ( 4544 1296 240 ) ( 4544 1392 240 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 4416 1296 48 ) ( 4416 1296 240 ) ( 4544 1296 240 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 4416 1392 64 ) ( 4416 1392 256 ) ( 4416 1296 256 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +} +// brush 567 +{ +( 4256 1312 336 ) ( 4256 864 336 ) ( 4704 864 336 ) water/waterfloor2 0 -64 0.00 1 1 0 0 0 +( 4704 864 352 ) ( 4256 864 352 ) ( 4256 1312 352 ) water/waterfloor2 0 -64 0.00 1 1 0 0 0 +( 4704 1312 304 ) ( 4704 1312 368 ) ( 4256 1312 368 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +( 4704 864 304 ) ( 4704 864 368 ) ( 4704 1312 368 ) water/waterfloor2 64 0 0.00 1 1 0 0 0 +( 4256 864 304 ) ( 4256 864 368 ) ( 4704 864 368 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +( 4256 1312 304 ) ( 4256 1312 368 ) ( 4256 864 368 ) water/waterfloor2 64 0 0.00 1 1 0 0 0 +} +// brush 568 +{ +( 4256 1312 -32 ) ( 4256 864 -32 ) ( 4704 864 -32 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 4704 864 0 ) ( 4256 864 0 ) ( 4256 1312 0 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 4704 1376 -64 ) ( 4704 1376 0 ) ( 4256 1376 0 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 4736 864 -64 ) ( 4736 864 0 ) ( 4736 1312 0 ) we_cemetary/cemtrim5 64 0 0.00 1 1 0 0 0 +( 4256 832 -64 ) ( 4256 832 0 ) ( 4704 832 0 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 4224 1312 -64 ) ( 4224 1312 0 ) ( 4224 864 0 ) we_cemetary/cemtrim5 64 0 0.00 1 1 0 0 0 +} +// brush 569 +{ +( 4288 1376 272 ) ( 4480 1376 272 ) ( 4480 1408 272 ) we_cemetary/cemrunner2 -64 0 -90.00 1 1 0 0 0 +( 4480 1408 336 ) ( 4480 1376 336 ) ( 4288 1376 336 ) we_cemetary/cemtrim2 41 0 -90.00 1 1 0 0 0 +( 4480 1408 272 ) ( 4480 1408 592 ) ( 4288 1408 592 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( 4288 1344 272 ) ( 4288 1344 592 ) ( 4480 1344 592 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( 4736 1376 336 ) ( 4736 1408 272 ) ( 4736 1344 272 ) we_cemetary/cemtrim2 0 16 0.00 1 1 0 0 0 +( 4224 1392 336 ) ( 4224 1376 272 ) ( 4224 1408 272 ) we_cemetary/cemtrim2 0 16 0.00 1 1 0 0 0 +} +// brush 570 +{ +( 4480 1344 256 ) ( 4480 1392 256 ) ( 4288 1392 256 ) we_cemetary/fogtrunk 73 63 -90.00 1 1 0 0 0 +( 4480 1408 272 ) ( 4480 1344 272 ) ( 4288 1344 272 ) we_cemetary/fogtrunk 73 63 -90.00 1 1 0 0 0 +( 4288 1408 272 ) ( 4288 1392 256 ) ( 4480 1392 256 ) we_cemetary/fogtrunk 73 63 -90.00 1 1 0 0 0 +( 4288 1344 256 ) ( 4288 1344 272 ) ( 4480 1344 272 ) we_cemetary/fogtrunk -64 0 0.00 1 1 0 0 0 +( 4736 1376 272 ) ( 4736 1408 256 ) ( 4736 1344 256 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +( 4224 1392 272 ) ( 4224 1376 256 ) ( 4224 1408 256 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +} +// brush 571 +{ +( 4288 1344 0 ) ( 4480 1344 0 ) ( 4480 1376 0 ) we_cemetary/cemtrim2 73 0 -90.00 1 1 0 0 0 +( 4480 1376 64 ) ( 4480 1344 64 ) ( 4288 1344 64 ) we_cemetary/cemtrim2 73 0 -90.00 1 1 0 0 0 +( 4288 1376 0 ) ( 4288 1376 320 ) ( 4096 1376 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 4288 1344 0 ) ( 4288 1344 320 ) ( 4480 1344 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 4416 1344 64 ) ( 4416 1376 0 ) ( 4416 1312 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( 4224 1392 64 ) ( 4224 1376 0 ) ( 4224 1408 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +} +// brush 572 +{ +( 4288 1344 64 ) ( 4480 1344 64 ) ( 4480 1376 64 ) we_cemetary/cemstair2 73 0 -90.00 1 1 0 0 0 +( 4288 1344 64 ) ( 4288 1344 384 ) ( 4480 1344 384 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 4288 1376 64 ) ( 4480 1384 80 ) ( 4288 1392 96 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 4288 1344 256 ) ( 4288 1408 256 ) ( 4480 1408 256 ) we_cemetary/cemstair2 73 0 -90.00 1 1 0 0 0 +( 4288 1392 144 ) ( 4480 1392 176 ) ( 4288 1392 208 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 4416 1344 256 ) ( 4416 1376 64 ) ( 4416 1312 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 4224 1392 256 ) ( 4224 1376 64 ) ( 4224 1408 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +} +// brush 573 +{ +( 4288 1344 0 ) ( 4480 1344 0 ) ( 4480 1376 0 ) we_cemetary/cemtrim2 73 0 -90.00 1 1 0 0 0 +( 4480 1376 64 ) ( 4480 1344 64 ) ( 4288 1344 64 ) we_cemetary/cemtrim2 73 0 -90.00 1 1 0 0 0 +( 4576 1376 0 ) ( 4576 1376 320 ) ( 4384 1376 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 4288 1344 0 ) ( 4288 1344 320 ) ( 4480 1344 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 4544 1344 64 ) ( 4544 1312 0 ) ( 4544 1376 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( 4736 1376 64 ) ( 4736 1408 0 ) ( 4736 1344 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +} +// brush 574 +{ +( 4288 1344 64 ) ( 4480 1344 64 ) ( 4480 1376 64 ) we_cemetary/cemstair2 73 0 -90.00 1 1 0 0 0 +( 4288 1344 64 ) ( 4288 1344 384 ) ( 4480 1344 384 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 4288 1376 64 ) ( 4480 1384 80 ) ( 4288 1392 96 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 4288 1344 256 ) ( 4288 1408 256 ) ( 4480 1408 256 ) we_cemetary/cemstair2 73 0 -90.00 1 1 0 0 0 +( 4384 1392 144 ) ( 4576 1392 176 ) ( 4384 1392 208 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 4544 1344 256 ) ( 4544 1312 64 ) ( 4544 1376 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 4736 1376 256 ) ( 4736 1408 64 ) ( 4736 1344 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +} +// brush 575 +{ +( 4480 1312 64 ) ( 4480 1344 64 ) ( 4288 1344 64 ) we_cemetary/cemstair2 -116 0 -90.00 1 1 0 0 0 +( 4480 1344 384 ) ( 4288 1344 384 ) ( 4288 1344 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 4288 1296 96 ) ( 4480 1304 80 ) ( 4288 1312 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 4480 1280 256 ) ( 4288 1280 256 ) ( 4288 1344 256 ) we_cemetary/cemstair2 -116 0 -90.00 1 1 0 0 0 +( 4416 1296 208 ) ( 4608 1296 176 ) ( 4416 1296 144 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 4736 1344 64 ) ( 4704 1312 64 ) ( 4720 1328 256 ) we_cemetary/cemstair2 64 0 0.00 1 1 0 0 0 +( 4544 1344 256 ) ( 4544 1312 64 ) ( 4544 1376 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +} +// brush 576 +{ +( 4480 1312 64 ) ( 4480 1344 64 ) ( 4288 1344 64 ) we_cemetary/cemstair2 -116 0 -90.00 1 1 0 0 0 +( 4480 1344 384 ) ( 4288 1344 384 ) ( 4288 1344 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 4288 1296 96 ) ( 4480 1304 80 ) ( 4288 1312 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 4480 1280 256 ) ( 4288 1280 256 ) ( 4288 1344 256 ) we_cemetary/cemstair2 -116 0 -90.00 1 1 0 0 0 +( 4288 1296 208 ) ( 4480 1296 176 ) ( 4288 1296 144 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 4240 1328 256 ) ( 4256 1312 64 ) ( 4224 1344 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 4416 1344 256 ) ( 4416 1376 64 ) ( 4416 1312 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +} +// brush 577 +{ +( 4480 1312 0 ) ( 4480 1344 0 ) ( 4288 1344 0 ) we_cemetary/cemtrim2 -116 0 -90.00 1 1 0 0 0 +( 4288 1344 64 ) ( 4480 1344 64 ) ( 4480 1312 64 ) we_cemetary/cemtrim2 -116 0 -90.00 1 1 0 0 0 +( 4288 1312 320 ) ( 4480 1312 320 ) ( 4480 1312 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 4480 1344 320 ) ( 4288 1344 320 ) ( 4288 1344 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 4736 1344 0 ) ( 4704 1312 0 ) ( 4720 1328 64 ) we_cemetary/cemtrim2 64 0 0.00 1 1 0 0 0 +( 4544 1344 64 ) ( 4544 1312 0 ) ( 4544 1376 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +} +// brush 578 +{ +( 4480 1312 0 ) ( 4480 1344 0 ) ( 4288 1344 0 ) we_cemetary/cemtrim2 -116 0 -90.00 1 1 0 0 0 +( 4288 1344 64 ) ( 4480 1344 64 ) ( 4480 1312 64 ) we_cemetary/cemtrim2 -116 0 -90.00 1 1 0 0 0 +( 4160 1312 320 ) ( 4352 1312 320 ) ( 4352 1312 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 4480 1344 320 ) ( 4288 1344 320 ) ( 4288 1344 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 4240 1328 64 ) ( 4256 1312 0 ) ( 4224 1344 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 4416 1344 64 ) ( 4416 1376 0 ) ( 4416 1312 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +} +// brush 579 +{ +( 4224 1280 0 ) ( 4224 1088 0 ) ( 4256 1088 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( 4256 1088 64 ) ( 4224 1088 64 ) ( 4224 1280 64 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( 4256 1152 0 ) ( 4256 1152 320 ) ( 4256 1344 320 ) we_cemetary/cemtrim2 64 0 0.00 1 1 0 0 0 +( 4224 1280 0 ) ( 4224 1280 320 ) ( 4224 1088 320 ) we_cemetary/cemtrim2 64 0 0.00 1 1 0 0 0 +( 4240 848 64 ) ( 4256 864 0 ) ( 4224 832 0 ) we_cemetary/cemtrim2 64 0 0.00 1 1 0 0 0 +( 4272 1296 64 ) ( 4256 1312 0 ) ( 4288 1280 0 ) we_cemetary/cemtrim2 64 0 0.00 1 1 0 0 0 +} +// brush 580 +{ +( 4224 1280 64 ) ( 4224 1088 64 ) ( 4256 1088 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 4224 1280 64 ) ( 4224 1280 384 ) ( 4224 1088 384 ) we_cemetary/cemstair2 64 0 0.00 1 1 0 0 0 +( 4256 1280 64 ) ( 4264 1088 80 ) ( 4272 1280 96 ) we_cemetary/cemstair2 64 0 0.00 1 1 0 0 0 +( 4224 1280 256 ) ( 4288 1280 256 ) ( 4288 1088 256 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 4272 1280 144 ) ( 4272 1088 176 ) ( 4272 1280 208 ) we_cemetary/cemstair2 64 0 0.00 1 1 0 0 0 +( 4240 848 256 ) ( 4256 864 64 ) ( 4224 832 64 ) we_cemetary/cemstair2 64 0 0.00 1 1 0 0 0 +( 4272 1296 256 ) ( 4256 1312 64 ) ( 4288 1280 64 ) we_cemetary/cemstair2 64 0 0.00 1 1 0 0 0 +} +// brush 581 +{ +( 4224 1088 256 ) ( 4272 1088 256 ) ( 4272 1280 256 ) we_cemetary/fogtrunk 0 -64 0.00 1 1 0 0 0 +( 4288 1088 272 ) ( 4224 1088 272 ) ( 4224 1280 272 ) we_cemetary/fogtrunk 0 -64 0.00 1 1 0 0 0 +( 4288 1280 272 ) ( 4272 1280 256 ) ( 4272 1088 256 ) we_cemetary/fogtrunk 0 -64 0.00 1 1 0 0 0 +( 4224 1280 256 ) ( 4224 1280 272 ) ( 4224 1088 272 ) we_cemetary/fogtrunk 64 0 0.00 1 1 0 0 0 +( 4240 848 272 ) ( 4256 864 256 ) ( 4224 832 256 ) we_cemetary/fogtrunk 64 0 0.00 1 1 0 0 0 +( 4272 1296 272 ) ( 4256 1312 256 ) ( 4288 1280 256 ) we_cemetary/fogtrunk 64 0 0.00 1 1 0 0 0 +} +// brush 582 +{ +( 4256 1280 272 ) ( 4256 1088 272 ) ( 4288 1088 272 ) we_cemetary/cemrunner2 0 0 0.00 1 1 0 0 0 +( 4288 1088 336 ) ( 4256 1088 336 ) ( 4256 1280 336 ) we_cemetary/cemtrim2 -32 0 0.00 1 1 0 0 0 +( 4288 1088 272 ) ( 4288 1088 592 ) ( 4288 1280 592 ) we_cemetary/cemtrim2 64 16 0.00 1 1 0 0 0 +( 4224 1280 272 ) ( 4224 1280 592 ) ( 4224 1088 592 ) we_cemetary/cemtrim2 64 16 0.00 1 1 0 0 0 +( 4240 848 336 ) ( 4256 864 272 ) ( 4224 832 272 ) we_cemetary/cemtrim2 64 16 0.00 1 1 0 0 0 +( 4272 1296 336 ) ( 4256 1312 272 ) ( 4288 1280 272 ) we_cemetary/cemtrim2 64 16 0.00 1 1 0 0 0 +} +// brush 583 +{ +( 4288 1296 256 ) ( 4480 1296 256 ) ( 4480 1344 256 ) we_cemetary/fogtrunk -116 63 -90.00 1 1 0 0 0 +( 4288 1344 272 ) ( 4480 1344 272 ) ( 4480 1280 272 ) we_cemetary/fogtrunk -116 63 -90.00 1 1 0 0 0 +( 4480 1296 256 ) ( 4288 1296 256 ) ( 4288 1280 272 ) we_cemetary/fogtrunk -116 63 -90.00 1 1 0 0 0 +( 4480 1344 272 ) ( 4288 1344 272 ) ( 4288 1344 256 ) we_cemetary/fogtrunk -64 0 0.00 1 1 0 0 0 +( 4736 1344 256 ) ( 4704 1312 256 ) ( 4720 1328 272 ) we_cemetary/fogtrunk 64 0 0.00 1 1 0 0 0 +( 4240 1328 272 ) ( 4256 1312 256 ) ( 4224 1344 256 ) we_cemetary/fogtrunk -64 0 0.00 1 1 0 0 0 +} +// brush 584 +{ +( 4480 1280 272 ) ( 4480 1312 272 ) ( 4288 1312 272 ) we_cemetary/cemrunner2 12 0 -90.00 1 1 0 0 0 +( 4288 1312 336 ) ( 4480 1312 336 ) ( 4480 1280 336 ) we_cemetary/cemtrim2 106 0 -90.00 1 1 0 0 0 +( 4288 1280 592 ) ( 4480 1280 592 ) ( 4480 1280 272 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( 4480 1344 592 ) ( 4288 1344 592 ) ( 4288 1344 272 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( 4736 1344 272 ) ( 4704 1312 272 ) ( 4720 1328 336 ) we_cemetary/cemtrim2 64 15 0.00 1 1 0 0 0 +( 4240 1328 336 ) ( 4256 1312 272 ) ( 4224 1344 272 ) we_cemetary/cemtrim2 -64 16 0.00 1 1 0 0 0 +} +// brush 585 +{ +( 4672 1088 272 ) ( 4704 1088 272 ) ( 4704 1280 272 ) we_cemetary/cemrunner2 62 0 -180.00 1 1 0 0 0 +( 4704 1280 336 ) ( 4704 1088 336 ) ( 4672 1088 336 ) we_cemetary/cemtrim2 159 0 -180.00 1 1 0 0 0 +( 4672 1280 592 ) ( 4672 1088 592 ) ( 4672 1088 272 ) we_cemetary/cemtrim2 0 13 -180.00 1 -1 0 0 0 +( 4736 1088 592 ) ( 4736 1280 592 ) ( 4736 1280 272 ) we_cemetary/cemtrim2 0 13 -180.00 1 -1 0 0 0 +( 4736 832 272 ) ( 4704 864 272 ) ( 4720 848 336 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( 4720 1328 336 ) ( 4704 1312 272 ) ( 4736 1344 272 ) we_cemetary/cemtrim2 -64 14 -180.00 1 -1 0 0 0 +} +// brush 586 +{ +( 4688 1280 256 ) ( 4688 1088 256 ) ( 4736 1088 256 ) we_cemetary/fogtrunk 191 0 -180.00 1 1 0 0 0 +( 4736 1280 272 ) ( 4736 1088 272 ) ( 4672 1088 272 ) we_cemetary/fogtrunk 191 0 -180.00 1 1 0 0 0 +( 4688 1088 256 ) ( 4688 1280 256 ) ( 4672 1280 272 ) we_cemetary/fogtrunk 191 0 -180.00 1 1 0 0 0 +( 4736 1088 272 ) ( 4736 1280 272 ) ( 4736 1280 256 ) we_cemetary/fogtrunk 0 0 -180.00 1 -1 0 0 0 +( 4736 832 256 ) ( 4704 864 256 ) ( 4720 848 272 ) we_cemetary/fogtrunk -64 0 0.00 1 1 0 0 0 +( 4720 1328 272 ) ( 4704 1312 256 ) ( 4736 1344 256 ) we_cemetary/fogtrunk -64 0 -180.00 1 -1 0 0 0 +} +// brush 587 +{ +( 4704 1088 64 ) ( 4736 1088 64 ) ( 4736 1280 64 ) we_cemetary/cemstair2 191 0 -180.00 1 1 0 0 0 +( 4736 1088 384 ) ( 4736 1280 384 ) ( 4736 1280 64 ) we_cemetary/cemstair2 0 0 -180.00 1 -1 0 0 0 +( 4688 1280 96 ) ( 4696 1088 80 ) ( 4704 1280 64 ) we_cemetary/cemstair2 0 0 -180.00 1 -1 0 0 0 +( 4672 1088 256 ) ( 4672 1280 256 ) ( 4736 1280 256 ) we_cemetary/cemstair2 191 0 -180.00 1 1 0 0 0 +( 4688 1280 208 ) ( 4688 1088 176 ) ( 4688 1280 144 ) we_cemetary/cemstair2 0 0 -180.00 1 -1 0 0 0 +( 4736 832 64 ) ( 4704 864 64 ) ( 4720 848 256 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 4720 1328 256 ) ( 4704 1312 64 ) ( 4736 1344 64 ) we_cemetary/cemstair2 -64 0 -180.00 1 -1 0 0 0 +} +// brush 588 +{ +( 4704 1088 0 ) ( 4736 1088 0 ) ( 4736 1280 0 ) we_cemetary/cemtrim2 191 0 -180.00 1 1 0 0 0 +( 4736 1280 64 ) ( 4736 1088 64 ) ( 4704 1088 64 ) we_cemetary/cemtrim2 191 0 -180.00 1 1 0 0 0 +( 4704 1408 320 ) ( 4704 1216 320 ) ( 4704 1216 0 ) we_cemetary/cemtrim2 0 0 -180.00 1 -1 0 0 0 +( 4736 1088 320 ) ( 4736 1280 320 ) ( 4736 1280 0 ) we_cemetary/cemtrim2 0 0 -180.00 1 -1 0 0 0 +( 4736 832 0 ) ( 4704 864 0 ) ( 4720 848 64 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 4720 1328 64 ) ( 4704 1312 0 ) ( 4736 1344 0 ) we_cemetary/cemtrim2 -64 0 -180.00 1 -1 0 0 0 +} +// brush 589 +{ +( 4480 864 0 ) ( 4480 832 0 ) ( 4672 832 0 ) we_cemetary/cemtrim2 13 0 90.00 1 1 0 0 0 +( 4672 832 64 ) ( 4480 832 64 ) ( 4480 864 64 ) we_cemetary/cemtrim2 13 0 90.00 1 1 0 0 0 +( 4736 864 320 ) ( 4544 864 320 ) ( 4544 864 0 ) we_cemetary/cemtrim2 128 0 -180.00 1 -1 0 0 0 +( 4480 832 320 ) ( 4672 832 320 ) ( 4672 832 0 ) we_cemetary/cemtrim2 128 0 -180.00 1 -1 0 0 0 +( 4224 832 0 ) ( 4256 864 0 ) ( 4240 848 64 ) we_cemetary/cemtrim2 128 0 -180.00 1 -1 0 0 0 +( 4720 848 64 ) ( 4704 864 0 ) ( 4736 832 0 ) we_cemetary/cemtrim2 128 0 -180.00 1 -1 0 0 0 +} +// brush 590 +{ +( 4480 864 64 ) ( 4480 832 64 ) ( 4672 832 64 ) we_cemetary/cemstair2 13 0 90.00 1 1 0 0 0 +( 4480 832 384 ) ( 4672 832 384 ) ( 4672 832 64 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +( 4672 880 96 ) ( 4480 872 80 ) ( 4672 864 64 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +( 4480 896 256 ) ( 4672 896 256 ) ( 4672 832 256 ) we_cemetary/cemstair2 13 0 90.00 1 1 0 0 0 +( 4672 880 208 ) ( 4480 880 176 ) ( 4672 880 144 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +( 4224 832 64 ) ( 4256 864 64 ) ( 4240 848 256 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +( 4720 848 256 ) ( 4704 864 64 ) ( 4736 832 64 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +} +// brush 591 +{ +( 4672 880 256 ) ( 4480 880 256 ) ( 4480 832 256 ) we_cemetary/fogtrunk 13 -127 90.00 1 1 0 0 0 +( 4672 832 272 ) ( 4480 832 272 ) ( 4480 896 272 ) we_cemetary/fogtrunk 13 -127 90.00 1 1 0 0 0 +( 4480 880 256 ) ( 4672 880 256 ) ( 4672 896 272 ) we_cemetary/fogtrunk 13 -127 90.00 1 1 0 0 0 +( 4480 832 272 ) ( 4672 832 272 ) ( 4672 832 256 ) we_cemetary/fogtrunk 128 0 -180.00 1 -1 0 0 0 +( 4224 832 256 ) ( 4256 864 256 ) ( 4240 848 272 ) we_cemetary/fogtrunk 128 0 -180.00 1 -1 0 0 0 +( 4720 848 272 ) ( 4704 864 256 ) ( 4736 832 256 ) we_cemetary/fogtrunk 128 0 -180.00 1 -1 0 0 0 +} +// brush 592 +{ +( 4480 896 272 ) ( 4480 864 272 ) ( 4672 864 272 ) we_cemetary/cemrunner2 13 5 90.00 1 1.000122 0 0 0 +( 4672 864 336 ) ( 4480 864 336 ) ( 4480 896 336 ) we_cemetary/cemtrim2 -19 0 90.00 1 1 0 0 0 +( 4672 896 592 ) ( 4480 896 592 ) ( 4480 896 272 ) we_cemetary/cemtrim2 128 15 -180.00 1 -1 0 0 0 +( 4480 832 592 ) ( 4672 832 592 ) ( 4672 832 272 ) we_cemetary/cemtrim2 128 15 -180.00 1 -1 0 0 0 +( 4224 832 272 ) ( 4256 864 272 ) ( 4240 848 336 ) we_cemetary/cemtrim2 128 14 -180.00 1 -1 0 0 0 +( 4720 848 336 ) ( 4704 864 272 ) ( 4736 832 272 ) we_cemetary/cemtrim2 128 14 -180.00 1 -1 0 0 0 +} +// brush 593 +{ +( 4992 896 272 ) ( 4992 864 272 ) ( 5184 864 272 ) we_cemetary/cemrunner2 14 5 90.00 1 1.000122 0 0 0 +( 5184 864 336 ) ( 4992 864 336 ) ( 4992 896 336 ) we_cemetary/cemtrim2 -18 0 90.00 1 1 0 0 0 +( 5184 896 592 ) ( 4992 896 592 ) ( 4992 896 272 ) we_cemetary/cemtrim2 128 15 -180.00 1 -1 0 0 0 +( 4992 832 592 ) ( 5184 832 592 ) ( 5184 832 272 ) we_cemetary/cemtrim2 128 15 -180.00 1 -1 0 0 0 +( 4736 832 272 ) ( 4768 864 272 ) ( 4752 848 336 ) we_cemetary/cemtrim2 128 14 -180.00 1 -1 0 0 0 +( 5232 848 336 ) ( 5216 864 272 ) ( 5248 832 272 ) we_cemetary/cemtrim2 128 14 -180.00 1 -1 0 0 0 +} +// brush 594 +{ +( 5184 880 256 ) ( 4992 880 256 ) ( 4992 832 256 ) we_cemetary/fogtrunk 14 -127 90.00 1 1 0 0 0 +( 5184 832 272 ) ( 4992 832 272 ) ( 4992 896 272 ) we_cemetary/fogtrunk 14 -127 90.00 1 1 0 0 0 +( 4992 880 256 ) ( 5184 880 256 ) ( 5184 896 272 ) we_cemetary/fogtrunk 14 -127 90.00 1 1 0 0 0 +( 4992 832 272 ) ( 5184 832 272 ) ( 5184 832 256 ) we_cemetary/fogtrunk 128 0 -180.00 1 -1 0 0 0 +( 4736 832 256 ) ( 4768 864 256 ) ( 4752 848 272 ) we_cemetary/fogtrunk 128 0 -180.00 1 -1 0 0 0 +( 5232 848 272 ) ( 5216 864 256 ) ( 5248 832 256 ) we_cemetary/fogtrunk 128 0 -180.00 1 -1 0 0 0 +} +// brush 595 +{ +( 4992 864 64 ) ( 4992 832 64 ) ( 5184 832 64 ) we_cemetary/cemstair2 14 0 90.00 1 1 0 0 0 +( 4992 832 384 ) ( 5184 832 384 ) ( 5184 832 64 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +( 5184 880 96 ) ( 4992 872 80 ) ( 5184 864 64 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +( 4992 896 256 ) ( 5184 896 256 ) ( 5184 832 256 ) we_cemetary/cemstair2 14 0 90.00 1 1 0 0 0 +( 5184 880 208 ) ( 4992 880 176 ) ( 5184 880 144 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +( 4736 832 64 ) ( 4768 864 64 ) ( 4752 848 256 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +( 5232 848 256 ) ( 5216 864 64 ) ( 5248 832 64 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +} +// brush 596 +{ +( 4992 864 0 ) ( 4992 832 0 ) ( 5184 832 0 ) we_cemetary/cemtrim2 14 0 90.00 1 1 0 0 0 +( 5184 832 64 ) ( 4992 832 64 ) ( 4992 864 64 ) we_cemetary/cemtrim2 14 0 90.00 1 1 0 0 0 +( 5248 864 320 ) ( 5056 864 320 ) ( 5056 864 0 ) we_cemetary/cemtrim2 128 0 -180.00 1 -1 0 0 0 +( 4992 832 320 ) ( 5184 832 320 ) ( 5184 832 0 ) we_cemetary/cemtrim2 128 0 -180.00 1 -1 0 0 0 +( 4736 832 0 ) ( 4768 864 0 ) ( 4752 848 64 ) we_cemetary/cemtrim2 128 0 -180.00 1 -1 0 0 0 +( 5232 848 64 ) ( 5216 864 0 ) ( 5248 832 0 ) we_cemetary/cemtrim2 128 0 -180.00 1 -1 0 0 0 +} +// brush 597 +{ +( 5216 1088 0 ) ( 5248 1088 0 ) ( 5248 1280 0 ) we_cemetary/cemtrim2 191 0 -180.00 1 1 0 0 0 +( 5248 1280 64 ) ( 5248 1088 64 ) ( 5216 1088 64 ) we_cemetary/cemtrim2 191 0 -180.00 1 1 0 0 0 +( 5216 1408 320 ) ( 5216 1216 320 ) ( 5216 1216 0 ) we_cemetary/cemtrim2 0 0 -180.00 1 -1 0 0 0 +( 5248 1088 320 ) ( 5248 1280 320 ) ( 5248 1280 0 ) we_cemetary/cemtrim2 0 0 -180.00 1 -1 0 0 0 +( 5248 832 0 ) ( 5216 864 0 ) ( 5232 848 64 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 5232 1328 64 ) ( 5216 1312 0 ) ( 5248 1344 0 ) we_cemetary/cemtrim2 -64 0 -180.00 1 -1 0 0 0 +} +// brush 598 +{ +( 5216 1088 64 ) ( 5248 1088 64 ) ( 5248 1280 64 ) we_cemetary/cemstair2 191 0 -180.00 1 1 0 0 0 +( 5248 1088 384 ) ( 5248 1280 384 ) ( 5248 1280 64 ) we_cemetary/cemstair2 0 0 -180.00 1 -1 0 0 0 +( 5200 1280 96 ) ( 5208 1088 80 ) ( 5216 1280 64 ) we_cemetary/cemstair2 0 0 -180.00 1 -1 0 0 0 +( 5184 1088 256 ) ( 5184 1280 256 ) ( 5248 1280 256 ) we_cemetary/cemstair2 191 0 -180.00 1 1 0 0 0 +( 5200 1280 208 ) ( 5200 1088 176 ) ( 5200 1280 144 ) we_cemetary/cemstair2 0 0 -180.00 1 -1 0 0 0 +( 5248 832 64 ) ( 5216 864 64 ) ( 5232 848 256 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 5232 1328 256 ) ( 5216 1312 64 ) ( 5248 1344 64 ) we_cemetary/cemstair2 -64 0 -180.00 1 -1 0 0 0 +} +// brush 599 +{ +( 5200 1280 256 ) ( 5200 1088 256 ) ( 5248 1088 256 ) we_cemetary/fogtrunk 191 0 -180.00 1 1 0 0 0 +( 5248 1280 272 ) ( 5248 1088 272 ) ( 5184 1088 272 ) we_cemetary/fogtrunk 191 0 -180.00 1 1 0 0 0 +( 5200 1088 256 ) ( 5200 1280 256 ) ( 5184 1280 272 ) we_cemetary/fogtrunk 191 0 -180.00 1 1 0 0 0 +( 5248 1088 272 ) ( 5248 1280 272 ) ( 5248 1280 256 ) we_cemetary/fogtrunk 0 0 -180.00 1 -1 0 0 0 +( 5248 832 256 ) ( 5216 864 256 ) ( 5232 848 272 ) we_cemetary/fogtrunk -64 0 0.00 1 1 0 0 0 +( 5232 1328 272 ) ( 5216 1312 256 ) ( 5248 1344 256 ) we_cemetary/fogtrunk -64 0 -180.00 1 -1 0 0 0 +} +// brush 600 +{ +( 5184 1088 272 ) ( 5216 1088 272 ) ( 5216 1280 272 ) we_cemetary/cemrunner2 62 0 -180.00 1 1 0 0 0 +( 5216 1280 336 ) ( 5216 1088 336 ) ( 5184 1088 336 ) we_cemetary/cemtrim2 159 0 -180.00 1 1 0 0 0 +( 5184 1280 592 ) ( 5184 1088 592 ) ( 5184 1088 272 ) we_cemetary/cemtrim2 0 13 -180.00 1 -1 0 0 0 +( 5248 1088 592 ) ( 5248 1280 592 ) ( 5248 1280 272 ) we_cemetary/cemtrim2 0 13 -180.00 1 -1 0 0 0 +( 5248 832 272 ) ( 5216 864 272 ) ( 5232 848 336 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( 5232 1328 336 ) ( 5216 1312 272 ) ( 5248 1344 272 ) we_cemetary/cemtrim2 -64 14 -180.00 1 -1 0 0 0 +} +// brush 601 +{ +( 4992 1280 272 ) ( 4992 1312 272 ) ( 4800 1312 272 ) we_cemetary/cemrunner2 13 0 -90.00 1 1 0 0 0 +( 4800 1312 336 ) ( 4992 1312 336 ) ( 4992 1280 336 ) we_cemetary/cemtrim2 107 -63 -90.00 1 1 0 0 0 +( 4800 1280 592 ) ( 4992 1280 592 ) ( 4992 1280 272 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( 4992 1344 592 ) ( 4800 1344 592 ) ( 4800 1344 272 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( 5248 1344 272 ) ( 5216 1312 272 ) ( 5232 1328 336 ) we_cemetary/cemtrim2 64 15 0.00 1 1 0 0 0 +( 4752 1328 336 ) ( 4768 1312 272 ) ( 4736 1344 272 ) we_cemetary/cemtrim2 -64 16 0.00 1 1 0 0 0 +} +// brush 602 +{ +( 4800 1296 256 ) ( 4992 1296 256 ) ( 4992 1344 256 ) we_cemetary/fogtrunk -115 63 -90.00 1 1 0 0 0 +( 4800 1344 272 ) ( 4992 1344 272 ) ( 4992 1280 272 ) we_cemetary/fogtrunk -115 63 -90.00 1 1 0 0 0 +( 4992 1296 256 ) ( 4800 1296 256 ) ( 4800 1280 272 ) we_cemetary/fogtrunk -115 63 -90.00 1 1 0 0 0 +( 4992 1344 272 ) ( 4800 1344 272 ) ( 4800 1344 256 ) we_cemetary/fogtrunk -64 0 0.00 1 1 0 0 0 +( 5248 1344 256 ) ( 5216 1312 256 ) ( 5232 1328 272 ) we_cemetary/fogtrunk 64 0 0.00 1 1 0 0 0 +( 4752 1328 272 ) ( 4768 1312 256 ) ( 4736 1344 256 ) we_cemetary/fogtrunk -64 0 0.00 1 1 0 0 0 +} +// brush 603 +{ +( 4768 1280 272 ) ( 4768 1088 272 ) ( 4800 1088 272 ) we_cemetary/cemrunner2 0 0 0.00 1 1 0 0 0 +( 4800 1088 336 ) ( 4768 1088 336 ) ( 4768 1280 336 ) we_cemetary/cemtrim2 -32 0 0.00 1 1 0 0 0 +( 4800 1088 272 ) ( 4800 1088 592 ) ( 4800 1280 592 ) we_cemetary/cemtrim2 64 16 0.00 1 1 0 0 0 +( 4736 1280 272 ) ( 4736 1280 592 ) ( 4736 1088 592 ) we_cemetary/cemtrim2 64 16 0.00 1 1 0 0 0 +( 4752 848 336 ) ( 4768 864 272 ) ( 4736 832 272 ) we_cemetary/cemtrim2 64 16 0.00 1 1 0 0 0 +( 4784 1296 336 ) ( 4768 1312 272 ) ( 4800 1280 272 ) we_cemetary/cemtrim2 64 16 0.00 1 1 0 0 0 +} +// brush 604 +{ +( 4736 1088 256 ) ( 4784 1088 256 ) ( 4784 1280 256 ) we_cemetary/fogtrunk 0 -64 0.00 1 1 0 0 0 +( 4800 1088 272 ) ( 4736 1088 272 ) ( 4736 1280 272 ) we_cemetary/fogtrunk 0 -64 0.00 1 1 0 0 0 +( 4800 1280 272 ) ( 4784 1280 256 ) ( 4784 1088 256 ) we_cemetary/fogtrunk 0 -64 0.00 1 1 0 0 0 +( 4736 1280 256 ) ( 4736 1280 272 ) ( 4736 1088 272 ) we_cemetary/fogtrunk 64 0 0.00 1 1 0 0 0 +( 4752 848 272 ) ( 4768 864 256 ) ( 4736 832 256 ) we_cemetary/fogtrunk 64 0 0.00 1 1 0 0 0 +( 4784 1296 272 ) ( 4768 1312 256 ) ( 4800 1280 256 ) we_cemetary/fogtrunk 64 0 0.00 1 1 0 0 0 +} +// brush 605 +{ +( 4736 1280 64 ) ( 4736 1088 64 ) ( 4768 1088 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 4736 1280 64 ) ( 4736 1280 384 ) ( 4736 1088 384 ) we_cemetary/cemstair2 64 0 0.00 1 1 0 0 0 +( 4768 1280 64 ) ( 4776 1088 80 ) ( 4784 1280 96 ) we_cemetary/cemstair2 64 0 0.00 1 1 0 0 0 +( 4736 1280 256 ) ( 4800 1280 256 ) ( 4800 1088 256 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 4784 1280 144 ) ( 4784 1088 176 ) ( 4784 1280 208 ) we_cemetary/cemstair2 64 0 0.00 1 1 0 0 0 +( 4752 848 256 ) ( 4768 864 64 ) ( 4736 832 64 ) we_cemetary/cemstair2 64 0 0.00 1 1 0 0 0 +( 4784 1296 256 ) ( 4768 1312 64 ) ( 4800 1280 64 ) we_cemetary/cemstair2 64 0 0.00 1 1 0 0 0 +} +// brush 606 +{ +( 4736 1280 0 ) ( 4736 1088 0 ) ( 4768 1088 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( 4768 1088 64 ) ( 4736 1088 64 ) ( 4736 1280 64 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( 4768 1152 0 ) ( 4768 1152 320 ) ( 4768 1344 320 ) we_cemetary/cemtrim2 64 0 0.00 1 1 0 0 0 +( 4736 1280 0 ) ( 4736 1280 320 ) ( 4736 1088 320 ) we_cemetary/cemtrim2 64 0 0.00 1 1 0 0 0 +( 4752 848 64 ) ( 4768 864 0 ) ( 4736 832 0 ) we_cemetary/cemtrim2 64 0 0.00 1 1 0 0 0 +( 4784 1296 64 ) ( 4768 1312 0 ) ( 4800 1280 0 ) we_cemetary/cemtrim2 64 0 0.00 1 1 0 0 0 +} +// brush 607 +{ +( 4992 1312 0 ) ( 4992 1344 0 ) ( 4800 1344 0 ) we_cemetary/cemtrim2 -115 -63 -90.00 1 1 0 0 0 +( 4800 1344 64 ) ( 4992 1344 64 ) ( 4992 1312 64 ) we_cemetary/cemtrim2 -115 -63 -90.00 1 1 0 0 0 +( 4672 1312 320 ) ( 4864 1312 320 ) ( 4864 1312 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 4992 1344 320 ) ( 4800 1344 320 ) ( 4800 1344 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 4752 1328 64 ) ( 4768 1312 0 ) ( 4736 1344 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 4928 1344 64 ) ( 4928 1376 0 ) ( 4928 1312 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +} +// brush 608 +{ +( 4992 1312 0 ) ( 4992 1344 0 ) ( 4800 1344 0 ) we_cemetary/cemtrim2 -115 -63 -90.00 1 1 0 0 0 +( 4800 1344 64 ) ( 4992 1344 64 ) ( 4992 1312 64 ) we_cemetary/cemtrim2 -115 -63 -90.00 1 1 0 0 0 +( 4800 1312 320 ) ( 4992 1312 320 ) ( 4992 1312 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 4992 1344 320 ) ( 4800 1344 320 ) ( 4800 1344 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 5248 1344 0 ) ( 5216 1312 0 ) ( 5232 1328 64 ) we_cemetary/cemtrim2 64 0 0.00 1 1 0 0 0 +( 5056 1344 64 ) ( 5056 1312 0 ) ( 5056 1376 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +} +// brush 609 +{ +( 4992 1312 64 ) ( 4992 1344 64 ) ( 4800 1344 64 ) we_cemetary/cemstair2 -115 -63 -90.00 1 1 0 0 0 +( 4992 1344 384 ) ( 4800 1344 384 ) ( 4800 1344 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 4800 1296 96 ) ( 4992 1304 80 ) ( 4800 1312 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 4992 1280 256 ) ( 4800 1280 256 ) ( 4800 1344 256 ) we_cemetary/cemstair2 -115 -63 -90.00 1 1 0 0 0 +( 4800 1296 208 ) ( 4992 1296 176 ) ( 4800 1296 144 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 4752 1328 256 ) ( 4768 1312 64 ) ( 4736 1344 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 4928 1344 256 ) ( 4928 1376 64 ) ( 4928 1312 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +} +// brush 610 +{ +( 4992 1312 64 ) ( 4992 1344 64 ) ( 4800 1344 64 ) we_cemetary/cemstair2 -115 -63 -90.00 1 1 0 0 0 +( 4992 1344 384 ) ( 4800 1344 384 ) ( 4800 1344 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 4800 1296 96 ) ( 4992 1304 80 ) ( 4800 1312 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 4992 1280 256 ) ( 4800 1280 256 ) ( 4800 1344 256 ) we_cemetary/cemstair2 -115 -63 -90.00 1 1 0 0 0 +( 4928 1296 208 ) ( 5120 1296 176 ) ( 4928 1296 144 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 5248 1344 64 ) ( 5216 1312 64 ) ( 5232 1328 256 ) we_cemetary/cemstair2 64 0 0.00 1 1 0 0 0 +( 5056 1344 256 ) ( 5056 1312 64 ) ( 5056 1376 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +} +// brush 611 +{ +( 4800 1344 64 ) ( 4992 1344 64 ) ( 4992 1376 64 ) we_cemetary/cemstair2 74 -63 -90.00 1 1 0 0 0 +( 4800 1344 64 ) ( 4800 1344 384 ) ( 4992 1344 384 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 4800 1376 64 ) ( 4992 1384 80 ) ( 4800 1392 96 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 4800 1344 256 ) ( 4800 1408 256 ) ( 4992 1408 256 ) we_cemetary/cemstair2 74 -63 -90.00 1 1 0 0 0 +( 4896 1392 144 ) ( 5088 1392 176 ) ( 4896 1392 208 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 5056 1344 256 ) ( 5056 1312 64 ) ( 5056 1376 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 5248 1376 256 ) ( 5248 1408 64 ) ( 5248 1344 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +} +// brush 612 +{ +( 4800 1344 0 ) ( 4992 1344 0 ) ( 4992 1376 0 ) we_cemetary/cemtrim2 74 -63 -90.00 1 1 0 0 0 +( 4992 1376 64 ) ( 4992 1344 64 ) ( 4800 1344 64 ) we_cemetary/cemtrim2 74 -63 -90.00 1 1 0 0 0 +( 5088 1376 0 ) ( 5088 1376 320 ) ( 4896 1376 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 4800 1344 0 ) ( 4800 1344 320 ) ( 4992 1344 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 5056 1344 64 ) ( 5056 1312 0 ) ( 5056 1376 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( 5248 1376 64 ) ( 5248 1408 0 ) ( 5248 1344 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +} +// brush 613 +{ +( 4800 1344 64 ) ( 4992 1344 64 ) ( 4992 1376 64 ) we_cemetary/cemstair2 74 -63 -90.00 1 1 0 0 0 +( 4800 1344 64 ) ( 4800 1344 384 ) ( 4992 1344 384 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 4800 1376 64 ) ( 4992 1384 80 ) ( 4800 1392 96 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 4800 1344 256 ) ( 4800 1408 256 ) ( 4992 1408 256 ) we_cemetary/cemstair2 74 -63 -90.00 1 1 0 0 0 +( 4800 1392 144 ) ( 4992 1392 176 ) ( 4800 1392 208 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 4928 1344 256 ) ( 4928 1376 64 ) ( 4928 1312 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 4736 1392 256 ) ( 4736 1376 64 ) ( 4736 1408 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +} +// brush 614 +{ +( 4800 1344 0 ) ( 4992 1344 0 ) ( 4992 1376 0 ) we_cemetary/cemtrim2 74 -63 -90.00 1 1 0 0 0 +( 4992 1376 64 ) ( 4992 1344 64 ) ( 4800 1344 64 ) we_cemetary/cemtrim2 74 -63 -90.00 1 1 0 0 0 +( 4800 1376 0 ) ( 4800 1376 320 ) ( 4608 1376 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 4800 1344 0 ) ( 4800 1344 320 ) ( 4992 1344 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 4928 1344 64 ) ( 4928 1376 0 ) ( 4928 1312 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( 4736 1392 64 ) ( 4736 1376 0 ) ( 4736 1408 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +} +// brush 615 +{ +( 4992 1344 256 ) ( 4992 1392 256 ) ( 4800 1392 256 ) we_cemetary/fogtrunk 74 63 -90.00 1 1 0 0 0 +( 4992 1408 272 ) ( 4992 1344 272 ) ( 4800 1344 272 ) we_cemetary/fogtrunk 74 63 -90.00 1 1 0 0 0 +( 4800 1408 272 ) ( 4800 1392 256 ) ( 4992 1392 256 ) we_cemetary/fogtrunk 74 63 -90.00 1 1 0 0 0 +( 4800 1344 256 ) ( 4800 1344 272 ) ( 4992 1344 272 ) we_cemetary/fogtrunk -64 0 0.00 1 1 0 0 0 +( 5248 1376 272 ) ( 5248 1408 256 ) ( 5248 1344 256 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +( 4736 1392 272 ) ( 4736 1376 256 ) ( 4736 1408 256 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +} +// brush 616 +{ +( 4800 1376 272 ) ( 4992 1376 272 ) ( 4992 1408 272 ) we_cemetary/cemrunner2 -64 0 -90.00 1 1 0 0 0 +( 4992 1408 336 ) ( 4992 1376 336 ) ( 4800 1376 336 ) we_cemetary/cemtrim2 42 -63 -90.00 1 1 0 0 0 +( 4992 1408 272 ) ( 4992 1408 592 ) ( 4800 1408 592 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( 4800 1344 272 ) ( 4800 1344 592 ) ( 4992 1344 592 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( 5248 1376 336 ) ( 5248 1408 272 ) ( 5248 1344 272 ) we_cemetary/cemtrim2 0 16 0.00 1 1 0 0 0 +( 4736 1392 336 ) ( 4736 1376 272 ) ( 4736 1408 272 ) we_cemetary/cemtrim2 0 16 0.00 1 1 0 0 0 +} +// brush 617 +{ +( 4768 1312 -32 ) ( 4768 864 -32 ) ( 5216 864 -32 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 5216 864 0 ) ( 4768 864 0 ) ( 4768 1312 0 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 5216 1376 -64 ) ( 5216 1376 0 ) ( 4768 1376 0 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 5248 864 -64 ) ( 5248 864 0 ) ( 5248 1312 0 ) we_cemetary/cemtrim5 64 0 0.00 1 1 0 0 0 +( 4768 832 -64 ) ( 4768 832 0 ) ( 5216 832 0 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 4736 1312 -64 ) ( 4736 1312 0 ) ( 4736 864 0 ) we_cemetary/cemtrim5 64 0 0.00 1 1 0 0 0 +} +// brush 618 +{ +( 4768 1312 336 ) ( 4768 864 336 ) ( 5216 864 336 ) water/waterfloor2 0 -64 0.00 1 1 0 0 0 +( 5216 864 352 ) ( 4768 864 352 ) ( 4768 1312 352 ) water/waterfloor2 0 -64 0.00 1 1 0 0 0 +( 5216 1312 304 ) ( 5216 1312 368 ) ( 4768 1312 368 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +( 5216 864 304 ) ( 5216 864 368 ) ( 5216 1312 368 ) water/waterfloor2 64 0 0.00 1 1 0 0 0 +( 4768 864 304 ) ( 4768 864 368 ) ( 5216 864 368 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +( 4768 1312 304 ) ( 4768 1312 368 ) ( 4768 864 368 ) water/waterfloor2 64 0 0.00 1 1 0 0 0 +} +// brush 619 +{ +( 4928 1392 208 ) ( 4928 1296 208 ) ( 5056 1296 208 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 5056 1296 256 ) ( 4928 1296 256 ) ( 4928 1392 256 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 5056 1392 64 ) ( 5056 1392 256 ) ( 4928 1392 256 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 5056 1296 48 ) ( 5056 1296 240 ) ( 5056 1392 240 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 4928 1296 48 ) ( 4928 1296 240 ) ( 5056 1296 240 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 4928 1392 64 ) ( 4928 1392 256 ) ( 4928 1296 256 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +} +// brush 620 +{ +( 5056 1840 208 ) ( 4928 1840 208 ) ( 4928 1744 208 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 4928 1744 256 ) ( 4928 1840 256 ) ( 5056 1840 256 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 4928 1744 256 ) ( 5056 1744 256 ) ( 5056 1744 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 5056 1744 240 ) ( 5056 1840 240 ) ( 5056 1840 48 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +( 5056 1840 240 ) ( 4928 1840 240 ) ( 4928 1840 48 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 4928 1840 256 ) ( 4928 1744 256 ) ( 4928 1744 64 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +} +// brush 621 +{ +( 5216 2272 336 ) ( 4768 2272 336 ) ( 4768 1824 336 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +( 4768 1824 352 ) ( 4768 2272 352 ) ( 5216 2272 352 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +( 4768 1824 368 ) ( 5216 1824 368 ) ( 5216 1824 304 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +( 5216 1824 368 ) ( 5216 2272 368 ) ( 5216 2272 304 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +( 5216 2272 368 ) ( 4768 2272 368 ) ( 4768 2272 304 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +( 4768 2272 368 ) ( 4768 1824 368 ) ( 4768 1824 304 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +} +// brush 622 +{ +( 5216 2272 -32 ) ( 4768 2272 -32 ) ( 4768 1824 -32 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 4768 1824 0 ) ( 4768 2272 0 ) ( 5216 2272 0 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 4768 1760 0 ) ( 5216 1760 0 ) ( 5216 1760 -64 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 5248 1824 0 ) ( 5248 2272 0 ) ( 5248 2272 -64 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 5216 2304 0 ) ( 4768 2304 0 ) ( 4768 2304 -64 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 4736 2272 0 ) ( 4736 1824 0 ) ( 4736 1824 -64 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +} +// brush 623 +{ +( 4992 1728 272 ) ( 4992 1760 272 ) ( 4800 1760 272 ) we_cemetary/cemrunner2 0 -1 -90.00 1 1 0 0 0 +( 4800 1760 336 ) ( 4992 1760 336 ) ( 4992 1728 336 ) we_cemetary/cemtrim2 -150 0 -90.00 1 1 0 0 0 +( 4800 1728 592 ) ( 4992 1728 592 ) ( 4992 1728 272 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( 4992 1792 592 ) ( 4800 1792 592 ) ( 4800 1792 272 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( 5248 1792 272 ) ( 5248 1728 272 ) ( 5248 1760 336 ) we_cemetary/cemtrim2 192 16 0.00 1 1 0 0 0 +( 4736 1728 272 ) ( 4736 1760 272 ) ( 4736 1744 336 ) we_cemetary/cemtrim2 192 16 0.00 1 1 0 0 0 +} +// brush 624 +{ +( 4800 1744 256 ) ( 4992 1744 256 ) ( 4992 1792 256 ) we_cemetary/fogtrunk -118 63 -90.00 1 1 0 0 0 +( 4800 1792 272 ) ( 4992 1792 272 ) ( 4992 1728 272 ) we_cemetary/fogtrunk -118 63 -90.00 1 1 0 0 0 +( 4992 1744 256 ) ( 4800 1744 256 ) ( 4800 1728 272 ) we_cemetary/fogtrunk -118 63 -90.00 1 1 0 0 0 +( 4992 1792 272 ) ( 4800 1792 272 ) ( 4800 1792 256 ) we_cemetary/fogtrunk -64 0 0.00 1 1 0 0 0 +( 5248 1792 256 ) ( 5248 1728 256 ) ( 5248 1760 272 ) we_cemetary/fogtrunk 192 0 0.00 1 1 0 0 0 +( 4736 1728 256 ) ( 4736 1760 256 ) ( 4736 1744 272 ) we_cemetary/fogtrunk 192 0 0.00 1 1 0 0 0 +} +// brush 625 +{ +( 4992 1760 0 ) ( 4992 1792 0 ) ( 4800 1792 0 ) we_cemetary/cemtrim2 -118 0 -90.00 1 1 0 0 0 +( 4800 1792 64 ) ( 4992 1792 64 ) ( 4992 1760 64 ) we_cemetary/cemtrim2 -118 0 -90.00 1 1 0 0 0 +( 4608 1760 320 ) ( 4800 1760 320 ) ( 4800 1760 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 4992 1792 320 ) ( 4800 1792 320 ) ( 4800 1792 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 4928 1824 0 ) ( 4928 1760 0 ) ( 4928 1792 64 ) we_cemetary/cemtrim2 192 0 0.00 1 1 0 0 0 +( 4736 1728 0 ) ( 4736 1760 0 ) ( 4736 1744 64 ) we_cemetary/cemtrim2 192 0 0.00 1 1 0 0 0 +} +// brush 626 +{ +( 4992 1760 64 ) ( 4992 1792 64 ) ( 4800 1792 64 ) we_cemetary/cemstair2 -118 0 -90.00 1 1 0 0 0 +( 4992 1792 384 ) ( 4800 1792 384 ) ( 4800 1792 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 4800 1744 96 ) ( 4992 1752 80 ) ( 4800 1760 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 4992 1728 256 ) ( 4800 1728 256 ) ( 4800 1792 256 ) we_cemetary/cemstair2 -118 0 -90.00 1 1 0 0 0 +( 4800 1744 208 ) ( 4992 1744 176 ) ( 4800 1744 144 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 4928 1824 64 ) ( 4928 1760 64 ) ( 4928 1792 256 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +( 4736 1728 64 ) ( 4736 1760 64 ) ( 4736 1744 256 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +} +// brush 627 +{ +( 4992 1760 0 ) ( 4992 1792 0 ) ( 4800 1792 0 ) we_cemetary/cemtrim2 -118 0 -90.00 1 1 0 0 0 +( 4800 1792 64 ) ( 4992 1792 64 ) ( 4992 1760 64 ) we_cemetary/cemtrim2 -118 0 -90.00 1 1 0 0 0 +( 4896 1760 320 ) ( 5088 1760 320 ) ( 5088 1760 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 4992 1792 320 ) ( 4800 1792 320 ) ( 4800 1792 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 5056 1760 0 ) ( 5056 1824 0 ) ( 5056 1792 64 ) we_cemetary/cemtrim2 192 0 0.00 1 1 0 0 0 +( 5248 1792 0 ) ( 5248 1728 0 ) ( 5248 1760 64 ) we_cemetary/cemtrim2 192 0 0.00 1 1 0 0 0 +} +// brush 628 +{ +( 4992 1760 64 ) ( 4992 1792 64 ) ( 4800 1792 64 ) we_cemetary/cemstair2 -118 0 -90.00 1 1 0 0 0 +( 4992 1792 384 ) ( 4800 1792 384 ) ( 4800 1792 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 4800 1744 96 ) ( 4992 1752 80 ) ( 4800 1760 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 4992 1728 256 ) ( 4800 1728 256 ) ( 4800 1792 256 ) we_cemetary/cemstair2 -118 0 -90.00 1 1 0 0 0 +( 4896 1744 208 ) ( 5088 1744 176 ) ( 4896 1744 144 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 5056 1760 64 ) ( 5056 1824 64 ) ( 5056 1792 256 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +( 5248 1792 64 ) ( 5248 1728 64 ) ( 5248 1760 256 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +} +// brush 629 +{ +( 4800 1792 64 ) ( 4992 1792 64 ) ( 4992 1824 64 ) we_cemetary/cemstair2 -51 0 -90.00 1 1 0 0 0 +( 4800 1792 64 ) ( 4800 1792 384 ) ( 4992 1792 384 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 4800 1824 64 ) ( 4992 1832 80 ) ( 4800 1840 96 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 4800 1792 256 ) ( 4800 1856 256 ) ( 4992 1856 256 ) we_cemetary/cemstair2 -51 0 -90.00 1 1 0 0 0 +( 4928 1840 144 ) ( 5120 1840 176 ) ( 4928 1840 208 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 5232 1808 256 ) ( 5216 1824 64 ) ( 5248 1792 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 5056 1760 64 ) ( 5056 1824 64 ) ( 5056 1792 256 ) we_cemetary/cemstair2 128 0 0.00 1 1 0 0 0 +} +// brush 630 +{ +( 4800 1792 64 ) ( 4992 1792 64 ) ( 4992 1824 64 ) we_cemetary/cemstair2 -51 0 -90.00 1 1 0 0 0 +( 4800 1792 64 ) ( 4800 1792 384 ) ( 4992 1792 384 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 4800 1824 64 ) ( 4992 1832 80 ) ( 4800 1840 96 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 4800 1792 256 ) ( 4800 1856 256 ) ( 4992 1856 256 ) we_cemetary/cemstair2 -51 0 -90.00 1 1 0 0 0 +( 4800 1840 144 ) ( 4992 1840 176 ) ( 4800 1840 208 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 4736 1792 64 ) ( 4768 1824 64 ) ( 4752 1808 256 ) we_cemetary/cemstair2 128 0 0.00 1 1 0 0 0 +( 4928 1824 64 ) ( 4928 1760 64 ) ( 4928 1792 256 ) we_cemetary/cemstair2 128 0 0.00 1 1 0 0 0 +} +// brush 631 +{ +( 4800 1792 0 ) ( 4992 1792 0 ) ( 4992 1824 0 ) we_cemetary/cemtrim2 -51 0 -90.00 1 1 0 0 0 +( 4992 1824 64 ) ( 4992 1792 64 ) ( 4800 1792 64 ) we_cemetary/cemtrim2 -51 0 -90.00 1 1 0 0 0 +( 4992 1824 0 ) ( 4992 1824 320 ) ( 4800 1824 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 4800 1792 0 ) ( 4800 1792 320 ) ( 4992 1792 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 5232 1808 64 ) ( 5216 1824 0 ) ( 5248 1792 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( 5056 1760 0 ) ( 5056 1824 0 ) ( 5056 1792 64 ) we_cemetary/cemtrim2 128 0 0.00 1 1 0 0 0 +} +// brush 632 +{ +( 4800 1792 0 ) ( 4992 1792 0 ) ( 4992 1824 0 ) we_cemetary/cemtrim2 -51 0 -90.00 1 1 0 0 0 +( 4992 1824 64 ) ( 4992 1792 64 ) ( 4800 1792 64 ) we_cemetary/cemtrim2 -51 0 -90.00 1 1 0 0 0 +( 4864 1824 0 ) ( 4864 1824 320 ) ( 4672 1824 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 4800 1792 0 ) ( 4800 1792 320 ) ( 4992 1792 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 4736 1792 0 ) ( 4768 1824 0 ) ( 4752 1808 64 ) we_cemetary/cemtrim2 128 0 0.00 1 1 0 0 0 +( 4928 1824 0 ) ( 4928 1760 0 ) ( 4928 1792 64 ) we_cemetary/cemtrim2 128 0 0.00 1 1 0 0 0 +} +// brush 633 +{ +( 4768 2048 0 ) ( 4736 2048 0 ) ( 4736 1856 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( 4736 1856 64 ) ( 4736 2048 64 ) ( 4768 2048 64 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( 4768 1792 320 ) ( 4768 1984 320 ) ( 4768 1984 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( 4736 2048 320 ) ( 4736 1856 320 ) ( 4736 1856 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( 4736 2304 0 ) ( 4768 2272 0 ) ( 4752 2288 64 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( 4800 1856 0 ) ( 4768 1824 0 ) ( 4784 1840 64 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +} +// brush 634 +{ +( 4768 2048 64 ) ( 4736 2048 64 ) ( 4736 1856 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 4736 2048 384 ) ( 4736 1856 384 ) ( 4736 1856 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 4784 1856 96 ) ( 4776 2048 80 ) ( 4768 1856 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 4800 2048 256 ) ( 4800 1856 256 ) ( 4736 1856 256 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 4784 1856 208 ) ( 4784 2048 176 ) ( 4784 1856 144 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 4736 2304 64 ) ( 4768 2272 64 ) ( 4752 2288 256 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 4800 1856 64 ) ( 4768 1824 64 ) ( 4784 1840 256 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +} +// brush 635 +{ +( 4784 1856 256 ) ( 4784 2048 256 ) ( 4736 2048 256 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +( 4736 1856 272 ) ( 4736 2048 272 ) ( 4800 2048 272 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +( 4784 2048 256 ) ( 4784 1856 256 ) ( 4800 1856 272 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +( 4736 2048 272 ) ( 4736 1856 272 ) ( 4736 1856 256 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +( 4736 2304 256 ) ( 4768 2272 256 ) ( 4752 2288 272 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +( 4800 1856 256 ) ( 4768 1824 256 ) ( 4784 1840 272 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +} +// brush 636 +{ +( 4800 2048 272 ) ( 4768 2048 272 ) ( 4768 1856 272 ) we_cemetary/cemrunner2 0 0 0.00 1 1 0 0 0 +( 4768 1856 336 ) ( 4768 2048 336 ) ( 4800 2048 336 ) we_cemetary/cemtrim2 -32 0 0.00 1 1 0 0 0 +( 4800 1856 592 ) ( 4800 2048 592 ) ( 4800 2048 272 ) we_cemetary/cemtrim2 0 16 0.00 1 1 0 0 0 +( 4736 2048 592 ) ( 4736 1856 592 ) ( 4736 1856 272 ) we_cemetary/cemtrim2 0 16 0.00 1 1 0 0 0 +( 4736 2304 272 ) ( 4768 2272 272 ) ( 4752 2288 336 ) we_cemetary/cemtrim2 0 16 0.00 1 1 0 0 0 +( 4800 1856 272 ) ( 4768 1824 272 ) ( 4784 1840 336 ) we_cemetary/cemtrim2 0 16 0.00 1 1 0 0 0 +} +// brush 637 +{ +( 4992 1792 256 ) ( 4992 1840 256 ) ( 4800 1840 256 ) we_cemetary/fogtrunk -51 63 -90.00 1 1 0 0 0 +( 4992 1856 272 ) ( 4992 1792 272 ) ( 4800 1792 272 ) we_cemetary/fogtrunk -51 63 -90.00 1 1 0 0 0 +( 4800 1856 272 ) ( 4800 1840 256 ) ( 4992 1840 256 ) we_cemetary/fogtrunk -51 63 -90.00 1 1 0 0 0 +( 4800 1792 256 ) ( 4800 1792 272 ) ( 4992 1792 272 ) we_cemetary/fogtrunk -64 0 0.00 1 1 0 0 0 +( 5232 1808 272 ) ( 5216 1824 256 ) ( 5248 1792 256 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +( 4736 1792 256 ) ( 4768 1824 256 ) ( 4752 1808 272 ) we_cemetary/fogtrunk 128 0 0.00 1 1 0 0 0 +} +// brush 638 +{ +( 4800 1824 272 ) ( 4992 1824 272 ) ( 4992 1856 272 ) we_cemetary/cemrunner2 -51 -1 -90.00 1 1 0 0 0 +( 4992 1856 336 ) ( 4992 1824 336 ) ( 4800 1824 336 ) we_cemetary/cemtrim2 -85 0 -90.00 1 1 0 0 0 +( 4992 1856 272 ) ( 4992 1856 592 ) ( 4800 1856 592 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( 4800 1792 272 ) ( 4800 1792 592 ) ( 4992 1792 592 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( 5232 1808 336 ) ( 5216 1824 272 ) ( 5248 1792 272 ) we_cemetary/cemtrim2 0 15 0.00 1 1 0 0 0 +( 4736 1792 272 ) ( 4768 1824 272 ) ( 4752 1808 336 ) we_cemetary/cemtrim2 128 16 0.00 1 1 0 0 0 +} +// brush 639 +{ +( 5216 1856 272 ) ( 5216 2048 272 ) ( 5184 2048 272 ) we_cemetary/cemrunner2 62 0 -180.00 1 1 0 0 0 +( 5184 2048 336 ) ( 5216 2048 336 ) ( 5216 1856 336 ) we_cemetary/cemtrim2 159 0 -180.00 1 1 0 0 0 +( 5184 2048 272 ) ( 5184 2048 592 ) ( 5184 1856 592 ) we_cemetary/cemtrim2 64 14 -180.00 1 -1 0 0 0 +( 5248 1856 272 ) ( 5248 1856 592 ) ( 5248 2048 592 ) we_cemetary/cemtrim2 64 14 -180.00 1 -1 0 0 0 +( 5232 2288 336 ) ( 5216 2272 272 ) ( 5248 2304 272 ) we_cemetary/cemtrim2 128 15 0.00 1 1 0 0 0 +( 5248 1792 272 ) ( 5216 1824 272 ) ( 5232 1808 336 ) we_cemetary/cemtrim2 0 15 -180.00 1 -1 0 0 0 +} +// brush 640 +{ +( 5248 2048 256 ) ( 5200 2048 256 ) ( 5200 1856 256 ) we_cemetary/fogtrunk 191 -64 -180.00 1 1 0 0 0 +( 5184 2048 272 ) ( 5248 2048 272 ) ( 5248 1856 272 ) we_cemetary/fogtrunk 191 -64 -180.00 1 1 0 0 0 +( 5184 1856 272 ) ( 5200 1856 256 ) ( 5200 2048 256 ) we_cemetary/fogtrunk 191 -64 -180.00 1 1 0 0 0 +( 5248 1856 256 ) ( 5248 1856 272 ) ( 5248 2048 272 ) we_cemetary/fogtrunk 64 0 -180.00 1 -1 0 0 0 +( 5232 2288 272 ) ( 5216 2272 256 ) ( 5248 2304 256 ) we_cemetary/fogtrunk 128 0 0.00 1 1 0 0 0 +( 5248 1792 256 ) ( 5216 1824 256 ) ( 5232 1808 272 ) we_cemetary/fogtrunk 0 0 -180.00 1 -1 0 0 0 +} +// brush 641 +{ +( 5248 1856 64 ) ( 5248 2048 64 ) ( 5216 2048 64 ) we_cemetary/cemstair2 191 0 -180.00 1 1 0 0 0 +( 5248 1856 64 ) ( 5248 1856 384 ) ( 5248 2048 384 ) we_cemetary/cemstair2 64 0 -180.00 1 -1 0 0 0 +( 5216 1856 64 ) ( 5208 2048 80 ) ( 5200 1856 96 ) we_cemetary/cemstair2 64 0 -180.00 1 -1 0 0 0 +( 5248 1856 256 ) ( 5184 1856 256 ) ( 5184 2048 256 ) we_cemetary/cemstair2 191 0 -180.00 1 1 0 0 0 +( 5200 1856 144 ) ( 5200 2048 176 ) ( 5200 1856 208 ) we_cemetary/cemstair2 64 0 -180.00 1 -1 0 0 0 +( 5232 2288 256 ) ( 5216 2272 64 ) ( 5248 2304 64 ) we_cemetary/cemstair2 128 0 0.00 1 1 0 0 0 +( 5248 1792 64 ) ( 5216 1824 64 ) ( 5232 1808 256 ) we_cemetary/cemstair2 0 0 -180.00 1 -1 0 0 0 +} +// brush 642 +{ +( 5248 1856 0 ) ( 5248 2048 0 ) ( 5216 2048 0 ) we_cemetary/cemtrim2 191 0 -180.00 1 1 0 0 0 +( 5216 2048 64 ) ( 5248 2048 64 ) ( 5248 1856 64 ) we_cemetary/cemtrim2 191 0 -180.00 1 1 0 0 0 +( 5216 1920 0 ) ( 5216 1920 320 ) ( 5216 1728 320 ) we_cemetary/cemtrim2 64 0 -180.00 1 -1 0 0 0 +( 5248 1856 0 ) ( 5248 1856 320 ) ( 5248 2048 320 ) we_cemetary/cemtrim2 64 0 -180.00 1 -1 0 0 0 +( 5232 2288 64 ) ( 5216 2272 0 ) ( 5248 2304 0 ) we_cemetary/cemtrim2 128 0 0.00 1 1 0 0 0 +( 5248 1792 0 ) ( 5216 1824 0 ) ( 5232 1808 64 ) we_cemetary/cemtrim2 0 0 -180.00 1 -1 0 0 0 +} +// brush 643 +{ +( 5184 2304 0 ) ( 4992 2304 0 ) ( 4992 2272 0 ) we_cemetary/cemtrim2 -50 0 90.00 1 1 0 0 0 +( 4992 2272 64 ) ( 4992 2304 64 ) ( 5184 2304 64 ) we_cemetary/cemtrim2 -50 0 90.00 1 1 0 0 0 +( 5056 2272 0 ) ( 5056 2272 320 ) ( 5248 2272 320 ) we_cemetary/cemtrim2 128 0 -180.00 1 -1 0 0 0 +( 5184 2304 0 ) ( 5184 2304 320 ) ( 4992 2304 320 ) we_cemetary/cemtrim2 128 0 -180.00 1 -1 0 0 0 +( 4752 2288 64 ) ( 4768 2272 0 ) ( 4736 2304 0 ) we_cemetary/cemtrim2 192 0 -180.00 1 -1 0 0 0 +( 5248 2304 0 ) ( 5216 2272 0 ) ( 5232 2288 64 ) we_cemetary/cemtrim2 192 0 -180.00 1 -1 0 0 0 +} +// brush 644 +{ +( 5184 2304 64 ) ( 4992 2304 64 ) ( 4992 2272 64 ) we_cemetary/cemstair2 -50 0 90.00 1 1 0 0 0 +( 5184 2304 64 ) ( 5184 2304 384 ) ( 4992 2304 384 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +( 5184 2272 64 ) ( 4992 2264 80 ) ( 5184 2256 96 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +( 5184 2304 256 ) ( 5184 2240 256 ) ( 4992 2240 256 ) we_cemetary/cemstair2 -50 0 90.00 1 1 0 0 0 +( 5184 2256 144 ) ( 4992 2256 176 ) ( 5184 2256 208 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +( 4752 2288 256 ) ( 4768 2272 64 ) ( 4736 2304 64 ) we_cemetary/cemstair2 192 0 -180.00 1 -1 0 0 0 +( 5248 2304 64 ) ( 5216 2272 64 ) ( 5232 2288 256 ) we_cemetary/cemstair2 192 0 -180.00 1 -1 0 0 0 +} +// brush 645 +{ +( 4992 2304 256 ) ( 4992 2256 256 ) ( 5184 2256 256 ) we_cemetary/fogtrunk -50 -128 90.00 1 1 0 0 0 +( 4992 2240 272 ) ( 4992 2304 272 ) ( 5184 2304 272 ) we_cemetary/fogtrunk -50 -128 90.00 1 1 0 0 0 +( 5184 2240 272 ) ( 5184 2256 256 ) ( 4992 2256 256 ) we_cemetary/fogtrunk -50 -128 90.00 1 1 0 0 0 +( 5184 2304 256 ) ( 5184 2304 272 ) ( 4992 2304 272 ) we_cemetary/fogtrunk 128 0 -180.00 1 -1 0 0 0 +( 4752 2288 272 ) ( 4768 2272 256 ) ( 4736 2304 256 ) we_cemetary/fogtrunk 192 0 -180.00 1 -1 0 0 0 +( 5248 2304 256 ) ( 5216 2272 256 ) ( 5232 2288 272 ) we_cemetary/fogtrunk 192 0 -180.00 1 -1 0 0 0 +} +// brush 646 +{ +( 5184 2272 272 ) ( 4992 2272 272 ) ( 4992 2240 272 ) we_cemetary/cemrunner2 -50 5 90.00 1 1.000122 0 0 0 +( 4992 2240 336 ) ( 4992 2272 336 ) ( 5184 2272 336 ) we_cemetary/cemtrim2 -82 0 90.00 1 1 0 0 0 +( 4992 2240 272 ) ( 4992 2240 592 ) ( 5184 2240 592 ) we_cemetary/cemtrim2 128 15 -180.00 1 -1 0 0 0 +( 5184 2304 272 ) ( 5184 2304 592 ) ( 4992 2304 592 ) we_cemetary/cemtrim2 128 15 -180.00 1 -1 0 0 0 +( 4752 2288 336 ) ( 4768 2272 272 ) ( 4736 2304 272 ) we_cemetary/cemtrim2 192 15 -180.00 1 -1 0 0 0 +( 5248 2304 272 ) ( 5216 2272 272 ) ( 5232 2288 336 ) we_cemetary/cemtrim2 192 15 -180.00 1 -1 0 0 0 +} +// brush 647 +{ +( 4672 2272 272 ) ( 4480 2272 272 ) ( 4480 2240 272 ) we_cemetary/cemrunner2 -51 5 90.00 1 1.000122 0 0 0 +( 4480 2240 336 ) ( 4480 2272 336 ) ( 4672 2272 336 ) we_cemetary/cemtrim2 -83 0 90.00 1 1 0 0 0 +( 4480 2240 272 ) ( 4480 2240 592 ) ( 4672 2240 592 ) we_cemetary/cemtrim2 128 15 -180.00 1 -1 0 0 0 +( 4672 2304 272 ) ( 4672 2304 592 ) ( 4480 2304 592 ) we_cemetary/cemtrim2 128 15 -180.00 1 -1 0 0 0 +( 4240 2288 336 ) ( 4256 2272 272 ) ( 4224 2304 272 ) we_cemetary/cemtrim2 192 15 -180.00 1 -1 0 0 0 +( 4736 2304 272 ) ( 4704 2272 272 ) ( 4720 2288 336 ) we_cemetary/cemtrim2 192 15 -180.00 1 -1 0 0 0 +} +// brush 648 +{ +( 4480 2304 256 ) ( 4480 2256 256 ) ( 4672 2256 256 ) we_cemetary/fogtrunk -51 -128 90.00 1 1 0 0 0 +( 4480 2240 272 ) ( 4480 2304 272 ) ( 4672 2304 272 ) we_cemetary/fogtrunk -51 -128 90.00 1 1 0 0 0 +( 4672 2240 272 ) ( 4672 2256 256 ) ( 4480 2256 256 ) we_cemetary/fogtrunk -51 -128 90.00 1 1 0 0 0 +( 4672 2304 256 ) ( 4672 2304 272 ) ( 4480 2304 272 ) we_cemetary/fogtrunk 128 0 -180.00 1 -1 0 0 0 +( 4240 2288 272 ) ( 4256 2272 256 ) ( 4224 2304 256 ) we_cemetary/fogtrunk 192 0 -180.00 1 -1 0 0 0 +( 4736 2304 256 ) ( 4704 2272 256 ) ( 4720 2288 272 ) we_cemetary/fogtrunk 192 0 -180.00 1 -1 0 0 0 +} +// brush 649 +{ +( 4672 2304 64 ) ( 4480 2304 64 ) ( 4480 2272 64 ) we_cemetary/cemstair2 -51 0 90.00 1 1 0 0 0 +( 4672 2304 64 ) ( 4672 2304 384 ) ( 4480 2304 384 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +( 4672 2272 64 ) ( 4480 2264 80 ) ( 4672 2256 96 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +( 4672 2304 256 ) ( 4672 2240 256 ) ( 4480 2240 256 ) we_cemetary/cemstair2 -51 0 90.00 1 1 0 0 0 +( 4672 2256 144 ) ( 4480 2256 176 ) ( 4672 2256 208 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +( 4240 2288 256 ) ( 4256 2272 64 ) ( 4224 2304 64 ) we_cemetary/cemstair2 192 0 -180.00 1 -1 0 0 0 +( 4736 2304 64 ) ( 4704 2272 64 ) ( 4720 2288 256 ) we_cemetary/cemstair2 192 0 -180.00 1 -1 0 0 0 +} +// brush 650 +{ +( 4672 2304 0 ) ( 4480 2304 0 ) ( 4480 2272 0 ) we_cemetary/cemtrim2 -51 0 90.00 1 1 0 0 0 +( 4480 2272 64 ) ( 4480 2304 64 ) ( 4672 2304 64 ) we_cemetary/cemtrim2 -51 0 90.00 1 1 0 0 0 +( 4544 2272 0 ) ( 4544 2272 320 ) ( 4736 2272 320 ) we_cemetary/cemtrim2 128 0 -180.00 1 -1 0 0 0 +( 4672 2304 0 ) ( 4672 2304 320 ) ( 4480 2304 320 ) we_cemetary/cemtrim2 128 0 -180.00 1 -1 0 0 0 +( 4240 2288 64 ) ( 4256 2272 0 ) ( 4224 2304 0 ) we_cemetary/cemtrim2 192 0 -180.00 1 -1 0 0 0 +( 4736 2304 0 ) ( 4704 2272 0 ) ( 4720 2288 64 ) we_cemetary/cemtrim2 192 0 -180.00 1 -1 0 0 0 +} +// brush 651 +{ +( 4736 1856 0 ) ( 4736 2048 0 ) ( 4704 2048 0 ) we_cemetary/cemtrim2 191 0 -180.00 1 1 0 0 0 +( 4704 2048 64 ) ( 4736 2048 64 ) ( 4736 1856 64 ) we_cemetary/cemtrim2 191 0 -180.00 1 1 0 0 0 +( 4704 1920 0 ) ( 4704 1920 320 ) ( 4704 1728 320 ) we_cemetary/cemtrim2 64 0 -180.00 1 -1 0 0 0 +( 4736 1856 0 ) ( 4736 1856 320 ) ( 4736 2048 320 ) we_cemetary/cemtrim2 64 0 -180.00 1 -1 0 0 0 +( 4720 2288 64 ) ( 4704 2272 0 ) ( 4736 2304 0 ) we_cemetary/cemtrim2 128 0 0.00 1 1 0 0 0 +( 4736 1792 0 ) ( 4704 1824 0 ) ( 4720 1808 64 ) we_cemetary/cemtrim2 0 0 -180.00 1 -1 0 0 0 +} +// brush 652 +{ +( 4736 1856 64 ) ( 4736 2048 64 ) ( 4704 2048 64 ) we_cemetary/cemstair2 191 0 -180.00 1 1 0 0 0 +( 4736 1856 64 ) ( 4736 1856 384 ) ( 4736 2048 384 ) we_cemetary/cemstair2 64 0 -180.00 1 -1 0 0 0 +( 4704 1856 64 ) ( 4696 2048 80 ) ( 4688 1856 96 ) we_cemetary/cemstair2 64 0 -180.00 1 -1 0 0 0 +( 4736 1856 256 ) ( 4672 1856 256 ) ( 4672 2048 256 ) we_cemetary/cemstair2 191 0 -180.00 1 1 0 0 0 +( 4688 1856 144 ) ( 4688 2048 176 ) ( 4688 1856 208 ) we_cemetary/cemstair2 64 0 -180.00 1 -1 0 0 0 +( 4720 2288 256 ) ( 4704 2272 64 ) ( 4736 2304 64 ) we_cemetary/cemstair2 128 0 0.00 1 1 0 0 0 +( 4736 1792 64 ) ( 4704 1824 64 ) ( 4720 1808 256 ) we_cemetary/cemstair2 0 0 -180.00 1 -1 0 0 0 +} +// brush 653 +{ +( 4736 2048 256 ) ( 4688 2048 256 ) ( 4688 1856 256 ) we_cemetary/fogtrunk 191 -64 -180.00 1 1 0 0 0 +( 4672 2048 272 ) ( 4736 2048 272 ) ( 4736 1856 272 ) we_cemetary/fogtrunk 191 -64 -180.00 1 1 0 0 0 +( 4672 1856 272 ) ( 4688 1856 256 ) ( 4688 2048 256 ) we_cemetary/fogtrunk 191 -64 -180.00 1 1 0 0 0 +( 4736 1856 256 ) ( 4736 1856 272 ) ( 4736 2048 272 ) we_cemetary/fogtrunk 64 0 -180.00 1 -1 0 0 0 +( 4720 2288 272 ) ( 4704 2272 256 ) ( 4736 2304 256 ) we_cemetary/fogtrunk 128 0 0.00 1 1 0 0 0 +( 4736 1792 256 ) ( 4704 1824 256 ) ( 4720 1808 272 ) we_cemetary/fogtrunk 0 0 -180.00 1 -1 0 0 0 +} +// brush 654 +{ +( 4704 1856 272 ) ( 4704 2048 272 ) ( 4672 2048 272 ) we_cemetary/cemrunner2 62 0 -180.00 1 1 0 0 0 +( 4672 2048 336 ) ( 4704 2048 336 ) ( 4704 1856 336 ) we_cemetary/cemtrim2 159 0 -180.00 1 1 0 0 0 +( 4672 2048 272 ) ( 4672 2048 592 ) ( 4672 1856 592 ) we_cemetary/cemtrim2 64 14 -180.00 1 -1 0 0 0 +( 4736 1856 272 ) ( 4736 1856 592 ) ( 4736 2048 592 ) we_cemetary/cemtrim2 64 14 -180.00 1 -1 0 0 0 +( 4720 2288 336 ) ( 4704 2272 272 ) ( 4736 2304 272 ) we_cemetary/cemtrim2 128 15 0.00 1 1 0 0 0 +( 4736 1792 272 ) ( 4704 1824 272 ) ( 4720 1808 336 ) we_cemetary/cemtrim2 0 15 -180.00 1 -1 0 0 0 +} +// brush 655 +{ +( 4288 1824 272 ) ( 4480 1824 272 ) ( 4480 1856 272 ) we_cemetary/cemrunner2 -52 -1 -90.00 1 1 0 0 0 +( 4480 1856 336 ) ( 4480 1824 336 ) ( 4288 1824 336 ) we_cemetary/cemtrim2 -86 -1 -90.00 1 1 0 0 0 +( 4480 1856 272 ) ( 4480 1856 592 ) ( 4288 1856 592 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( 4288 1792 272 ) ( 4288 1792 592 ) ( 4480 1792 592 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( 4720 1808 336 ) ( 4704 1824 272 ) ( 4736 1792 272 ) we_cemetary/cemtrim2 0 15 0.00 1 1 0 0 0 +( 4224 1792 272 ) ( 4256 1824 272 ) ( 4240 1808 336 ) we_cemetary/cemtrim2 128 16 0.00 1 1 0 0 0 +} +// brush 656 +{ +( 4480 1792 256 ) ( 4480 1840 256 ) ( 4288 1840 256 ) we_cemetary/fogtrunk -52 63 -90.00 1 1 0 0 0 +( 4480 1856 272 ) ( 4480 1792 272 ) ( 4288 1792 272 ) we_cemetary/fogtrunk -52 63 -90.00 1 1 0 0 0 +( 4288 1856 272 ) ( 4288 1840 256 ) ( 4480 1840 256 ) we_cemetary/fogtrunk -52 63 -90.00 1 1 0 0 0 +( 4288 1792 256 ) ( 4288 1792 272 ) ( 4480 1792 272 ) we_cemetary/fogtrunk -64 0 0.00 1 1 0 0 0 +( 4720 1808 272 ) ( 4704 1824 256 ) ( 4736 1792 256 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +( 4224 1792 256 ) ( 4256 1824 256 ) ( 4240 1808 272 ) we_cemetary/fogtrunk 128 0 0.00 1 1 0 0 0 +} +// brush 657 +{ +( 4288 2048 272 ) ( 4256 2048 272 ) ( 4256 1856 272 ) we_cemetary/cemrunner2 0 0 0.00 1 1 0 0 0 +( 4256 1856 336 ) ( 4256 2048 336 ) ( 4288 2048 336 ) we_cemetary/cemtrim2 -32 0 0.00 1 1 0 0 0 +( 4288 1856 592 ) ( 4288 2048 592 ) ( 4288 2048 272 ) we_cemetary/cemtrim2 0 16 0.00 1 1 0 0 0 +( 4224 2048 592 ) ( 4224 1856 592 ) ( 4224 1856 272 ) we_cemetary/cemtrim2 0 16 0.00 1 1 0 0 0 +( 4224 2304 272 ) ( 4256 2272 272 ) ( 4240 2288 336 ) we_cemetary/cemtrim2 0 16 0.00 1 1 0 0 0 +( 4288 1856 272 ) ( 4256 1824 272 ) ( 4272 1840 336 ) we_cemetary/cemtrim2 0 16 0.00 1 1 0 0 0 +} +// brush 658 +{ +( 4272 1856 256 ) ( 4272 2048 256 ) ( 4224 2048 256 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +( 4224 1856 272 ) ( 4224 2048 272 ) ( 4288 2048 272 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +( 4272 2048 256 ) ( 4272 1856 256 ) ( 4288 1856 272 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +( 4224 2048 272 ) ( 4224 1856 272 ) ( 4224 1856 256 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +( 4224 2304 256 ) ( 4256 2272 256 ) ( 4240 2288 272 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +( 4288 1856 256 ) ( 4256 1824 256 ) ( 4272 1840 272 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +} +// brush 659 +{ +( 4256 2048 64 ) ( 4224 2048 64 ) ( 4224 1856 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 4224 2048 384 ) ( 4224 1856 384 ) ( 4224 1856 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 4272 1856 96 ) ( 4264 2048 80 ) ( 4256 1856 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 4288 2048 256 ) ( 4288 1856 256 ) ( 4224 1856 256 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 4272 1856 208 ) ( 4272 2048 176 ) ( 4272 1856 144 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 4224 2304 64 ) ( 4256 2272 64 ) ( 4240 2288 256 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 4288 1856 64 ) ( 4256 1824 64 ) ( 4272 1840 256 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +} +// brush 660 +{ +( 4256 2048 0 ) ( 4224 2048 0 ) ( 4224 1856 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( 4224 1856 64 ) ( 4224 2048 64 ) ( 4256 2048 64 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( 4256 1792 320 ) ( 4256 1984 320 ) ( 4256 1984 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( 4224 2048 320 ) ( 4224 1856 320 ) ( 4224 1856 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( 4224 2304 0 ) ( 4256 2272 0 ) ( 4240 2288 64 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( 4288 1856 0 ) ( 4256 1824 0 ) ( 4272 1840 64 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +} +// brush 661 +{ +( 4288 1792 0 ) ( 4480 1792 0 ) ( 4480 1824 0 ) we_cemetary/cemtrim2 -52 -1 -90.00 1 1 0 0 0 +( 4480 1824 64 ) ( 4480 1792 64 ) ( 4288 1792 64 ) we_cemetary/cemtrim2 -52 -1 -90.00 1 1 0 0 0 +( 4352 1824 0 ) ( 4352 1824 320 ) ( 4160 1824 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 4288 1792 0 ) ( 4288 1792 320 ) ( 4480 1792 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 4224 1792 0 ) ( 4256 1824 0 ) ( 4240 1808 64 ) we_cemetary/cemtrim2 128 0 0.00 1 1 0 0 0 +( 4416 1824 0 ) ( 4416 1760 0 ) ( 4416 1792 64 ) we_cemetary/cemtrim2 128 0 0.00 1 1 0 0 0 +} +// brush 662 +{ +( 4288 1792 0 ) ( 4480 1792 0 ) ( 4480 1824 0 ) we_cemetary/cemtrim2 -52 -1 -90.00 1 1 0 0 0 +( 4480 1824 64 ) ( 4480 1792 64 ) ( 4288 1792 64 ) we_cemetary/cemtrim2 -52 -1 -90.00 1 1 0 0 0 +( 4480 1824 0 ) ( 4480 1824 320 ) ( 4288 1824 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 4288 1792 0 ) ( 4288 1792 320 ) ( 4480 1792 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 4720 1808 64 ) ( 4704 1824 0 ) ( 4736 1792 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( 4544 1760 0 ) ( 4544 1824 0 ) ( 4544 1792 64 ) we_cemetary/cemtrim2 128 0 0.00 1 1 0 0 0 +} +// brush 663 +{ +( 4288 1792 64 ) ( 4480 1792 64 ) ( 4480 1824 64 ) we_cemetary/cemstair2 -52 -1 -90.00 1 1 0 0 0 +( 4288 1792 64 ) ( 4288 1792 384 ) ( 4480 1792 384 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 4288 1824 64 ) ( 4480 1832 80 ) ( 4288 1840 96 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 4288 1792 256 ) ( 4288 1856 256 ) ( 4480 1856 256 ) we_cemetary/cemstair2 -52 -1 -90.00 1 1 0 0 0 +( 4288 1840 144 ) ( 4480 1840 176 ) ( 4288 1840 208 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 4224 1792 64 ) ( 4256 1824 64 ) ( 4240 1808 256 ) we_cemetary/cemstair2 128 0 0.00 1 1 0 0 0 +( 4416 1824 64 ) ( 4416 1760 64 ) ( 4416 1792 256 ) we_cemetary/cemstair2 128 0 0.00 1 1 0 0 0 +} +// brush 664 +{ +( 4288 1792 64 ) ( 4480 1792 64 ) ( 4480 1824 64 ) we_cemetary/cemstair2 -52 -1 -90.00 1 1 0 0 0 +( 4288 1792 64 ) ( 4288 1792 384 ) ( 4480 1792 384 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 4288 1824 64 ) ( 4480 1832 80 ) ( 4288 1840 96 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 4288 1792 256 ) ( 4288 1856 256 ) ( 4480 1856 256 ) we_cemetary/cemstair2 -52 -1 -90.00 1 1 0 0 0 +( 4416 1840 144 ) ( 4608 1840 176 ) ( 4416 1840 208 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 4720 1808 256 ) ( 4704 1824 64 ) ( 4736 1792 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 4544 1760 64 ) ( 4544 1824 64 ) ( 4544 1792 256 ) we_cemetary/cemstair2 128 0 0.00 1 1 0 0 0 +} +// brush 665 +{ +( 4480 1760 64 ) ( 4480 1792 64 ) ( 4288 1792 64 ) we_cemetary/cemstair2 -119 -1 -90.00 1 1 0 0 0 +( 4480 1792 384 ) ( 4288 1792 384 ) ( 4288 1792 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 4288 1744 96 ) ( 4480 1752 80 ) ( 4288 1760 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 4480 1728 256 ) ( 4288 1728 256 ) ( 4288 1792 256 ) we_cemetary/cemstair2 -119 -1 -90.00 1 1 0 0 0 +( 4384 1744 208 ) ( 4576 1744 176 ) ( 4384 1744 144 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 4544 1760 64 ) ( 4544 1824 64 ) ( 4544 1792 256 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +( 4736 1792 64 ) ( 4736 1728 64 ) ( 4736 1760 256 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +} +// brush 666 +{ +( 4480 1760 0 ) ( 4480 1792 0 ) ( 4288 1792 0 ) we_cemetary/cemtrim2 -119 -1 -90.00 1 1 0 0 0 +( 4288 1792 64 ) ( 4480 1792 64 ) ( 4480 1760 64 ) we_cemetary/cemtrim2 -119 -1 -90.00 1 1 0 0 0 +( 4384 1760 320 ) ( 4576 1760 320 ) ( 4576 1760 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 4480 1792 320 ) ( 4288 1792 320 ) ( 4288 1792 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 4544 1760 0 ) ( 4544 1824 0 ) ( 4544 1792 64 ) we_cemetary/cemtrim2 192 0 0.00 1 1 0 0 0 +( 4736 1792 0 ) ( 4736 1728 0 ) ( 4736 1760 64 ) we_cemetary/cemtrim2 192 0 0.00 1 1 0 0 0 +} +// brush 667 +{ +( 4480 1760 64 ) ( 4480 1792 64 ) ( 4288 1792 64 ) we_cemetary/cemstair2 -119 -1 -90.00 1 1 0 0 0 +( 4480 1792 384 ) ( 4288 1792 384 ) ( 4288 1792 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 4288 1744 96 ) ( 4480 1752 80 ) ( 4288 1760 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 4480 1728 256 ) ( 4288 1728 256 ) ( 4288 1792 256 ) we_cemetary/cemstair2 -119 -1 -90.00 1 1 0 0 0 +( 4288 1744 208 ) ( 4480 1744 176 ) ( 4288 1744 144 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 4416 1824 64 ) ( 4416 1760 64 ) ( 4416 1792 256 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +( 4224 1728 64 ) ( 4224 1760 64 ) ( 4224 1744 256 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +} +// brush 668 +{ +( 4480 1760 0 ) ( 4480 1792 0 ) ( 4288 1792 0 ) we_cemetary/cemtrim2 -119 -1 -90.00 1 1 0 0 0 +( 4288 1792 64 ) ( 4480 1792 64 ) ( 4480 1760 64 ) we_cemetary/cemtrim2 -119 -1 -90.00 1 1 0 0 0 +( 4096 1760 320 ) ( 4288 1760 320 ) ( 4288 1760 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 4480 1792 320 ) ( 4288 1792 320 ) ( 4288 1792 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 4416 1824 0 ) ( 4416 1760 0 ) ( 4416 1792 64 ) we_cemetary/cemtrim2 192 0 0.00 1 1 0 0 0 +( 4224 1728 0 ) ( 4224 1760 0 ) ( 4224 1744 64 ) we_cemetary/cemtrim2 192 0 0.00 1 1 0 0 0 +} +// brush 669 +{ +( 4288 1744 256 ) ( 4480 1744 256 ) ( 4480 1792 256 ) we_cemetary/fogtrunk -119 63 -90.00 1 1 0 0 0 +( 4288 1792 272 ) ( 4480 1792 272 ) ( 4480 1728 272 ) we_cemetary/fogtrunk -119 63 -90.00 1 1 0 0 0 +( 4480 1744 256 ) ( 4288 1744 256 ) ( 4288 1728 272 ) we_cemetary/fogtrunk -119 63 -90.00 1 1 0 0 0 +( 4480 1792 272 ) ( 4288 1792 272 ) ( 4288 1792 256 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +( 4736 1792 256 ) ( 4736 1728 256 ) ( 4736 1760 272 ) we_cemetary/fogtrunk 192 0 0.00 1 1 0 0 0 +( 4224 1728 256 ) ( 4224 1760 256 ) ( 4224 1744 272 ) we_cemetary/fogtrunk 192 0 0.00 1 1 0 0 0 +} +// brush 670 +{ +( 4480 1728 272 ) ( 4480 1760 272 ) ( 4288 1760 272 ) we_cemetary/cemrunner2 0 -1 -90.00 1 1 0 0 0 +( 4288 1760 336 ) ( 4480 1760 336 ) ( 4480 1728 336 ) we_cemetary/cemtrim2 -151 -1 -90.00 1 1 0 0 0 +( 4288 1728 592 ) ( 4480 1728 592 ) ( 4480 1728 272 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( 4480 1792 592 ) ( 4288 1792 592 ) ( 4288 1792 272 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( 4736 1792 272 ) ( 4736 1728 272 ) ( 4736 1760 336 ) we_cemetary/cemtrim2 192 16 0.00 1 1 0 0 0 +( 4224 1728 272 ) ( 4224 1760 272 ) ( 4224 1744 336 ) we_cemetary/cemtrim2 192 16 0.00 1 1 0 0 0 +} +// brush 671 +{ +( 4704 2272 -32 ) ( 4256 2272 -32 ) ( 4256 1824 -32 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 4256 1824 0 ) ( 4256 2272 0 ) ( 4704 2272 0 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 4256 1760 0 ) ( 4704 1760 0 ) ( 4704 1760 -64 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 4736 1824 0 ) ( 4736 2272 0 ) ( 4736 2272 -64 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 4704 2304 0 ) ( 4256 2304 0 ) ( 4256 2304 -64 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 4224 2272 0 ) ( 4224 1824 0 ) ( 4224 1824 -64 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +} +// brush 672 +{ +( 4704 2272 336 ) ( 4256 2272 336 ) ( 4256 1824 336 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +( 4256 1824 352 ) ( 4256 2272 352 ) ( 4704 2272 352 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +( 4256 1824 368 ) ( 4704 1824 368 ) ( 4704 1824 304 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +( 4704 1824 368 ) ( 4704 2272 368 ) ( 4704 2272 304 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +( 4704 2272 368 ) ( 4256 2272 368 ) ( 4256 2272 304 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +( 4256 2272 368 ) ( 4256 1824 368 ) ( 4256 1824 304 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +} +// brush 673 +{ +( 4544 1840 208 ) ( 4416 1840 208 ) ( 4416 1744 208 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 4416 1744 256 ) ( 4416 1840 256 ) ( 4544 1840 256 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 4416 1744 256 ) ( 4544 1744 256 ) ( 4544 1744 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 4544 1744 240 ) ( 4544 1840 240 ) ( 4544 1840 48 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +( 4544 1840 240 ) ( 4416 1840 240 ) ( 4416 1840 48 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 4416 1840 256 ) ( 4416 1744 256 ) ( 4416 1744 64 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +} +// brush 674 +{ +( 4032 1840 208 ) ( 3904 1840 208 ) ( 3904 1744 208 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 3904 1744 256 ) ( 3904 1840 256 ) ( 4032 1840 256 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 3904 1744 256 ) ( 4032 1744 256 ) ( 4032 1744 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 4032 1744 240 ) ( 4032 1840 240 ) ( 4032 1840 48 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +( 4032 1840 240 ) ( 3904 1840 240 ) ( 3904 1840 48 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 3904 1840 256 ) ( 3904 1744 256 ) ( 3904 1744 64 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +} +// brush 675 +{ +( 4192 2272 336 ) ( 3744 2272 336 ) ( 3744 1824 336 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +( 3744 1824 352 ) ( 3744 2272 352 ) ( 4192 2272 352 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +( 3744 1824 368 ) ( 4192 1824 368 ) ( 4192 1824 304 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +( 4192 1824 368 ) ( 4192 2272 368 ) ( 4192 2272 304 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +( 4192 2272 368 ) ( 3744 2272 368 ) ( 3744 2272 304 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +( 3744 2272 368 ) ( 3744 1824 368 ) ( 3744 1824 304 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +} +// brush 676 +{ +( 4192 2272 -32 ) ( 3744 2272 -32 ) ( 3744 1824 -32 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 3744 1824 0 ) ( 3744 2272 0 ) ( 4192 2272 0 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 3744 1760 0 ) ( 4192 1760 0 ) ( 4192 1760 -64 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 4224 1824 0 ) ( 4224 2272 0 ) ( 4224 2272 -64 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 4192 2304 0 ) ( 3744 2304 0 ) ( 3744 2304 -64 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 3712 2272 0 ) ( 3712 1824 0 ) ( 3712 1824 -64 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +} +// brush 677 +{ +( 3968 1728 272 ) ( 3968 1760 272 ) ( 3776 1760 272 ) we_cemetary/cemrunner2 0 -1 -90.00 1 1 0 0 0 +( 3776 1760 336 ) ( 3968 1760 336 ) ( 3968 1728 336 ) we_cemetary/cemtrim2 -152 -1 -90.00 1 1 0 0 0 +( 3776 1728 592 ) ( 3968 1728 592 ) ( 3968 1728 272 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( 3968 1792 592 ) ( 3776 1792 592 ) ( 3776 1792 272 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( 4224 1792 272 ) ( 4224 1728 272 ) ( 4224 1760 336 ) we_cemetary/cemtrim2 192 16 0.00 1 1 0 0 0 +( 3712 1728 272 ) ( 3712 1760 272 ) ( 3712 1744 336 ) we_cemetary/cemtrim2 192 16 0.00 1 1 0 0 0 +} +// brush 678 +{ +( 3776 1744 256 ) ( 3968 1744 256 ) ( 3968 1792 256 ) we_cemetary/fogtrunk -120 63 -90.00 1 1 0 0 0 +( 3776 1792 272 ) ( 3968 1792 272 ) ( 3968 1728 272 ) we_cemetary/fogtrunk -120 63 -90.00 1 1 0 0 0 +( 3968 1744 256 ) ( 3776 1744 256 ) ( 3776 1728 272 ) we_cemetary/fogtrunk -120 63 -90.00 1 1 0 0 0 +( 3968 1792 272 ) ( 3776 1792 272 ) ( 3776 1792 256 ) we_cemetary/fogtrunk -64 0 0.00 1 1 0 0 0 +( 4224 1792 256 ) ( 4224 1728 256 ) ( 4224 1760 272 ) we_cemetary/fogtrunk 192 0 0.00 1 1 0 0 0 +( 3712 1728 256 ) ( 3712 1760 256 ) ( 3712 1744 272 ) we_cemetary/fogtrunk 192 0 0.00 1 1 0 0 0 +} +// brush 679 +{ +( 3968 1760 0 ) ( 3968 1792 0 ) ( 3776 1792 0 ) we_cemetary/cemtrim2 -120 -1 -90.00 1 1 0 0 0 +( 3776 1792 64 ) ( 3968 1792 64 ) ( 3968 1760 64 ) we_cemetary/cemtrim2 -120 -1 -90.00 1 1 0 0 0 +( 3584 1760 320 ) ( 3776 1760 320 ) ( 3776 1760 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 3968 1792 320 ) ( 3776 1792 320 ) ( 3776 1792 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 3904 1824 0 ) ( 3904 1760 0 ) ( 3904 1792 64 ) we_cemetary/cemtrim2 192 0 0.00 1 1 0 0 0 +( 3712 1728 0 ) ( 3712 1760 0 ) ( 3712 1744 64 ) we_cemetary/cemtrim2 192 0 0.00 1 1 0 0 0 +} +// brush 680 +{ +( 3968 1760 64 ) ( 3968 1792 64 ) ( 3776 1792 64 ) we_cemetary/cemstair2 -120 -1 -90.00 1 1 0 0 0 +( 3968 1792 384 ) ( 3776 1792 384 ) ( 3776 1792 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 3776 1744 96 ) ( 3968 1752 80 ) ( 3776 1760 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 3968 1728 256 ) ( 3776 1728 256 ) ( 3776 1792 256 ) we_cemetary/cemstair2 -120 -1 -90.00 1 1 0 0 0 +( 3776 1744 208 ) ( 3968 1744 176 ) ( 3776 1744 144 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 3904 1824 64 ) ( 3904 1760 64 ) ( 3904 1792 256 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +( 3712 1728 64 ) ( 3712 1760 64 ) ( 3712 1744 256 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +} +// brush 681 +{ +( 3968 1760 0 ) ( 3968 1792 0 ) ( 3776 1792 0 ) we_cemetary/cemtrim2 -120 -1 -90.00 1 1 0 0 0 +( 3776 1792 64 ) ( 3968 1792 64 ) ( 3968 1760 64 ) we_cemetary/cemtrim2 -120 -1 -90.00 1 1 0 0 0 +( 3872 1760 320 ) ( 4064 1760 320 ) ( 4064 1760 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 3968 1792 320 ) ( 3776 1792 320 ) ( 3776 1792 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 4032 1760 0 ) ( 4032 1824 0 ) ( 4032 1792 64 ) we_cemetary/cemtrim2 192 0 0.00 1 1 0 0 0 +( 4224 1792 0 ) ( 4224 1728 0 ) ( 4224 1760 64 ) we_cemetary/cemtrim2 192 0 0.00 1 1 0 0 0 +} +// brush 682 +{ +( 3968 1760 64 ) ( 3968 1792 64 ) ( 3776 1792 64 ) we_cemetary/cemstair2 -120 -1 -90.00 1 1 0 0 0 +( 3968 1792 384 ) ( 3776 1792 384 ) ( 3776 1792 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 3776 1744 96 ) ( 3968 1752 80 ) ( 3776 1760 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 3968 1728 256 ) ( 3776 1728 256 ) ( 3776 1792 256 ) we_cemetary/cemstair2 -120 -1 -90.00 1 1 0 0 0 +( 3872 1744 208 ) ( 4064 1744 176 ) ( 3872 1744 144 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 4032 1760 64 ) ( 4032 1824 64 ) ( 4032 1792 256 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +( 4224 1792 64 ) ( 4224 1728 64 ) ( 4224 1760 256 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +} +// brush 683 +{ +( 3776 1792 64 ) ( 3968 1792 64 ) ( 3968 1824 64 ) we_cemetary/cemstair2 -53 -1 -90.00 1 1 0 0 0 +( 3776 1792 64 ) ( 3776 1792 384 ) ( 3968 1792 384 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 3776 1824 64 ) ( 3968 1832 80 ) ( 3776 1840 96 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 3776 1792 256 ) ( 3776 1856 256 ) ( 3968 1856 256 ) we_cemetary/cemstair2 -53 -1 -90.00 1 1 0 0 0 +( 3904 1840 144 ) ( 4096 1840 176 ) ( 3904 1840 208 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 4208 1808 256 ) ( 4192 1824 64 ) ( 4224 1792 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 4032 1760 64 ) ( 4032 1824 64 ) ( 4032 1792 256 ) we_cemetary/cemstair2 128 0 0.00 1 1 0 0 0 +} +// brush 684 +{ +( 3776 1792 64 ) ( 3968 1792 64 ) ( 3968 1824 64 ) we_cemetary/cemstair2 -53 -1 -90.00 1 1 0 0 0 +( 3776 1792 64 ) ( 3776 1792 384 ) ( 3968 1792 384 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 3776 1824 64 ) ( 3968 1832 80 ) ( 3776 1840 96 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 3776 1792 256 ) ( 3776 1856 256 ) ( 3968 1856 256 ) we_cemetary/cemstair2 -53 -1 -90.00 1 1 0 0 0 +( 3776 1840 144 ) ( 3968 1840 176 ) ( 3776 1840 208 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 3712 1792 64 ) ( 3744 1824 64 ) ( 3728 1808 256 ) we_cemetary/cemstair2 128 0 0.00 1 1 0 0 0 +( 3904 1824 64 ) ( 3904 1760 64 ) ( 3904 1792 256 ) we_cemetary/cemstair2 128 0 0.00 1 1 0 0 0 +} +// brush 685 +{ +( 3776 1792 0 ) ( 3968 1792 0 ) ( 3968 1824 0 ) we_cemetary/cemtrim2 -53 -1 -90.00 1 1 0 0 0 +( 3968 1824 64 ) ( 3968 1792 64 ) ( 3776 1792 64 ) we_cemetary/cemtrim2 -53 -1 -90.00 1 1 0 0 0 +( 3968 1824 0 ) ( 3968 1824 320 ) ( 3776 1824 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 3776 1792 0 ) ( 3776 1792 320 ) ( 3968 1792 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 4208 1808 64 ) ( 4192 1824 0 ) ( 4224 1792 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( 4032 1760 0 ) ( 4032 1824 0 ) ( 4032 1792 64 ) we_cemetary/cemtrim2 128 0 0.00 1 1 0 0 0 +} +// brush 686 +{ +( 3776 1792 0 ) ( 3968 1792 0 ) ( 3968 1824 0 ) we_cemetary/cemtrim2 -53 -1 -90.00 1 1 0 0 0 +( 3968 1824 64 ) ( 3968 1792 64 ) ( 3776 1792 64 ) we_cemetary/cemtrim2 -53 -1 -90.00 1 1 0 0 0 +( 3840 1824 0 ) ( 3840 1824 320 ) ( 3648 1824 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 3776 1792 0 ) ( 3776 1792 320 ) ( 3968 1792 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 3712 1792 0 ) ( 3744 1824 0 ) ( 3728 1808 64 ) we_cemetary/cemtrim2 128 0 0.00 1 1 0 0 0 +( 3904 1824 0 ) ( 3904 1760 0 ) ( 3904 1792 64 ) we_cemetary/cemtrim2 128 0 0.00 1 1 0 0 0 +} +// brush 687 +{ +( 3744 2048 0 ) ( 3712 2048 0 ) ( 3712 1856 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( 3712 1856 64 ) ( 3712 2048 64 ) ( 3744 2048 64 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( 3744 1792 320 ) ( 3744 1984 320 ) ( 3744 1984 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( 3712 2048 320 ) ( 3712 1856 320 ) ( 3712 1856 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( 3712 2304 0 ) ( 3744 2272 0 ) ( 3728 2288 64 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( 3776 1856 0 ) ( 3744 1824 0 ) ( 3760 1840 64 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +} +// brush 688 +{ +( 3744 2048 64 ) ( 3712 2048 64 ) ( 3712 1856 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 3712 2048 384 ) ( 3712 1856 384 ) ( 3712 1856 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 3760 1856 96 ) ( 3752 2048 80 ) ( 3744 1856 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 3776 2048 256 ) ( 3776 1856 256 ) ( 3712 1856 256 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 3760 1856 208 ) ( 3760 2048 176 ) ( 3760 1856 144 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 3712 2304 64 ) ( 3744 2272 64 ) ( 3728 2288 256 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 3776 1856 64 ) ( 3744 1824 64 ) ( 3760 1840 256 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +} +// brush 689 +{ +( 3760 1856 256 ) ( 3760 2048 256 ) ( 3712 2048 256 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +( 3712 1856 272 ) ( 3712 2048 272 ) ( 3776 2048 272 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +( 3760 2048 256 ) ( 3760 1856 256 ) ( 3776 1856 272 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +( 3712 2048 272 ) ( 3712 1856 272 ) ( 3712 1856 256 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +( 3712 2304 256 ) ( 3744 2272 256 ) ( 3728 2288 272 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +( 3776 1856 256 ) ( 3744 1824 256 ) ( 3760 1840 272 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +} +// brush 690 +{ +( 3776 2048 272 ) ( 3744 2048 272 ) ( 3744 1856 272 ) we_cemetary/cemrunner2 0 0 0.00 1 1 0 0 0 +( 3744 1856 336 ) ( 3744 2048 336 ) ( 3776 2048 336 ) we_cemetary/cemtrim2 -32 0 0.00 1 1 0 0 0 +( 3776 1856 592 ) ( 3776 2048 592 ) ( 3776 2048 272 ) we_cemetary/cemtrim2 0 16 0.00 1 1 0 0 0 +( 3712 2048 592 ) ( 3712 1856 592 ) ( 3712 1856 272 ) we_cemetary/cemtrim2 0 16 0.00 1 1 0 0 0 +( 3712 2304 272 ) ( 3744 2272 272 ) ( 3728 2288 336 ) we_cemetary/cemtrim2 0 16 0.00 1 1 0 0 0 +( 3776 1856 272 ) ( 3744 1824 272 ) ( 3760 1840 336 ) we_cemetary/cemtrim2 0 16 0.00 1 1 0 0 0 +} +// brush 691 +{ +( 3968 1792 256 ) ( 3968 1840 256 ) ( 3776 1840 256 ) we_cemetary/fogtrunk -53 63 -90.00 1 1 0 0 0 +( 3968 1856 272 ) ( 3968 1792 272 ) ( 3776 1792 272 ) we_cemetary/fogtrunk -53 63 -90.00 1 1 0 0 0 +( 3776 1856 272 ) ( 3776 1840 256 ) ( 3968 1840 256 ) we_cemetary/fogtrunk -53 63 -90.00 1 1 0 0 0 +( 3776 1792 256 ) ( 3776 1792 272 ) ( 3968 1792 272 ) we_cemetary/fogtrunk -64 0 0.00 1 1 0 0 0 +( 4208 1808 272 ) ( 4192 1824 256 ) ( 4224 1792 256 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +( 3712 1792 256 ) ( 3744 1824 256 ) ( 3728 1808 272 ) we_cemetary/fogtrunk 128 0 0.00 1 1 0 0 0 +} +// brush 692 +{ +( 3776 1824 272 ) ( 3968 1824 272 ) ( 3968 1856 272 ) we_cemetary/cemrunner2 -53 -1 -90.00 1 1 0 0 0 +( 3968 1856 336 ) ( 3968 1824 336 ) ( 3776 1824 336 ) we_cemetary/cemtrim2 -87 -1 -90.00 1 1 0 0 0 +( 3968 1856 272 ) ( 3968 1856 592 ) ( 3776 1856 592 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( 3776 1792 272 ) ( 3776 1792 592 ) ( 3968 1792 592 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( 4208 1808 336 ) ( 4192 1824 272 ) ( 4224 1792 272 ) we_cemetary/cemtrim2 0 15 0.00 1 1 0 0 0 +( 3712 1792 272 ) ( 3744 1824 272 ) ( 3728 1808 336 ) we_cemetary/cemtrim2 128 16 0.00 1 1 0 0 0 +} +// brush 693 +{ +( 4192 1856 272 ) ( 4192 2048 272 ) ( 4160 2048 272 ) we_cemetary/cemrunner2 -66 0 -180.00 1 1 0 0 0 +( 4160 2048 336 ) ( 4192 2048 336 ) ( 4192 1856 336 ) we_cemetary/cemtrim2 -97 0 -180.00 1 1 0 0 0 +( 4160 2048 272 ) ( 4160 2048 592 ) ( 4160 1856 592 ) we_cemetary/cemtrim2 64 14 -180.00 1 -1 0 0 0 +( 4224 1856 272 ) ( 4224 1856 592 ) ( 4224 2048 592 ) we_cemetary/cemtrim2 64 14 -180.00 1 -1 0 0 0 +( 4208 2288 336 ) ( 4192 2272 272 ) ( 4224 2304 272 ) we_cemetary/cemtrim2 128 15 0.00 1 1 0 0 0 +( 4224 1792 272 ) ( 4192 1824 272 ) ( 4208 1808 336 ) we_cemetary/cemtrim2 0 15 -180.00 1 -1 0 0 0 +} +// brush 694 +{ +( 4224 2048 256 ) ( 4176 2048 256 ) ( 4176 1856 256 ) we_cemetary/fogtrunk -65 -64 -180.00 1 1 0 0 0 +( 4160 2048 272 ) ( 4224 2048 272 ) ( 4224 1856 272 ) we_cemetary/fogtrunk -65 -64 -180.00 1 1 0 0 0 +( 4160 1856 272 ) ( 4176 1856 256 ) ( 4176 2048 256 ) we_cemetary/fogtrunk -65 -64 -180.00 1 1 0 0 0 +( 4224 1856 256 ) ( 4224 1856 272 ) ( 4224 2048 272 ) we_cemetary/fogtrunk 64 0 -180.00 1 -1 0 0 0 +( 4208 2288 272 ) ( 4192 2272 256 ) ( 4224 2304 256 ) we_cemetary/fogtrunk 128 0 0.00 1 1 0 0 0 +( 4224 1792 256 ) ( 4192 1824 256 ) ( 4208 1808 272 ) we_cemetary/fogtrunk 0 0 -180.00 1 -1 0 0 0 +} +// brush 695 +{ +( 4224 1856 64 ) ( 4224 2048 64 ) ( 4192 2048 64 ) we_cemetary/cemstair2 -65 0 -180.00 1 1 0 0 0 +( 4224 1856 64 ) ( 4224 1856 384 ) ( 4224 2048 384 ) we_cemetary/cemstair2 64 0 -180.00 1 -1 0 0 0 +( 4192 1856 64 ) ( 4184 2048 80 ) ( 4176 1856 96 ) we_cemetary/cemstair2 64 0 -180.00 1 -1 0 0 0 +( 4224 1856 256 ) ( 4160 1856 256 ) ( 4160 2048 256 ) we_cemetary/cemstair2 -65 0 -180.00 1 1 0 0 0 +( 4176 1856 144 ) ( 4176 2048 176 ) ( 4176 1856 208 ) we_cemetary/cemstair2 64 0 -180.00 1 -1 0 0 0 +( 4208 2288 256 ) ( 4192 2272 64 ) ( 4224 2304 64 ) we_cemetary/cemstair2 128 0 0.00 1 1 0 0 0 +( 4224 1792 64 ) ( 4192 1824 64 ) ( 4208 1808 256 ) we_cemetary/cemstair2 0 0 -180.00 1 -1 0 0 0 +} +// brush 696 +{ +( 4224 1856 0 ) ( 4224 2048 0 ) ( 4192 2048 0 ) we_cemetary/cemtrim2 -65 0 -180.00 1 1 0 0 0 +( 4192 2048 64 ) ( 4224 2048 64 ) ( 4224 1856 64 ) we_cemetary/cemtrim2 -65 0 -180.00 1 1 0 0 0 +( 4192 1920 0 ) ( 4192 1920 320 ) ( 4192 1728 320 ) we_cemetary/cemtrim2 64 0 -180.00 1 -1 0 0 0 +( 4224 1856 0 ) ( 4224 1856 320 ) ( 4224 2048 320 ) we_cemetary/cemtrim2 64 0 -180.00 1 -1 0 0 0 +( 4208 2288 64 ) ( 4192 2272 0 ) ( 4224 2304 0 ) we_cemetary/cemtrim2 128 0 0.00 1 1 0 0 0 +( 4224 1792 0 ) ( 4192 1824 0 ) ( 4208 1808 64 ) we_cemetary/cemtrim2 0 0 -180.00 1 -1 0 0 0 +} +// brush 697 +{ +( 4160 2304 0 ) ( 3968 2304 0 ) ( 3968 2272 0 ) we_cemetary/cemtrim2 -52 0 90.00 1 1 0 0 0 +( 3968 2272 64 ) ( 3968 2304 64 ) ( 4160 2304 64 ) we_cemetary/cemtrim2 -52 0 90.00 1 1 0 0 0 +( 4032 2272 0 ) ( 4032 2272 320 ) ( 4224 2272 320 ) we_cemetary/cemtrim2 128 0 -180.00 1 -1 0 0 0 +( 4160 2304 0 ) ( 4160 2304 320 ) ( 3968 2304 320 ) we_cemetary/cemtrim2 128 0 -180.00 1 -1 0 0 0 +( 3728 2288 64 ) ( 3744 2272 0 ) ( 3712 2304 0 ) we_cemetary/cemtrim2 192 0 -180.00 1 -1 0 0 0 +( 4224 2304 0 ) ( 4192 2272 0 ) ( 4208 2288 64 ) we_cemetary/cemtrim2 192 0 -180.00 1 -1 0 0 0 +} +// brush 698 +{ +( 4160 2304 64 ) ( 3968 2304 64 ) ( 3968 2272 64 ) we_cemetary/cemstair2 -52 0 90.00 1 1 0 0 0 +( 4160 2304 64 ) ( 4160 2304 384 ) ( 3968 2304 384 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +( 4160 2272 64 ) ( 3968 2264 80 ) ( 4160 2256 96 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +( 4160 2304 256 ) ( 4160 2240 256 ) ( 3968 2240 256 ) we_cemetary/cemstair2 -52 0 90.00 1 1 0 0 0 +( 4160 2256 144 ) ( 3968 2256 176 ) ( 4160 2256 208 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +( 3728 2288 256 ) ( 3744 2272 64 ) ( 3712 2304 64 ) we_cemetary/cemstair2 192 0 -180.00 1 -1 0 0 0 +( 4224 2304 64 ) ( 4192 2272 64 ) ( 4208 2288 256 ) we_cemetary/cemstair2 192 0 -180.00 1 -1 0 0 0 +} +// brush 699 +{ +( 3968 2304 256 ) ( 3968 2256 256 ) ( 4160 2256 256 ) we_cemetary/fogtrunk -52 -128 90.00 1 1 0 0 0 +( 3968 2240 272 ) ( 3968 2304 272 ) ( 4160 2304 272 ) we_cemetary/fogtrunk -52 -128 90.00 1 1 0 0 0 +( 4160 2240 272 ) ( 4160 2256 256 ) ( 3968 2256 256 ) we_cemetary/fogtrunk -52 -128 90.00 1 1 0 0 0 +( 4160 2304 256 ) ( 4160 2304 272 ) ( 3968 2304 272 ) we_cemetary/fogtrunk 128 0 -180.00 1 -1 0 0 0 +( 3728 2288 272 ) ( 3744 2272 256 ) ( 3712 2304 256 ) we_cemetary/fogtrunk 192 0 -180.00 1 -1 0 0 0 +( 4224 2304 256 ) ( 4192 2272 256 ) ( 4208 2288 272 ) we_cemetary/fogtrunk 192 0 -180.00 1 -1 0 0 0 +} +// brush 700 +{ +( 4160 2272 272 ) ( 3968 2272 272 ) ( 3968 2240 272 ) we_cemetary/cemrunner2 -52 5 90.00 1 1.000122 0 0 0 +( 3968 2240 336 ) ( 3968 2272 336 ) ( 4160 2272 336 ) we_cemetary/cemtrim2 -84 0 90.00 1 1 0 0 0 +( 3968 2240 272 ) ( 3968 2240 592 ) ( 4160 2240 592 ) we_cemetary/cemtrim2 128 15 -180.00 1 -1 0 0 0 +( 4160 2304 272 ) ( 4160 2304 592 ) ( 3968 2304 592 ) we_cemetary/cemtrim2 128 15 -180.00 1 -1 0 0 0 +( 3728 2288 336 ) ( 3744 2272 272 ) ( 3712 2304 272 ) we_cemetary/cemtrim2 192 15 -180.00 1 -1 0 0 0 +( 4224 2304 272 ) ( 4192 2272 272 ) ( 4208 2288 336 ) we_cemetary/cemtrim2 192 15 -180.00 1 -1 0 0 0 +} +// brush 701 +{ +( 3648 2272 272 ) ( 3456 2272 272 ) ( 3456 2240 272 ) we_cemetary/cemrunner2 -53 -27 90.00 1 1.000122 0 0 0 +( 3456 2240 336 ) ( 3456 2272 336 ) ( 3648 2272 336 ) we_cemetary/cemtrim2 -85 0 90.00 1 1 0 0 0 +( 3456 2240 272 ) ( 3456 2240 592 ) ( 3648 2240 592 ) we_cemetary/cemtrim2 128 15 -180.00 1 -1 0 0 0 +( 3648 2304 272 ) ( 3648 2304 592 ) ( 3456 2304 592 ) we_cemetary/cemtrim2 128 15 -180.00 1 -1 0 0 0 +( 3216 2288 336 ) ( 3232 2272 272 ) ( 3200 2304 272 ) we_cemetary/cemtrim2 192 15 -180.00 1 -1 0 0 0 +( 3712 2304 272 ) ( 3680 2272 272 ) ( 3696 2288 336 ) we_cemetary/cemtrim2 192 15 -180.00 1 -1 0 0 0 +} +// brush 702 +{ +( 3456 2304 256 ) ( 3456 2256 256 ) ( 3648 2256 256 ) we_cemetary/fogtrunk -53 -128 90.00 1 1 0 0 0 +( 3456 2240 272 ) ( 3456 2304 272 ) ( 3648 2304 272 ) we_cemetary/fogtrunk -53 -128 90.00 1 1 0 0 0 +( 3648 2240 272 ) ( 3648 2256 256 ) ( 3456 2256 256 ) we_cemetary/fogtrunk -53 -128 90.00 1 1 0 0 0 +( 3648 2304 256 ) ( 3648 2304 272 ) ( 3456 2304 272 ) we_cemetary/fogtrunk 128 0 -180.00 1 -1 0 0 0 +( 3216 2288 272 ) ( 3232 2272 256 ) ( 3200 2304 256 ) we_cemetary/fogtrunk 192 0 -180.00 1 -1 0 0 0 +( 3712 2304 256 ) ( 3680 2272 256 ) ( 3696 2288 272 ) we_cemetary/fogtrunk 192 0 -180.00 1 -1 0 0 0 +} +// brush 703 +{ +( 3648 2304 64 ) ( 3456 2304 64 ) ( 3456 2272 64 ) we_cemetary/cemstair2 -53 0 90.00 1 1 0 0 0 +( 3648 2304 64 ) ( 3648 2304 384 ) ( 3456 2304 384 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +( 3648 2272 64 ) ( 3456 2264 80 ) ( 3648 2256 96 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +( 3648 2304 256 ) ( 3648 2240 256 ) ( 3456 2240 256 ) we_cemetary/cemstair2 -53 0 90.00 1 1 0 0 0 +( 3648 2256 144 ) ( 3456 2256 176 ) ( 3648 2256 208 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +( 3216 2288 256 ) ( 3232 2272 64 ) ( 3200 2304 64 ) we_cemetary/cemstair2 192 0 -180.00 1 -1 0 0 0 +( 3712 2304 64 ) ( 3680 2272 64 ) ( 3696 2288 256 ) we_cemetary/cemstair2 192 0 -180.00 1 -1 0 0 0 +} +// brush 704 +{ +( 3648 2304 0 ) ( 3456 2304 0 ) ( 3456 2272 0 ) we_cemetary/cemtrim2 -53 0 90.00 1 1 0 0 0 +( 3456 2272 64 ) ( 3456 2304 64 ) ( 3648 2304 64 ) we_cemetary/cemtrim2 -53 0 90.00 1 1 0 0 0 +( 3520 2272 0 ) ( 3520 2272 320 ) ( 3712 2272 320 ) we_cemetary/cemtrim2 128 0 -180.00 1 -1 0 0 0 +( 3648 2304 0 ) ( 3648 2304 320 ) ( 3456 2304 320 ) we_cemetary/cemtrim2 128 0 -180.00 1 -1 0 0 0 +( 3216 2288 64 ) ( 3232 2272 0 ) ( 3200 2304 0 ) we_cemetary/cemtrim2 192 0 -180.00 1 -1 0 0 0 +( 3712 2304 0 ) ( 3680 2272 0 ) ( 3696 2288 64 ) we_cemetary/cemtrim2 192 0 -180.00 1 -1 0 0 0 +} +// brush 705 +{ +( 3712 1856 0 ) ( 3712 2048 0 ) ( 3680 2048 0 ) we_cemetary/cemtrim2 191 0 -180.00 1 1 0 0 0 +( 3680 2048 64 ) ( 3712 2048 64 ) ( 3712 1856 64 ) we_cemetary/cemtrim2 191 0 -180.00 1 1 0 0 0 +( 3680 1920 0 ) ( 3680 1920 320 ) ( 3680 1728 320 ) we_cemetary/cemtrim2 64 0 -180.00 1 -1 0 0 0 +( 3712 1856 0 ) ( 3712 1856 320 ) ( 3712 2048 320 ) we_cemetary/cemtrim2 64 0 -180.00 1 -1 0 0 0 +( 3696 2288 64 ) ( 3680 2272 0 ) ( 3712 2304 0 ) we_cemetary/cemtrim2 128 0 0.00 1 1 0 0 0 +( 3712 1792 0 ) ( 3680 1824 0 ) ( 3696 1808 64 ) we_cemetary/cemtrim2 0 0 -180.00 1 -1 0 0 0 +} +// brush 706 +{ +( 3712 1856 64 ) ( 3712 2048 64 ) ( 3680 2048 64 ) we_cemetary/cemstair2 191 0 -180.00 1 1 0 0 0 +( 3712 1856 64 ) ( 3712 1856 384 ) ( 3712 2048 384 ) we_cemetary/cemstair2 64 0 -180.00 1 -1 0 0 0 +( 3680 1856 64 ) ( 3672 2048 80 ) ( 3664 1856 96 ) we_cemetary/cemstair2 64 0 -180.00 1 -1 0 0 0 +( 3712 1856 256 ) ( 3648 1856 256 ) ( 3648 2048 256 ) we_cemetary/cemstair2 191 0 -180.00 1 1 0 0 0 +( 3664 1856 144 ) ( 3664 2048 176 ) ( 3664 1856 208 ) we_cemetary/cemstair2 64 0 -180.00 1 -1 0 0 0 +( 3696 2288 256 ) ( 3680 2272 64 ) ( 3712 2304 64 ) we_cemetary/cemstair2 128 0 0.00 1 1 0 0 0 +( 3712 1792 64 ) ( 3680 1824 64 ) ( 3696 1808 256 ) we_cemetary/cemstair2 0 0 -180.00 1 -1 0 0 0 +} +// brush 707 +{ +( 3712 2048 256 ) ( 3664 2048 256 ) ( 3664 1856 256 ) we_cemetary/fogtrunk 191 -64 -180.00 1 1 0 0 0 +( 3648 2048 272 ) ( 3712 2048 272 ) ( 3712 1856 272 ) we_cemetary/fogtrunk 191 -64 -180.00 1 1 0 0 0 +( 3648 1856 272 ) ( 3664 1856 256 ) ( 3664 2048 256 ) we_cemetary/fogtrunk 191 -64 -180.00 1 1 0 0 0 +( 3712 1856 256 ) ( 3712 1856 272 ) ( 3712 2048 272 ) we_cemetary/fogtrunk 64 0 -180.00 1 -1 0 0 0 +( 3696 2288 272 ) ( 3680 2272 256 ) ( 3712 2304 256 ) we_cemetary/fogtrunk 128 0 0.00 1 1 0 0 0 +( 3712 1792 256 ) ( 3680 1824 256 ) ( 3696 1808 272 ) we_cemetary/fogtrunk 0 0 -180.00 1 -1 0 0 0 +} +// brush 708 +{ +( 3680 1856 272 ) ( 3680 2048 272 ) ( 3648 2048 272 ) we_cemetary/cemrunner2 62 0 -180.00 1 1 0 0 0 +( 3648 2048 336 ) ( 3680 2048 336 ) ( 3680 1856 336 ) we_cemetary/cemtrim2 159 0 -180.00 1 1 0 0 0 +( 3648 2048 272 ) ( 3648 2048 592 ) ( 3648 1856 592 ) we_cemetary/cemtrim2 64 14 -180.00 1 -1 0 0 0 +( 3712 1856 272 ) ( 3712 1856 592 ) ( 3712 2048 592 ) we_cemetary/cemtrim2 64 14 -180.00 1 -1 0 0 0 +( 3696 2288 336 ) ( 3680 2272 272 ) ( 3712 2304 272 ) we_cemetary/cemtrim2 128 15 0.00 1 1 0 0 0 +( 3712 1792 272 ) ( 3680 1824 272 ) ( 3696 1808 336 ) we_cemetary/cemtrim2 0 15 -180.00 1 -1 0 0 0 +} +// brush 709 +{ +( 3264 1824 272 ) ( 3456 1824 272 ) ( 3456 1856 272 ) we_cemetary/cemrunner2 -54 31 -90.00 1 1 0 0 0 +( 3456 1856 336 ) ( 3456 1824 336 ) ( 3264 1824 336 ) we_cemetary/cemtrim2 -88 63 -90.00 1 1 0 0 0 +( 3456 1856 272 ) ( 3456 1856 592 ) ( 3264 1856 592 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( 3264 1792 272 ) ( 3264 1792 592 ) ( 3456 1792 592 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( 3696 1808 336 ) ( 3680 1824 272 ) ( 3712 1792 272 ) we_cemetary/cemtrim2 0 15 0.00 1 1 0 0 0 +( 3200 1792 272 ) ( 3232 1824 272 ) ( 3216 1808 336 ) we_cemetary/cemtrim2 128 16 0.00 1 1 0 0 0 +} +// brush 710 +{ +( 3456 1792 256 ) ( 3456 1840 256 ) ( 3264 1840 256 ) we_cemetary/fogtrunk -54 63 -90.00 1 1 0 0 0 +( 3456 1856 272 ) ( 3456 1792 272 ) ( 3264 1792 272 ) we_cemetary/fogtrunk -54 63 -90.00 1 1 0 0 0 +( 3264 1856 272 ) ( 3264 1840 256 ) ( 3456 1840 256 ) we_cemetary/fogtrunk -54 63 -90.00 1 1 0 0 0 +( 3264 1792 256 ) ( 3264 1792 272 ) ( 3456 1792 272 ) we_cemetary/fogtrunk -64 0 0.00 1 1 0 0 0 +( 3696 1808 272 ) ( 3680 1824 256 ) ( 3712 1792 256 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +( 3200 1792 256 ) ( 3232 1824 256 ) ( 3216 1808 272 ) we_cemetary/fogtrunk 128 0 0.00 1 1 0 0 0 +} +// brush 711 +{ +( 3264 2048 272 ) ( 3232 2048 272 ) ( 3232 1856 272 ) we_cemetary/cemrunner2 0 0 0.00 1 1 0 0 0 +( 3232 1856 336 ) ( 3232 2048 336 ) ( 3264 2048 336 ) we_cemetary/cemtrim2 -32 0 0.00 1 1 0 0 0 +( 3264 1856 592 ) ( 3264 2048 592 ) ( 3264 2048 272 ) we_cemetary/cemtrim2 0 16 0.00 1 1 0 0 0 +( 3200 2048 592 ) ( 3200 1856 592 ) ( 3200 1856 272 ) we_cemetary/cemtrim2 0 16 0.00 1 1 0 0 0 +( 3200 2304 272 ) ( 3232 2272 272 ) ( 3216 2288 336 ) we_cemetary/cemtrim2 0 16 0.00 1 1 0 0 0 +( 3264 1856 272 ) ( 3232 1824 272 ) ( 3248 1840 336 ) we_cemetary/cemtrim2 0 16 0.00 1 1 0 0 0 +} +// brush 712 +{ +( 3248 1856 256 ) ( 3248 2048 256 ) ( 3200 2048 256 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +( 3200 1856 272 ) ( 3200 2048 272 ) ( 3264 2048 272 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +( 3248 2048 256 ) ( 3248 1856 256 ) ( 3264 1856 272 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +( 3200 2048 272 ) ( 3200 1856 272 ) ( 3200 1856 256 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +( 3200 2304 256 ) ( 3232 2272 256 ) ( 3216 2288 272 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +( 3264 1856 256 ) ( 3232 1824 256 ) ( 3248 1840 272 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +} +// brush 713 +{ +( 3232 2048 64 ) ( 3200 2048 64 ) ( 3200 1856 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 3200 2048 384 ) ( 3200 1856 384 ) ( 3200 1856 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 3248 1856 96 ) ( 3240 2048 80 ) ( 3232 1856 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 3264 2048 256 ) ( 3264 1856 256 ) ( 3200 1856 256 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 3248 1856 208 ) ( 3248 2048 176 ) ( 3248 1856 144 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 3200 2304 64 ) ( 3232 2272 64 ) ( 3216 2288 256 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 3264 1856 64 ) ( 3232 1824 64 ) ( 3248 1840 256 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +} +// brush 714 +{ +( 3232 2048 0 ) ( 3200 2048 0 ) ( 3200 1856 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( 3200 1856 64 ) ( 3200 2048 64 ) ( 3232 2048 64 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( 3232 1792 320 ) ( 3232 1984 320 ) ( 3232 1984 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( 3200 2048 320 ) ( 3200 1856 320 ) ( 3200 1856 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( 3200 2304 0 ) ( 3232 2272 0 ) ( 3216 2288 64 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( 3264 1856 0 ) ( 3232 1824 0 ) ( 3248 1840 64 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +} +// brush 715 +{ +( 3264 1792 0 ) ( 3456 1792 0 ) ( 3456 1824 0 ) we_cemetary/cemtrim2 -54 63 -90.00 1 1 0 0 0 +( 3456 1824 64 ) ( 3456 1792 64 ) ( 3264 1792 64 ) we_cemetary/cemtrim2 -54 63 -90.00 1 1 0 0 0 +( 3328 1824 0 ) ( 3328 1824 320 ) ( 3136 1824 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 3264 1792 0 ) ( 3264 1792 320 ) ( 3456 1792 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 3200 1792 0 ) ( 3232 1824 0 ) ( 3216 1808 64 ) we_cemetary/cemtrim2 128 0 0.00 1 1 0 0 0 +( 3392 1824 0 ) ( 3392 1760 0 ) ( 3392 1792 64 ) we_cemetary/cemtrim2 128 0 0.00 1 1 0 0 0 +} +// brush 716 +{ +( 3264 1792 0 ) ( 3456 1792 0 ) ( 3456 1824 0 ) we_cemetary/cemtrim2 -54 63 -90.00 1 1 0 0 0 +( 3456 1824 64 ) ( 3456 1792 64 ) ( 3264 1792 64 ) we_cemetary/cemtrim2 -54 63 -90.00 1 1 0 0 0 +( 3456 1824 0 ) ( 3456 1824 320 ) ( 3264 1824 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 3264 1792 0 ) ( 3264 1792 320 ) ( 3456 1792 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 3696 1808 64 ) ( 3680 1824 0 ) ( 3712 1792 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( 3520 1760 0 ) ( 3520 1824 0 ) ( 3520 1792 64 ) we_cemetary/cemtrim2 128 0 0.00 1 1 0 0 0 +} +// brush 717 +{ +( 3264 1792 64 ) ( 3456 1792 64 ) ( 3456 1824 64 ) we_cemetary/cemstair2 -54 63 -90.00 1 1 0 0 0 +( 3264 1792 64 ) ( 3264 1792 384 ) ( 3456 1792 384 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 3264 1824 64 ) ( 3456 1832 80 ) ( 3264 1840 96 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 3264 1792 256 ) ( 3264 1856 256 ) ( 3456 1856 256 ) we_cemetary/cemstair2 -54 63 -90.00 1 1 0 0 0 +( 3264 1840 144 ) ( 3456 1840 176 ) ( 3264 1840 208 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 3200 1792 64 ) ( 3232 1824 64 ) ( 3216 1808 256 ) we_cemetary/cemstair2 128 0 0.00 1 1 0 0 0 +( 3392 1824 64 ) ( 3392 1760 64 ) ( 3392 1792 256 ) we_cemetary/cemstair2 128 0 0.00 1 1 0 0 0 +} +// brush 718 +{ +( 3264 1792 64 ) ( 3456 1792 64 ) ( 3456 1824 64 ) we_cemetary/cemstair2 -54 63 -90.00 1 1 0 0 0 +( 3264 1792 64 ) ( 3264 1792 384 ) ( 3456 1792 384 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 3264 1824 64 ) ( 3456 1832 80 ) ( 3264 1840 96 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 3264 1792 256 ) ( 3264 1856 256 ) ( 3456 1856 256 ) we_cemetary/cemstair2 -54 63 -90.00 1 1 0 0 0 +( 3392 1840 144 ) ( 3584 1840 176 ) ( 3392 1840 208 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 3696 1808 256 ) ( 3680 1824 64 ) ( 3712 1792 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 3520 1760 64 ) ( 3520 1824 64 ) ( 3520 1792 256 ) we_cemetary/cemstair2 128 0 0.00 1 1 0 0 0 +} +// brush 719 +{ +( 3456 1760 64 ) ( 3456 1792 64 ) ( 3264 1792 64 ) we_cemetary/cemstair2 -121 63 -90.00 1 1 0 0 0 +( 3456 1792 384 ) ( 3264 1792 384 ) ( 3264 1792 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 3264 1744 96 ) ( 3456 1752 80 ) ( 3264 1760 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 3456 1728 256 ) ( 3264 1728 256 ) ( 3264 1792 256 ) we_cemetary/cemstair2 -121 63 -90.00 1 1 0 0 0 +( 3360 1744 208 ) ( 3552 1744 176 ) ( 3360 1744 144 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 3520 1760 64 ) ( 3520 1824 64 ) ( 3520 1792 256 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +( 3712 1792 64 ) ( 3712 1728 64 ) ( 3712 1760 256 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +} +// brush 720 +{ +( 3456 1760 0 ) ( 3456 1792 0 ) ( 3264 1792 0 ) we_cemetary/cemtrim2 -121 63 -90.00 1 1 0 0 0 +( 3264 1792 64 ) ( 3456 1792 64 ) ( 3456 1760 64 ) we_cemetary/cemtrim2 -121 63 -90.00 1 1 0 0 0 +( 3360 1760 320 ) ( 3552 1760 320 ) ( 3552 1760 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 3456 1792 320 ) ( 3264 1792 320 ) ( 3264 1792 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 3520 1760 0 ) ( 3520 1824 0 ) ( 3520 1792 64 ) we_cemetary/cemtrim2 192 0 0.00 1 1 0 0 0 +( 3712 1792 0 ) ( 3712 1728 0 ) ( 3712 1760 64 ) we_cemetary/cemtrim2 192 0 0.00 1 1 0 0 0 +} +// brush 721 +{ +( 3456 1760 64 ) ( 3456 1792 64 ) ( 3264 1792 64 ) we_cemetary/cemstair2 -121 63 -90.00 1 1 0 0 0 +( 3456 1792 384 ) ( 3264 1792 384 ) ( 3264 1792 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 3264 1744 96 ) ( 3456 1752 80 ) ( 3264 1760 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 3456 1728 256 ) ( 3264 1728 256 ) ( 3264 1792 256 ) we_cemetary/cemstair2 -121 63 -90.00 1 1 0 0 0 +( 3264 1744 208 ) ( 3456 1744 176 ) ( 3264 1744 144 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 3392 1824 64 ) ( 3392 1760 64 ) ( 3392 1792 256 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +( 3200 1728 64 ) ( 3200 1760 64 ) ( 3200 1744 256 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +} +// brush 722 +{ +( 3456 1760 0 ) ( 3456 1792 0 ) ( 3264 1792 0 ) we_cemetary/cemtrim2 -121 63 -90.00 1 1 0 0 0 +( 3264 1792 64 ) ( 3456 1792 64 ) ( 3456 1760 64 ) we_cemetary/cemtrim2 -121 63 -90.00 1 1 0 0 0 +( 3072 1760 320 ) ( 3264 1760 320 ) ( 3264 1760 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 3456 1792 320 ) ( 3264 1792 320 ) ( 3264 1792 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 3392 1824 0 ) ( 3392 1760 0 ) ( 3392 1792 64 ) we_cemetary/cemtrim2 192 0 0.00 1 1 0 0 0 +( 3200 1728 0 ) ( 3200 1760 0 ) ( 3200 1744 64 ) we_cemetary/cemtrim2 192 0 0.00 1 1 0 0 0 +} +// brush 723 +{ +( 3264 1744 256 ) ( 3456 1744 256 ) ( 3456 1792 256 ) we_cemetary/fogtrunk -121 63 -90.00 1 1 0 0 0 +( 3264 1792 272 ) ( 3456 1792 272 ) ( 3456 1728 272 ) we_cemetary/fogtrunk -121 63 -90.00 1 1 0 0 0 +( 3456 1744 256 ) ( 3264 1744 256 ) ( 3264 1728 272 ) we_cemetary/fogtrunk -121 63 -90.00 1 1 0 0 0 +( 3456 1792 272 ) ( 3264 1792 272 ) ( 3264 1792 256 ) we_cemetary/fogtrunk -64 0 0.00 1 1 0 0 0 +( 3712 1792 256 ) ( 3712 1728 256 ) ( 3712 1760 272 ) we_cemetary/fogtrunk 192 0 0.00 1 1 0 0 0 +( 3200 1728 256 ) ( 3200 1760 256 ) ( 3200 1744 272 ) we_cemetary/fogtrunk 192 0 0.00 1 1 0 0 0 +} +// brush 724 +{ +( 3456 1728 272 ) ( 3456 1760 272 ) ( 3264 1760 272 ) we_cemetary/cemrunner2 0 31 -90.00 1 1 0 0 0 +( 3264 1760 336 ) ( 3456 1760 336 ) ( 3456 1728 336 ) we_cemetary/cemtrim2 -153 63 -90.00 1 1 0 0 0 +( 3264 1728 592 ) ( 3456 1728 592 ) ( 3456 1728 272 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( 3456 1792 592 ) ( 3264 1792 592 ) ( 3264 1792 272 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( 3712 1792 272 ) ( 3712 1728 272 ) ( 3712 1760 336 ) we_cemetary/cemtrim2 192 16 0.00 1 1 0 0 0 +( 3200 1728 272 ) ( 3200 1760 272 ) ( 3200 1744 336 ) we_cemetary/cemtrim2 192 16 0.00 1 1 0 0 0 +} +// brush 725 +{ +( 3680 2272 -32 ) ( 3232 2272 -32 ) ( 3232 1824 -32 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 3232 1824 0 ) ( 3232 2272 0 ) ( 3680 2272 0 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 3232 1760 0 ) ( 3680 1760 0 ) ( 3680 1760 -64 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 3712 1824 0 ) ( 3712 2272 0 ) ( 3712 2272 -64 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 3680 2304 0 ) ( 3232 2304 0 ) ( 3232 2304 -64 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 3200 2272 0 ) ( 3200 1824 0 ) ( 3200 1824 -64 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +} +// brush 726 +{ +( 3680 2272 336 ) ( 3232 2272 336 ) ( 3232 1824 336 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +( 3232 1824 352 ) ( 3232 2272 352 ) ( 3680 2272 352 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +( 3232 1824 368 ) ( 3680 1824 368 ) ( 3680 1824 304 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +( 3680 1824 368 ) ( 3680 2272 368 ) ( 3680 2272 304 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +( 3680 2272 368 ) ( 3232 2272 368 ) ( 3232 2272 304 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +( 3232 2272 368 ) ( 3232 1824 368 ) ( 3232 1824 304 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +} +// brush 727 +{ +( 3520 1840 208 ) ( 3392 1840 208 ) ( 3392 1744 208 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 3392 1744 256 ) ( 3392 1840 256 ) ( 3520 1840 256 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 3392 1744 256 ) ( 3520 1744 256 ) ( 3520 1744 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 3520 1744 240 ) ( 3520 1840 240 ) ( 3520 1840 48 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +( 3520 1840 240 ) ( 3392 1840 240 ) ( 3392 1840 48 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 3392 1840 256 ) ( 3392 1744 256 ) ( 3392 1744 64 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +} +// brush 728 +{ +( 3008 1840 208 ) ( 2880 1840 208 ) ( 2880 1744 208 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 2880 1744 256 ) ( 2880 1840 256 ) ( 3008 1840 256 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 2880 1744 256 ) ( 3008 1744 256 ) ( 3008 1744 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 3008 1744 240 ) ( 3008 1840 240 ) ( 3008 1840 48 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +( 3008 1840 240 ) ( 2880 1840 240 ) ( 2880 1840 48 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 2880 1840 256 ) ( 2880 1744 256 ) ( 2880 1744 64 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +} +// brush 729 +{ +( 3168 2272 336 ) ( 2720 2272 336 ) ( 2720 1824 336 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +( 2720 1824 352 ) ( 2720 2272 352 ) ( 3168 2272 352 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +( 2720 1824 368 ) ( 3168 1824 368 ) ( 3168 1824 304 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +( 3168 1824 368 ) ( 3168 2272 368 ) ( 3168 2272 304 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +( 3168 2272 368 ) ( 2720 2272 368 ) ( 2720 2272 304 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +( 2720 2272 368 ) ( 2720 1824 368 ) ( 2720 1824 304 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +} +// brush 730 +{ +( 3168 2272 -32 ) ( 2720 2272 -32 ) ( 2720 1824 -32 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 2720 1824 0 ) ( 2720 2272 0 ) ( 3168 2272 0 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 2720 1760 0 ) ( 3168 1760 0 ) ( 3168 1760 -64 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 3200 1824 0 ) ( 3200 2272 0 ) ( 3200 2272 -64 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 3168 2304 0 ) ( 2720 2304 0 ) ( 2720 2304 -64 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 2688 2272 0 ) ( 2688 1824 0 ) ( 2688 1824 -64 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +} +// brush 731 +{ +( 2944 1728 272 ) ( 2944 1760 272 ) ( 2752 1760 272 ) we_cemetary/cemrunner2 0 -1 -90.00 1 1 0 0 0 +( 2752 1760 336 ) ( 2944 1760 336 ) ( 2944 1728 336 ) we_cemetary/cemtrim2 -153 -1 -90.00 1 1 0 0 0 +( 2752 1728 592 ) ( 2944 1728 592 ) ( 2944 1728 272 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( 2944 1792 592 ) ( 2752 1792 592 ) ( 2752 1792 272 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( 3200 1792 272 ) ( 3200 1728 272 ) ( 3200 1760 336 ) we_cemetary/cemtrim2 192 16 0.00 1 1 0 0 0 +( 2688 1728 272 ) ( 2688 1760 272 ) ( 2688 1744 336 ) we_cemetary/cemtrim2 192 16 0.00 1 1 0 0 0 +} +// brush 732 +{ +( 2752 1744 256 ) ( 2944 1744 256 ) ( 2944 1792 256 ) we_cemetary/fogtrunk -121 63 -90.00 1 1 0 0 0 +( 2752 1792 272 ) ( 2944 1792 272 ) ( 2944 1728 272 ) we_cemetary/fogtrunk -121 63 -90.00 1 1 0 0 0 +( 2944 1744 256 ) ( 2752 1744 256 ) ( 2752 1728 272 ) we_cemetary/fogtrunk -121 63 -90.00 1 1 0 0 0 +( 2944 1792 272 ) ( 2752 1792 272 ) ( 2752 1792 256 ) we_cemetary/fogtrunk -64 0 0.00 1 1 0 0 0 +( 3200 1792 256 ) ( 3200 1728 256 ) ( 3200 1760 272 ) we_cemetary/fogtrunk 192 0 0.00 1 1 0 0 0 +( 2688 1728 256 ) ( 2688 1760 256 ) ( 2688 1744 272 ) we_cemetary/fogtrunk 192 0 0.00 1 1 0 0 0 +} +// brush 733 +{ +( 2944 1760 0 ) ( 2944 1792 0 ) ( 2752 1792 0 ) we_cemetary/cemtrim2 -121 -1 -90.00 1 1 0 0 0 +( 2752 1792 64 ) ( 2944 1792 64 ) ( 2944 1760 64 ) we_cemetary/cemtrim2 -121 -1 -90.00 1 1 0 0 0 +( 2560 1760 320 ) ( 2752 1760 320 ) ( 2752 1760 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 2944 1792 320 ) ( 2752 1792 320 ) ( 2752 1792 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 2880 1824 0 ) ( 2880 1760 0 ) ( 2880 1792 64 ) we_cemetary/cemtrim2 192 0 0.00 1 1 0 0 0 +( 2688 1728 0 ) ( 2688 1760 0 ) ( 2688 1744 64 ) we_cemetary/cemtrim2 192 0 0.00 1 1 0 0 0 +} +// brush 734 +{ +( 2944 1760 64 ) ( 2944 1792 64 ) ( 2752 1792 64 ) we_cemetary/cemstair2 -121 -1 -90.00 1 1 0 0 0 +( 2944 1792 384 ) ( 2752 1792 384 ) ( 2752 1792 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 2752 1744 96 ) ( 2944 1752 80 ) ( 2752 1760 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 2944 1728 256 ) ( 2752 1728 256 ) ( 2752 1792 256 ) we_cemetary/cemstair2 -121 -1 -90.00 1 1 0 0 0 +( 2752 1744 208 ) ( 2944 1744 176 ) ( 2752 1744 144 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 2880 1824 64 ) ( 2880 1760 64 ) ( 2880 1792 256 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +( 2688 1728 64 ) ( 2688 1760 64 ) ( 2688 1744 256 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +} +// brush 735 +{ +( 2944 1760 0 ) ( 2944 1792 0 ) ( 2752 1792 0 ) we_cemetary/cemtrim2 -121 -1 -90.00 1 1 0 0 0 +( 2752 1792 64 ) ( 2944 1792 64 ) ( 2944 1760 64 ) we_cemetary/cemtrim2 -121 -1 -90.00 1 1 0 0 0 +( 2848 1760 320 ) ( 3040 1760 320 ) ( 3040 1760 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 2944 1792 320 ) ( 2752 1792 320 ) ( 2752 1792 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 3008 1760 0 ) ( 3008 1824 0 ) ( 3008 1792 64 ) we_cemetary/cemtrim2 192 0 0.00 1 1 0 0 0 +( 3200 1792 0 ) ( 3200 1728 0 ) ( 3200 1760 64 ) we_cemetary/cemtrim2 192 0 0.00 1 1 0 0 0 +} +// brush 736 +{ +( 2944 1760 64 ) ( 2944 1792 64 ) ( 2752 1792 64 ) we_cemetary/cemstair2 -121 -1 -90.00 1 1 0 0 0 +( 2944 1792 384 ) ( 2752 1792 384 ) ( 2752 1792 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 2752 1744 96 ) ( 2944 1752 80 ) ( 2752 1760 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 2944 1728 256 ) ( 2752 1728 256 ) ( 2752 1792 256 ) we_cemetary/cemstair2 -121 -1 -90.00 1 1 0 0 0 +( 2848 1744 208 ) ( 3040 1744 176 ) ( 2848 1744 144 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 3008 1760 64 ) ( 3008 1824 64 ) ( 3008 1792 256 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +( 3200 1792 64 ) ( 3200 1728 64 ) ( 3200 1760 256 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +} +// brush 737 +{ +( 2752 1792 64 ) ( 2944 1792 64 ) ( 2944 1824 64 ) we_cemetary/cemstair2 -55 -1 -90.00 1 1 0 0 0 +( 2752 1792 64 ) ( 2752 1792 384 ) ( 2944 1792 384 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 2752 1824 64 ) ( 2944 1832 80 ) ( 2752 1840 96 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 2752 1792 256 ) ( 2752 1856 256 ) ( 2944 1856 256 ) we_cemetary/cemstair2 -55 -1 -90.00 1 1 0 0 0 +( 2880 1840 144 ) ( 3072 1840 176 ) ( 2880 1840 208 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 3184 1808 256 ) ( 3168 1824 64 ) ( 3200 1792 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 3008 1760 64 ) ( 3008 1824 64 ) ( 3008 1792 256 ) we_cemetary/cemstair2 128 0 0.00 1 1 0 0 0 +} +// brush 738 +{ +( 2752 1792 64 ) ( 2944 1792 64 ) ( 2944 1824 64 ) we_cemetary/cemstair2 -55 -1 -90.00 1 1 0 0 0 +( 2752 1792 64 ) ( 2752 1792 384 ) ( 2944 1792 384 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 2752 1824 64 ) ( 2944 1832 80 ) ( 2752 1840 96 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 2752 1792 256 ) ( 2752 1856 256 ) ( 2944 1856 256 ) we_cemetary/cemstair2 -55 -1 -90.00 1 1 0 0 0 +( 2752 1840 144 ) ( 2944 1840 176 ) ( 2752 1840 208 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 2688 1792 64 ) ( 2720 1824 64 ) ( 2704 1808 256 ) we_cemetary/cemstair2 128 0 0.00 1 1 0 0 0 +( 2880 1824 64 ) ( 2880 1760 64 ) ( 2880 1792 256 ) we_cemetary/cemstair2 128 0 0.00 1 1 0 0 0 +} +// brush 739 +{ +( 2752 1792 0 ) ( 2944 1792 0 ) ( 2944 1824 0 ) we_cemetary/cemtrim2 -55 -1 -90.00 1 1 0 0 0 +( 2944 1824 64 ) ( 2944 1792 64 ) ( 2752 1792 64 ) we_cemetary/cemtrim2 -55 -1 -90.00 1 1 0 0 0 +( 2944 1824 0 ) ( 2944 1824 320 ) ( 2752 1824 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 2752 1792 0 ) ( 2752 1792 320 ) ( 2944 1792 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 3184 1808 64 ) ( 3168 1824 0 ) ( 3200 1792 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( 3008 1760 0 ) ( 3008 1824 0 ) ( 3008 1792 64 ) we_cemetary/cemtrim2 128 0 0.00 1 1 0 0 0 +} +// brush 740 +{ +( 2752 1792 0 ) ( 2944 1792 0 ) ( 2944 1824 0 ) we_cemetary/cemtrim2 -55 -1 -90.00 1 1 0 0 0 +( 2944 1824 64 ) ( 2944 1792 64 ) ( 2752 1792 64 ) we_cemetary/cemtrim2 -55 -1 -90.00 1 1 0 0 0 +( 2816 1824 0 ) ( 2816 1824 320 ) ( 2624 1824 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 2752 1792 0 ) ( 2752 1792 320 ) ( 2944 1792 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 2688 1792 0 ) ( 2720 1824 0 ) ( 2704 1808 64 ) we_cemetary/cemtrim2 128 0 0.00 1 1 0 0 0 +( 2880 1824 0 ) ( 2880 1760 0 ) ( 2880 1792 64 ) we_cemetary/cemtrim2 128 0 0.00 1 1 0 0 0 +} +// brush 741 +{ +( 2720 2048 0 ) ( 2688 2048 0 ) ( 2688 1856 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( 2688 1856 64 ) ( 2688 2048 64 ) ( 2720 2048 64 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( 2720 1792 320 ) ( 2720 1984 320 ) ( 2720 1984 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( 2688 2048 320 ) ( 2688 1856 320 ) ( 2688 1856 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( 2688 2304 0 ) ( 2720 2272 0 ) ( 2704 2288 64 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( 2752 1856 0 ) ( 2720 1824 0 ) ( 2736 1840 64 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +} +// brush 742 +{ +( 2720 2048 64 ) ( 2688 2048 64 ) ( 2688 1856 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 2688 2048 384 ) ( 2688 1856 384 ) ( 2688 1856 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 2736 1856 96 ) ( 2728 2048 80 ) ( 2720 1856 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 2752 2048 256 ) ( 2752 1856 256 ) ( 2688 1856 256 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 2736 1856 208 ) ( 2736 2048 176 ) ( 2736 1856 144 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 2688 2304 64 ) ( 2720 2272 64 ) ( 2704 2288 256 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 2752 1856 64 ) ( 2720 1824 64 ) ( 2736 1840 256 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +} +// brush 743 +{ +( 2736 1856 256 ) ( 2736 2048 256 ) ( 2688 2048 256 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +( 2688 1856 272 ) ( 2688 2048 272 ) ( 2752 2048 272 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +( 2736 2048 256 ) ( 2736 1856 256 ) ( 2752 1856 272 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +( 2688 2048 272 ) ( 2688 1856 272 ) ( 2688 1856 256 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +( 2688 2304 256 ) ( 2720 2272 256 ) ( 2704 2288 272 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +( 2752 1856 256 ) ( 2720 1824 256 ) ( 2736 1840 272 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +} +// brush 744 +{ +( 2752 2048 272 ) ( 2720 2048 272 ) ( 2720 1856 272 ) we_cemetary/cemrunner2 0 0 0.00 1 1 0 0 0 +( 2720 1856 336 ) ( 2720 2048 336 ) ( 2752 2048 336 ) we_cemetary/cemtrim2 -32 0 0.00 1 1 0 0 0 +( 2752 1856 592 ) ( 2752 2048 592 ) ( 2752 2048 272 ) we_cemetary/cemtrim2 0 16 0.00 1 1 0 0 0 +( 2688 2048 592 ) ( 2688 1856 592 ) ( 2688 1856 272 ) we_cemetary/cemtrim2 0 16 0.00 1 1 0 0 0 +( 2688 2304 272 ) ( 2720 2272 272 ) ( 2704 2288 336 ) we_cemetary/cemtrim2 0 16 0.00 1 1 0 0 0 +( 2752 1856 272 ) ( 2720 1824 272 ) ( 2736 1840 336 ) we_cemetary/cemtrim2 0 16 0.00 1 1 0 0 0 +} +// brush 745 +{ +( 2944 1792 256 ) ( 2944 1840 256 ) ( 2752 1840 256 ) we_cemetary/fogtrunk -55 63 -90.00 1 1 0 0 0 +( 2944 1856 272 ) ( 2944 1792 272 ) ( 2752 1792 272 ) we_cemetary/fogtrunk -55 63 -90.00 1 1 0 0 0 +( 2752 1856 272 ) ( 2752 1840 256 ) ( 2944 1840 256 ) we_cemetary/fogtrunk -55 63 -90.00 1 1 0 0 0 +( 2752 1792 256 ) ( 2752 1792 272 ) ( 2944 1792 272 ) we_cemetary/fogtrunk -64 0 0.00 1 1 0 0 0 +( 3184 1808 272 ) ( 3168 1824 256 ) ( 3200 1792 256 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +( 2688 1792 256 ) ( 2720 1824 256 ) ( 2704 1808 272 ) we_cemetary/fogtrunk 128 0 0.00 1 1 0 0 0 +} +// brush 746 +{ +( 2752 1824 272 ) ( 2944 1824 272 ) ( 2944 1856 272 ) we_cemetary/cemrunner2 -55 -1 -90.00 1 1 0 0 0 +( 2944 1856 336 ) ( 2944 1824 336 ) ( 2752 1824 336 ) we_cemetary/cemtrim2 -89 -1 -90.00 1 1 0 0 0 +( 2944 1856 272 ) ( 2944 1856 592 ) ( 2752 1856 592 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( 2752 1792 272 ) ( 2752 1792 592 ) ( 2944 1792 592 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( 3184 1808 336 ) ( 3168 1824 272 ) ( 3200 1792 272 ) we_cemetary/cemtrim2 0 15 0.00 1 1 0 0 0 +( 2688 1792 272 ) ( 2720 1824 272 ) ( 2704 1808 336 ) we_cemetary/cemtrim2 128 16 0.00 1 1 0 0 0 +} +// brush 747 +{ +( 3168 1856 272 ) ( 3168 2048 272 ) ( 3136 2048 272 ) we_cemetary/cemrunner2 63 0 -180.00 1 1 0 0 0 +( 3136 2048 336 ) ( 3168 2048 336 ) ( 3168 1856 336 ) we_cemetary/cemtrim2 159 0 -180.00 1 1 0 0 0 +( 3136 2048 272 ) ( 3136 2048 592 ) ( 3136 1856 592 ) we_cemetary/cemtrim2 64 15 -180.00 1 -1 0 0 0 +( 3200 1856 272 ) ( 3200 1856 592 ) ( 3200 2048 592 ) we_cemetary/cemtrim2 64 15 -180.00 1 -1 0 0 0 +( 3184 2288 336 ) ( 3168 2272 272 ) ( 3200 2304 272 ) we_cemetary/cemtrim2 128 15 0.00 1 1 0 0 0 +( 3200 1792 272 ) ( 3168 1824 272 ) ( 3184 1808 336 ) we_cemetary/cemtrim2 0 16 -180.00 1 -1 0 0 0 +} +// brush 748 +{ +( 3200 2048 256 ) ( 3152 2048 256 ) ( 3152 1856 256 ) we_cemetary/fogtrunk 191 -64 -180.00 1 1 0 0 0 +( 3136 2048 272 ) ( 3200 2048 272 ) ( 3200 1856 272 ) we_cemetary/fogtrunk 191 -64 -180.00 1 1 0 0 0 +( 3136 1856 272 ) ( 3152 1856 256 ) ( 3152 2048 256 ) we_cemetary/fogtrunk 191 -64 -180.00 1 1 0 0 0 +( 3200 1856 256 ) ( 3200 1856 272 ) ( 3200 2048 272 ) we_cemetary/fogtrunk 64 0 -180.00 1 -1 0 0 0 +( 3184 2288 272 ) ( 3168 2272 256 ) ( 3200 2304 256 ) we_cemetary/fogtrunk 128 0 0.00 1 1 0 0 0 +( 3200 1792 256 ) ( 3168 1824 256 ) ( 3184 1808 272 ) we_cemetary/fogtrunk 0 0 -180.00 1 -1 0 0 0 +} +// brush 749 +{ +( 3200 1856 64 ) ( 3200 2048 64 ) ( 3168 2048 64 ) we_cemetary/cemstair2 191 0 -180.00 1 1 0 0 0 +( 3200 1856 64 ) ( 3200 1856 384 ) ( 3200 2048 384 ) we_cemetary/cemstair2 64 0 -180.00 1 -1 0 0 0 +( 3168 1856 64 ) ( 3160 2048 80 ) ( 3152 1856 96 ) we_cemetary/cemstair2 64 0 -180.00 1 -1 0 0 0 +( 3200 1856 256 ) ( 3136 1856 256 ) ( 3136 2048 256 ) we_cemetary/cemstair2 191 0 -180.00 1 1 0 0 0 +( 3152 1856 144 ) ( 3152 2048 176 ) ( 3152 1856 208 ) we_cemetary/cemstair2 64 0 -180.00 1 -1 0 0 0 +( 3184 2288 256 ) ( 3168 2272 64 ) ( 3200 2304 64 ) we_cemetary/cemstair2 128 0 0.00 1 1 0 0 0 +( 3200 1792 64 ) ( 3168 1824 64 ) ( 3184 1808 256 ) we_cemetary/cemstair2 0 0 -180.00 1 -1 0 0 0 +} +// brush 750 +{ +( 3200 1856 0 ) ( 3200 2048 0 ) ( 3168 2048 0 ) we_cemetary/cemtrim2 191 0 -180.00 1 1 0 0 0 +( 3168 2048 64 ) ( 3200 2048 64 ) ( 3200 1856 64 ) we_cemetary/cemtrim2 191 0 -180.00 1 1 0 0 0 +( 3168 1920 0 ) ( 3168 1920 320 ) ( 3168 1728 320 ) we_cemetary/cemtrim2 64 0 -180.00 1 -1 0 0 0 +( 3200 1856 0 ) ( 3200 1856 320 ) ( 3200 2048 320 ) we_cemetary/cemtrim2 64 0 -180.00 1 -1 0 0 0 +( 3184 2288 64 ) ( 3168 2272 0 ) ( 3200 2304 0 ) we_cemetary/cemtrim2 128 0 0.00 1 1 0 0 0 +( 3200 1792 0 ) ( 3168 1824 0 ) ( 3184 1808 64 ) we_cemetary/cemtrim2 0 0 -180.00 1 -1 0 0 0 +} +// brush 751 +{ +( 3136 2304 0 ) ( 2944 2304 0 ) ( 2944 2272 0 ) we_cemetary/cemtrim2 -54 0 90.00 1 1 0 0 0 +( 2944 2272 64 ) ( 2944 2304 64 ) ( 3136 2304 64 ) we_cemetary/cemtrim2 -54 0 90.00 1 1 0 0 0 +( 3008 2272 0 ) ( 3008 2272 320 ) ( 3200 2272 320 ) we_cemetary/cemtrim2 128 0 -180.00 1 -1 0 0 0 +( 3136 2304 0 ) ( 3136 2304 320 ) ( 2944 2304 320 ) we_cemetary/cemtrim2 128 0 -180.00 1 -1 0 0 0 +( 2704 2288 64 ) ( 2720 2272 0 ) ( 2688 2304 0 ) we_cemetary/cemtrim2 192 0 -180.00 1 -1 0 0 0 +( 3200 2304 0 ) ( 3168 2272 0 ) ( 3184 2288 64 ) we_cemetary/cemtrim2 192 0 -180.00 1 -1 0 0 0 +} +// brush 752 +{ +( 3136 2304 64 ) ( 2944 2304 64 ) ( 2944 2272 64 ) we_cemetary/cemstair2 -54 0 90.00 1 1 0 0 0 +( 3136 2304 64 ) ( 3136 2304 384 ) ( 2944 2304 384 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +( 3136 2272 64 ) ( 2944 2264 80 ) ( 3136 2256 96 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +( 3136 2304 256 ) ( 3136 2240 256 ) ( 2944 2240 256 ) we_cemetary/cemstair2 -54 0 90.00 1 1 0 0 0 +( 3136 2256 144 ) ( 2944 2256 176 ) ( 3136 2256 208 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +( 2704 2288 256 ) ( 2720 2272 64 ) ( 2688 2304 64 ) we_cemetary/cemstair2 192 0 -180.00 1 -1 0 0 0 +( 3200 2304 64 ) ( 3168 2272 64 ) ( 3184 2288 256 ) we_cemetary/cemstair2 192 0 -180.00 1 -1 0 0 0 +} +// brush 753 +{ +( 2944 2304 256 ) ( 2944 2256 256 ) ( 3136 2256 256 ) we_cemetary/fogtrunk -54 -128 90.00 1 1 0 0 0 +( 2944 2240 272 ) ( 2944 2304 272 ) ( 3136 2304 272 ) we_cemetary/fogtrunk -54 -128 90.00 1 1 0 0 0 +( 3136 2240 272 ) ( 3136 2256 256 ) ( 2944 2256 256 ) we_cemetary/fogtrunk -54 -128 90.00 1 1 0 0 0 +( 3136 2304 256 ) ( 3136 2304 272 ) ( 2944 2304 272 ) we_cemetary/fogtrunk 128 0 -180.00 1 -1 0 0 0 +( 2704 2288 272 ) ( 2720 2272 256 ) ( 2688 2304 256 ) we_cemetary/fogtrunk 192 0 -180.00 1 -1 0 0 0 +( 3200 2304 256 ) ( 3168 2272 256 ) ( 3184 2288 272 ) we_cemetary/fogtrunk 192 0 -180.00 1 -1 0 0 0 +} +// brush 754 +{ +( 3136 2272 272 ) ( 2944 2272 272 ) ( 2944 2240 272 ) we_cemetary/cemrunner2 -54 4 90.00 1 1.000122 0 0 0 +( 2944 2240 336 ) ( 2944 2272 336 ) ( 3136 2272 336 ) we_cemetary/cemtrim2 -86 0 90.00 1 1 0 0 0 +( 2944 2240 272 ) ( 2944 2240 592 ) ( 3136 2240 592 ) we_cemetary/cemtrim2 128 15 -180.00 1 -1 0 0 0 +( 3136 2304 272 ) ( 3136 2304 592 ) ( 2944 2304 592 ) we_cemetary/cemtrim2 128 15 -180.00 1 -1 0 0 0 +( 2704 2288 336 ) ( 2720 2272 272 ) ( 2688 2304 272 ) we_cemetary/cemtrim2 192 16 -180.00 1 -1 0 0 0 +( 3200 2304 272 ) ( 3168 2272 272 ) ( 3184 2288 336 ) we_cemetary/cemtrim2 192 16 -180.00 1 -1 0 0 0 +} +// brush 755 +{ +( 2624 2272 272 ) ( 2432 2272 272 ) ( 2432 2240 272 ) we_cemetary/cemrunner2 -55 -28 90.00 1 1.000122 0 0 0 +( 2432 2240 336 ) ( 2432 2272 336 ) ( 2624 2272 336 ) we_cemetary/cemtrim2 -87 0 90.00 1 1 0 0 0 +( 2432 2240 272 ) ( 2432 2240 592 ) ( 2624 2240 592 ) we_cemetary/cemtrim2 128 15 -180.00 1 -1 0 0 0 +( 2624 2304 272 ) ( 2624 2304 592 ) ( 2432 2304 592 ) we_cemetary/cemtrim2 128 15 -180.00 1 -1 0 0 0 +( 2192 2288 336 ) ( 2208 2272 272 ) ( 2176 2304 272 ) we_cemetary/cemtrim2 192 16 -180.00 1 -1 0 0 0 +( 2688 2304 272 ) ( 2656 2272 272 ) ( 2672 2288 336 ) we_cemetary/cemtrim2 192 16 -180.00 1 -1 0 0 0 +} +// brush 756 +{ +( 2432 2304 256 ) ( 2432 2256 256 ) ( 2624 2256 256 ) we_cemetary/fogtrunk -55 -128 90.00 1 1 0 0 0 +( 2432 2240 272 ) ( 2432 2304 272 ) ( 2624 2304 272 ) we_cemetary/fogtrunk -55 -128 90.00 1 1 0 0 0 +( 2624 2240 272 ) ( 2624 2256 256 ) ( 2432 2256 256 ) we_cemetary/fogtrunk -55 -128 90.00 1 1 0 0 0 +( 2624 2304 256 ) ( 2624 2304 272 ) ( 2432 2304 272 ) we_cemetary/fogtrunk 128 0 -180.00 1 -1 0 0 0 +( 2192 2288 272 ) ( 2208 2272 256 ) ( 2176 2304 256 ) we_cemetary/fogtrunk 192 0 -180.00 1 -1 0 0 0 +( 2688 2304 256 ) ( 2656 2272 256 ) ( 2672 2288 272 ) we_cemetary/fogtrunk 192 0 -180.00 1 -1 0 0 0 +} +// brush 757 +{ +( 2624 2304 64 ) ( 2432 2304 64 ) ( 2432 2272 64 ) we_cemetary/cemstair2 -55 0 90.00 1 1 0 0 0 +( 2624 2304 64 ) ( 2624 2304 384 ) ( 2432 2304 384 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +( 2624 2272 64 ) ( 2432 2264 80 ) ( 2624 2256 96 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +( 2624 2304 256 ) ( 2624 2240 256 ) ( 2432 2240 256 ) we_cemetary/cemstair2 -55 0 90.00 1 1 0 0 0 +( 2624 2256 144 ) ( 2432 2256 176 ) ( 2624 2256 208 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +( 2192 2288 256 ) ( 2208 2272 64 ) ( 2176 2304 64 ) we_cemetary/cemstair2 192 0 -180.00 1 -1 0 0 0 +( 2688 2304 64 ) ( 2656 2272 64 ) ( 2672 2288 256 ) we_cemetary/cemstair2 192 0 -180.00 1 -1 0 0 0 +} +// brush 758 +{ +( 2624 2304 0 ) ( 2432 2304 0 ) ( 2432 2272 0 ) we_cemetary/cemtrim2 -55 0 90.00 1 1 0 0 0 +( 2432 2272 64 ) ( 2432 2304 64 ) ( 2624 2304 64 ) we_cemetary/cemtrim2 -55 0 90.00 1 1 0 0 0 +( 2496 2272 0 ) ( 2496 2272 320 ) ( 2688 2272 320 ) we_cemetary/cemtrim2 128 0 -180.00 1 -1 0 0 0 +( 2624 2304 0 ) ( 2624 2304 320 ) ( 2432 2304 320 ) we_cemetary/cemtrim2 128 0 -180.00 1 -1 0 0 0 +( 2192 2288 64 ) ( 2208 2272 0 ) ( 2176 2304 0 ) we_cemetary/cemtrim2 192 0 -180.00 1 -1 0 0 0 +( 2688 2304 0 ) ( 2656 2272 0 ) ( 2672 2288 64 ) we_cemetary/cemtrim2 192 0 -180.00 1 -1 0 0 0 +} +// brush 759 +{ +( 2688 1856 0 ) ( 2688 2048 0 ) ( 2656 2048 0 ) we_cemetary/cemtrim2 191 0 -180.00 1 1 0 0 0 +( 2656 2048 64 ) ( 2688 2048 64 ) ( 2688 1856 64 ) we_cemetary/cemtrim2 191 0 -180.00 1 1 0 0 0 +( 2656 1920 0 ) ( 2656 1920 320 ) ( 2656 1728 320 ) we_cemetary/cemtrim2 64 0 -180.00 1 -1 0 0 0 +( 2688 1856 0 ) ( 2688 1856 320 ) ( 2688 2048 320 ) we_cemetary/cemtrim2 64 0 -180.00 1 -1 0 0 0 +( 2672 2288 64 ) ( 2656 2272 0 ) ( 2688 2304 0 ) we_cemetary/cemtrim2 128 0 0.00 1 1 0 0 0 +( 2688 1792 0 ) ( 2656 1824 0 ) ( 2672 1808 64 ) we_cemetary/cemtrim2 0 0 -180.00 1 -1 0 0 0 +} +// brush 760 +{ +( 2688 1856 64 ) ( 2688 2048 64 ) ( 2656 2048 64 ) we_cemetary/cemstair2 191 0 -180.00 1 1 0 0 0 +( 2688 1856 64 ) ( 2688 1856 384 ) ( 2688 2048 384 ) we_cemetary/cemstair2 64 0 -180.00 1 -1 0 0 0 +( 2656 1856 64 ) ( 2648 2048 80 ) ( 2640 1856 96 ) we_cemetary/cemstair2 64 0 -180.00 1 -1 0 0 0 +( 2688 1856 256 ) ( 2624 1856 256 ) ( 2624 2048 256 ) we_cemetary/cemstair2 191 0 -180.00 1 1 0 0 0 +( 2640 1856 144 ) ( 2640 2048 176 ) ( 2640 1856 208 ) we_cemetary/cemstair2 64 0 -180.00 1 -1 0 0 0 +( 2672 2288 256 ) ( 2656 2272 64 ) ( 2688 2304 64 ) we_cemetary/cemstair2 128 0 0.00 1 1 0 0 0 +( 2688 1792 64 ) ( 2656 1824 64 ) ( 2672 1808 256 ) we_cemetary/cemstair2 0 0 -180.00 1 -1 0 0 0 +} +// brush 761 +{ +( 2688 2048 256 ) ( 2640 2048 256 ) ( 2640 1856 256 ) we_cemetary/fogtrunk 191 -64 -180.00 1 1 0 0 0 +( 2624 2048 272 ) ( 2688 2048 272 ) ( 2688 1856 272 ) we_cemetary/fogtrunk 191 -64 -180.00 1 1 0 0 0 +( 2624 1856 272 ) ( 2640 1856 256 ) ( 2640 2048 256 ) we_cemetary/fogtrunk 191 -64 -180.00 1 1 0 0 0 +( 2688 1856 256 ) ( 2688 1856 272 ) ( 2688 2048 272 ) we_cemetary/fogtrunk 64 0 -180.00 1 -1 0 0 0 +( 2672 2288 272 ) ( 2656 2272 256 ) ( 2688 2304 256 ) we_cemetary/fogtrunk 128 0 0.00 1 1 0 0 0 +( 2688 1792 256 ) ( 2656 1824 256 ) ( 2672 1808 272 ) we_cemetary/fogtrunk 0 0 -180.00 1 -1 0 0 0 +} +// brush 762 +{ +( 2656 1856 272 ) ( 2656 2048 272 ) ( 2624 2048 272 ) we_cemetary/cemrunner2 63 0 -180.00 1 1 0 0 0 +( 2624 2048 336 ) ( 2656 2048 336 ) ( 2656 1856 336 ) we_cemetary/cemtrim2 159 0 -180.00 1 1 0 0 0 +( 2624 2048 272 ) ( 2624 2048 592 ) ( 2624 1856 592 ) we_cemetary/cemtrim2 64 15 -180.00 1 -1 0 0 0 +( 2688 1856 272 ) ( 2688 1856 592 ) ( 2688 2048 592 ) we_cemetary/cemtrim2 64 15 -180.00 1 -1 0 0 0 +( 2672 2288 336 ) ( 2656 2272 272 ) ( 2688 2304 272 ) we_cemetary/cemtrim2 128 15 0.00 1 1 0 0 0 +( 2688 1792 272 ) ( 2656 1824 272 ) ( 2672 1808 336 ) we_cemetary/cemtrim2 0 16 -180.00 1 -1 0 0 0 +} +// brush 763 +{ +( 2240 1824 272 ) ( 2432 1824 272 ) ( 2432 1856 272 ) we_cemetary/cemrunner2 -56 31 -90.00 1 1 0 0 0 +( 2432 1856 336 ) ( 2432 1824 336 ) ( 2240 1824 336 ) we_cemetary/cemtrim2 -90 63 -90.00 1 1 0 0 0 +( 2432 1856 272 ) ( 2432 1856 592 ) ( 2240 1856 592 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( 2240 1792 272 ) ( 2240 1792 592 ) ( 2432 1792 592 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( 2672 1808 336 ) ( 2656 1824 272 ) ( 2688 1792 272 ) we_cemetary/cemtrim2 0 15 0.00 1 1 0 0 0 +( 2176 1792 272 ) ( 2208 1824 272 ) ( 2192 1808 336 ) we_cemetary/cemtrim2 128 16 0.00 1 1 0 0 0 +} +// brush 764 +{ +( 2432 1792 256 ) ( 2432 1840 256 ) ( 2240 1840 256 ) we_cemetary/fogtrunk -56 63 -90.00 1 1 0 0 0 +( 2432 1856 272 ) ( 2432 1792 272 ) ( 2240 1792 272 ) we_cemetary/fogtrunk -56 63 -90.00 1 1 0 0 0 +( 2240 1856 272 ) ( 2240 1840 256 ) ( 2432 1840 256 ) we_cemetary/fogtrunk -56 63 -90.00 1 1 0 0 0 +( 2240 1792 256 ) ( 2240 1792 272 ) ( 2432 1792 272 ) we_cemetary/fogtrunk -64 0 0.00 1 1 0 0 0 +( 2672 1808 272 ) ( 2656 1824 256 ) ( 2688 1792 256 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +( 2176 1792 256 ) ( 2208 1824 256 ) ( 2192 1808 272 ) we_cemetary/fogtrunk 128 0 0.00 1 1 0 0 0 +} +// brush 765 +{ +( 2240 2048 272 ) ( 2208 2048 272 ) ( 2208 1856 272 ) we_cemetary/cemrunner2 0 0 0.00 1 1 0 0 0 +( 2208 1856 336 ) ( 2208 2048 336 ) ( 2240 2048 336 ) we_cemetary/cemtrim2 -32 0 0.00 1 1 0 0 0 +( 2240 1856 592 ) ( 2240 2048 592 ) ( 2240 2048 272 ) we_cemetary/cemtrim2 0 16 0.00 1 1 0 0 0 +( 2176 2048 592 ) ( 2176 1856 592 ) ( 2176 1856 272 ) we_cemetary/cemtrim2 0 16 0.00 1 1 0 0 0 +( 2176 2304 272 ) ( 2208 2272 272 ) ( 2192 2288 336 ) we_cemetary/cemtrim2 0 16 0.00 1 1 0 0 0 +( 2240 1856 272 ) ( 2208 1824 272 ) ( 2224 1840 336 ) we_cemetary/cemtrim2 0 16 0.00 1 1 0 0 0 +} +// brush 766 +{ +( 2224 1856 256 ) ( 2224 2048 256 ) ( 2176 2048 256 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +( 2176 1856 272 ) ( 2176 2048 272 ) ( 2240 2048 272 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +( 2224 2048 256 ) ( 2224 1856 256 ) ( 2240 1856 272 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +( 2176 2048 272 ) ( 2176 1856 272 ) ( 2176 1856 256 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +( 2176 2304 256 ) ( 2208 2272 256 ) ( 2192 2288 272 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +( 2240 1856 256 ) ( 2208 1824 256 ) ( 2224 1840 272 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +} +// brush 767 +{ +( 2208 2048 64 ) ( 2176 2048 64 ) ( 2176 1856 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 2176 2048 384 ) ( 2176 1856 384 ) ( 2176 1856 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 2224 1856 96 ) ( 2216 2048 80 ) ( 2208 1856 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 2240 2048 256 ) ( 2240 1856 256 ) ( 2176 1856 256 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 2224 1856 208 ) ( 2224 2048 176 ) ( 2224 1856 144 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 2176 2304 64 ) ( 2208 2272 64 ) ( 2192 2288 256 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 2240 1856 64 ) ( 2208 1824 64 ) ( 2224 1840 256 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +} +// brush 768 +{ +( 2208 2048 0 ) ( 2176 2048 0 ) ( 2176 1856 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( 2176 1856 64 ) ( 2176 2048 64 ) ( 2208 2048 64 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( 2208 1792 320 ) ( 2208 1984 320 ) ( 2208 1984 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( 2176 2048 320 ) ( 2176 1856 320 ) ( 2176 1856 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( 2176 2304 0 ) ( 2208 2272 0 ) ( 2192 2288 64 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( 2240 1856 0 ) ( 2208 1824 0 ) ( 2224 1840 64 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +} +// brush 769 +{ +( 2240 1792 0 ) ( 2432 1792 0 ) ( 2432 1824 0 ) we_cemetary/cemtrim2 -56 63 -90.00 1 1 0 0 0 +( 2432 1824 64 ) ( 2432 1792 64 ) ( 2240 1792 64 ) we_cemetary/cemtrim2 -56 63 -90.00 1 1 0 0 0 +( 2304 1824 0 ) ( 2304 1824 320 ) ( 2112 1824 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 2240 1792 0 ) ( 2240 1792 320 ) ( 2432 1792 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 2176 1792 0 ) ( 2208 1824 0 ) ( 2192 1808 64 ) we_cemetary/cemtrim2 128 0 0.00 1 1 0 0 0 +( 2368 1824 0 ) ( 2368 1760 0 ) ( 2368 1792 64 ) we_cemetary/cemtrim2 128 0 0.00 1 1 0 0 0 +} +// brush 770 +{ +( 2240 1792 0 ) ( 2432 1792 0 ) ( 2432 1824 0 ) we_cemetary/cemtrim2 -56 63 -90.00 1 1 0 0 0 +( 2432 1824 64 ) ( 2432 1792 64 ) ( 2240 1792 64 ) we_cemetary/cemtrim2 -56 63 -90.00 1 1 0 0 0 +( 2432 1824 0 ) ( 2432 1824 320 ) ( 2240 1824 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 2240 1792 0 ) ( 2240 1792 320 ) ( 2432 1792 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 2672 1808 64 ) ( 2656 1824 0 ) ( 2688 1792 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( 2496 1760 0 ) ( 2496 1824 0 ) ( 2496 1792 64 ) we_cemetary/cemtrim2 128 0 0.00 1 1 0 0 0 +} +// brush 771 +{ +( 2240 1792 64 ) ( 2432 1792 64 ) ( 2432 1824 64 ) we_cemetary/cemstair2 -56 63 -90.00 1 1 0 0 0 +( 2240 1792 64 ) ( 2240 1792 384 ) ( 2432 1792 384 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 2240 1824 64 ) ( 2432 1832 80 ) ( 2240 1840 96 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 2240 1792 256 ) ( 2240 1856 256 ) ( 2432 1856 256 ) we_cemetary/cemstair2 -56 63 -90.00 1 1 0 0 0 +( 2240 1840 144 ) ( 2432 1840 176 ) ( 2240 1840 208 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 2176 1792 64 ) ( 2208 1824 64 ) ( 2192 1808 256 ) we_cemetary/cemstair2 128 0 0.00 1 1 0 0 0 +( 2368 1824 64 ) ( 2368 1760 64 ) ( 2368 1792 256 ) we_cemetary/cemstair2 128 0 0.00 1 1 0 0 0 +} +// brush 772 +{ +( 2240 1792 64 ) ( 2432 1792 64 ) ( 2432 1824 64 ) we_cemetary/cemstair2 -56 63 -90.00 1 1 0 0 0 +( 2240 1792 64 ) ( 2240 1792 384 ) ( 2432 1792 384 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 2240 1824 64 ) ( 2432 1832 80 ) ( 2240 1840 96 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 2240 1792 256 ) ( 2240 1856 256 ) ( 2432 1856 256 ) we_cemetary/cemstair2 -56 63 -90.00 1 1 0 0 0 +( 2368 1840 144 ) ( 2560 1840 176 ) ( 2368 1840 208 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 2672 1808 256 ) ( 2656 1824 64 ) ( 2688 1792 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 2496 1760 64 ) ( 2496 1824 64 ) ( 2496 1792 256 ) we_cemetary/cemstair2 128 0 0.00 1 1 0 0 0 +} +// brush 773 +{ +( 2432 1760 64 ) ( 2432 1792 64 ) ( 2240 1792 64 ) we_cemetary/cemstair2 -122 63 -90.00 1 1 0 0 0 +( 2432 1792 384 ) ( 2240 1792 384 ) ( 2240 1792 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 2240 1744 96 ) ( 2432 1752 80 ) ( 2240 1760 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 2432 1728 256 ) ( 2240 1728 256 ) ( 2240 1792 256 ) we_cemetary/cemstair2 -122 63 -90.00 1 1 0 0 0 +( 2336 1744 208 ) ( 2528 1744 176 ) ( 2336 1744 144 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 2496 1760 64 ) ( 2496 1824 64 ) ( 2496 1792 256 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +( 2688 1792 64 ) ( 2688 1728 64 ) ( 2688 1760 256 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +} +// brush 774 +{ +( 2432 1760 0 ) ( 2432 1792 0 ) ( 2240 1792 0 ) we_cemetary/cemtrim2 -122 63 -90.00 1 1 0 0 0 +( 2240 1792 64 ) ( 2432 1792 64 ) ( 2432 1760 64 ) we_cemetary/cemtrim2 -122 63 -90.00 1 1 0 0 0 +( 2336 1760 320 ) ( 2528 1760 320 ) ( 2528 1760 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 2432 1792 320 ) ( 2240 1792 320 ) ( 2240 1792 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 2496 1760 0 ) ( 2496 1824 0 ) ( 2496 1792 64 ) we_cemetary/cemtrim2 192 0 0.00 1 1 0 0 0 +( 2688 1792 0 ) ( 2688 1728 0 ) ( 2688 1760 64 ) we_cemetary/cemtrim2 192 0 0.00 1 1 0 0 0 +} +// brush 775 +{ +( 2432 1760 64 ) ( 2432 1792 64 ) ( 2240 1792 64 ) we_cemetary/cemstair2 -122 63 -90.00 1 1 0 0 0 +( 2432 1792 384 ) ( 2240 1792 384 ) ( 2240 1792 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 2240 1744 96 ) ( 2432 1752 80 ) ( 2240 1760 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 2432 1728 256 ) ( 2240 1728 256 ) ( 2240 1792 256 ) we_cemetary/cemstair2 -122 63 -90.00 1 1 0 0 0 +( 2240 1744 208 ) ( 2432 1744 176 ) ( 2240 1744 144 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 2368 1824 64 ) ( 2368 1760 64 ) ( 2368 1792 256 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +( 2176 1728 64 ) ( 2176 1760 64 ) ( 2176 1744 256 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +} +// brush 776 +{ +( 2432 1760 0 ) ( 2432 1792 0 ) ( 2240 1792 0 ) we_cemetary/cemtrim2 -122 63 -90.00 1 1 0 0 0 +( 2240 1792 64 ) ( 2432 1792 64 ) ( 2432 1760 64 ) we_cemetary/cemtrim2 -122 63 -90.00 1 1 0 0 0 +( 2048 1760 320 ) ( 2240 1760 320 ) ( 2240 1760 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 2432 1792 320 ) ( 2240 1792 320 ) ( 2240 1792 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 2368 1824 0 ) ( 2368 1760 0 ) ( 2368 1792 64 ) we_cemetary/cemtrim2 192 0 0.00 1 1 0 0 0 +( 2176 1728 0 ) ( 2176 1760 0 ) ( 2176 1744 64 ) we_cemetary/cemtrim2 192 0 0.00 1 1 0 0 0 +} +// brush 777 +{ +( 2240 1744 256 ) ( 2432 1744 256 ) ( 2432 1792 256 ) we_cemetary/fogtrunk -122 63 -90.00 1 1 0 0 0 +( 2240 1792 272 ) ( 2432 1792 272 ) ( 2432 1728 272 ) we_cemetary/fogtrunk -122 63 -90.00 1 1 0 0 0 +( 2432 1744 256 ) ( 2240 1744 256 ) ( 2240 1728 272 ) we_cemetary/fogtrunk -122 63 -90.00 1 1 0 0 0 +( 2432 1792 272 ) ( 2240 1792 272 ) ( 2240 1792 256 ) we_cemetary/fogtrunk -64 0 0.00 1 1 0 0 0 +( 2688 1792 256 ) ( 2688 1728 256 ) ( 2688 1760 272 ) we_cemetary/fogtrunk 192 0 0.00 1 1 0 0 0 +( 2176 1728 256 ) ( 2176 1760 256 ) ( 2176 1744 272 ) we_cemetary/fogtrunk 192 0 0.00 1 1 0 0 0 +} +// brush 778 +{ +( 2432 1728 272 ) ( 2432 1760 272 ) ( 2240 1760 272 ) we_cemetary/cemrunner2 0 31 -90.00 1 1 0 0 0 +( 2240 1760 336 ) ( 2432 1760 336 ) ( 2432 1728 336 ) we_cemetary/cemtrim2 -154 63 -90.00 1 1 0 0 0 +( 2240 1728 592 ) ( 2432 1728 592 ) ( 2432 1728 272 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( 2432 1792 592 ) ( 2240 1792 592 ) ( 2240 1792 272 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( 2688 1792 272 ) ( 2688 1728 272 ) ( 2688 1760 336 ) we_cemetary/cemtrim2 192 16 0.00 1 1 0 0 0 +( 2176 1728 272 ) ( 2176 1760 272 ) ( 2176 1744 336 ) we_cemetary/cemtrim2 192 16 0.00 1 1 0 0 0 +} +// brush 779 +{ +( 2656 2272 -32 ) ( 2208 2272 -32 ) ( 2208 1824 -32 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 2208 1824 0 ) ( 2208 2272 0 ) ( 2656 2272 0 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 2208 1760 0 ) ( 2656 1760 0 ) ( 2656 1760 -64 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 2688 1824 0 ) ( 2688 2272 0 ) ( 2688 2272 -64 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 2656 2304 0 ) ( 2208 2304 0 ) ( 2208 2304 -64 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 2176 2272 0 ) ( 2176 1824 0 ) ( 2176 1824 -64 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +} +// brush 780 +{ +( 2656 2272 336 ) ( 2208 2272 336 ) ( 2208 1824 336 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +( 2208 1824 352 ) ( 2208 2272 352 ) ( 2656 2272 352 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +( 2208 1824 368 ) ( 2656 1824 368 ) ( 2656 1824 304 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +( 2656 1824 368 ) ( 2656 2272 368 ) ( 2656 2272 304 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +( 2656 2272 368 ) ( 2208 2272 368 ) ( 2208 2272 304 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +( 2208 2272 368 ) ( 2208 1824 368 ) ( 2208 1824 304 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +} +// brush 781 +{ +( 2496 1840 208 ) ( 2368 1840 208 ) ( 2368 1744 208 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 2368 1744 256 ) ( 2368 1840 256 ) ( 2496 1840 256 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 2368 1744 256 ) ( 2496 1744 256 ) ( 2496 1744 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 2496 1744 240 ) ( 2496 1840 240 ) ( 2496 1840 48 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +( 2496 1840 240 ) ( 2368 1840 240 ) ( 2368 1840 48 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 2368 1840 256 ) ( 2368 1744 256 ) ( 2368 1744 64 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +} +// brush 782 +{ +( 1984 1840 208 ) ( 1856 1840 208 ) ( 1856 1744 208 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 1856 1744 256 ) ( 1856 1840 256 ) ( 1984 1840 256 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 1856 1744 256 ) ( 1984 1744 256 ) ( 1984 1744 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 1984 1744 240 ) ( 1984 1840 240 ) ( 1984 1840 48 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +( 1984 1840 240 ) ( 1856 1840 240 ) ( 1856 1840 48 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 1856 1840 256 ) ( 1856 1744 256 ) ( 1856 1744 64 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +} +// brush 783 +{ +( 2144 2272 336 ) ( 1696 2272 336 ) ( 1696 1824 336 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +( 1696 1824 352 ) ( 1696 2272 352 ) ( 2144 2272 352 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +( 1696 1824 368 ) ( 2144 1824 368 ) ( 2144 1824 304 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +( 2144 1824 368 ) ( 2144 2272 368 ) ( 2144 2272 304 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +( 2144 2272 368 ) ( 1696 2272 368 ) ( 1696 2272 304 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +( 1696 2272 368 ) ( 1696 1824 368 ) ( 1696 1824 304 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +} +// brush 784 +{ +( 2144 2272 -32 ) ( 1696 2272 -32 ) ( 1696 1824 -32 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 1696 1824 0 ) ( 1696 2272 0 ) ( 2144 2272 0 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 1696 1760 0 ) ( 2144 1760 0 ) ( 2144 1760 -64 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 2176 1824 0 ) ( 2176 2272 0 ) ( 2176 2272 -64 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 2144 2304 0 ) ( 1696 2304 0 ) ( 1696 2304 -64 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 1664 2272 0 ) ( 1664 1824 0 ) ( 1664 1824 -64 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +} +// brush 785 +{ +( 1920 1728 272 ) ( 1920 1760 272 ) ( 1728 1760 272 ) we_cemetary/cemrunner2 0 -1 -90.00 1 1 0 0 0 +( 1728 1760 336 ) ( 1920 1760 336 ) ( 1920 1728 336 ) we_cemetary/cemtrim2 -155 -1 -90.00 1 1 0 0 0 +( 1728 1728 592 ) ( 1920 1728 592 ) ( 1920 1728 272 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( 1920 1792 592 ) ( 1728 1792 592 ) ( 1728 1792 272 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( 2176 1792 272 ) ( 2176 1728 272 ) ( 2176 1760 336 ) we_cemetary/cemtrim2 192 16 0.00 1 1 0 0 0 +( 1664 1728 272 ) ( 1664 1760 272 ) ( 1664 1744 336 ) we_cemetary/cemtrim2 192 16 0.00 1 1 0 0 0 +} +// brush 786 +{ +( 1728 1744 256 ) ( 1920 1744 256 ) ( 1920 1792 256 ) we_cemetary/fogtrunk -123 63 -90.00 1 1 0 0 0 +( 1728 1792 272 ) ( 1920 1792 272 ) ( 1920 1728 272 ) we_cemetary/fogtrunk -123 63 -90.00 1 1 0 0 0 +( 1920 1744 256 ) ( 1728 1744 256 ) ( 1728 1728 272 ) we_cemetary/fogtrunk -123 63 -90.00 1 1 0 0 0 +( 1920 1792 272 ) ( 1728 1792 272 ) ( 1728 1792 256 ) we_cemetary/fogtrunk -64 0 0.00 1 1 0 0 0 +( 2176 1792 256 ) ( 2176 1728 256 ) ( 2176 1760 272 ) we_cemetary/fogtrunk 192 0 0.00 1 1 0 0 0 +( 1664 1728 256 ) ( 1664 1760 256 ) ( 1664 1744 272 ) we_cemetary/fogtrunk 192 0 0.00 1 1 0 0 0 +} +// brush 787 +{ +( 1920 1760 0 ) ( 1920 1792 0 ) ( 1728 1792 0 ) we_cemetary/cemtrim2 -123 -1 -90.00 1 1 0 0 0 +( 1728 1792 64 ) ( 1920 1792 64 ) ( 1920 1760 64 ) we_cemetary/cemtrim2 -123 -1 -90.00 1 1 0 0 0 +( 1536 1760 320 ) ( 1728 1760 320 ) ( 1728 1760 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 1920 1792 320 ) ( 1728 1792 320 ) ( 1728 1792 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 1856 1824 0 ) ( 1856 1760 0 ) ( 1856 1792 64 ) we_cemetary/cemtrim2 192 0 0.00 1 1 0 0 0 +( 1664 1728 0 ) ( 1664 1760 0 ) ( 1664 1744 64 ) we_cemetary/cemtrim2 192 0 0.00 1 1 0 0 0 +} +// brush 788 +{ +( 1920 1760 64 ) ( 1920 1792 64 ) ( 1728 1792 64 ) we_cemetary/cemstair2 -123 -1 -90.00 1 1 0 0 0 +( 1920 1792 384 ) ( 1728 1792 384 ) ( 1728 1792 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 1728 1744 96 ) ( 1920 1752 80 ) ( 1728 1760 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 1920 1728 256 ) ( 1728 1728 256 ) ( 1728 1792 256 ) we_cemetary/cemstair2 -123 -1 -90.00 1 1 0 0 0 +( 1728 1744 208 ) ( 1920 1744 176 ) ( 1728 1744 144 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 1856 1824 64 ) ( 1856 1760 64 ) ( 1856 1792 256 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +( 1664 1728 64 ) ( 1664 1760 64 ) ( 1664 1744 256 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +} +// brush 789 +{ +( 1920 1760 0 ) ( 1920 1792 0 ) ( 1728 1792 0 ) we_cemetary/cemtrim2 -123 -1 -90.00 1 1 0 0 0 +( 1728 1792 64 ) ( 1920 1792 64 ) ( 1920 1760 64 ) we_cemetary/cemtrim2 -123 -1 -90.00 1 1 0 0 0 +( 1824 1760 320 ) ( 2016 1760 320 ) ( 2016 1760 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 1920 1792 320 ) ( 1728 1792 320 ) ( 1728 1792 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 1984 1760 0 ) ( 1984 1824 0 ) ( 1984 1792 64 ) we_cemetary/cemtrim2 192 0 0.00 1 1 0 0 0 +( 2176 1792 0 ) ( 2176 1728 0 ) ( 2176 1760 64 ) we_cemetary/cemtrim2 192 0 0.00 1 1 0 0 0 +} +// brush 790 +{ +( 1920 1760 64 ) ( 1920 1792 64 ) ( 1728 1792 64 ) we_cemetary/cemstair2 -123 -1 -90.00 1 1 0 0 0 +( 1920 1792 384 ) ( 1728 1792 384 ) ( 1728 1792 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 1728 1744 96 ) ( 1920 1752 80 ) ( 1728 1760 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 1920 1728 256 ) ( 1728 1728 256 ) ( 1728 1792 256 ) we_cemetary/cemstair2 -123 -1 -90.00 1 1 0 0 0 +( 1824 1744 208 ) ( 2016 1744 176 ) ( 1824 1744 144 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 1984 1760 64 ) ( 1984 1824 64 ) ( 1984 1792 256 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +( 2176 1792 64 ) ( 2176 1728 64 ) ( 2176 1760 256 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +} +// brush 791 +{ +( 1728 1792 64 ) ( 1920 1792 64 ) ( 1920 1824 64 ) we_cemetary/cemstair2 -57 -1 -90.00 1 1 0 0 0 +( 1728 1792 64 ) ( 1728 1792 384 ) ( 1920 1792 384 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 1728 1824 64 ) ( 1920 1832 80 ) ( 1728 1840 96 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 1728 1792 256 ) ( 1728 1856 256 ) ( 1920 1856 256 ) we_cemetary/cemstair2 -57 -1 -90.00 1 1 0 0 0 +( 1856 1840 144 ) ( 2048 1840 176 ) ( 1856 1840 208 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 2160 1808 256 ) ( 2144 1824 64 ) ( 2176 1792 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 1984 1760 64 ) ( 1984 1824 64 ) ( 1984 1792 256 ) we_cemetary/cemstair2 128 0 0.00 1 1 0 0 0 +} +// brush 792 +{ +( 1728 1792 64 ) ( 1920 1792 64 ) ( 1920 1824 64 ) we_cemetary/cemstair2 -57 -1 -90.00 1 1 0 0 0 +( 1728 1792 64 ) ( 1728 1792 384 ) ( 1920 1792 384 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 1728 1824 64 ) ( 1920 1832 80 ) ( 1728 1840 96 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 1728 1792 256 ) ( 1728 1856 256 ) ( 1920 1856 256 ) we_cemetary/cemstair2 -57 -1 -90.00 1 1 0 0 0 +( 1728 1840 144 ) ( 1920 1840 176 ) ( 1728 1840 208 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 1664 1792 64 ) ( 1696 1824 64 ) ( 1680 1808 256 ) we_cemetary/cemstair2 128 0 0.00 1 1 0 0 0 +( 1856 1824 64 ) ( 1856 1760 64 ) ( 1856 1792 256 ) we_cemetary/cemstair2 128 0 0.00 1 1 0 0 0 +} +// brush 793 +{ +( 1728 1792 0 ) ( 1920 1792 0 ) ( 1920 1824 0 ) we_cemetary/cemtrim2 -57 -1 -90.00 1 1 0 0 0 +( 1920 1824 64 ) ( 1920 1792 64 ) ( 1728 1792 64 ) we_cemetary/cemtrim2 -57 -1 -90.00 1 1 0 0 0 +( 1920 1824 0 ) ( 1920 1824 320 ) ( 1728 1824 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 1728 1792 0 ) ( 1728 1792 320 ) ( 1920 1792 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 2160 1808 64 ) ( 2144 1824 0 ) ( 2176 1792 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( 1984 1760 0 ) ( 1984 1824 0 ) ( 1984 1792 64 ) we_cemetary/cemtrim2 128 0 0.00 1 1 0 0 0 +} +// brush 794 +{ +( 1728 1792 0 ) ( 1920 1792 0 ) ( 1920 1824 0 ) we_cemetary/cemtrim2 -57 -1 -90.00 1 1 0 0 0 +( 1920 1824 64 ) ( 1920 1792 64 ) ( 1728 1792 64 ) we_cemetary/cemtrim2 -57 -1 -90.00 1 1 0 0 0 +( 1792 1824 0 ) ( 1792 1824 320 ) ( 1600 1824 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 1728 1792 0 ) ( 1728 1792 320 ) ( 1920 1792 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 1664 1792 0 ) ( 1696 1824 0 ) ( 1680 1808 64 ) we_cemetary/cemtrim2 128 0 0.00 1 1 0 0 0 +( 1856 1824 0 ) ( 1856 1760 0 ) ( 1856 1792 64 ) we_cemetary/cemtrim2 128 0 0.00 1 1 0 0 0 +} +// brush 795 +{ +( 1696 2048 0 ) ( 1664 2048 0 ) ( 1664 1856 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( 1664 1856 64 ) ( 1664 2048 64 ) ( 1696 2048 64 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( 1696 1792 320 ) ( 1696 1984 320 ) ( 1696 1984 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( 1664 2048 320 ) ( 1664 1856 320 ) ( 1664 1856 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( 1664 2304 0 ) ( 1696 2272 0 ) ( 1680 2288 64 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( 1728 1856 0 ) ( 1696 1824 0 ) ( 1712 1840 64 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +} +// brush 796 +{ +( 1696 2048 64 ) ( 1664 2048 64 ) ( 1664 1856 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 1664 2048 384 ) ( 1664 1856 384 ) ( 1664 1856 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 1712 1856 96 ) ( 1704 2048 80 ) ( 1696 1856 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 1728 2048 256 ) ( 1728 1856 256 ) ( 1664 1856 256 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 1712 1856 208 ) ( 1712 2048 176 ) ( 1712 1856 144 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 1664 2304 64 ) ( 1696 2272 64 ) ( 1680 2288 256 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 1728 1856 64 ) ( 1696 1824 64 ) ( 1712 1840 256 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +} +// brush 797 +{ +( 1712 1856 256 ) ( 1712 2048 256 ) ( 1664 2048 256 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +( 1664 1856 272 ) ( 1664 2048 272 ) ( 1728 2048 272 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +( 1712 2048 256 ) ( 1712 1856 256 ) ( 1728 1856 272 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +( 1664 2048 272 ) ( 1664 1856 272 ) ( 1664 1856 256 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +( 1664 2304 256 ) ( 1696 2272 256 ) ( 1680 2288 272 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +( 1728 1856 256 ) ( 1696 1824 256 ) ( 1712 1840 272 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +} +// brush 798 +{ +( 1728 2048 272 ) ( 1696 2048 272 ) ( 1696 1856 272 ) we_cemetary/cemrunner2 0 0 0.00 1 1 0 0 0 +( 1696 1856 336 ) ( 1696 2048 336 ) ( 1728 2048 336 ) we_cemetary/cemtrim2 -32 0 0.00 1 1 0 0 0 +( 1728 1856 592 ) ( 1728 2048 592 ) ( 1728 2048 272 ) we_cemetary/cemtrim2 0 16 0.00 1 1 0 0 0 +( 1664 2048 592 ) ( 1664 1856 592 ) ( 1664 1856 272 ) we_cemetary/cemtrim2 0 16 0.00 1 1 0 0 0 +( 1664 2304 272 ) ( 1696 2272 272 ) ( 1680 2288 336 ) we_cemetary/cemtrim2 0 16 0.00 1 1 0 0 0 +( 1728 1856 272 ) ( 1696 1824 272 ) ( 1712 1840 336 ) we_cemetary/cemtrim2 0 16 0.00 1 1 0 0 0 +} +// brush 799 +{ +( 1920 1792 256 ) ( 1920 1840 256 ) ( 1728 1840 256 ) we_cemetary/fogtrunk -57 63 -90.00 1 1 0 0 0 +( 1920 1856 272 ) ( 1920 1792 272 ) ( 1728 1792 272 ) we_cemetary/fogtrunk -57 63 -90.00 1 1 0 0 0 +( 1728 1856 272 ) ( 1728 1840 256 ) ( 1920 1840 256 ) we_cemetary/fogtrunk -57 63 -90.00 1 1 0 0 0 +( 1728 1792 256 ) ( 1728 1792 272 ) ( 1920 1792 272 ) we_cemetary/fogtrunk -64 0 0.00 1 1 0 0 0 +( 2160 1808 272 ) ( 2144 1824 256 ) ( 2176 1792 256 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +( 1664 1792 256 ) ( 1696 1824 256 ) ( 1680 1808 272 ) we_cemetary/fogtrunk 128 0 0.00 1 1 0 0 0 +} +// brush 800 +{ +( 1728 1824 272 ) ( 1920 1824 272 ) ( 1920 1856 272 ) we_cemetary/cemrunner2 -57 -1 -90.00 1 1 0 0 0 +( 1920 1856 336 ) ( 1920 1824 336 ) ( 1728 1824 336 ) we_cemetary/cemtrim2 -91 -1 -90.00 1 1 0 0 0 +( 1920 1856 272 ) ( 1920 1856 592 ) ( 1728 1856 592 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( 1728 1792 272 ) ( 1728 1792 592 ) ( 1920 1792 592 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( 2160 1808 336 ) ( 2144 1824 272 ) ( 2176 1792 272 ) we_cemetary/cemtrim2 0 15 0.00 1 1 0 0 0 +( 1664 1792 272 ) ( 1696 1824 272 ) ( 1680 1808 336 ) we_cemetary/cemtrim2 128 16 0.00 1 1 0 0 0 +} +// brush 801 +{ +( 2144 1856 272 ) ( 2144 2048 272 ) ( 2112 2048 272 ) we_cemetary/cemrunner2 -65 0 -180.00 1 1 0 0 0 +( 2112 2048 336 ) ( 2144 2048 336 ) ( 2144 1856 336 ) we_cemetary/cemtrim2 159 0 -180.00 1 1 0 0 0 +( 2112 2048 272 ) ( 2112 2048 592 ) ( 2112 1856 592 ) we_cemetary/cemtrim2 64 15 -180.00 1 -1 0 0 0 +( 2176 1856 272 ) ( 2176 1856 592 ) ( 2176 2048 592 ) we_cemetary/cemtrim2 64 15 -180.00 1 -1 0 0 0 +( 2160 2288 336 ) ( 2144 2272 272 ) ( 2176 2304 272 ) we_cemetary/cemtrim2 128 15 0.00 1 1 0 0 0 +( 2176 1792 272 ) ( 2144 1824 272 ) ( 2160 1808 336 ) we_cemetary/cemtrim2 0 16 -180.00 1 -1 0 0 0 +} +// brush 802 +{ +( 2176 2048 256 ) ( 2128 2048 256 ) ( 2128 1856 256 ) we_cemetary/fogtrunk -65 -64 -180.00 1 1 0 0 0 +( 2112 2048 272 ) ( 2176 2048 272 ) ( 2176 1856 272 ) we_cemetary/fogtrunk -65 -64 -180.00 1 1 0 0 0 +( 2112 1856 272 ) ( 2128 1856 256 ) ( 2128 2048 256 ) we_cemetary/fogtrunk -65 -64 -180.00 1 1 0 0 0 +( 2176 1856 256 ) ( 2176 1856 272 ) ( 2176 2048 272 ) we_cemetary/fogtrunk 64 0 -180.00 1 -1 0 0 0 +( 2160 2288 272 ) ( 2144 2272 256 ) ( 2176 2304 256 ) we_cemetary/fogtrunk 128 0 0.00 1 1 0 0 0 +( 2176 1792 256 ) ( 2144 1824 256 ) ( 2160 1808 272 ) we_cemetary/fogtrunk 0 0 -180.00 1 -1 0 0 0 +} +// brush 803 +{ +( 2176 1856 64 ) ( 2176 2048 64 ) ( 2144 2048 64 ) we_cemetary/cemstair2 -65 0 -180.00 1 1 0 0 0 +( 2176 1856 64 ) ( 2176 1856 384 ) ( 2176 2048 384 ) we_cemetary/cemstair2 64 0 -180.00 1 -1 0 0 0 +( 2144 1856 64 ) ( 2136 2048 80 ) ( 2128 1856 96 ) we_cemetary/cemstair2 64 0 -180.00 1 -1 0 0 0 +( 2176 1856 256 ) ( 2112 1856 256 ) ( 2112 2048 256 ) we_cemetary/cemstair2 -65 0 -180.00 1 1 0 0 0 +( 2128 1856 144 ) ( 2128 2048 176 ) ( 2128 1856 208 ) we_cemetary/cemstair2 64 0 -180.00 1 -1 0 0 0 +( 2160 2288 256 ) ( 2144 2272 64 ) ( 2176 2304 64 ) we_cemetary/cemstair2 128 0 0.00 1 1 0 0 0 +( 2176 1792 64 ) ( 2144 1824 64 ) ( 2160 1808 256 ) we_cemetary/cemstair2 0 0 -180.00 1 -1 0 0 0 +} +// brush 804 +{ +( 2176 1856 0 ) ( 2176 2048 0 ) ( 2144 2048 0 ) we_cemetary/cemtrim2 -65 0 -180.00 1 1 0 0 0 +( 2144 2048 64 ) ( 2176 2048 64 ) ( 2176 1856 64 ) we_cemetary/cemtrim2 -65 0 -180.00 1 1 0 0 0 +( 2144 1920 0 ) ( 2144 1920 320 ) ( 2144 1728 320 ) we_cemetary/cemtrim2 64 0 -180.00 1 -1 0 0 0 +( 2176 1856 0 ) ( 2176 1856 320 ) ( 2176 2048 320 ) we_cemetary/cemtrim2 64 0 -180.00 1 -1 0 0 0 +( 2160 2288 64 ) ( 2144 2272 0 ) ( 2176 2304 0 ) we_cemetary/cemtrim2 128 0 0.00 1 1 0 0 0 +( 2176 1792 0 ) ( 2144 1824 0 ) ( 2160 1808 64 ) we_cemetary/cemtrim2 0 0 -180.00 1 -1 0 0 0 +} +// brush 805 +{ +( 2112 2304 0 ) ( 1920 2304 0 ) ( 1920 2272 0 ) we_cemetary/cemtrim2 -56 0 90.00 1 1 0 0 0 +( 1920 2272 64 ) ( 1920 2304 64 ) ( 2112 2304 64 ) we_cemetary/cemtrim2 -56 0 90.00 1 1 0 0 0 +( 1984 2272 0 ) ( 1984 2272 320 ) ( 2176 2272 320 ) we_cemetary/cemtrim2 128 0 -180.00 1 -1 0 0 0 +( 2112 2304 0 ) ( 2112 2304 320 ) ( 1920 2304 320 ) we_cemetary/cemtrim2 128 0 -180.00 1 -1 0 0 0 +( 1680 2288 64 ) ( 1696 2272 0 ) ( 1664 2304 0 ) we_cemetary/cemtrim2 192 0 -180.00 1 -1 0 0 0 +( 2176 2304 0 ) ( 2144 2272 0 ) ( 2160 2288 64 ) we_cemetary/cemtrim2 192 0 -180.00 1 -1 0 0 0 +} +// brush 806 +{ +( 2112 2304 64 ) ( 1920 2304 64 ) ( 1920 2272 64 ) we_cemetary/cemstair2 -56 0 90.00 1 1 0 0 0 +( 2112 2304 64 ) ( 2112 2304 384 ) ( 1920 2304 384 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +( 2112 2272 64 ) ( 1920 2264 80 ) ( 2112 2256 96 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +( 2112 2304 256 ) ( 2112 2240 256 ) ( 1920 2240 256 ) we_cemetary/cemstair2 -56 0 90.00 1 1 0 0 0 +( 2112 2256 144 ) ( 1920 2256 176 ) ( 2112 2256 208 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +( 1680 2288 256 ) ( 1696 2272 64 ) ( 1664 2304 64 ) we_cemetary/cemstair2 192 0 -180.00 1 -1 0 0 0 +( 2176 2304 64 ) ( 2144 2272 64 ) ( 2160 2288 256 ) we_cemetary/cemstair2 192 0 -180.00 1 -1 0 0 0 +} +// brush 807 +{ +( 1920 2304 256 ) ( 1920 2256 256 ) ( 2112 2256 256 ) we_cemetary/fogtrunk -56 -128 90.00 1 1 0 0 0 +( 1920 2240 272 ) ( 1920 2304 272 ) ( 2112 2304 272 ) we_cemetary/fogtrunk -56 -128 90.00 1 1 0 0 0 +( 2112 2240 272 ) ( 2112 2256 256 ) ( 1920 2256 256 ) we_cemetary/fogtrunk -56 -128 90.00 1 1 0 0 0 +( 2112 2304 256 ) ( 2112 2304 272 ) ( 1920 2304 272 ) we_cemetary/fogtrunk 128 0 -180.00 1 -1 0 0 0 +( 1680 2288 272 ) ( 1696 2272 256 ) ( 1664 2304 256 ) we_cemetary/fogtrunk 192 0 -180.00 1 -1 0 0 0 +( 2176 2304 256 ) ( 2144 2272 256 ) ( 2160 2288 272 ) we_cemetary/fogtrunk 192 0 -180.00 1 -1 0 0 0 +} +// brush 808 +{ +( 2112 2272 272 ) ( 1920 2272 272 ) ( 1920 2240 272 ) we_cemetary/cemrunner2 -56 3 90.00 1 1.000122 0 0 0 +( 1920 2240 336 ) ( 1920 2272 336 ) ( 2112 2272 336 ) we_cemetary/cemtrim2 -88 0 90.00 1 1 0 0 0 +( 1920 2240 272 ) ( 1920 2240 592 ) ( 2112 2240 592 ) we_cemetary/cemtrim2 128 15 -180.00 1 -1 0 0 0 +( 2112 2304 272 ) ( 2112 2304 592 ) ( 1920 2304 592 ) we_cemetary/cemtrim2 128 15 -180.00 1 -1 0 0 0 +( 1680 2288 336 ) ( 1696 2272 272 ) ( 1664 2304 272 ) we_cemetary/cemtrim2 192 16 -180.00 1 -1 0 0 0 +( 2176 2304 272 ) ( 2144 2272 272 ) ( 2160 2288 336 ) we_cemetary/cemtrim2 192 16 -180.00 1 -1 0 0 0 +} +// brush 809 +{ +( 1600 2272 272 ) ( 1408 2272 272 ) ( 1408 2240 272 ) we_cemetary/cemrunner2 -57 -29 90.00 1 1.000122 0 0 0 +( 1408 2240 336 ) ( 1408 2272 336 ) ( 1600 2272 336 ) we_cemetary/cemtrim2 -89 0 90.00 1 1 0 0 0 +( 1408 2240 272 ) ( 1408 2240 592 ) ( 1600 2240 592 ) we_cemetary/cemtrim2 128 15 -180.00 1 -1 0 0 0 +( 1600 2304 272 ) ( 1600 2304 592 ) ( 1408 2304 592 ) we_cemetary/cemtrim2 128 15 -180.00 1 -1 0 0 0 +( 1168 2288 336 ) ( 1184 2272 272 ) ( 1152 2304 272 ) we_cemetary/cemtrim2 192 16 -180.00 1 -1 0 0 0 +( 1664 2304 272 ) ( 1632 2272 272 ) ( 1648 2288 336 ) we_cemetary/cemtrim2 192 16 -180.00 1 -1 0 0 0 +} +// brush 810 +{ +( 1408 2304 256 ) ( 1408 2256 256 ) ( 1600 2256 256 ) we_cemetary/fogtrunk -57 -128 90.00 1 1 0 0 0 +( 1408 2240 272 ) ( 1408 2304 272 ) ( 1600 2304 272 ) we_cemetary/fogtrunk -57 -128 90.00 1 1 0 0 0 +( 1600 2240 272 ) ( 1600 2256 256 ) ( 1408 2256 256 ) we_cemetary/fogtrunk -57 -128 90.00 1 1 0 0 0 +( 1600 2304 256 ) ( 1600 2304 272 ) ( 1408 2304 272 ) we_cemetary/fogtrunk 128 0 -180.00 1 -1 0 0 0 +( 1168 2288 272 ) ( 1184 2272 256 ) ( 1152 2304 256 ) we_cemetary/fogtrunk 192 0 -180.00 1 -1 0 0 0 +( 1664 2304 256 ) ( 1632 2272 256 ) ( 1648 2288 272 ) we_cemetary/fogtrunk 192 0 -180.00 1 -1 0 0 0 +} +// brush 811 +{ +( 1600 2304 64 ) ( 1408 2304 64 ) ( 1408 2272 64 ) we_cemetary/cemstair2 -57 0 90.00 1 1 0 0 0 +( 1600 2304 64 ) ( 1600 2304 384 ) ( 1408 2304 384 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +( 1600 2272 64 ) ( 1408 2264 80 ) ( 1600 2256 96 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +( 1600 2304 256 ) ( 1600 2240 256 ) ( 1408 2240 256 ) we_cemetary/cemstair2 -57 0 90.00 1 1 0 0 0 +( 1600 2256 144 ) ( 1408 2256 176 ) ( 1600 2256 208 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +( 1168 2288 256 ) ( 1184 2272 64 ) ( 1152 2304 64 ) we_cemetary/cemstair2 192 0 -180.00 1 -1 0 0 0 +( 1664 2304 64 ) ( 1632 2272 64 ) ( 1648 2288 256 ) we_cemetary/cemstair2 192 0 -180.00 1 -1 0 0 0 +} +// brush 812 +{ +( 1600 2304 0 ) ( 1408 2304 0 ) ( 1408 2272 0 ) we_cemetary/cemtrim2 -57 0 90.00 1 1 0 0 0 +( 1408 2272 64 ) ( 1408 2304 64 ) ( 1600 2304 64 ) we_cemetary/cemtrim2 -57 0 90.00 1 1 0 0 0 +( 1472 2272 0 ) ( 1472 2272 320 ) ( 1664 2272 320 ) we_cemetary/cemtrim2 128 0 -180.00 1 -1 0 0 0 +( 1600 2304 0 ) ( 1600 2304 320 ) ( 1408 2304 320 ) we_cemetary/cemtrim2 128 0 -180.00 1 -1 0 0 0 +( 1168 2288 64 ) ( 1184 2272 0 ) ( 1152 2304 0 ) we_cemetary/cemtrim2 192 0 -180.00 1 -1 0 0 0 +( 1664 2304 0 ) ( 1632 2272 0 ) ( 1648 2288 64 ) we_cemetary/cemtrim2 192 0 -180.00 1 -1 0 0 0 +} +// brush 813 +{ +( 1664 1856 0 ) ( 1664 2048 0 ) ( 1632 2048 0 ) we_cemetary/cemtrim2 191 0 -180.00 1 1 0 0 0 +( 1632 2048 64 ) ( 1664 2048 64 ) ( 1664 1856 64 ) we_cemetary/cemtrim2 191 0 -180.00 1 1 0 0 0 +( 1632 1920 0 ) ( 1632 1920 320 ) ( 1632 1728 320 ) we_cemetary/cemtrim2 64 0 -180.00 1 -1 0 0 0 +( 1664 1856 0 ) ( 1664 1856 320 ) ( 1664 2048 320 ) we_cemetary/cemtrim2 64 0 -180.00 1 -1 0 0 0 +( 1648 2288 64 ) ( 1632 2272 0 ) ( 1664 2304 0 ) we_cemetary/cemtrim2 128 0 0.00 1 1 0 0 0 +( 1664 1792 0 ) ( 1632 1824 0 ) ( 1648 1808 64 ) we_cemetary/cemtrim2 0 0 -180.00 1 -1 0 0 0 +} +// brush 814 +{ +( 1664 1856 64 ) ( 1664 2048 64 ) ( 1632 2048 64 ) we_cemetary/cemstair2 191 0 -180.00 1 1 0 0 0 +( 1664 1856 64 ) ( 1664 1856 384 ) ( 1664 2048 384 ) we_cemetary/cemstair2 64 0 -180.00 1 -1 0 0 0 +( 1632 1856 64 ) ( 1624 2048 80 ) ( 1616 1856 96 ) we_cemetary/cemstair2 64 0 -180.00 1 -1 0 0 0 +( 1664 1856 256 ) ( 1600 1856 256 ) ( 1600 2048 256 ) we_cemetary/cemstair2 191 0 -180.00 1 1 0 0 0 +( 1616 1856 144 ) ( 1616 2048 176 ) ( 1616 1856 208 ) we_cemetary/cemstair2 64 0 -180.00 1 -1 0 0 0 +( 1648 2288 256 ) ( 1632 2272 64 ) ( 1664 2304 64 ) we_cemetary/cemstair2 128 0 0.00 1 1 0 0 0 +( 1664 1792 64 ) ( 1632 1824 64 ) ( 1648 1808 256 ) we_cemetary/cemstair2 0 0 -180.00 1 -1 0 0 0 +} +// brush 815 +{ +( 1664 2048 256 ) ( 1616 2048 256 ) ( 1616 1856 256 ) we_cemetary/fogtrunk 191 -64 -180.00 1 1 0 0 0 +( 1600 2048 272 ) ( 1664 2048 272 ) ( 1664 1856 272 ) we_cemetary/fogtrunk 191 -64 -180.00 1 1 0 0 0 +( 1600 1856 272 ) ( 1616 1856 256 ) ( 1616 2048 256 ) we_cemetary/fogtrunk 191 -64 -180.00 1 1 0 0 0 +( 1664 1856 256 ) ( 1664 1856 272 ) ( 1664 2048 272 ) we_cemetary/fogtrunk 64 0 -180.00 1 -1 0 0 0 +( 1648 2288 272 ) ( 1632 2272 256 ) ( 1664 2304 256 ) we_cemetary/fogtrunk 128 0 0.00 1 1 0 0 0 +( 1664 1792 256 ) ( 1632 1824 256 ) ( 1648 1808 272 ) we_cemetary/fogtrunk 0 0 -180.00 1 -1 0 0 0 +} +// brush 816 +{ +( 1632 1856 272 ) ( 1632 2048 272 ) ( 1600 2048 272 ) we_cemetary/cemrunner2 63 0 -180.00 1 1 0 0 0 +( 1600 2048 336 ) ( 1632 2048 336 ) ( 1632 1856 336 ) we_cemetary/cemtrim2 159 0 -180.00 1 1 0 0 0 +( 1600 2048 272 ) ( 1600 2048 592 ) ( 1600 1856 592 ) we_cemetary/cemtrim2 64 15 -180.00 1 -1 0 0 0 +( 1664 1856 272 ) ( 1664 1856 592 ) ( 1664 2048 592 ) we_cemetary/cemtrim2 64 15 -180.00 1 -1 0 0 0 +( 1648 2288 336 ) ( 1632 2272 272 ) ( 1664 2304 272 ) we_cemetary/cemtrim2 128 15 0.00 1 1 0 0 0 +( 1664 1792 272 ) ( 1632 1824 272 ) ( 1648 1808 336 ) we_cemetary/cemtrim2 0 16 -180.00 1 -1 0 0 0 +} +// brush 817 +{ +( 1216 1824 272 ) ( 1408 1824 272 ) ( 1408 1856 272 ) we_cemetary/cemrunner2 -58 31 -90.00 1 1 0 0 0 +( 1408 1856 336 ) ( 1408 1824 336 ) ( 1216 1824 336 ) we_cemetary/cemtrim2 -92 63 -90.00 1 1 0 0 0 +( 1408 1856 272 ) ( 1408 1856 592 ) ( 1216 1856 592 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( 1216 1792 272 ) ( 1216 1792 592 ) ( 1408 1792 592 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( 1648 1808 336 ) ( 1632 1824 272 ) ( 1664 1792 272 ) we_cemetary/cemtrim2 0 15 0.00 1 1 0 0 0 +( 1152 1792 272 ) ( 1184 1824 272 ) ( 1168 1808 336 ) we_cemetary/cemtrim2 128 16 0.00 1 1 0 0 0 +} +// brush 818 +{ +( 1408 1792 256 ) ( 1408 1840 256 ) ( 1216 1840 256 ) we_cemetary/fogtrunk -58 63 -90.00 1 1 0 0 0 +( 1408 1856 272 ) ( 1408 1792 272 ) ( 1216 1792 272 ) we_cemetary/fogtrunk -58 63 -90.00 1 1 0 0 0 +( 1216 1856 272 ) ( 1216 1840 256 ) ( 1408 1840 256 ) we_cemetary/fogtrunk -58 63 -90.00 1 1 0 0 0 +( 1216 1792 256 ) ( 1216 1792 272 ) ( 1408 1792 272 ) we_cemetary/fogtrunk -64 0 0.00 1 1 0 0 0 +( 1648 1808 272 ) ( 1632 1824 256 ) ( 1664 1792 256 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +( 1152 1792 256 ) ( 1184 1824 256 ) ( 1168 1808 272 ) we_cemetary/fogtrunk 128 0 0.00 1 1 0 0 0 +} +// brush 819 +{ +( 1216 2048 272 ) ( 1184 2048 272 ) ( 1184 1856 272 ) we_cemetary/cemrunner2 0 0 0.00 1 1 0 0 0 +( 1184 1856 336 ) ( 1184 2048 336 ) ( 1216 2048 336 ) we_cemetary/cemtrim2 -32 0 0.00 1 1 0 0 0 +( 1216 1856 592 ) ( 1216 2048 592 ) ( 1216 2048 272 ) we_cemetary/cemtrim2 0 16 0.00 1 1 0 0 0 +( 1152 2048 592 ) ( 1152 1856 592 ) ( 1152 1856 272 ) we_cemetary/cemtrim2 0 16 0.00 1 1 0 0 0 +( 1152 2304 272 ) ( 1184 2272 272 ) ( 1168 2288 336 ) we_cemetary/cemtrim2 0 16 0.00 1 1 0 0 0 +( 1216 1856 272 ) ( 1184 1824 272 ) ( 1200 1840 336 ) we_cemetary/cemtrim2 0 16 0.00 1 1 0 0 0 +} +// brush 820 +{ +( 1200 1856 256 ) ( 1200 2048 256 ) ( 1152 2048 256 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +( 1152 1856 272 ) ( 1152 2048 272 ) ( 1216 2048 272 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +( 1200 2048 256 ) ( 1200 1856 256 ) ( 1216 1856 272 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +( 1152 2048 272 ) ( 1152 1856 272 ) ( 1152 1856 256 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +( 1152 2304 256 ) ( 1184 2272 256 ) ( 1168 2288 272 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +( 1216 1856 256 ) ( 1184 1824 256 ) ( 1200 1840 272 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +} +// brush 821 +{ +( 1184 2048 64 ) ( 1152 2048 64 ) ( 1152 1856 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 1152 2048 384 ) ( 1152 1856 384 ) ( 1152 1856 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 1200 1856 96 ) ( 1192 2048 80 ) ( 1184 1856 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 1216 2048 256 ) ( 1216 1856 256 ) ( 1152 1856 256 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 1200 1856 208 ) ( 1200 2048 176 ) ( 1200 1856 144 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 1152 2304 64 ) ( 1184 2272 64 ) ( 1168 2288 256 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 1216 1856 64 ) ( 1184 1824 64 ) ( 1200 1840 256 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +} +// brush 822 +{ +( 1184 2048 0 ) ( 1152 2048 0 ) ( 1152 1856 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( 1152 1856 64 ) ( 1152 2048 64 ) ( 1184 2048 64 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( 1184 1792 320 ) ( 1184 1984 320 ) ( 1184 1984 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( 1152 2048 320 ) ( 1152 1856 320 ) ( 1152 1856 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( 1152 2304 0 ) ( 1184 2272 0 ) ( 1168 2288 64 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( 1216 1856 0 ) ( 1184 1824 0 ) ( 1200 1840 64 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +} +// brush 823 +{ +( 1216 1792 0 ) ( 1408 1792 0 ) ( 1408 1824 0 ) we_cemetary/cemtrim2 -58 63 -90.00 1 1 0 0 0 +( 1408 1824 64 ) ( 1408 1792 64 ) ( 1216 1792 64 ) we_cemetary/cemtrim2 -58 63 -90.00 1 1 0 0 0 +( 1280 1824 0 ) ( 1280 1824 320 ) ( 1088 1824 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 1216 1792 0 ) ( 1216 1792 320 ) ( 1408 1792 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 1152 1792 0 ) ( 1184 1824 0 ) ( 1168 1808 64 ) we_cemetary/cemtrim2 128 0 0.00 1 1 0 0 0 +( 1344 1824 0 ) ( 1344 1760 0 ) ( 1344 1792 64 ) we_cemetary/cemtrim2 128 0 0.00 1 1 0 0 0 +} +// brush 824 +{ +( 1216 1792 0 ) ( 1408 1792 0 ) ( 1408 1824 0 ) we_cemetary/cemtrim2 -58 63 -90.00 1 1 0 0 0 +( 1408 1824 64 ) ( 1408 1792 64 ) ( 1216 1792 64 ) we_cemetary/cemtrim2 -58 63 -90.00 1 1 0 0 0 +( 1408 1824 0 ) ( 1408 1824 320 ) ( 1216 1824 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 1216 1792 0 ) ( 1216 1792 320 ) ( 1408 1792 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 1648 1808 64 ) ( 1632 1824 0 ) ( 1664 1792 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( 1472 1760 0 ) ( 1472 1824 0 ) ( 1472 1792 64 ) we_cemetary/cemtrim2 128 0 0.00 1 1 0 0 0 +} +// brush 825 +{ +( 1216 1792 64 ) ( 1408 1792 64 ) ( 1408 1824 64 ) we_cemetary/cemstair2 -58 63 -90.00 1 1 0 0 0 +( 1216 1792 64 ) ( 1216 1792 384 ) ( 1408 1792 384 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 1216 1824 64 ) ( 1408 1832 80 ) ( 1216 1840 96 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 1216 1792 256 ) ( 1216 1856 256 ) ( 1408 1856 256 ) we_cemetary/cemstair2 -58 63 -90.00 1 1 0 0 0 +( 1216 1840 144 ) ( 1408 1840 176 ) ( 1216 1840 208 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 1152 1792 64 ) ( 1184 1824 64 ) ( 1168 1808 256 ) we_cemetary/cemstair2 128 0 0.00 1 1 0 0 0 +( 1344 1824 64 ) ( 1344 1760 64 ) ( 1344 1792 256 ) we_cemetary/cemstair2 128 0 0.00 1 1 0 0 0 +} +// brush 826 +{ +( 1216 1792 64 ) ( 1408 1792 64 ) ( 1408 1824 64 ) we_cemetary/cemstair2 -58 63 -90.00 1 1 0 0 0 +( 1216 1792 64 ) ( 1216 1792 384 ) ( 1408 1792 384 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 1216 1824 64 ) ( 1408 1832 80 ) ( 1216 1840 96 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 1216 1792 256 ) ( 1216 1856 256 ) ( 1408 1856 256 ) we_cemetary/cemstair2 -58 63 -90.00 1 1 0 0 0 +( 1344 1840 144 ) ( 1536 1840 176 ) ( 1344 1840 208 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 1648 1808 256 ) ( 1632 1824 64 ) ( 1664 1792 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 1472 1760 64 ) ( 1472 1824 64 ) ( 1472 1792 256 ) we_cemetary/cemstair2 128 0 0.00 1 1 0 0 0 +} +// brush 827 +{ +( 1408 1760 64 ) ( 1408 1792 64 ) ( 1216 1792 64 ) we_cemetary/cemstair2 -124 63 -90.00 1 1 0 0 0 +( 1408 1792 384 ) ( 1216 1792 384 ) ( 1216 1792 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 1216 1744 96 ) ( 1408 1752 80 ) ( 1216 1760 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 1408 1728 256 ) ( 1216 1728 256 ) ( 1216 1792 256 ) we_cemetary/cemstair2 -124 63 -90.00 1 1 0 0 0 +( 1312 1744 208 ) ( 1504 1744 176 ) ( 1312 1744 144 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 1472 1760 64 ) ( 1472 1824 64 ) ( 1472 1792 256 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +( 1664 1792 64 ) ( 1664 1728 64 ) ( 1664 1760 256 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +} +// brush 828 +{ +( 1408 1760 0 ) ( 1408 1792 0 ) ( 1216 1792 0 ) we_cemetary/cemtrim2 -124 63 -90.00 1 1 0 0 0 +( 1216 1792 64 ) ( 1408 1792 64 ) ( 1408 1760 64 ) we_cemetary/cemtrim2 -124 63 -90.00 1 1 0 0 0 +( 1312 1760 320 ) ( 1504 1760 320 ) ( 1504 1760 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 1408 1792 320 ) ( 1216 1792 320 ) ( 1216 1792 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 1472 1760 0 ) ( 1472 1824 0 ) ( 1472 1792 64 ) we_cemetary/cemtrim2 192 0 0.00 1 1 0 0 0 +( 1664 1792 0 ) ( 1664 1728 0 ) ( 1664 1760 64 ) we_cemetary/cemtrim2 192 0 0.00 1 1 0 0 0 +} +// brush 829 +{ +( 1408 1760 64 ) ( 1408 1792 64 ) ( 1216 1792 64 ) we_cemetary/cemstair2 -124 63 -90.00 1 1 0 0 0 +( 1408 1792 384 ) ( 1216 1792 384 ) ( 1216 1792 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 1216 1744 96 ) ( 1408 1752 80 ) ( 1216 1760 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 1408 1728 256 ) ( 1216 1728 256 ) ( 1216 1792 256 ) we_cemetary/cemstair2 -124 63 -90.00 1 1 0 0 0 +( 1216 1744 208 ) ( 1408 1744 176 ) ( 1216 1744 144 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 1344 1824 64 ) ( 1344 1760 64 ) ( 1344 1792 256 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +( 1152 1728 64 ) ( 1152 1760 64 ) ( 1152 1744 256 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +} +// brush 830 +{ +( 1408 1760 0 ) ( 1408 1792 0 ) ( 1216 1792 0 ) we_cemetary/cemtrim2 -124 63 -90.00 1 1 0 0 0 +( 1216 1792 64 ) ( 1408 1792 64 ) ( 1408 1760 64 ) we_cemetary/cemtrim2 -124 63 -90.00 1 1 0 0 0 +( 1024 1760 320 ) ( 1216 1760 320 ) ( 1216 1760 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 1408 1792 320 ) ( 1216 1792 320 ) ( 1216 1792 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 1344 1824 0 ) ( 1344 1760 0 ) ( 1344 1792 64 ) we_cemetary/cemtrim2 192 0 0.00 1 1 0 0 0 +( 1152 1728 0 ) ( 1152 1760 0 ) ( 1152 1744 64 ) we_cemetary/cemtrim2 192 0 0.00 1 1 0 0 0 +} +// brush 831 +{ +( 1216 1744 256 ) ( 1408 1744 256 ) ( 1408 1792 256 ) we_cemetary/fogtrunk -124 63 -90.00 1 1 0 0 0 +( 1216 1792 272 ) ( 1408 1792 272 ) ( 1408 1728 272 ) we_cemetary/fogtrunk -124 63 -90.00 1 1 0 0 0 +( 1408 1744 256 ) ( 1216 1744 256 ) ( 1216 1728 272 ) we_cemetary/fogtrunk -124 63 -90.00 1 1 0 0 0 +( 1408 1792 272 ) ( 1216 1792 272 ) ( 1216 1792 256 ) we_cemetary/fogtrunk -64 0 0.00 1 1 0 0 0 +( 1664 1792 256 ) ( 1664 1728 256 ) ( 1664 1760 272 ) we_cemetary/fogtrunk 192 0 0.00 1 1 0 0 0 +( 1152 1728 256 ) ( 1152 1760 256 ) ( 1152 1744 272 ) we_cemetary/fogtrunk 192 0 0.00 1 1 0 0 0 +} +// brush 832 +{ +( 1408 1728 272 ) ( 1408 1760 272 ) ( 1216 1760 272 ) we_cemetary/cemrunner2 0 31 -90.00 1 1 0 0 0 +( 1216 1760 336 ) ( 1408 1760 336 ) ( 1408 1728 336 ) we_cemetary/cemtrim2 -156 63 -90.00 1 1 0 0 0 +( 1216 1728 592 ) ( 1408 1728 592 ) ( 1408 1728 272 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( 1408 1792 592 ) ( 1216 1792 592 ) ( 1216 1792 272 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( 1664 1792 272 ) ( 1664 1728 272 ) ( 1664 1760 336 ) we_cemetary/cemtrim2 192 16 0.00 1 1 0 0 0 +( 1152 1728 272 ) ( 1152 1760 272 ) ( 1152 1744 336 ) we_cemetary/cemtrim2 192 16 0.00 1 1 0 0 0 +} +// brush 833 +{ +( 1632 2272 -32 ) ( 1184 2272 -32 ) ( 1184 1824 -32 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 1184 1824 0 ) ( 1184 2272 0 ) ( 1632 2272 0 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 1184 1760 0 ) ( 1632 1760 0 ) ( 1632 1760 -64 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 1664 1824 0 ) ( 1664 2272 0 ) ( 1664 2272 -64 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 1632 2304 0 ) ( 1184 2304 0 ) ( 1184 2304 -64 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 1152 2272 0 ) ( 1152 1824 0 ) ( 1152 1824 -64 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +} +// brush 834 +{ +( 1632 2272 336 ) ( 1184 2272 336 ) ( 1184 1824 336 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +( 1184 1824 352 ) ( 1184 2272 352 ) ( 1632 2272 352 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +( 1184 1824 368 ) ( 1632 1824 368 ) ( 1632 1824 304 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +( 1632 1824 368 ) ( 1632 2272 368 ) ( 1632 2272 304 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +( 1632 2272 368 ) ( 1184 2272 368 ) ( 1184 2272 304 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +( 1184 2272 368 ) ( 1184 1824 368 ) ( 1184 1824 304 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +} +// brush 835 +{ +( 1472 1840 208 ) ( 1344 1840 208 ) ( 1344 1744 208 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 1344 1744 256 ) ( 1344 1840 256 ) ( 1472 1840 256 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 1344 1744 256 ) ( 1472 1744 256 ) ( 1472 1744 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 1472 1744 240 ) ( 1472 1840 240 ) ( 1472 1840 48 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +( 1472 1840 240 ) ( 1344 1840 240 ) ( 1344 1840 48 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 1344 1840 256 ) ( 1344 1744 256 ) ( 1344 1744 64 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +} +// brush 836 +{ +( 960 1840 208 ) ( 832 1840 208 ) ( 832 1744 208 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 832 1744 256 ) ( 832 1840 256 ) ( 960 1840 256 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 832 1744 256 ) ( 960 1744 256 ) ( 960 1744 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 960 1744 240 ) ( 960 1840 240 ) ( 960 1840 48 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +( 960 1840 240 ) ( 832 1840 240 ) ( 832 1840 48 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 832 1840 256 ) ( 832 1744 256 ) ( 832 1744 64 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +} +// brush 837 +{ +( 1120 2272 336 ) ( 672 2272 336 ) ( 672 1824 336 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +( 672 1824 352 ) ( 672 2272 352 ) ( 1120 2272 352 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +( 672 1824 368 ) ( 1120 1824 368 ) ( 1120 1824 304 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +( 1120 1824 368 ) ( 1120 2272 368 ) ( 1120 2272 304 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +( 1120 2272 368 ) ( 672 2272 368 ) ( 672 2272 304 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +( 672 2272 368 ) ( 672 1824 368 ) ( 672 1824 304 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +} +// brush 838 +{ +( 1120 2272 -32 ) ( 672 2272 -32 ) ( 672 1824 -32 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 672 1824 0 ) ( 672 2272 0 ) ( 1120 2272 0 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 672 1760 0 ) ( 1120 1760 0 ) ( 1120 1760 -64 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 1152 1824 0 ) ( 1152 2272 0 ) ( 1152 2272 -64 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 1120 2304 0 ) ( 672 2304 0 ) ( 672 2304 -64 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 640 2272 0 ) ( 640 1824 0 ) ( 640 1824 -64 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +} +// brush 839 +{ +( 896 1728 272 ) ( 896 1760 272 ) ( 704 1760 272 ) we_cemetary/cemrunner2 0 31 -90.00 1 1 0 0 0 +( 704 1760 336 ) ( 896 1760 336 ) ( 896 1728 336 ) we_cemetary/cemtrim2 -157 63 -90.00 1 1 0 0 0 +( 704 1728 592 ) ( 896 1728 592 ) ( 896 1728 272 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( 896 1792 592 ) ( 704 1792 592 ) ( 704 1792 272 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( 1152 1792 272 ) ( 1152 1728 272 ) ( 1152 1760 336 ) we_cemetary/cemtrim2 192 16 0.00 1 1 0 0 0 +( 640 1728 272 ) ( 640 1760 272 ) ( 640 1744 336 ) we_cemetary/cemtrim2 192 16 0.00 1 1 0 0 0 +} +// brush 840 +{ +( 704 1744 256 ) ( 896 1744 256 ) ( 896 1792 256 ) we_cemetary/fogtrunk -125 63 -90.00 1 1 0 0 0 +( 704 1792 272 ) ( 896 1792 272 ) ( 896 1728 272 ) we_cemetary/fogtrunk -125 63 -90.00 1 1 0 0 0 +( 896 1744 256 ) ( 704 1744 256 ) ( 704 1728 272 ) we_cemetary/fogtrunk -125 63 -90.00 1 1 0 0 0 +( 896 1792 272 ) ( 704 1792 272 ) ( 704 1792 256 ) we_cemetary/fogtrunk -64 0 0.00 1 1 0 0 0 +( 1152 1792 256 ) ( 1152 1728 256 ) ( 1152 1760 272 ) we_cemetary/fogtrunk 192 0 0.00 1 1 0 0 0 +( 640 1728 256 ) ( 640 1760 256 ) ( 640 1744 272 ) we_cemetary/fogtrunk 192 0 0.00 1 1 0 0 0 +} +// brush 841 +{ +( 896 1760 0 ) ( 896 1792 0 ) ( 704 1792 0 ) we_cemetary/cemtrim2 -125 63 -90.00 1 1 0 0 0 +( 704 1792 64 ) ( 896 1792 64 ) ( 896 1760 64 ) we_cemetary/cemtrim2 -125 63 -90.00 1 1 0 0 0 +( 512 1760 320 ) ( 704 1760 320 ) ( 704 1760 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 896 1792 320 ) ( 704 1792 320 ) ( 704 1792 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 832 1824 0 ) ( 832 1760 0 ) ( 832 1792 64 ) we_cemetary/cemtrim2 192 0 0.00 1 1 0 0 0 +( 640 1728 0 ) ( 640 1760 0 ) ( 640 1744 64 ) we_cemetary/cemtrim2 192 0 0.00 1 1 0 0 0 +} +// brush 842 +{ +( 896 1760 64 ) ( 896 1792 64 ) ( 704 1792 64 ) we_cemetary/cemstair2 -125 63 -90.00 1 1 0 0 0 +( 896 1792 384 ) ( 704 1792 384 ) ( 704 1792 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 704 1744 96 ) ( 896 1752 80 ) ( 704 1760 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 896 1728 256 ) ( 704 1728 256 ) ( 704 1792 256 ) we_cemetary/cemstair2 -125 63 -90.00 1 1 0 0 0 +( 704 1744 208 ) ( 896 1744 176 ) ( 704 1744 144 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 832 1824 64 ) ( 832 1760 64 ) ( 832 1792 256 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +( 640 1728 64 ) ( 640 1760 64 ) ( 640 1744 256 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +} +// brush 843 +{ +( 896 1760 0 ) ( 896 1792 0 ) ( 704 1792 0 ) we_cemetary/cemtrim2 -125 63 -90.00 1 1 0 0 0 +( 704 1792 64 ) ( 896 1792 64 ) ( 896 1760 64 ) we_cemetary/cemtrim2 -125 63 -90.00 1 1 0 0 0 +( 800 1760 320 ) ( 992 1760 320 ) ( 992 1760 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 896 1792 320 ) ( 704 1792 320 ) ( 704 1792 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 960 1760 0 ) ( 960 1824 0 ) ( 960 1792 64 ) we_cemetary/cemtrim2 192 0 0.00 1 1 0 0 0 +( 1152 1792 0 ) ( 1152 1728 0 ) ( 1152 1760 64 ) we_cemetary/cemtrim2 192 0 0.00 1 1 0 0 0 +} +// brush 844 +{ +( 896 1760 64 ) ( 896 1792 64 ) ( 704 1792 64 ) we_cemetary/cemstair2 -125 63 -90.00 1 1 0 0 0 +( 896 1792 384 ) ( 704 1792 384 ) ( 704 1792 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 704 1744 96 ) ( 896 1752 80 ) ( 704 1760 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 896 1728 256 ) ( 704 1728 256 ) ( 704 1792 256 ) we_cemetary/cemstair2 -125 63 -90.00 1 1 0 0 0 +( 800 1744 208 ) ( 992 1744 176 ) ( 800 1744 144 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 960 1760 64 ) ( 960 1824 64 ) ( 960 1792 256 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +( 1152 1792 64 ) ( 1152 1728 64 ) ( 1152 1760 256 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +} +// brush 845 +{ +( 704 1792 64 ) ( 896 1792 64 ) ( 896 1824 64 ) we_cemetary/cemstair2 -59 63 -90.00 1 1 0 0 0 +( 704 1792 64 ) ( 704 1792 384 ) ( 896 1792 384 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 704 1824 64 ) ( 896 1832 80 ) ( 704 1840 96 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 704 1792 256 ) ( 704 1856 256 ) ( 896 1856 256 ) we_cemetary/cemstair2 -59 63 -90.00 1 1 0 0 0 +( 832 1840 144 ) ( 1024 1840 176 ) ( 832 1840 208 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 1136 1808 256 ) ( 1120 1824 64 ) ( 1152 1792 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 960 1760 64 ) ( 960 1824 64 ) ( 960 1792 256 ) we_cemetary/cemstair2 128 0 0.00 1 1 0 0 0 +} +// brush 846 +{ +( 704 1792 64 ) ( 896 1792 64 ) ( 896 1824 64 ) we_cemetary/cemstair2 -59 63 -90.00 1 1 0 0 0 +( 704 1792 64 ) ( 704 1792 384 ) ( 896 1792 384 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 704 1824 64 ) ( 896 1832 80 ) ( 704 1840 96 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 704 1792 256 ) ( 704 1856 256 ) ( 896 1856 256 ) we_cemetary/cemstair2 -59 63 -90.00 1 1 0 0 0 +( 704 1840 144 ) ( 896 1840 176 ) ( 704 1840 208 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 640 1792 64 ) ( 672 1824 64 ) ( 656 1808 256 ) we_cemetary/cemstair2 128 0 0.00 1 1 0 0 0 +( 832 1824 64 ) ( 832 1760 64 ) ( 832 1792 256 ) we_cemetary/cemstair2 128 0 0.00 1 1 0 0 0 +} +// brush 847 +{ +( 704 1792 0 ) ( 896 1792 0 ) ( 896 1824 0 ) we_cemetary/cemtrim2 -59 63 -90.00 1 1 0 0 0 +( 896 1824 64 ) ( 896 1792 64 ) ( 704 1792 64 ) we_cemetary/cemtrim2 -59 63 -90.00 1 1 0 0 0 +( 896 1824 0 ) ( 896 1824 320 ) ( 704 1824 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 704 1792 0 ) ( 704 1792 320 ) ( 896 1792 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 1136 1808 64 ) ( 1120 1824 0 ) ( 1152 1792 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( 960 1760 0 ) ( 960 1824 0 ) ( 960 1792 64 ) we_cemetary/cemtrim2 128 0 0.00 1 1 0 0 0 +} +// brush 848 +{ +( 704 1792 0 ) ( 896 1792 0 ) ( 896 1824 0 ) we_cemetary/cemtrim2 -59 63 -90.00 1 1 0 0 0 +( 896 1824 64 ) ( 896 1792 64 ) ( 704 1792 64 ) we_cemetary/cemtrim2 -59 63 -90.00 1 1 0 0 0 +( 768 1824 0 ) ( 768 1824 320 ) ( 576 1824 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 704 1792 0 ) ( 704 1792 320 ) ( 896 1792 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 640 1792 0 ) ( 672 1824 0 ) ( 656 1808 64 ) we_cemetary/cemtrim2 128 0 0.00 1 1 0 0 0 +( 832 1824 0 ) ( 832 1760 0 ) ( 832 1792 64 ) we_cemetary/cemtrim2 128 0 0.00 1 1 0 0 0 +} +// brush 849 +{ +( 672 2048 0 ) ( 640 2048 0 ) ( 640 1856 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( 640 1856 64 ) ( 640 2048 64 ) ( 672 2048 64 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( 672 1792 320 ) ( 672 1984 320 ) ( 672 1984 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( 640 2048 320 ) ( 640 1856 320 ) ( 640 1856 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( 640 2304 0 ) ( 672 2272 0 ) ( 656 2288 64 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( 704 1856 0 ) ( 672 1824 0 ) ( 688 1840 64 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +} +// brush 850 +{ +( 672 2048 64 ) ( 640 2048 64 ) ( 640 1856 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 640 2048 384 ) ( 640 1856 384 ) ( 640 1856 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 688 1856 96 ) ( 680 2048 80 ) ( 672 1856 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 704 2048 256 ) ( 704 1856 256 ) ( 640 1856 256 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 688 1856 208 ) ( 688 2048 176 ) ( 688 1856 144 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 640 2304 64 ) ( 672 2272 64 ) ( 656 2288 256 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 704 1856 64 ) ( 672 1824 64 ) ( 688 1840 256 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +} +// brush 851 +{ +( 688 1856 256 ) ( 688 2048 256 ) ( 640 2048 256 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +( 640 1856 272 ) ( 640 2048 272 ) ( 704 2048 272 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +( 688 2048 256 ) ( 688 1856 256 ) ( 704 1856 272 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +( 640 2048 272 ) ( 640 1856 272 ) ( 640 1856 256 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +( 640 2304 256 ) ( 672 2272 256 ) ( 656 2288 272 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +( 704 1856 256 ) ( 672 1824 256 ) ( 688 1840 272 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +} +// brush 852 +{ +( 704 2048 272 ) ( 672 2048 272 ) ( 672 1856 272 ) we_cemetary/cemrunner2 0 0 0.00 1 1 0 0 0 +( 672 1856 336 ) ( 672 2048 336 ) ( 704 2048 336 ) we_cemetary/cemtrim2 -32 0 0.00 1 1 0 0 0 +( 704 1856 592 ) ( 704 2048 592 ) ( 704 2048 272 ) we_cemetary/cemtrim2 0 16 0.00 1 1 0 0 0 +( 640 2048 592 ) ( 640 1856 592 ) ( 640 1856 272 ) we_cemetary/cemtrim2 0 16 0.00 1 1 0 0 0 +( 640 2304 272 ) ( 672 2272 272 ) ( 656 2288 336 ) we_cemetary/cemtrim2 0 16 0.00 1 1 0 0 0 +( 704 1856 272 ) ( 672 1824 272 ) ( 688 1840 336 ) we_cemetary/cemtrim2 0 16 0.00 1 1 0 0 0 +} +// brush 853 +{ +( 896 1792 256 ) ( 896 1840 256 ) ( 704 1840 256 ) we_cemetary/fogtrunk -59 63 -90.00 1 1 0 0 0 +( 896 1856 272 ) ( 896 1792 272 ) ( 704 1792 272 ) we_cemetary/fogtrunk -59 63 -90.00 1 1 0 0 0 +( 704 1856 272 ) ( 704 1840 256 ) ( 896 1840 256 ) we_cemetary/fogtrunk -59 63 -90.00 1 1 0 0 0 +( 704 1792 256 ) ( 704 1792 272 ) ( 896 1792 272 ) we_cemetary/fogtrunk -64 0 0.00 1 1 0 0 0 +( 1136 1808 272 ) ( 1120 1824 256 ) ( 1152 1792 256 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +( 640 1792 256 ) ( 672 1824 256 ) ( 656 1808 272 ) we_cemetary/fogtrunk 128 0 0.00 1 1 0 0 0 +} +// brush 854 +{ +( 704 1824 272 ) ( 896 1824 272 ) ( 896 1856 272 ) we_cemetary/cemrunner2 -59 31 -90.00 1 1 0 0 0 +( 896 1856 336 ) ( 896 1824 336 ) ( 704 1824 336 ) we_cemetary/cemtrim2 -93 63 -90.00 1 1 0 0 0 +( 896 1856 272 ) ( 896 1856 592 ) ( 704 1856 592 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( 704 1792 272 ) ( 704 1792 592 ) ( 896 1792 592 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( 1136 1808 336 ) ( 1120 1824 272 ) ( 1152 1792 272 ) we_cemetary/cemtrim2 0 15 0.00 1 1 0 0 0 +( 640 1792 272 ) ( 672 1824 272 ) ( 656 1808 336 ) we_cemetary/cemtrim2 128 16 0.00 1 1 0 0 0 +} +// brush 855 +{ +( 1120 1856 272 ) ( 1120 2048 272 ) ( 1088 2048 272 ) we_cemetary/cemrunner2 63 0 -180.00 1 1 0 0 0 +( 1088 2048 336 ) ( 1120 2048 336 ) ( 1120 1856 336 ) we_cemetary/cemtrim2 159 0 -180.00 1 1 0 0 0 +( 1088 2048 272 ) ( 1088 2048 592 ) ( 1088 1856 592 ) we_cemetary/cemtrim2 64 15 -180.00 1 -1 0 0 0 +( 1152 1856 272 ) ( 1152 1856 592 ) ( 1152 2048 592 ) we_cemetary/cemtrim2 64 15 -180.00 1 -1 0 0 0 +( 1136 2288 336 ) ( 1120 2272 272 ) ( 1152 2304 272 ) we_cemetary/cemtrim2 128 15 0.00 1 1 0 0 0 +( 1152 1792 272 ) ( 1120 1824 272 ) ( 1136 1808 336 ) we_cemetary/cemtrim2 0 16 -180.00 1 -1 0 0 0 +} +// brush 856 +{ +( 1152 2048 256 ) ( 1104 2048 256 ) ( 1104 1856 256 ) we_cemetary/fogtrunk 191 -64 -180.00 1 1 0 0 0 +( 1088 2048 272 ) ( 1152 2048 272 ) ( 1152 1856 272 ) we_cemetary/fogtrunk 191 -64 -180.00 1 1 0 0 0 +( 1088 1856 272 ) ( 1104 1856 256 ) ( 1104 2048 256 ) we_cemetary/fogtrunk 191 -64 -180.00 1 1 0 0 0 +( 1152 1856 256 ) ( 1152 1856 272 ) ( 1152 2048 272 ) we_cemetary/fogtrunk 64 0 -180.00 1 -1 0 0 0 +( 1136 2288 272 ) ( 1120 2272 256 ) ( 1152 2304 256 ) we_cemetary/fogtrunk 128 0 0.00 1 1 0 0 0 +( 1152 1792 256 ) ( 1120 1824 256 ) ( 1136 1808 272 ) we_cemetary/fogtrunk 0 0 -180.00 1 -1 0 0 0 +} +// brush 857 +{ +( 1152 1856 64 ) ( 1152 2048 64 ) ( 1120 2048 64 ) we_cemetary/cemstair2 191 0 -180.00 1 1 0 0 0 +( 1152 1856 64 ) ( 1152 1856 384 ) ( 1152 2048 384 ) we_cemetary/cemstair2 64 0 -180.00 1 -1 0 0 0 +( 1120 1856 64 ) ( 1112 2048 80 ) ( 1104 1856 96 ) we_cemetary/cemstair2 64 0 -180.00 1 -1 0 0 0 +( 1152 1856 256 ) ( 1088 1856 256 ) ( 1088 2048 256 ) we_cemetary/cemstair2 191 0 -180.00 1 1 0 0 0 +( 1104 1856 144 ) ( 1104 2048 176 ) ( 1104 1856 208 ) we_cemetary/cemstair2 64 0 -180.00 1 -1 0 0 0 +( 1136 2288 256 ) ( 1120 2272 64 ) ( 1152 2304 64 ) we_cemetary/cemstair2 128 0 0.00 1 1 0 0 0 +( 1152 1792 64 ) ( 1120 1824 64 ) ( 1136 1808 256 ) we_cemetary/cemstair2 0 0 -180.00 1 -1 0 0 0 +} +// brush 858 +{ +( 1152 1856 0 ) ( 1152 2048 0 ) ( 1120 2048 0 ) we_cemetary/cemtrim2 191 0 -180.00 1 1 0 0 0 +( 1120 2048 64 ) ( 1152 2048 64 ) ( 1152 1856 64 ) we_cemetary/cemtrim2 191 0 -180.00 1 1 0 0 0 +( 1120 1920 0 ) ( 1120 1920 320 ) ( 1120 1728 320 ) we_cemetary/cemtrim2 64 0 -180.00 1 -1 0 0 0 +( 1152 1856 0 ) ( 1152 1856 320 ) ( 1152 2048 320 ) we_cemetary/cemtrim2 64 0 -180.00 1 -1 0 0 0 +( 1136 2288 64 ) ( 1120 2272 0 ) ( 1152 2304 0 ) we_cemetary/cemtrim2 128 0 0.00 1 1 0 0 0 +( 1152 1792 0 ) ( 1120 1824 0 ) ( 1136 1808 64 ) we_cemetary/cemtrim2 0 0 -180.00 1 -1 0 0 0 +} +// brush 859 +{ +( 1088 2304 0 ) ( 896 2304 0 ) ( 896 2272 0 ) we_cemetary/cemtrim2 -58 0 90.00 1 1 0 0 0 +( 896 2272 64 ) ( 896 2304 64 ) ( 1088 2304 64 ) we_cemetary/cemtrim2 -58 0 90.00 1 1 0 0 0 +( 960 2272 0 ) ( 960 2272 320 ) ( 1152 2272 320 ) we_cemetary/cemtrim2 128 0 -180.00 1 -1 0 0 0 +( 1088 2304 0 ) ( 1088 2304 320 ) ( 896 2304 320 ) we_cemetary/cemtrim2 128 0 -180.00 1 -1 0 0 0 +( 656 2288 64 ) ( 672 2272 0 ) ( 640 2304 0 ) we_cemetary/cemtrim2 192 0 -180.00 1 -1 0 0 0 +( 1152 2304 0 ) ( 1120 2272 0 ) ( 1136 2288 64 ) we_cemetary/cemtrim2 192 0 -180.00 1 -1 0 0 0 +} +// brush 860 +{ +( 1088 2304 64 ) ( 896 2304 64 ) ( 896 2272 64 ) we_cemetary/cemstair2 -58 0 90.00 1 1 0 0 0 +( 1088 2304 64 ) ( 1088 2304 384 ) ( 896 2304 384 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +( 1088 2272 64 ) ( 896 2264 80 ) ( 1088 2256 96 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +( 1088 2304 256 ) ( 1088 2240 256 ) ( 896 2240 256 ) we_cemetary/cemstair2 -58 0 90.00 1 1 0 0 0 +( 1088 2256 144 ) ( 896 2256 176 ) ( 1088 2256 208 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +( 656 2288 256 ) ( 672 2272 64 ) ( 640 2304 64 ) we_cemetary/cemstair2 192 0 -180.00 1 -1 0 0 0 +( 1152 2304 64 ) ( 1120 2272 64 ) ( 1136 2288 256 ) we_cemetary/cemstair2 192 0 -180.00 1 -1 0 0 0 +} +// brush 861 +{ +( 896 2304 256 ) ( 896 2256 256 ) ( 1088 2256 256 ) we_cemetary/fogtrunk -58 -128 90.00 1 1 0 0 0 +( 896 2240 272 ) ( 896 2304 272 ) ( 1088 2304 272 ) we_cemetary/fogtrunk -58 -128 90.00 1 1 0 0 0 +( 1088 2240 272 ) ( 1088 2256 256 ) ( 896 2256 256 ) we_cemetary/fogtrunk -58 -128 90.00 1 1 0 0 0 +( 1088 2304 256 ) ( 1088 2304 272 ) ( 896 2304 272 ) we_cemetary/fogtrunk 128 0 -180.00 1 -1 0 0 0 +( 656 2288 272 ) ( 672 2272 256 ) ( 640 2304 256 ) we_cemetary/fogtrunk 192 0 -180.00 1 -1 0 0 0 +( 1152 2304 256 ) ( 1120 2272 256 ) ( 1136 2288 272 ) we_cemetary/fogtrunk 192 0 -180.00 1 -1 0 0 0 +} +// brush 862 +{ +( 1088 2272 272 ) ( 896 2272 272 ) ( 896 2240 272 ) we_cemetary/cemrunner2 -58 -30 90.00 1 1.000122 0 0 0 +( 896 2240 336 ) ( 896 2272 336 ) ( 1088 2272 336 ) we_cemetary/cemtrim2 -90 0 90.00 1 1 0 0 0 +( 896 2240 272 ) ( 896 2240 592 ) ( 1088 2240 592 ) we_cemetary/cemtrim2 128 15 -180.00 1 -1 0 0 0 +( 1088 2304 272 ) ( 1088 2304 592 ) ( 896 2304 592 ) we_cemetary/cemtrim2 128 15 -180.00 1 -1 0 0 0 +( 656 2288 336 ) ( 672 2272 272 ) ( 640 2304 272 ) we_cemetary/cemtrim2 192 16 -180.00 1 -1 0 0 0 +( 1152 2304 272 ) ( 1120 2272 272 ) ( 1136 2288 336 ) we_cemetary/cemtrim2 192 16 -180.00 1 -1 0 0 0 +} +// brush 863 +{ +( 576 2272 272 ) ( 384 2272 272 ) ( 384 2240 272 ) we_cemetary/cemrunner2 -59 1 90.00 1 1.000122 0 0 0 +( 384 2240 336 ) ( 384 2272 336 ) ( 576 2272 336 ) we_cemetary/cemtrim2 -91 0 90.00 1 1 0 0 0 +( 384 2240 272 ) ( 384 2240 592 ) ( 576 2240 592 ) we_cemetary/cemtrim2 128 15 -180.00 1 -1 0 0 0 +( 576 2304 272 ) ( 576 2304 592 ) ( 384 2304 592 ) we_cemetary/cemtrim2 128 15 -180.00 1 -1 0 0 0 +( 144 2288 336 ) ( 160 2272 272 ) ( 128 2304 272 ) we_cemetary/cemtrim2 192 16 -180.00 1 -1 0 0 0 +( 640 2304 272 ) ( 608 2272 272 ) ( 624 2288 336 ) we_cemetary/cemtrim2 192 16 -180.00 1 -1 0 0 0 +} +// brush 864 +{ +( 384 2304 256 ) ( 384 2256 256 ) ( 576 2256 256 ) we_cemetary/fogtrunk -59 -128 90.00 1 1 0 0 0 +( 384 2240 272 ) ( 384 2304 272 ) ( 576 2304 272 ) we_cemetary/fogtrunk -59 -128 90.00 1 1 0 0 0 +( 576 2240 272 ) ( 576 2256 256 ) ( 384 2256 256 ) we_cemetary/fogtrunk -59 -128 90.00 1 1 0 0 0 +( 576 2304 256 ) ( 576 2304 272 ) ( 384 2304 272 ) we_cemetary/fogtrunk 128 0 -180.00 1 -1 0 0 0 +( 144 2288 272 ) ( 160 2272 256 ) ( 128 2304 256 ) we_cemetary/fogtrunk 192 0 -180.00 1 -1 0 0 0 +( 640 2304 256 ) ( 608 2272 256 ) ( 624 2288 272 ) we_cemetary/fogtrunk 192 0 -180.00 1 -1 0 0 0 +} +// brush 865 +{ +( 576 2304 64 ) ( 384 2304 64 ) ( 384 2272 64 ) we_cemetary/cemstair2 -59 0 90.00 1 1 0 0 0 +( 576 2304 64 ) ( 576 2304 384 ) ( 384 2304 384 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +( 576 2272 64 ) ( 384 2264 80 ) ( 576 2256 96 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +( 576 2304 256 ) ( 576 2240 256 ) ( 384 2240 256 ) we_cemetary/cemstair2 -59 0 90.00 1 1 0 0 0 +( 576 2256 144 ) ( 384 2256 176 ) ( 576 2256 208 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +( 144 2288 256 ) ( 160 2272 64 ) ( 128 2304 64 ) we_cemetary/cemstair2 192 0 -180.00 1 -1 0 0 0 +( 640 2304 64 ) ( 608 2272 64 ) ( 624 2288 256 ) we_cemetary/cemstair2 192 0 -180.00 1 -1 0 0 0 +} +// brush 866 +{ +( 576 2304 0 ) ( 384 2304 0 ) ( 384 2272 0 ) we_cemetary/cemtrim2 -59 0 90.00 1 1 0 0 0 +( 384 2272 64 ) ( 384 2304 64 ) ( 576 2304 64 ) we_cemetary/cemtrim2 -59 0 90.00 1 1 0 0 0 +( 448 2272 0 ) ( 448 2272 320 ) ( 640 2272 320 ) we_cemetary/cemtrim2 128 0 -180.00 1 -1 0 0 0 +( 576 2304 0 ) ( 576 2304 320 ) ( 384 2304 320 ) we_cemetary/cemtrim2 128 0 -180.00 1 -1 0 0 0 +( 144 2288 64 ) ( 160 2272 0 ) ( 128 2304 0 ) we_cemetary/cemtrim2 192 0 -180.00 1 -1 0 0 0 +( 640 2304 0 ) ( 608 2272 0 ) ( 624 2288 64 ) we_cemetary/cemtrim2 192 0 -180.00 1 -1 0 0 0 +} +// brush 867 +{ +( 640 1856 0 ) ( 640 2048 0 ) ( 608 2048 0 ) we_cemetary/cemtrim2 191 0 -180.00 1 1 0 0 0 +( 608 2048 64 ) ( 640 2048 64 ) ( 640 1856 64 ) we_cemetary/cemtrim2 191 0 -180.00 1 1 0 0 0 +( 608 1920 0 ) ( 608 1920 320 ) ( 608 1728 320 ) we_cemetary/cemtrim2 64 0 -180.00 1 -1 0 0 0 +( 640 1856 0 ) ( 640 1856 320 ) ( 640 2048 320 ) we_cemetary/cemtrim2 64 0 -180.00 1 -1 0 0 0 +( 624 2288 64 ) ( 608 2272 0 ) ( 640 2304 0 ) we_cemetary/cemtrim2 128 0 0.00 1 1 0 0 0 +( 640 1792 0 ) ( 608 1824 0 ) ( 624 1808 64 ) we_cemetary/cemtrim2 0 0 -180.00 1 -1 0 0 0 +} +// brush 868 +{ +( 640 1856 64 ) ( 640 2048 64 ) ( 608 2048 64 ) we_cemetary/cemstair2 191 0 -180.00 1 1 0 0 0 +( 640 1856 64 ) ( 640 1856 384 ) ( 640 2048 384 ) we_cemetary/cemstair2 64 0 -180.00 1 -1 0 0 0 +( 608 1856 64 ) ( 600 2048 80 ) ( 592 1856 96 ) we_cemetary/cemstair2 64 0 -180.00 1 -1 0 0 0 +( 640 1856 256 ) ( 576 1856 256 ) ( 576 2048 256 ) we_cemetary/cemstair2 191 0 -180.00 1 1 0 0 0 +( 592 1856 144 ) ( 592 2048 176 ) ( 592 1856 208 ) we_cemetary/cemstair2 64 0 -180.00 1 -1 0 0 0 +( 624 2288 256 ) ( 608 2272 64 ) ( 640 2304 64 ) we_cemetary/cemstair2 128 0 0.00 1 1 0 0 0 +( 640 1792 64 ) ( 608 1824 64 ) ( 624 1808 256 ) we_cemetary/cemstair2 0 0 -180.00 1 -1 0 0 0 +} +// brush 869 +{ +( 640 2048 256 ) ( 592 2048 256 ) ( 592 1856 256 ) we_cemetary/fogtrunk 191 -64 -180.00 1 1 0 0 0 +( 576 2048 272 ) ( 640 2048 272 ) ( 640 1856 272 ) we_cemetary/fogtrunk 191 -64 -180.00 1 1 0 0 0 +( 576 1856 272 ) ( 592 1856 256 ) ( 592 2048 256 ) we_cemetary/fogtrunk 191 -64 -180.00 1 1 0 0 0 +( 640 1856 256 ) ( 640 1856 272 ) ( 640 2048 272 ) we_cemetary/fogtrunk 64 0 -180.00 1 -1 0 0 0 +( 624 2288 272 ) ( 608 2272 256 ) ( 640 2304 256 ) we_cemetary/fogtrunk 128 0 0.00 1 1 0 0 0 +( 640 1792 256 ) ( 608 1824 256 ) ( 624 1808 272 ) we_cemetary/fogtrunk 0 0 -180.00 1 -1 0 0 0 +} +// brush 870 +{ +( 608 1856 272 ) ( 608 2048 272 ) ( 576 2048 272 ) we_cemetary/cemrunner2 63 0 -180.00 1 1 0 0 0 +( 576 2048 336 ) ( 608 2048 336 ) ( 608 1856 336 ) we_cemetary/cemtrim2 159 0 -180.00 1 1 0 0 0 +( 576 2048 272 ) ( 576 2048 592 ) ( 576 1856 592 ) we_cemetary/cemtrim2 64 15 -180.00 1 -1 0 0 0 +( 640 1856 272 ) ( 640 1856 592 ) ( 640 2048 592 ) we_cemetary/cemtrim2 64 15 -180.00 1 -1 0 0 0 +( 624 2288 336 ) ( 608 2272 272 ) ( 640 2304 272 ) we_cemetary/cemtrim2 128 15 0.00 1 1 0 0 0 +( 640 1792 272 ) ( 608 1824 272 ) ( 624 1808 336 ) we_cemetary/cemtrim2 0 16 -180.00 1 -1 0 0 0 +} +// brush 871 +{ +( 192 1824 272 ) ( 384 1824 272 ) ( 384 1856 272 ) we_cemetary/cemrunner2 -60 0 -90.00 1 1 0 0 0 +( 384 1856 336 ) ( 384 1824 336 ) ( 192 1824 336 ) we_cemetary/cemtrim2 -93 0 -90.00 1 1 0 0 0 +( 384 1856 272 ) ( 384 1856 592 ) ( 192 1856 592 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( 192 1792 272 ) ( 192 1792 592 ) ( 384 1792 592 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( 624 1808 336 ) ( 608 1824 272 ) ( 640 1792 272 ) we_cemetary/cemtrim2 0 15 0.00 1 1 0 0 0 +( 128 1792 272 ) ( 160 1824 272 ) ( 144 1808 336 ) we_cemetary/cemtrim2 128 16 0.00 1 1 0 0 0 +} +// brush 872 +{ +( 384 1792 256 ) ( 384 1840 256 ) ( 192 1840 256 ) we_cemetary/fogtrunk -60 64 -90.00 1 1 0 0 0 +( 384 1856 272 ) ( 384 1792 272 ) ( 192 1792 272 ) we_cemetary/fogtrunk -60 64 -90.00 1 1 0 0 0 +( 192 1856 272 ) ( 192 1840 256 ) ( 384 1840 256 ) we_cemetary/fogtrunk -60 64 -90.00 1 1 0 0 0 +( 192 1792 256 ) ( 192 1792 272 ) ( 384 1792 272 ) we_cemetary/fogtrunk -64 0 0.00 1 1 0 0 0 +( 624 1808 272 ) ( 608 1824 256 ) ( 640 1792 256 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +( 128 1792 256 ) ( 160 1824 256 ) ( 144 1808 272 ) we_cemetary/fogtrunk 128 0 0.00 1 1 0 0 0 +} +// brush 873 +{ +( 192 2048 272 ) ( 160 2048 272 ) ( 160 1856 272 ) we_cemetary/cemrunner2 0 0 0.00 1 1 0 0 0 +( 160 1856 336 ) ( 160 2048 336 ) ( 192 2048 336 ) we_cemetary/cemtrim2 -32 0 0.00 1 1 0 0 0 +( 192 1856 592 ) ( 192 2048 592 ) ( 192 2048 272 ) we_cemetary/cemtrim2 0 16 0.00 1 1 0 0 0 +( 128 2048 592 ) ( 128 1856 592 ) ( 128 1856 272 ) we_cemetary/cemtrim2 0 16 0.00 1 1 0 0 0 +( 128 2304 272 ) ( 160 2272 272 ) ( 144 2288 336 ) we_cemetary/cemtrim2 0 16 0.00 1 1 0 0 0 +( 192 1856 272 ) ( 160 1824 272 ) ( 176 1840 336 ) we_cemetary/cemtrim2 0 16 0.00 1 1 0 0 0 +} +// brush 874 +{ +( 176 1856 256 ) ( 176 2048 256 ) ( 128 2048 256 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +( 128 1856 272 ) ( 128 2048 272 ) ( 192 2048 272 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +( 176 2048 256 ) ( 176 1856 256 ) ( 192 1856 272 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +( 128 2048 272 ) ( 128 1856 272 ) ( 128 1856 256 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +( 128 2304 256 ) ( 160 2272 256 ) ( 144 2288 272 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +( 192 1856 256 ) ( 160 1824 256 ) ( 176 1840 272 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +} +// brush 875 +{ +( 160 2048 64 ) ( 128 2048 64 ) ( 128 1856 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 128 2048 384 ) ( 128 1856 384 ) ( 128 1856 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 176 1856 96 ) ( 168 2048 80 ) ( 160 1856 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 192 2048 256 ) ( 192 1856 256 ) ( 128 1856 256 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 176 1856 208 ) ( 176 2048 176 ) ( 176 1856 144 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 128 2304 64 ) ( 160 2272 64 ) ( 144 2288 256 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 192 1856 64 ) ( 160 1824 64 ) ( 176 1840 256 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +} +// brush 876 +{ +( 160 2048 0 ) ( 128 2048 0 ) ( 128 1856 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( 128 1856 64 ) ( 128 2048 64 ) ( 160 2048 64 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( 160 1792 320 ) ( 160 1984 320 ) ( 160 1984 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( 128 2048 320 ) ( 128 1856 320 ) ( 128 1856 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( 128 2304 0 ) ( 160 2272 0 ) ( 144 2288 64 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( 192 1856 0 ) ( 160 1824 0 ) ( 176 1840 64 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +} +// brush 877 +{ +( 192 1792 0 ) ( 384 1792 0 ) ( 384 1824 0 ) we_cemetary/cemtrim2 -60 0 -90.00 1 1 0 0 0 +( 384 1824 64 ) ( 384 1792 64 ) ( 192 1792 64 ) we_cemetary/cemtrim2 -60 0 -90.00 1 1 0 0 0 +( 256 1824 0 ) ( 256 1824 320 ) ( 64 1824 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 192 1792 0 ) ( 192 1792 320 ) ( 384 1792 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 128 1792 0 ) ( 160 1824 0 ) ( 144 1808 64 ) we_cemetary/cemtrim2 128 0 0.00 1 1 0 0 0 +( 320 1824 0 ) ( 320 1760 0 ) ( 320 1792 64 ) we_cemetary/cemtrim2 128 0 0.00 1 1 0 0 0 +} +// brush 878 +{ +( 192 1792 0 ) ( 384 1792 0 ) ( 384 1824 0 ) we_cemetary/cemtrim2 -60 0 -90.00 1 1 0 0 0 +( 384 1824 64 ) ( 384 1792 64 ) ( 192 1792 64 ) we_cemetary/cemtrim2 -60 0 -90.00 1 1 0 0 0 +( 384 1824 0 ) ( 384 1824 320 ) ( 192 1824 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 192 1792 0 ) ( 192 1792 320 ) ( 384 1792 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 624 1808 64 ) ( 608 1824 0 ) ( 640 1792 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( 448 1760 0 ) ( 448 1824 0 ) ( 448 1792 64 ) we_cemetary/cemtrim2 128 0 0.00 1 1 0 0 0 +} +// brush 879 +{ +( 192 1792 64 ) ( 384 1792 64 ) ( 384 1824 64 ) we_cemetary/cemstair2 -60 0 -90.00 1 1 0 0 0 +( 192 1792 64 ) ( 192 1792 384 ) ( 384 1792 384 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 192 1824 64 ) ( 384 1832 80 ) ( 192 1840 96 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 192 1792 256 ) ( 192 1856 256 ) ( 384 1856 256 ) we_cemetary/cemstair2 -60 0 -90.00 1 1 0 0 0 +( 192 1840 144 ) ( 384 1840 176 ) ( 192 1840 208 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 128 1792 64 ) ( 160 1824 64 ) ( 144 1808 256 ) we_cemetary/cemstair2 128 0 0.00 1 1 0 0 0 +( 320 1824 64 ) ( 320 1760 64 ) ( 320 1792 256 ) we_cemetary/cemstair2 128 0 0.00 1 1 0 0 0 +} +// brush 880 +{ +( 192 1792 64 ) ( 384 1792 64 ) ( 384 1824 64 ) we_cemetary/cemstair2 -60 0 -90.00 1 1 0 0 0 +( 192 1792 64 ) ( 192 1792 384 ) ( 384 1792 384 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 192 1824 64 ) ( 384 1832 80 ) ( 192 1840 96 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 192 1792 256 ) ( 192 1856 256 ) ( 384 1856 256 ) we_cemetary/cemstair2 -60 0 -90.00 1 1 0 0 0 +( 320 1840 144 ) ( 512 1840 176 ) ( 320 1840 208 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 624 1808 256 ) ( 608 1824 64 ) ( 640 1792 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( 448 1760 64 ) ( 448 1824 64 ) ( 448 1792 256 ) we_cemetary/cemstair2 128 0 0.00 1 1 0 0 0 +} +// brush 881 +{ +( 384 1760 64 ) ( 384 1792 64 ) ( 192 1792 64 ) we_cemetary/cemstair2 -125 0 -90.00 1 1 0 0 0 +( 384 1792 384 ) ( 192 1792 384 ) ( 192 1792 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 192 1744 96 ) ( 384 1752 80 ) ( 192 1760 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 384 1728 256 ) ( 192 1728 256 ) ( 192 1792 256 ) we_cemetary/cemstair2 -125 0 -90.00 1 1 0 0 0 +( 288 1744 208 ) ( 480 1744 176 ) ( 288 1744 144 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 448 1760 64 ) ( 448 1824 64 ) ( 448 1792 256 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +( 640 1792 64 ) ( 640 1728 64 ) ( 640 1760 256 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +} +// brush 882 +{ +( 384 1760 0 ) ( 384 1792 0 ) ( 192 1792 0 ) we_cemetary/cemtrim2 -125 0 -90.00 1 1 0 0 0 +( 192 1792 64 ) ( 384 1792 64 ) ( 384 1760 64 ) we_cemetary/cemtrim2 -125 0 -90.00 1 1 0 0 0 +( 288 1760 320 ) ( 480 1760 320 ) ( 480 1760 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 384 1792 320 ) ( 192 1792 320 ) ( 192 1792 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 448 1760 0 ) ( 448 1824 0 ) ( 448 1792 64 ) we_cemetary/cemtrim2 192 0 0.00 1 1 0 0 0 +( 640 1792 0 ) ( 640 1728 0 ) ( 640 1760 64 ) we_cemetary/cemtrim2 192 0 0.00 1 1 0 0 0 +} +// brush 883 +{ +( 384 1760 64 ) ( 384 1792 64 ) ( 192 1792 64 ) we_cemetary/cemstair2 -125 0 -90.00 1 1 0 0 0 +( 384 1792 384 ) ( 192 1792 384 ) ( 192 1792 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 192 1744 96 ) ( 384 1752 80 ) ( 192 1760 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 384 1728 256 ) ( 192 1728 256 ) ( 192 1792 256 ) we_cemetary/cemstair2 -125 0 -90.00 1 1 0 0 0 +( 192 1744 208 ) ( 384 1744 176 ) ( 192 1744 144 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 320 1824 64 ) ( 320 1760 64 ) ( 320 1792 256 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +( 128 1728 64 ) ( 128 1760 64 ) ( 128 1744 256 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +} +// brush 884 +{ +( 384 1760 0 ) ( 384 1792 0 ) ( 192 1792 0 ) we_cemetary/cemtrim2 -125 0 -90.00 1 1 0 0 0 +( 192 1792 64 ) ( 384 1792 64 ) ( 384 1760 64 ) we_cemetary/cemtrim2 -125 0 -90.00 1 1 0 0 0 +( 0 1760 320 ) ( 192 1760 320 ) ( 192 1760 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 384 1792 320 ) ( 192 1792 320 ) ( 192 1792 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 320 1824 0 ) ( 320 1760 0 ) ( 320 1792 64 ) we_cemetary/cemtrim2 192 0 0.00 1 1 0 0 0 +( 128 1728 0 ) ( 128 1760 0 ) ( 128 1744 64 ) we_cemetary/cemtrim2 192 0 0.00 1 1 0 0 0 +} +// brush 885 +{ +( 192 1744 256 ) ( 384 1744 256 ) ( 384 1792 256 ) we_cemetary/fogtrunk -125 64 -90.00 1 1 0 0 0 +( 192 1792 272 ) ( 384 1792 272 ) ( 384 1728 272 ) we_cemetary/fogtrunk -125 64 -90.00 1 1 0 0 0 +( 384 1744 256 ) ( 192 1744 256 ) ( 192 1728 272 ) we_cemetary/fogtrunk -125 64 -90.00 1 1 0 0 0 +( 384 1792 272 ) ( 192 1792 272 ) ( 192 1792 256 ) we_cemetary/fogtrunk -64 0 0.00 1 1 0 0 0 +( 640 1792 256 ) ( 640 1728 256 ) ( 640 1760 272 ) we_cemetary/fogtrunk 192 0 0.00 1 1 0 0 0 +( 128 1728 256 ) ( 128 1760 256 ) ( 128 1744 272 ) we_cemetary/fogtrunk 192 0 0.00 1 1 0 0 0 +} +// brush 886 +{ +( 384 1728 272 ) ( 384 1760 272 ) ( 192 1760 272 ) we_cemetary/cemrunner2 0 0 -90.00 1 1 0 0 0 +( 192 1760 336 ) ( 384 1760 336 ) ( 384 1728 336 ) we_cemetary/cemtrim2 -157 0 -90.00 1 1 0 0 0 +( 192 1728 592 ) ( 384 1728 592 ) ( 384 1728 272 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( 384 1792 592 ) ( 192 1792 592 ) ( 192 1792 272 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( 640 1792 272 ) ( 640 1728 272 ) ( 640 1760 336 ) we_cemetary/cemtrim2 192 16 0.00 1 1 0 0 0 +( 128 1728 272 ) ( 128 1760 272 ) ( 128 1744 336 ) we_cemetary/cemtrim2 192 16 0.00 1 1 0 0 0 +} +// brush 887 +{ +( 608 2272 -32 ) ( 160 2272 -32 ) ( 160 1824 -32 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 160 1824 0 ) ( 160 2272 0 ) ( 608 2272 0 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 160 1760 0 ) ( 608 1760 0 ) ( 608 1760 -64 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 640 1824 0 ) ( 640 2272 0 ) ( 640 2272 -64 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 608 2304 0 ) ( 160 2304 0 ) ( 160 2304 -64 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 128 2272 0 ) ( 128 1824 0 ) ( 128 1824 -64 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +} +// brush 888 +{ +( 608 2272 336 ) ( 160 2272 336 ) ( 160 1824 336 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +( 160 1824 352 ) ( 160 2272 352 ) ( 608 2272 352 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +( 160 1824 368 ) ( 608 1824 368 ) ( 608 1824 304 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +( 608 1824 368 ) ( 608 2272 368 ) ( 608 2272 304 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +( 608 2272 368 ) ( 160 2272 368 ) ( 160 2272 304 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +( 160 2272 368 ) ( 160 1824 368 ) ( 160 1824 304 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +} +// brush 889 +{ +( 448 1840 208 ) ( 320 1840 208 ) ( 320 1744 208 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 320 1744 256 ) ( 320 1840 256 ) ( 448 1840 256 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 320 1744 256 ) ( 448 1744 256 ) ( 448 1744 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 448 1744 240 ) ( 448 1840 240 ) ( 448 1840 48 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +( 448 1840 240 ) ( 320 1840 240 ) ( 320 1840 48 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 320 1840 256 ) ( 320 1744 256 ) ( 320 1744 64 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +} +// brush 890 +{ +( -64 1840 208 ) ( -192 1840 208 ) ( -192 1744 208 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -192 1744 256 ) ( -192 1840 256 ) ( -64 1840 256 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -192 1744 256 ) ( -64 1744 256 ) ( -64 1744 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -64 1744 240 ) ( -64 1840 240 ) ( -64 1840 48 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +( -64 1840 240 ) ( -192 1840 240 ) ( -192 1840 48 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -192 1840 256 ) ( -192 1744 256 ) ( -192 1744 64 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +} +// brush 891 +{ +( 96 2272 336 ) ( -352 2272 336 ) ( -352 1824 336 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +( -352 1824 352 ) ( -352 2272 352 ) ( 96 2272 352 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +( -352 1824 368 ) ( 96 1824 368 ) ( 96 1824 304 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +( 96 1824 368 ) ( 96 2272 368 ) ( 96 2272 304 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +( 96 2272 368 ) ( -352 2272 368 ) ( -352 2272 304 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +( -352 2272 368 ) ( -352 1824 368 ) ( -352 1824 304 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +} +// brush 892 +{ +( 96 2272 -32 ) ( -352 2272 -32 ) ( -352 1824 -32 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( -352 1824 0 ) ( -352 2272 0 ) ( 96 2272 0 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( -352 1760 0 ) ( 96 1760 0 ) ( 96 1760 -64 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 128 1824 0 ) ( 128 2272 0 ) ( 128 2272 -64 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( 96 2304 0 ) ( -352 2304 0 ) ( -352 2304 -64 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( -384 2272 0 ) ( -384 1824 0 ) ( -384 1824 -64 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +} +// brush 893 +{ +( -128 1728 272 ) ( -128 1760 272 ) ( -320 1760 272 ) we_cemetary/cemrunner2 0 0 -90.00 1 1 0 0 0 +( -320 1760 336 ) ( -128 1760 336 ) ( -128 1728 336 ) we_cemetary/cemtrim2 -158 0 -90.00 1 1 0 0 0 +( -320 1728 592 ) ( -128 1728 592 ) ( -128 1728 272 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( -128 1792 592 ) ( -320 1792 592 ) ( -320 1792 272 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( 128 1792 272 ) ( 128 1728 272 ) ( 128 1760 336 ) we_cemetary/cemtrim2 192 16 0.00 1 1 0 0 0 +( -384 1728 272 ) ( -384 1760 272 ) ( -384 1744 336 ) we_cemetary/cemtrim2 192 16 0.00 1 1 0 0 0 +} +// brush 894 +{ +( -320 1744 256 ) ( -128 1744 256 ) ( -128 1792 256 ) we_cemetary/fogtrunk -126 64 -90.00 1 1 0 0 0 +( -320 1792 272 ) ( -128 1792 272 ) ( -128 1728 272 ) we_cemetary/fogtrunk -126 64 -90.00 1 1 0 0 0 +( -128 1744 256 ) ( -320 1744 256 ) ( -320 1728 272 ) we_cemetary/fogtrunk -126 64 -90.00 1 1 0 0 0 +( -128 1792 272 ) ( -320 1792 272 ) ( -320 1792 256 ) we_cemetary/fogtrunk -64 0 0.00 1 1 0 0 0 +( 128 1792 256 ) ( 128 1728 256 ) ( 128 1760 272 ) we_cemetary/fogtrunk 192 0 0.00 1 1 0 0 0 +( -384 1728 256 ) ( -384 1760 256 ) ( -384 1744 272 ) we_cemetary/fogtrunk 192 0 0.00 1 1 0 0 0 +} +// brush 895 +{ +( -128 1760 0 ) ( -128 1792 0 ) ( -320 1792 0 ) we_cemetary/cemtrim2 -126 0 -90.00 1 1 0 0 0 +( -320 1792 64 ) ( -128 1792 64 ) ( -128 1760 64 ) we_cemetary/cemtrim2 -126 0 -90.00 1 1 0 0 0 +( -512 1760 320 ) ( -320 1760 320 ) ( -320 1760 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( -128 1792 320 ) ( -320 1792 320 ) ( -320 1792 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( -192 1824 0 ) ( -192 1760 0 ) ( -192 1792 64 ) we_cemetary/cemtrim2 192 0 0.00 1 1 0 0 0 +( -384 1728 0 ) ( -384 1760 0 ) ( -384 1744 64 ) we_cemetary/cemtrim2 192 0 0.00 1 1 0 0 0 +} +// brush 896 +{ +( -128 1760 64 ) ( -128 1792 64 ) ( -320 1792 64 ) we_cemetary/cemstair2 -126 0 -90.00 1 1 0 0 0 +( -128 1792 384 ) ( -320 1792 384 ) ( -320 1792 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -320 1744 96 ) ( -128 1752 80 ) ( -320 1760 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -128 1728 256 ) ( -320 1728 256 ) ( -320 1792 256 ) we_cemetary/cemstair2 -126 0 -90.00 1 1 0 0 0 +( -320 1744 208 ) ( -128 1744 176 ) ( -320 1744 144 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -192 1824 64 ) ( -192 1760 64 ) ( -192 1792 256 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +( -384 1728 64 ) ( -384 1760 64 ) ( -384 1744 256 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +} +// brush 897 +{ +( -128 1760 0 ) ( -128 1792 0 ) ( -320 1792 0 ) we_cemetary/cemtrim2 -126 0 -90.00 1 1 0 0 0 +( -320 1792 64 ) ( -128 1792 64 ) ( -128 1760 64 ) we_cemetary/cemtrim2 -126 0 -90.00 1 1 0 0 0 +( -224 1760 320 ) ( -32 1760 320 ) ( -32 1760 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( -128 1792 320 ) ( -320 1792 320 ) ( -320 1792 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( -64 1760 0 ) ( -64 1824 0 ) ( -64 1792 64 ) we_cemetary/cemtrim2 192 0 0.00 1 1 0 0 0 +( 128 1792 0 ) ( 128 1728 0 ) ( 128 1760 64 ) we_cemetary/cemtrim2 192 0 0.00 1 1 0 0 0 +} +// brush 898 +{ +( -128 1760 64 ) ( -128 1792 64 ) ( -320 1792 64 ) we_cemetary/cemstair2 -126 0 -90.00 1 1 0 0 0 +( -128 1792 384 ) ( -320 1792 384 ) ( -320 1792 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -320 1744 96 ) ( -128 1752 80 ) ( -320 1760 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -128 1728 256 ) ( -320 1728 256 ) ( -320 1792 256 ) we_cemetary/cemstair2 -126 0 -90.00 1 1 0 0 0 +( -224 1744 208 ) ( -32 1744 176 ) ( -224 1744 144 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -64 1760 64 ) ( -64 1824 64 ) ( -64 1792 256 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +( 128 1792 64 ) ( 128 1728 64 ) ( 128 1760 256 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +} +// brush 899 +{ +( -320 1792 64 ) ( -128 1792 64 ) ( -128 1824 64 ) we_cemetary/cemstair2 -61 0 -90.00 1 1 0 0 0 +( -320 1792 64 ) ( -320 1792 384 ) ( -128 1792 384 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -320 1824 64 ) ( -128 1832 80 ) ( -320 1840 96 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -320 1792 256 ) ( -320 1856 256 ) ( -128 1856 256 ) we_cemetary/cemstair2 -61 0 -90.00 1 1 0 0 0 +( -192 1840 144 ) ( 0 1840 176 ) ( -192 1840 208 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( 112 1808 256 ) ( 96 1824 64 ) ( 128 1792 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( -64 1760 64 ) ( -64 1824 64 ) ( -64 1792 256 ) we_cemetary/cemstair2 128 0 0.00 1 1 0 0 0 +} +// brush 900 +{ +( -320 1792 64 ) ( -128 1792 64 ) ( -128 1824 64 ) we_cemetary/cemstair2 -61 0 -90.00 1 1 0 0 0 +( -320 1792 64 ) ( -320 1792 384 ) ( -128 1792 384 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -320 1824 64 ) ( -128 1832 80 ) ( -320 1840 96 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -320 1792 256 ) ( -320 1856 256 ) ( -128 1856 256 ) we_cemetary/cemstair2 -61 0 -90.00 1 1 0 0 0 +( -320 1840 144 ) ( -128 1840 176 ) ( -320 1840 208 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -384 1792 64 ) ( -352 1824 64 ) ( -368 1808 256 ) we_cemetary/cemstair2 128 0 0.00 1 1 0 0 0 +( -192 1824 64 ) ( -192 1760 64 ) ( -192 1792 256 ) we_cemetary/cemstair2 128 0 0.00 1 1 0 0 0 +} +// brush 901 +{ +( -320 1792 0 ) ( -128 1792 0 ) ( -128 1824 0 ) we_cemetary/cemtrim2 -61 0 -90.00 1 1 0 0 0 +( -128 1824 64 ) ( -128 1792 64 ) ( -320 1792 64 ) we_cemetary/cemtrim2 -61 0 -90.00 1 1 0 0 0 +( -128 1824 0 ) ( -128 1824 320 ) ( -320 1824 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( -320 1792 0 ) ( -320 1792 320 ) ( -128 1792 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( 112 1808 64 ) ( 96 1824 0 ) ( 128 1792 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( -64 1760 0 ) ( -64 1824 0 ) ( -64 1792 64 ) we_cemetary/cemtrim2 128 0 0.00 1 1 0 0 0 +} +// brush 902 +{ +( -320 1792 0 ) ( -128 1792 0 ) ( -128 1824 0 ) we_cemetary/cemtrim2 -61 0 -90.00 1 1 0 0 0 +( -128 1824 64 ) ( -128 1792 64 ) ( -320 1792 64 ) we_cemetary/cemtrim2 -61 0 -90.00 1 1 0 0 0 +( -256 1824 0 ) ( -256 1824 320 ) ( -448 1824 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( -320 1792 0 ) ( -320 1792 320 ) ( -128 1792 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( -384 1792 0 ) ( -352 1824 0 ) ( -368 1808 64 ) we_cemetary/cemtrim2 128 0 0.00 1 1 0 0 0 +( -192 1824 0 ) ( -192 1760 0 ) ( -192 1792 64 ) we_cemetary/cemtrim2 128 0 0.00 1 1 0 0 0 +} +// brush 903 +{ +( -352 2048 0 ) ( -384 2048 0 ) ( -384 1856 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( -384 1856 64 ) ( -384 2048 64 ) ( -352 2048 64 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( -352 1792 320 ) ( -352 1984 320 ) ( -352 1984 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( -384 2048 320 ) ( -384 1856 320 ) ( -384 1856 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( -384 2304 0 ) ( -352 2272 0 ) ( -368 2288 64 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( -320 1856 0 ) ( -352 1824 0 ) ( -336 1840 64 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +} +// brush 904 +{ +( -352 2048 64 ) ( -384 2048 64 ) ( -384 1856 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( -384 2048 384 ) ( -384 1856 384 ) ( -384 1856 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( -336 1856 96 ) ( -344 2048 80 ) ( -352 1856 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( -320 2048 256 ) ( -320 1856 256 ) ( -384 1856 256 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( -336 1856 208 ) ( -336 2048 176 ) ( -336 1856 144 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( -384 2304 64 ) ( -352 2272 64 ) ( -368 2288 256 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( -320 1856 64 ) ( -352 1824 64 ) ( -336 1840 256 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +} +// brush 905 +{ +( -336 1856 256 ) ( -336 2048 256 ) ( -384 2048 256 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +( -384 1856 272 ) ( -384 2048 272 ) ( -320 2048 272 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +( -336 2048 256 ) ( -336 1856 256 ) ( -320 1856 272 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +( -384 2048 272 ) ( -384 1856 272 ) ( -384 1856 256 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +( -384 2304 256 ) ( -352 2272 256 ) ( -368 2288 272 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +( -320 1856 256 ) ( -352 1824 256 ) ( -336 1840 272 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +} +// brush 906 +{ +( -320 2048 272 ) ( -352 2048 272 ) ( -352 1856 272 ) we_cemetary/cemrunner2 0 0 0.00 1 1 0 0 0 +( -352 1856 336 ) ( -352 2048 336 ) ( -320 2048 336 ) we_cemetary/cemtrim2 -32 0 0.00 1 1 0 0 0 +( -320 1856 592 ) ( -320 2048 592 ) ( -320 2048 272 ) we_cemetary/cemtrim2 0 16 0.00 1 1 0 0 0 +( -384 2048 592 ) ( -384 1856 592 ) ( -384 1856 272 ) we_cemetary/cemtrim2 0 16 0.00 1 1 0 0 0 +( -384 2304 272 ) ( -352 2272 272 ) ( -368 2288 336 ) we_cemetary/cemtrim2 0 16 0.00 1 1 0 0 0 +( -320 1856 272 ) ( -352 1824 272 ) ( -336 1840 336 ) we_cemetary/cemtrim2 0 16 0.00 1 1 0 0 0 +} +// brush 907 +{ +( -128 1792 256 ) ( -128 1840 256 ) ( -320 1840 256 ) we_cemetary/fogtrunk -61 64 -90.00 1 1 0 0 0 +( -128 1856 272 ) ( -128 1792 272 ) ( -320 1792 272 ) we_cemetary/fogtrunk -61 64 -90.00 1 1 0 0 0 +( -320 1856 272 ) ( -320 1840 256 ) ( -128 1840 256 ) we_cemetary/fogtrunk -61 64 -90.00 1 1 0 0 0 +( -320 1792 256 ) ( -320 1792 272 ) ( -128 1792 272 ) we_cemetary/fogtrunk -64 0 0.00 1 1 0 0 0 +( 112 1808 272 ) ( 96 1824 256 ) ( 128 1792 256 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +( -384 1792 256 ) ( -352 1824 256 ) ( -368 1808 272 ) we_cemetary/fogtrunk 128 0 0.00 1 1 0 0 0 +} +// brush 908 +{ +( -320 1824 272 ) ( -128 1824 272 ) ( -128 1856 272 ) we_cemetary/cemrunner2 -61 0 -90.00 1 1 0 0 0 +( -128 1856 336 ) ( -128 1824 336 ) ( -320 1824 336 ) we_cemetary/cemtrim2 -94 0 -90.00 1 1 0 0 0 +( -128 1856 272 ) ( -128 1856 592 ) ( -320 1856 592 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( -320 1792 272 ) ( -320 1792 592 ) ( -128 1792 592 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( 112 1808 336 ) ( 96 1824 272 ) ( 128 1792 272 ) we_cemetary/cemtrim2 0 15 0.00 1 1 0 0 0 +( -384 1792 272 ) ( -352 1824 272 ) ( -368 1808 336 ) we_cemetary/cemtrim2 128 16 0.00 1 1 0 0 0 +} +// brush 909 +{ +( 96 1856 272 ) ( 96 2048 272 ) ( 64 2048 272 ) we_cemetary/cemrunner2 63 0 -180.00 1 1 0 0 0 +( 64 2048 336 ) ( 96 2048 336 ) ( 96 1856 336 ) we_cemetary/cemtrim2 159 0 -180.00 1 1 0 0 0 +( 64 2048 272 ) ( 64 2048 592 ) ( 64 1856 592 ) we_cemetary/cemtrim2 64 15 -180.00 1 -1 0 0 0 +( 128 1856 272 ) ( 128 1856 592 ) ( 128 2048 592 ) we_cemetary/cemtrim2 64 15 -180.00 1 -1 0 0 0 +( 112 2288 336 ) ( 96 2272 272 ) ( 128 2304 272 ) we_cemetary/cemtrim2 128 15 0.00 1 1 0 0 0 +( 128 1792 272 ) ( 96 1824 272 ) ( 112 1808 336 ) we_cemetary/cemtrim2 0 16 -180.00 1 -1 0 0 0 +} +// brush 910 +{ +( 128 2048 256 ) ( 80 2048 256 ) ( 80 1856 256 ) we_cemetary/fogtrunk 191 -64 -180.00 1 1 0 0 0 +( 64 2048 272 ) ( 128 2048 272 ) ( 128 1856 272 ) we_cemetary/fogtrunk 191 -64 -180.00 1 1 0 0 0 +( 64 1856 272 ) ( 80 1856 256 ) ( 80 2048 256 ) we_cemetary/fogtrunk 191 -64 -180.00 1 1 0 0 0 +( 128 1856 256 ) ( 128 1856 272 ) ( 128 2048 272 ) we_cemetary/fogtrunk 64 0 -180.00 1 -1 0 0 0 +( 112 2288 272 ) ( 96 2272 256 ) ( 128 2304 256 ) we_cemetary/fogtrunk 128 0 0.00 1 1 0 0 0 +( 128 1792 256 ) ( 96 1824 256 ) ( 112 1808 272 ) we_cemetary/fogtrunk 0 0 -180.00 1 -1 0 0 0 +} +// brush 911 +{ +( 128 1856 64 ) ( 128 2048 64 ) ( 96 2048 64 ) we_cemetary/cemstair2 191 0 -180.00 1 1 0 0 0 +( 128 1856 64 ) ( 128 1856 384 ) ( 128 2048 384 ) we_cemetary/cemstair2 64 0 -180.00 1 -1 0 0 0 +( 96 1856 64 ) ( 88 2048 80 ) ( 80 1856 96 ) we_cemetary/cemstair2 64 0 -180.00 1 -1 0 0 0 +( 128 1856 256 ) ( 64 1856 256 ) ( 64 2048 256 ) we_cemetary/cemstair2 191 0 -180.00 1 1 0 0 0 +( 80 1856 144 ) ( 80 2048 176 ) ( 80 1856 208 ) we_cemetary/cemstair2 64 0 -180.00 1 -1 0 0 0 +( 112 2288 256 ) ( 96 2272 64 ) ( 128 2304 64 ) we_cemetary/cemstair2 128 0 0.00 1 1 0 0 0 +( 128 1792 64 ) ( 96 1824 64 ) ( 112 1808 256 ) we_cemetary/cemstair2 0 0 -180.00 1 -1 0 0 0 +} +// brush 912 +{ +( 128 1856 0 ) ( 128 2048 0 ) ( 96 2048 0 ) we_cemetary/cemtrim2 191 0 -180.00 1 1 0 0 0 +( 96 2048 64 ) ( 128 2048 64 ) ( 128 1856 64 ) we_cemetary/cemtrim2 191 0 -180.00 1 1 0 0 0 +( 96 1920 0 ) ( 96 1920 320 ) ( 96 1728 320 ) we_cemetary/cemtrim2 64 0 -180.00 1 -1 0 0 0 +( 128 1856 0 ) ( 128 1856 320 ) ( 128 2048 320 ) we_cemetary/cemtrim2 64 0 -180.00 1 -1 0 0 0 +( 112 2288 64 ) ( 96 2272 0 ) ( 128 2304 0 ) we_cemetary/cemtrim2 128 0 0.00 1 1 0 0 0 +( 128 1792 0 ) ( 96 1824 0 ) ( 112 1808 64 ) we_cemetary/cemtrim2 0 0 -180.00 1 -1 0 0 0 +} +// brush 913 +{ +( 64 2304 0 ) ( -128 2304 0 ) ( -128 2272 0 ) we_cemetary/cemtrim2 -60 0 90.00 1 1 0 0 0 +( -128 2272 64 ) ( -128 2304 64 ) ( 64 2304 64 ) we_cemetary/cemtrim2 -60 0 90.00 1 1 0 0 0 +( -64 2272 0 ) ( -64 2272 320 ) ( 128 2272 320 ) we_cemetary/cemtrim2 128 0 -180.00 1 -1 0 0 0 +( 64 2304 0 ) ( 64 2304 320 ) ( -128 2304 320 ) we_cemetary/cemtrim2 128 0 -180.00 1 -1 0 0 0 +( -368 2288 64 ) ( -352 2272 0 ) ( -384 2304 0 ) we_cemetary/cemtrim2 192 0 -180.00 1 -1 0 0 0 +( 128 2304 0 ) ( 96 2272 0 ) ( 112 2288 64 ) we_cemetary/cemtrim2 192 0 -180.00 1 -1 0 0 0 +} +// brush 914 +{ +( 64 2304 64 ) ( -128 2304 64 ) ( -128 2272 64 ) we_cemetary/cemstair2 -60 0 90.00 1 1 0 0 0 +( 64 2304 64 ) ( 64 2304 384 ) ( -128 2304 384 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +( 64 2272 64 ) ( -128 2264 80 ) ( 64 2256 96 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +( 64 2304 256 ) ( 64 2240 256 ) ( -128 2240 256 ) we_cemetary/cemstair2 -60 0 90.00 1 1 0 0 0 +( 64 2256 144 ) ( -128 2256 176 ) ( 64 2256 208 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +( -368 2288 256 ) ( -352 2272 64 ) ( -384 2304 64 ) we_cemetary/cemstair2 192 0 -180.00 1 -1 0 0 0 +( 128 2304 64 ) ( 96 2272 64 ) ( 112 2288 256 ) we_cemetary/cemstair2 192 0 -180.00 1 -1 0 0 0 +} +// brush 915 +{ +( -128 2304 256 ) ( -128 2256 256 ) ( 64 2256 256 ) we_cemetary/fogtrunk -60 -128 90.00 1 1 0 0 0 +( -128 2240 272 ) ( -128 2304 272 ) ( 64 2304 272 ) we_cemetary/fogtrunk -60 -128 90.00 1 1 0 0 0 +( 64 2240 272 ) ( 64 2256 256 ) ( -128 2256 256 ) we_cemetary/fogtrunk -60 -128 90.00 1 1 0 0 0 +( 64 2304 256 ) ( 64 2304 272 ) ( -128 2304 272 ) we_cemetary/fogtrunk 128 0 -180.00 1 -1 0 0 0 +( -368 2288 272 ) ( -352 2272 256 ) ( -384 2304 256 ) we_cemetary/fogtrunk 192 0 -180.00 1 -1 0 0 0 +( 128 2304 256 ) ( 96 2272 256 ) ( 112 2288 272 ) we_cemetary/fogtrunk 192 0 -180.00 1 -1 0 0 0 +} +// brush 916 +{ +( 64 2272 272 ) ( -128 2272 272 ) ( -128 2240 272 ) we_cemetary/cemrunner2 -60 1 90.00 1 1.000122 0 0 0 +( -128 2240 336 ) ( -128 2272 336 ) ( 64 2272 336 ) we_cemetary/cemtrim2 -92 0 90.00 1 1 0 0 0 +( -128 2240 272 ) ( -128 2240 592 ) ( 64 2240 592 ) we_cemetary/cemtrim2 128 15 -180.00 1 -1 0 0 0 +( 64 2304 272 ) ( 64 2304 592 ) ( -128 2304 592 ) we_cemetary/cemtrim2 128 15 -180.00 1 -1 0 0 0 +( -368 2288 336 ) ( -352 2272 272 ) ( -384 2304 272 ) we_cemetary/cemtrim2 192 16 -180.00 1 -1 0 0 0 +( 128 2304 272 ) ( 96 2272 272 ) ( 112 2288 336 ) we_cemetary/cemtrim2 192 16 -180.00 1 -1 0 0 0 +} +// brush 917 +{ +( -448 2272 272 ) ( -640 2272 272 ) ( -640 2240 272 ) we_cemetary/cemrunner2 -61 -31 90.00 1 1.000122 0 0 0 +( -640 2240 336 ) ( -640 2272 336 ) ( -448 2272 336 ) we_cemetary/cemtrim2 -93 0 90.00 1 1 0 0 0 +( -640 2240 272 ) ( -640 2240 592 ) ( -448 2240 592 ) we_cemetary/cemtrim2 128 15 -180.00 1 -1 0 0 0 +( -448 2304 272 ) ( -448 2304 592 ) ( -640 2304 592 ) we_cemetary/cemtrim2 128 15 -180.00 1 -1 0 0 0 +( -880 2288 336 ) ( -864 2272 272 ) ( -896 2304 272 ) we_cemetary/cemtrim2 192 16 -180.00 1 -1 0 0 0 +( -384 2304 272 ) ( -416 2272 272 ) ( -400 2288 336 ) we_cemetary/cemtrim2 192 16 -180.00 1 -1 0 0 0 +} +// brush 918 +{ +( -640 2304 256 ) ( -640 2256 256 ) ( -448 2256 256 ) we_cemetary/fogtrunk -61 -128 90.00 1 1 0 0 0 +( -640 2240 272 ) ( -640 2304 272 ) ( -448 2304 272 ) we_cemetary/fogtrunk -61 -128 90.00 1 1 0 0 0 +( -448 2240 272 ) ( -448 2256 256 ) ( -640 2256 256 ) we_cemetary/fogtrunk -61 -128 90.00 1 1 0 0 0 +( -448 2304 256 ) ( -448 2304 272 ) ( -640 2304 272 ) we_cemetary/fogtrunk 128 0 -180.00 1 -1 0 0 0 +( -880 2288 272 ) ( -864 2272 256 ) ( -896 2304 256 ) we_cemetary/fogtrunk 192 0 -180.00 1 -1 0 0 0 +( -384 2304 256 ) ( -416 2272 256 ) ( -400 2288 272 ) we_cemetary/fogtrunk 192 0 -180.00 1 -1 0 0 0 +} +// brush 919 +{ +( -448 2304 64 ) ( -640 2304 64 ) ( -640 2272 64 ) we_cemetary/cemstair2 -61 0 90.00 1 1 0 0 0 +( -448 2304 64 ) ( -448 2304 384 ) ( -640 2304 384 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +( -448 2272 64 ) ( -640 2264 80 ) ( -448 2256 96 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +( -448 2304 256 ) ( -448 2240 256 ) ( -640 2240 256 ) we_cemetary/cemstair2 -61 0 90.00 1 1 0 0 0 +( -448 2256 144 ) ( -640 2256 176 ) ( -448 2256 208 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +( -880 2288 256 ) ( -864 2272 64 ) ( -896 2304 64 ) we_cemetary/cemstair2 192 0 -180.00 1 -1 0 0 0 +( -384 2304 64 ) ( -416 2272 64 ) ( -400 2288 256 ) we_cemetary/cemstair2 192 0 -180.00 1 -1 0 0 0 +} +// brush 920 +{ +( -448 2304 0 ) ( -640 2304 0 ) ( -640 2272 0 ) we_cemetary/cemtrim2 -61 0 90.00 1 1 0 0 0 +( -640 2272 64 ) ( -640 2304 64 ) ( -448 2304 64 ) we_cemetary/cemtrim2 -61 0 90.00 1 1 0 0 0 +( -576 2272 0 ) ( -576 2272 320 ) ( -384 2272 320 ) we_cemetary/cemtrim2 128 0 -180.00 1 -1 0 0 0 +( -448 2304 0 ) ( -448 2304 320 ) ( -640 2304 320 ) we_cemetary/cemtrim2 128 0 -180.00 1 -1 0 0 0 +( -880 2288 64 ) ( -864 2272 0 ) ( -896 2304 0 ) we_cemetary/cemtrim2 192 0 -180.00 1 -1 0 0 0 +( -384 2304 0 ) ( -416 2272 0 ) ( -400 2288 64 ) we_cemetary/cemtrim2 192 0 -180.00 1 -1 0 0 0 +} +// brush 921 +{ +( -384 1856 0 ) ( -384 2048 0 ) ( -416 2048 0 ) we_cemetary/cemtrim2 191 0 -180.00 1 1 0 0 0 +( -416 2048 64 ) ( -384 2048 64 ) ( -384 1856 64 ) we_cemetary/cemtrim2 191 0 -180.00 1 1 0 0 0 +( -416 1920 0 ) ( -416 1920 320 ) ( -416 1728 320 ) we_cemetary/cemtrim2 64 0 -180.00 1 -1 0 0 0 +( -384 1856 0 ) ( -384 1856 320 ) ( -384 2048 320 ) we_cemetary/cemtrim2 64 0 -180.00 1 -1 0 0 0 +( -400 2288 64 ) ( -416 2272 0 ) ( -384 2304 0 ) we_cemetary/cemtrim2 128 0 0.00 1 1 0 0 0 +( -384 1792 0 ) ( -416 1824 0 ) ( -400 1808 64 ) we_cemetary/cemtrim2 0 0 -180.00 1 -1 0 0 0 +} +// brush 922 +{ +( -384 1856 64 ) ( -384 2048 64 ) ( -416 2048 64 ) we_cemetary/cemstair2 191 0 -180.00 1 1 0 0 0 +( -384 1856 64 ) ( -384 1856 384 ) ( -384 2048 384 ) we_cemetary/cemstair2 64 0 -180.00 1 -1 0 0 0 +( -416 1856 64 ) ( -424 2048 80 ) ( -432 1856 96 ) we_cemetary/cemstair2 64 0 -180.00 1 -1 0 0 0 +( -384 1856 256 ) ( -448 1856 256 ) ( -448 2048 256 ) we_cemetary/cemstair2 191 0 -180.00 1 1 0 0 0 +( -432 1856 144 ) ( -432 2048 176 ) ( -432 1856 208 ) we_cemetary/cemstair2 64 0 -180.00 1 -1 0 0 0 +( -400 2288 256 ) ( -416 2272 64 ) ( -384 2304 64 ) we_cemetary/cemstair2 128 0 0.00 1 1 0 0 0 +( -384 1792 64 ) ( -416 1824 64 ) ( -400 1808 256 ) we_cemetary/cemstair2 0 0 -180.00 1 -1 0 0 0 +} +// brush 923 +{ +( -384 2048 256 ) ( -432 2048 256 ) ( -432 1856 256 ) we_cemetary/fogtrunk 191 -64 -180.00 1 1 0 0 0 +( -448 2048 272 ) ( -384 2048 272 ) ( -384 1856 272 ) we_cemetary/fogtrunk 191 -64 -180.00 1 1 0 0 0 +( -448 1856 272 ) ( -432 1856 256 ) ( -432 2048 256 ) we_cemetary/fogtrunk 191 -64 -180.00 1 1 0 0 0 +( -384 1856 256 ) ( -384 1856 272 ) ( -384 2048 272 ) we_cemetary/fogtrunk 64 0 -180.00 1 -1 0 0 0 +( -400 2288 272 ) ( -416 2272 256 ) ( -384 2304 256 ) we_cemetary/fogtrunk 128 0 0.00 1 1 0 0 0 +( -384 1792 256 ) ( -416 1824 256 ) ( -400 1808 272 ) we_cemetary/fogtrunk 0 0 -180.00 1 -1 0 0 0 +} +// brush 924 +{ +( -416 1856 272 ) ( -416 2048 272 ) ( -448 2048 272 ) we_cemetary/cemrunner2 63 0 -180.00 1 1 0 0 0 +( -448 2048 336 ) ( -416 2048 336 ) ( -416 1856 336 ) we_cemetary/cemtrim2 159 0 -180.00 1 1 0 0 0 +( -448 2048 272 ) ( -448 2048 592 ) ( -448 1856 592 ) we_cemetary/cemtrim2 64 15 -180.00 1 -1 0 0 0 +( -384 1856 272 ) ( -384 1856 592 ) ( -384 2048 592 ) we_cemetary/cemtrim2 64 15 -180.00 1 -1 0 0 0 +( -400 2288 336 ) ( -416 2272 272 ) ( -384 2304 272 ) we_cemetary/cemtrim2 128 15 0.00 1 1 0 0 0 +( -384 1792 272 ) ( -416 1824 272 ) ( -400 1808 336 ) we_cemetary/cemtrim2 0 16 -180.00 1 -1 0 0 0 +} +// brush 925 +{ +( -832 1824 272 ) ( -640 1824 272 ) ( -640 1856 272 ) we_cemetary/cemrunner2 -62 0 -90.00 1 1 0 0 0 +( -640 1856 336 ) ( -640 1824 336 ) ( -832 1824 336 ) we_cemetary/cemtrim2 -95 0 -90.00 1 1 0 0 0 +( -640 1856 272 ) ( -640 1856 592 ) ( -832 1856 592 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( -832 1792 272 ) ( -832 1792 592 ) ( -640 1792 592 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( -400 1808 336 ) ( -416 1824 272 ) ( -384 1792 272 ) we_cemetary/cemtrim2 0 15 0.00 1 1 0 0 0 +( -896 1792 272 ) ( -864 1824 272 ) ( -880 1808 336 ) we_cemetary/cemtrim2 128 16 0.00 1 1 0 0 0 +} +// brush 926 +{ +( -640 1792 256 ) ( -640 1840 256 ) ( -832 1840 256 ) we_cemetary/fogtrunk -62 64 -90.00 1 1 0 0 0 +( -640 1856 272 ) ( -640 1792 272 ) ( -832 1792 272 ) we_cemetary/fogtrunk -62 64 -90.00 1 1 0 0 0 +( -832 1856 272 ) ( -832 1840 256 ) ( -640 1840 256 ) we_cemetary/fogtrunk -62 64 -90.00 1 1 0 0 0 +( -832 1792 256 ) ( -832 1792 272 ) ( -640 1792 272 ) we_cemetary/fogtrunk -64 0 0.00 1 1 0 0 0 +( -400 1808 272 ) ( -416 1824 256 ) ( -384 1792 256 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +( -896 1792 256 ) ( -864 1824 256 ) ( -880 1808 272 ) we_cemetary/fogtrunk 128 0 0.00 1 1 0 0 0 +} +// brush 927 +{ +( -832 2048 272 ) ( -864 2048 272 ) ( -864 1856 272 ) we_cemetary/cemrunner2 0 0 0.00 1 1 0 0 0 +( -864 1856 336 ) ( -864 2048 336 ) ( -832 2048 336 ) we_cemetary/cemtrim2 -32 0 0.00 1 1 0 0 0 +( -832 1856 592 ) ( -832 2048 592 ) ( -832 2048 272 ) we_cemetary/cemtrim2 0 16 0.00 1 1 0 0 0 +( -896 2048 592 ) ( -896 1856 592 ) ( -896 1856 272 ) we_cemetary/cemtrim2 0 16 0.00 1 1 0 0 0 +( -896 2304 272 ) ( -864 2272 272 ) ( -880 2288 336 ) we_cemetary/cemtrim2 0 16 0.00 1 1 0 0 0 +( -832 1856 272 ) ( -864 1824 272 ) ( -848 1840 336 ) we_cemetary/cemtrim2 0 16 0.00 1 1 0 0 0 +} +// brush 928 +{ +( -848 1856 256 ) ( -848 2048 256 ) ( -896 2048 256 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +( -896 1856 272 ) ( -896 2048 272 ) ( -832 2048 272 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +( -848 2048 256 ) ( -848 1856 256 ) ( -832 1856 272 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +( -896 2048 272 ) ( -896 1856 272 ) ( -896 1856 256 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +( -896 2304 256 ) ( -864 2272 256 ) ( -880 2288 272 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +( -832 1856 256 ) ( -864 1824 256 ) ( -848 1840 272 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +} +// brush 929 +{ +( -864 2048 64 ) ( -896 2048 64 ) ( -896 1856 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( -896 2048 384 ) ( -896 1856 384 ) ( -896 1856 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( -848 1856 96 ) ( -856 2048 80 ) ( -864 1856 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( -832 2048 256 ) ( -832 1856 256 ) ( -896 1856 256 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( -848 1856 208 ) ( -848 2048 176 ) ( -848 1856 144 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( -896 2304 64 ) ( -864 2272 64 ) ( -880 2288 256 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( -832 1856 64 ) ( -864 1824 64 ) ( -848 1840 256 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +} +// brush 930 +{ +( -864 2048 0 ) ( -896 2048 0 ) ( -896 1856 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( -896 1856 64 ) ( -896 2048 64 ) ( -864 2048 64 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( -864 1792 320 ) ( -864 1984 320 ) ( -864 1984 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( -896 2048 320 ) ( -896 1856 320 ) ( -896 1856 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( -896 2304 0 ) ( -864 2272 0 ) ( -880 2288 64 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( -832 1856 0 ) ( -864 1824 0 ) ( -848 1840 64 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +} +// brush 931 +{ +( -832 1792 0 ) ( -640 1792 0 ) ( -640 1824 0 ) we_cemetary/cemtrim2 -62 0 -90.00 1 1 0 0 0 +( -640 1824 64 ) ( -640 1792 64 ) ( -832 1792 64 ) we_cemetary/cemtrim2 -62 0 -90.00 1 1 0 0 0 +( -768 1824 0 ) ( -768 1824 320 ) ( -960 1824 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( -832 1792 0 ) ( -832 1792 320 ) ( -640 1792 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( -896 1792 0 ) ( -864 1824 0 ) ( -880 1808 64 ) we_cemetary/cemtrim2 128 0 0.00 1 1 0 0 0 +( -704 1824 0 ) ( -704 1760 0 ) ( -704 1792 64 ) we_cemetary/cemtrim2 128 0 0.00 1 1 0 0 0 +} +// brush 932 +{ +( -832 1792 0 ) ( -640 1792 0 ) ( -640 1824 0 ) we_cemetary/cemtrim2 -62 0 -90.00 1 1 0 0 0 +( -640 1824 64 ) ( -640 1792 64 ) ( -832 1792 64 ) we_cemetary/cemtrim2 -62 0 -90.00 1 1 0 0 0 +( -640 1824 0 ) ( -640 1824 320 ) ( -832 1824 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( -832 1792 0 ) ( -832 1792 320 ) ( -640 1792 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( -400 1808 64 ) ( -416 1824 0 ) ( -384 1792 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( -576 1760 0 ) ( -576 1824 0 ) ( -576 1792 64 ) we_cemetary/cemtrim2 128 0 0.00 1 1 0 0 0 +} +// brush 933 +{ +( -832 1792 64 ) ( -640 1792 64 ) ( -640 1824 64 ) we_cemetary/cemstair2 -62 0 -90.00 1 1 0 0 0 +( -832 1792 64 ) ( -832 1792 384 ) ( -640 1792 384 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -832 1824 64 ) ( -640 1832 80 ) ( -832 1840 96 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -832 1792 256 ) ( -832 1856 256 ) ( -640 1856 256 ) we_cemetary/cemstair2 -62 0 -90.00 1 1 0 0 0 +( -832 1840 144 ) ( -640 1840 176 ) ( -832 1840 208 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -896 1792 64 ) ( -864 1824 64 ) ( -880 1808 256 ) we_cemetary/cemstair2 128 0 0.00 1 1 0 0 0 +( -704 1824 64 ) ( -704 1760 64 ) ( -704 1792 256 ) we_cemetary/cemstair2 128 0 0.00 1 1 0 0 0 +} +// brush 934 +{ +( -832 1792 64 ) ( -640 1792 64 ) ( -640 1824 64 ) we_cemetary/cemstair2 -62 0 -90.00 1 1 0 0 0 +( -832 1792 64 ) ( -832 1792 384 ) ( -640 1792 384 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -832 1824 64 ) ( -640 1832 80 ) ( -832 1840 96 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -832 1792 256 ) ( -832 1856 256 ) ( -640 1856 256 ) we_cemetary/cemstair2 -62 0 -90.00 1 1 0 0 0 +( -704 1840 144 ) ( -512 1840 176 ) ( -704 1840 208 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -400 1808 256 ) ( -416 1824 64 ) ( -384 1792 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( -576 1760 64 ) ( -576 1824 64 ) ( -576 1792 256 ) we_cemetary/cemstair2 128 0 0.00 1 1 0 0 0 +} +// brush 935 +{ +( -640 1760 64 ) ( -640 1792 64 ) ( -832 1792 64 ) we_cemetary/cemstair2 -127 0 -90.00 1 1 0 0 0 +( -640 1792 384 ) ( -832 1792 384 ) ( -832 1792 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -832 1744 96 ) ( -640 1752 80 ) ( -832 1760 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -640 1728 256 ) ( -832 1728 256 ) ( -832 1792 256 ) we_cemetary/cemstair2 -127 0 -90.00 1 1 0 0 0 +( -736 1744 208 ) ( -544 1744 176 ) ( -736 1744 144 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -576 1760 64 ) ( -576 1824 64 ) ( -576 1792 256 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +( -384 1792 64 ) ( -384 1728 64 ) ( -384 1760 256 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +} +// brush 936 +{ +( -640 1760 0 ) ( -640 1792 0 ) ( -832 1792 0 ) we_cemetary/cemtrim2 -127 0 -90.00 1 1 0 0 0 +( -832 1792 64 ) ( -640 1792 64 ) ( -640 1760 64 ) we_cemetary/cemtrim2 -127 0 -90.00 1 1 0 0 0 +( -736 1760 320 ) ( -544 1760 320 ) ( -544 1760 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( -640 1792 320 ) ( -832 1792 320 ) ( -832 1792 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( -576 1760 0 ) ( -576 1824 0 ) ( -576 1792 64 ) we_cemetary/cemtrim2 192 0 0.00 1 1 0 0 0 +( -384 1792 0 ) ( -384 1728 0 ) ( -384 1760 64 ) we_cemetary/cemtrim2 192 0 0.00 1 1 0 0 0 +} +// brush 937 +{ +( -640 1760 64 ) ( -640 1792 64 ) ( -832 1792 64 ) we_cemetary/cemstair2 -127 0 -90.00 1 1 0 0 0 +( -640 1792 384 ) ( -832 1792 384 ) ( -832 1792 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -832 1744 96 ) ( -640 1752 80 ) ( -832 1760 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -640 1728 256 ) ( -832 1728 256 ) ( -832 1792 256 ) we_cemetary/cemstair2 -127 0 -90.00 1 1 0 0 0 +( -832 1744 208 ) ( -640 1744 176 ) ( -832 1744 144 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -704 1824 64 ) ( -704 1760 64 ) ( -704 1792 256 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +( -896 1728 64 ) ( -896 1760 64 ) ( -896 1744 256 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +} +// brush 938 +{ +( -640 1760 0 ) ( -640 1792 0 ) ( -832 1792 0 ) we_cemetary/cemtrim2 -127 0 -90.00 1 1 0 0 0 +( -832 1792 64 ) ( -640 1792 64 ) ( -640 1760 64 ) we_cemetary/cemtrim2 -127 0 -90.00 1 1 0 0 0 +( -1024 1760 320 ) ( -832 1760 320 ) ( -832 1760 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( -640 1792 320 ) ( -832 1792 320 ) ( -832 1792 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( -704 1824 0 ) ( -704 1760 0 ) ( -704 1792 64 ) we_cemetary/cemtrim2 192 0 0.00 1 1 0 0 0 +( -896 1728 0 ) ( -896 1760 0 ) ( -896 1744 64 ) we_cemetary/cemtrim2 192 0 0.00 1 1 0 0 0 +} +// brush 939 +{ +( -832 1744 256 ) ( -640 1744 256 ) ( -640 1792 256 ) we_cemetary/fogtrunk -127 64 -90.00 1 1 0 0 0 +( -832 1792 272 ) ( -640 1792 272 ) ( -640 1728 272 ) we_cemetary/fogtrunk -127 64 -90.00 1 1 0 0 0 +( -640 1744 256 ) ( -832 1744 256 ) ( -832 1728 272 ) we_cemetary/fogtrunk -127 64 -90.00 1 1 0 0 0 +( -640 1792 272 ) ( -832 1792 272 ) ( -832 1792 256 ) we_cemetary/fogtrunk -64 0 0.00 1 1 0 0 0 +( -384 1792 256 ) ( -384 1728 256 ) ( -384 1760 272 ) we_cemetary/fogtrunk 192 0 0.00 1 1 0 0 0 +( -896 1728 256 ) ( -896 1760 256 ) ( -896 1744 272 ) we_cemetary/fogtrunk 192 0 0.00 1 1 0 0 0 +} +// brush 940 +{ +( -640 1728 272 ) ( -640 1760 272 ) ( -832 1760 272 ) we_cemetary/cemrunner2 0 0 -90.00 1 1 0 0 0 +( -832 1760 336 ) ( -640 1760 336 ) ( -640 1728 336 ) we_cemetary/cemtrim2 -159 0 -90.00 1 1 0 0 0 +( -832 1728 592 ) ( -640 1728 592 ) ( -640 1728 272 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( -640 1792 592 ) ( -832 1792 592 ) ( -832 1792 272 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( -384 1792 272 ) ( -384 1728 272 ) ( -384 1760 336 ) we_cemetary/cemtrim2 192 16 0.00 1 1 0 0 0 +( -896 1728 272 ) ( -896 1760 272 ) ( -896 1744 336 ) we_cemetary/cemtrim2 192 16 0.00 1 1 0 0 0 +} +// brush 941 +{ +( -416 2272 -32 ) ( -864 2272 -32 ) ( -864 1824 -32 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( -864 1824 0 ) ( -864 2272 0 ) ( -416 2272 0 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( -864 1760 0 ) ( -416 1760 0 ) ( -416 1760 -64 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( -384 1824 0 ) ( -384 2272 0 ) ( -384 2272 -64 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( -416 2304 0 ) ( -864 2304 0 ) ( -864 2304 -64 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( -896 2272 0 ) ( -896 1824 0 ) ( -896 1824 -64 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +} +// brush 942 +{ +( -416 2272 336 ) ( -864 2272 336 ) ( -864 1824 336 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +( -864 1824 352 ) ( -864 2272 352 ) ( -416 2272 352 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +( -864 1824 368 ) ( -416 1824 368 ) ( -416 1824 304 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +( -416 1824 368 ) ( -416 2272 368 ) ( -416 2272 304 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +( -416 2272 368 ) ( -864 2272 368 ) ( -864 2272 304 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +( -864 2272 368 ) ( -864 1824 368 ) ( -864 1824 304 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +} +// brush 943 +{ +( -576 1840 208 ) ( -704 1840 208 ) ( -704 1744 208 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -704 1744 256 ) ( -704 1840 256 ) ( -576 1840 256 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -704 1744 256 ) ( -576 1744 256 ) ( -576 1744 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -576 1744 240 ) ( -576 1840 240 ) ( -576 1840 48 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +( -576 1840 240 ) ( -704 1840 240 ) ( -704 1840 48 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -704 1840 256 ) ( -704 1744 256 ) ( -704 1744 64 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +} +// brush 944 +{ +( -1088 1840 208 ) ( -1216 1840 208 ) ( -1216 1744 208 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -1216 1744 256 ) ( -1216 1840 256 ) ( -1088 1840 256 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -1216 1744 256 ) ( -1088 1744 256 ) ( -1088 1744 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -1088 1744 240 ) ( -1088 1840 240 ) ( -1088 1840 48 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +( -1088 1840 240 ) ( -1216 1840 240 ) ( -1216 1840 48 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -1216 1840 256 ) ( -1216 1744 256 ) ( -1216 1744 64 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +} +// brush 945 +{ +( -928 2272 336 ) ( -1376 2272 336 ) ( -1376 1824 336 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +( -1376 1824 352 ) ( -1376 2272 352 ) ( -928 2272 352 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +( -1376 1824 368 ) ( -928 1824 368 ) ( -928 1824 304 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +( -928 1824 368 ) ( -928 2272 368 ) ( -928 2272 304 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +( -928 2272 368 ) ( -1376 2272 368 ) ( -1376 2272 304 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +( -1376 2272 368 ) ( -1376 1824 368 ) ( -1376 1824 304 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +} +// brush 946 +{ +( -928 2272 -32 ) ( -1376 2272 -32 ) ( -1376 1824 -32 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( -1376 1824 0 ) ( -1376 2272 0 ) ( -928 2272 0 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( -1376 1760 0 ) ( -928 1760 0 ) ( -928 1760 -64 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( -896 1824 0 ) ( -896 2272 0 ) ( -896 2272 -64 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( -928 2304 0 ) ( -1376 2304 0 ) ( -1376 2304 -64 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( -1408 2272 0 ) ( -1408 1824 0 ) ( -1408 1824 -64 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +} +// brush 947 +{ +( -1152 1728 272 ) ( -1152 1760 272 ) ( -1344 1760 272 ) we_cemetary/cemrunner2 0 0 -90.00 1 1 0 0 0 +( -1344 1760 336 ) ( -1152 1760 336 ) ( -1152 1728 336 ) we_cemetary/cemtrim2 -160 0 -90.00 1 1 0 0 0 +( -1344 1728 592 ) ( -1152 1728 592 ) ( -1152 1728 272 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( -1152 1792 592 ) ( -1344 1792 592 ) ( -1344 1792 272 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( -896 1792 272 ) ( -896 1728 272 ) ( -896 1760 336 ) we_cemetary/cemtrim2 192 16 0.00 1 1 0 0 0 +( -1408 1728 272 ) ( -1408 1760 272 ) ( -1408 1744 336 ) we_cemetary/cemtrim2 192 16 0.00 1 1 0 0 0 +} +// brush 948 +{ +( -1344 1744 256 ) ( -1152 1744 256 ) ( -1152 1792 256 ) we_cemetary/fogtrunk -128 64 -90.00 1 1 0 0 0 +( -1344 1792 272 ) ( -1152 1792 272 ) ( -1152 1728 272 ) we_cemetary/fogtrunk -128 64 -90.00 1 1 0 0 0 +( -1152 1744 256 ) ( -1344 1744 256 ) ( -1344 1728 272 ) we_cemetary/fogtrunk -128 64 -90.00 1 1 0 0 0 +( -1152 1792 272 ) ( -1344 1792 272 ) ( -1344 1792 256 ) we_cemetary/fogtrunk -64 0 0.00 1 1 0 0 0 +( -896 1792 256 ) ( -896 1728 256 ) ( -896 1760 272 ) we_cemetary/fogtrunk 192 0 0.00 1 1 0 0 0 +( -1408 1728 256 ) ( -1408 1760 256 ) ( -1408 1744 272 ) we_cemetary/fogtrunk 192 0 0.00 1 1 0 0 0 +} +// brush 949 +{ +( -1152 1760 0 ) ( -1152 1792 0 ) ( -1344 1792 0 ) we_cemetary/cemtrim2 -128 0 -90.00 1 1 0 0 0 +( -1344 1792 64 ) ( -1152 1792 64 ) ( -1152 1760 64 ) we_cemetary/cemtrim2 -128 0 -90.00 1 1 0 0 0 +( -1536 1760 320 ) ( -1344 1760 320 ) ( -1344 1760 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( -1152 1792 320 ) ( -1344 1792 320 ) ( -1344 1792 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( -1216 1824 0 ) ( -1216 1760 0 ) ( -1216 1792 64 ) we_cemetary/cemtrim2 192 0 0.00 1 1 0 0 0 +( -1408 1728 0 ) ( -1408 1760 0 ) ( -1408 1744 64 ) we_cemetary/cemtrim2 192 0 0.00 1 1 0 0 0 +} +// brush 950 +{ +( -1152 1760 64 ) ( -1152 1792 64 ) ( -1344 1792 64 ) we_cemetary/cemstair2 -128 0 -90.00 1 1 0 0 0 +( -1152 1792 384 ) ( -1344 1792 384 ) ( -1344 1792 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -1344 1744 96 ) ( -1152 1752 80 ) ( -1344 1760 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -1152 1728 256 ) ( -1344 1728 256 ) ( -1344 1792 256 ) we_cemetary/cemstair2 -128 0 -90.00 1 1 0 0 0 +( -1344 1744 208 ) ( -1152 1744 176 ) ( -1344 1744 144 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -1216 1824 64 ) ( -1216 1760 64 ) ( -1216 1792 256 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +( -1408 1728 64 ) ( -1408 1760 64 ) ( -1408 1744 256 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +} +// brush 951 +{ +( -1152 1760 0 ) ( -1152 1792 0 ) ( -1344 1792 0 ) we_cemetary/cemtrim2 -128 0 -90.00 1 1 0 0 0 +( -1344 1792 64 ) ( -1152 1792 64 ) ( -1152 1760 64 ) we_cemetary/cemtrim2 -128 0 -90.00 1 1 0 0 0 +( -1248 1760 320 ) ( -1056 1760 320 ) ( -1056 1760 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( -1152 1792 320 ) ( -1344 1792 320 ) ( -1344 1792 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( -1088 1760 0 ) ( -1088 1824 0 ) ( -1088 1792 64 ) we_cemetary/cemtrim2 192 0 0.00 1 1 0 0 0 +( -896 1792 0 ) ( -896 1728 0 ) ( -896 1760 64 ) we_cemetary/cemtrim2 192 0 0.00 1 1 0 0 0 +} +// brush 952 +{ +( -1152 1760 64 ) ( -1152 1792 64 ) ( -1344 1792 64 ) we_cemetary/cemstair2 -128 0 -90.00 1 1 0 0 0 +( -1152 1792 384 ) ( -1344 1792 384 ) ( -1344 1792 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -1344 1744 96 ) ( -1152 1752 80 ) ( -1344 1760 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -1152 1728 256 ) ( -1344 1728 256 ) ( -1344 1792 256 ) we_cemetary/cemstair2 -128 0 -90.00 1 1 0 0 0 +( -1248 1744 208 ) ( -1056 1744 176 ) ( -1248 1744 144 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -1088 1760 64 ) ( -1088 1824 64 ) ( -1088 1792 256 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +( -896 1792 64 ) ( -896 1728 64 ) ( -896 1760 256 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +} +// brush 953 +{ +( -1344 1792 64 ) ( -1152 1792 64 ) ( -1152 1824 64 ) we_cemetary/cemstair2 -63 0 -90.00 1 1 0 0 0 +( -1344 1792 64 ) ( -1344 1792 384 ) ( -1152 1792 384 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -1344 1824 64 ) ( -1152 1832 80 ) ( -1344 1840 96 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -1344 1792 256 ) ( -1344 1856 256 ) ( -1152 1856 256 ) we_cemetary/cemstair2 -63 0 -90.00 1 1 0 0 0 +( -1216 1840 144 ) ( -1024 1840 176 ) ( -1216 1840 208 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -912 1808 256 ) ( -928 1824 64 ) ( -896 1792 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( -1088 1760 64 ) ( -1088 1824 64 ) ( -1088 1792 256 ) we_cemetary/cemstair2 128 0 0.00 1 1 0 0 0 +} +// brush 954 +{ +( -1344 1792 64 ) ( -1152 1792 64 ) ( -1152 1824 64 ) we_cemetary/cemstair2 -63 0 -90.00 1 1 0 0 0 +( -1344 1792 64 ) ( -1344 1792 384 ) ( -1152 1792 384 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -1344 1824 64 ) ( -1152 1832 80 ) ( -1344 1840 96 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -1344 1792 256 ) ( -1344 1856 256 ) ( -1152 1856 256 ) we_cemetary/cemstair2 -63 0 -90.00 1 1 0 0 0 +( -1344 1840 144 ) ( -1152 1840 176 ) ( -1344 1840 208 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -1408 1792 64 ) ( -1376 1824 64 ) ( -1392 1808 256 ) we_cemetary/cemstair2 128 0 0.00 1 1 0 0 0 +( -1216 1824 64 ) ( -1216 1760 64 ) ( -1216 1792 256 ) we_cemetary/cemstair2 128 0 0.00 1 1 0 0 0 +} +// brush 955 +{ +( -1344 1792 0 ) ( -1152 1792 0 ) ( -1152 1824 0 ) we_cemetary/cemtrim2 -63 0 -90.00 1 1 0 0 0 +( -1152 1824 64 ) ( -1152 1792 64 ) ( -1344 1792 64 ) we_cemetary/cemtrim2 -63 0 -90.00 1 1 0 0 0 +( -1152 1824 0 ) ( -1152 1824 320 ) ( -1344 1824 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( -1344 1792 0 ) ( -1344 1792 320 ) ( -1152 1792 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( -912 1808 64 ) ( -928 1824 0 ) ( -896 1792 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( -1088 1760 0 ) ( -1088 1824 0 ) ( -1088 1792 64 ) we_cemetary/cemtrim2 128 0 0.00 1 1 0 0 0 +} +// brush 956 +{ +( -1344 1792 0 ) ( -1152 1792 0 ) ( -1152 1824 0 ) we_cemetary/cemtrim2 -63 0 -90.00 1 1 0 0 0 +( -1152 1824 64 ) ( -1152 1792 64 ) ( -1344 1792 64 ) we_cemetary/cemtrim2 -63 0 -90.00 1 1 0 0 0 +( -1280 1824 0 ) ( -1280 1824 320 ) ( -1472 1824 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( -1344 1792 0 ) ( -1344 1792 320 ) ( -1152 1792 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( -1408 1792 0 ) ( -1376 1824 0 ) ( -1392 1808 64 ) we_cemetary/cemtrim2 128 0 0.00 1 1 0 0 0 +( -1216 1824 0 ) ( -1216 1760 0 ) ( -1216 1792 64 ) we_cemetary/cemtrim2 128 0 0.00 1 1 0 0 0 +} +// brush 957 +{ +( -1376 2048 0 ) ( -1408 2048 0 ) ( -1408 1856 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( -1408 1856 64 ) ( -1408 2048 64 ) ( -1376 2048 64 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( -1376 1792 320 ) ( -1376 1984 320 ) ( -1376 1984 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( -1408 2048 320 ) ( -1408 1856 320 ) ( -1408 1856 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( -1408 2304 0 ) ( -1376 2272 0 ) ( -1392 2288 64 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( -1344 1856 0 ) ( -1376 1824 0 ) ( -1360 1840 64 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +} +// brush 958 +{ +( -1376 2048 64 ) ( -1408 2048 64 ) ( -1408 1856 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( -1408 2048 384 ) ( -1408 1856 384 ) ( -1408 1856 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( -1360 1856 96 ) ( -1368 2048 80 ) ( -1376 1856 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( -1344 2048 256 ) ( -1344 1856 256 ) ( -1408 1856 256 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( -1360 1856 208 ) ( -1360 2048 176 ) ( -1360 1856 144 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( -1408 2304 64 ) ( -1376 2272 64 ) ( -1392 2288 256 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( -1344 1856 64 ) ( -1376 1824 64 ) ( -1360 1840 256 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +} +// brush 959 +{ +( -1360 1856 256 ) ( -1360 2048 256 ) ( -1408 2048 256 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +( -1408 1856 272 ) ( -1408 2048 272 ) ( -1344 2048 272 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +( -1360 2048 256 ) ( -1360 1856 256 ) ( -1344 1856 272 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +( -1408 2048 272 ) ( -1408 1856 272 ) ( -1408 1856 256 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +( -1408 2304 256 ) ( -1376 2272 256 ) ( -1392 2288 272 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +( -1344 1856 256 ) ( -1376 1824 256 ) ( -1360 1840 272 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +} +// brush 960 +{ +( -1344 2048 272 ) ( -1376 2048 272 ) ( -1376 1856 272 ) we_cemetary/cemrunner2 0 0 0.00 1 1 0 0 0 +( -1376 1856 336 ) ( -1376 2048 336 ) ( -1344 2048 336 ) we_cemetary/cemtrim2 -32 0 0.00 1 1 0 0 0 +( -1344 1856 592 ) ( -1344 2048 592 ) ( -1344 2048 272 ) we_cemetary/cemtrim2 0 16 0.00 1 1 0 0 0 +( -1408 2048 592 ) ( -1408 1856 592 ) ( -1408 1856 272 ) we_cemetary/cemtrim2 0 16 0.00 1 1 0 0 0 +( -1408 2304 272 ) ( -1376 2272 272 ) ( -1392 2288 336 ) we_cemetary/cemtrim2 0 16 0.00 1 1 0 0 0 +( -1344 1856 272 ) ( -1376 1824 272 ) ( -1360 1840 336 ) we_cemetary/cemtrim2 0 16 0.00 1 1 0 0 0 +} +// brush 961 +{ +( -1152 1792 256 ) ( -1152 1840 256 ) ( -1344 1840 256 ) we_cemetary/fogtrunk -63 64 -90.00 1 1 0 0 0 +( -1152 1856 272 ) ( -1152 1792 272 ) ( -1344 1792 272 ) we_cemetary/fogtrunk -63 64 -90.00 1 1 0 0 0 +( -1344 1856 272 ) ( -1344 1840 256 ) ( -1152 1840 256 ) we_cemetary/fogtrunk -63 64 -90.00 1 1 0 0 0 +( -1344 1792 256 ) ( -1344 1792 272 ) ( -1152 1792 272 ) we_cemetary/fogtrunk -64 0 0.00 1 1 0 0 0 +( -912 1808 272 ) ( -928 1824 256 ) ( -896 1792 256 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +( -1408 1792 256 ) ( -1376 1824 256 ) ( -1392 1808 272 ) we_cemetary/fogtrunk 128 0 0.00 1 1 0 0 0 +} +// brush 962 +{ +( -1344 1824 272 ) ( -1152 1824 272 ) ( -1152 1856 272 ) we_cemetary/cemrunner2 -63 0 -90.00 1 1 0 0 0 +( -1152 1856 336 ) ( -1152 1824 336 ) ( -1344 1824 336 ) we_cemetary/cemtrim2 -96 0 -90.00 1 1 0 0 0 +( -1152 1856 272 ) ( -1152 1856 592 ) ( -1344 1856 592 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( -1344 1792 272 ) ( -1344 1792 592 ) ( -1152 1792 592 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( -912 1808 336 ) ( -928 1824 272 ) ( -896 1792 272 ) we_cemetary/cemtrim2 0 15 0.00 1 1 0 0 0 +( -1408 1792 272 ) ( -1376 1824 272 ) ( -1392 1808 336 ) we_cemetary/cemtrim2 128 16 0.00 1 1 0 0 0 +} +// brush 963 +{ +( -928 1856 272 ) ( -928 2048 272 ) ( -960 2048 272 ) we_cemetary/cemrunner2 63 0 -180.00 1 1 0 0 0 +( -960 2048 336 ) ( -928 2048 336 ) ( -928 1856 336 ) we_cemetary/cemtrim2 159 0 -180.00 1 1 0 0 0 +( -960 2048 272 ) ( -960 2048 592 ) ( -960 1856 592 ) we_cemetary/cemtrim2 64 15 -180.00 1 -1 0 0 0 +( -896 1856 272 ) ( -896 1856 592 ) ( -896 2048 592 ) we_cemetary/cemtrim2 64 15 -180.00 1 -1 0 0 0 +( -912 2288 336 ) ( -928 2272 272 ) ( -896 2304 272 ) we_cemetary/cemtrim2 128 15 0.00 1 1 0 0 0 +( -896 1792 272 ) ( -928 1824 272 ) ( -912 1808 336 ) we_cemetary/cemtrim2 0 16 -180.00 1 -1 0 0 0 +} +// brush 964 +{ +( -896 2048 256 ) ( -944 2048 256 ) ( -944 1856 256 ) we_cemetary/fogtrunk 191 -64 -180.00 1 1 0 0 0 +( -960 2048 272 ) ( -896 2048 272 ) ( -896 1856 272 ) we_cemetary/fogtrunk 191 -64 -180.00 1 1 0 0 0 +( -960 1856 272 ) ( -944 1856 256 ) ( -944 2048 256 ) we_cemetary/fogtrunk 191 -64 -180.00 1 1 0 0 0 +( -896 1856 256 ) ( -896 1856 272 ) ( -896 2048 272 ) we_cemetary/fogtrunk 64 0 -180.00 1 -1 0 0 0 +( -912 2288 272 ) ( -928 2272 256 ) ( -896 2304 256 ) we_cemetary/fogtrunk 128 0 0.00 1 1 0 0 0 +( -896 1792 256 ) ( -928 1824 256 ) ( -912 1808 272 ) we_cemetary/fogtrunk 0 0 -180.00 1 -1 0 0 0 +} +// brush 965 +{ +( -896 1856 64 ) ( -896 2048 64 ) ( -928 2048 64 ) we_cemetary/cemstair2 191 0 -180.00 1 1 0 0 0 +( -896 1856 64 ) ( -896 1856 384 ) ( -896 2048 384 ) we_cemetary/cemstair2 64 0 -180.00 1 -1 0 0 0 +( -928 1856 64 ) ( -936 2048 80 ) ( -944 1856 96 ) we_cemetary/cemstair2 64 0 -180.00 1 -1 0 0 0 +( -896 1856 256 ) ( -960 1856 256 ) ( -960 2048 256 ) we_cemetary/cemstair2 191 0 -180.00 1 1 0 0 0 +( -944 1856 144 ) ( -944 2048 176 ) ( -944 1856 208 ) we_cemetary/cemstair2 64 0 -180.00 1 -1 0 0 0 +( -912 2288 256 ) ( -928 2272 64 ) ( -896 2304 64 ) we_cemetary/cemstair2 128 0 0.00 1 1 0 0 0 +( -896 1792 64 ) ( -928 1824 64 ) ( -912 1808 256 ) we_cemetary/cemstair2 0 0 -180.00 1 -1 0 0 0 +} +// brush 966 +{ +( -896 1856 0 ) ( -896 2048 0 ) ( -928 2048 0 ) we_cemetary/cemtrim2 191 0 -180.00 1 1 0 0 0 +( -928 2048 64 ) ( -896 2048 64 ) ( -896 1856 64 ) we_cemetary/cemtrim2 191 0 -180.00 1 1 0 0 0 +( -928 1920 0 ) ( -928 1920 320 ) ( -928 1728 320 ) we_cemetary/cemtrim2 64 0 -180.00 1 -1 0 0 0 +( -896 1856 0 ) ( -896 1856 320 ) ( -896 2048 320 ) we_cemetary/cemtrim2 64 0 -180.00 1 -1 0 0 0 +( -912 2288 64 ) ( -928 2272 0 ) ( -896 2304 0 ) we_cemetary/cemtrim2 128 0 0.00 1 1 0 0 0 +( -896 1792 0 ) ( -928 1824 0 ) ( -912 1808 64 ) we_cemetary/cemtrim2 0 0 -180.00 1 -1 0 0 0 +} +// brush 967 +{ +( -960 2304 0 ) ( -1152 2304 0 ) ( -1152 2272 0 ) we_cemetary/cemtrim2 -62 0 90.00 1 1 0 0 0 +( -1152 2272 64 ) ( -1152 2304 64 ) ( -960 2304 64 ) we_cemetary/cemtrim2 -62 0 90.00 1 1 0 0 0 +( -1088 2272 0 ) ( -1088 2272 320 ) ( -896 2272 320 ) we_cemetary/cemtrim2 128 0 -180.00 1 -1 0 0 0 +( -960 2304 0 ) ( -960 2304 320 ) ( -1152 2304 320 ) we_cemetary/cemtrim2 128 0 -180.00 1 -1 0 0 0 +( -1392 2288 64 ) ( -1376 2272 0 ) ( -1408 2304 0 ) we_cemetary/cemtrim2 192 0 -180.00 1 -1 0 0 0 +( -896 2304 0 ) ( -928 2272 0 ) ( -912 2288 64 ) we_cemetary/cemtrim2 192 0 -180.00 1 -1 0 0 0 +} +// brush 968 +{ +( -960 2304 64 ) ( -1152 2304 64 ) ( -1152 2272 64 ) we_cemetary/cemstair2 -62 0 90.00 1 1 0 0 0 +( -960 2304 64 ) ( -960 2304 384 ) ( -1152 2304 384 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +( -960 2272 64 ) ( -1152 2264 80 ) ( -960 2256 96 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +( -960 2304 256 ) ( -960 2240 256 ) ( -1152 2240 256 ) we_cemetary/cemstair2 -62 0 90.00 1 1 0 0 0 +( -960 2256 144 ) ( -1152 2256 176 ) ( -960 2256 208 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +( -1392 2288 256 ) ( -1376 2272 64 ) ( -1408 2304 64 ) we_cemetary/cemstair2 192 0 -180.00 1 -1 0 0 0 +( -896 2304 64 ) ( -928 2272 64 ) ( -912 2288 256 ) we_cemetary/cemstair2 192 0 -180.00 1 -1 0 0 0 +} +// brush 969 +{ +( -1152 2304 256 ) ( -1152 2256 256 ) ( -960 2256 256 ) we_cemetary/fogtrunk -62 -128 90.00 1 1 0 0 0 +( -1152 2240 272 ) ( -1152 2304 272 ) ( -960 2304 272 ) we_cemetary/fogtrunk -62 -128 90.00 1 1 0 0 0 +( -960 2240 272 ) ( -960 2256 256 ) ( -1152 2256 256 ) we_cemetary/fogtrunk -62 -128 90.00 1 1 0 0 0 +( -960 2304 256 ) ( -960 2304 272 ) ( -1152 2304 272 ) we_cemetary/fogtrunk 128 0 -180.00 1 -1 0 0 0 +( -1392 2288 272 ) ( -1376 2272 256 ) ( -1408 2304 256 ) we_cemetary/fogtrunk 192 0 -180.00 1 -1 0 0 0 +( -896 2304 256 ) ( -928 2272 256 ) ( -912 2288 272 ) we_cemetary/fogtrunk 192 0 -180.00 1 -1 0 0 0 +} +// brush 970 +{ +( -960 2272 272 ) ( -1152 2272 272 ) ( -1152 2240 272 ) we_cemetary/cemrunner2 -62 0 90.00 1 1.000122 0 0 0 +( -1152 2240 336 ) ( -1152 2272 336 ) ( -960 2272 336 ) we_cemetary/cemtrim2 -94 0 90.00 1 1 0 0 0 +( -1152 2240 272 ) ( -1152 2240 592 ) ( -960 2240 592 ) we_cemetary/cemtrim2 128 15 -180.00 1 -1 0 0 0 +( -960 2304 272 ) ( -960 2304 592 ) ( -1152 2304 592 ) we_cemetary/cemtrim2 128 15 -180.00 1 -1 0 0 0 +( -1392 2288 336 ) ( -1376 2272 272 ) ( -1408 2304 272 ) we_cemetary/cemtrim2 192 16 -180.00 1 -1 0 0 0 +( -896 2304 272 ) ( -928 2272 272 ) ( -912 2288 336 ) we_cemetary/cemtrim2 192 16 -180.00 1 -1 0 0 0 +} +// brush 971 +{ +( -1472 2272 272 ) ( -1664 2272 272 ) ( -1664 2240 272 ) we_cemetary/cemrunner2 -63 0 90.00 1 1.000122 0 0 0 +( -1664 2240 336 ) ( -1664 2272 336 ) ( -1472 2272 336 ) we_cemetary/cemtrim2 -95 0 90.00 1 1 0 0 0 +( -1664 2240 272 ) ( -1664 2240 592 ) ( -1472 2240 592 ) we_cemetary/cemtrim2 128 15 -180.00 1 -1 0 0 0 +( -1472 2304 272 ) ( -1472 2304 592 ) ( -1664 2304 592 ) we_cemetary/cemtrim2 128 15 -180.00 1 -1 0 0 0 +( -1904 2288 336 ) ( -1888 2272 272 ) ( -1920 2304 272 ) we_cemetary/cemtrim2 192 16 -180.00 1 -1 0 0 0 +( -1408 2304 272 ) ( -1440 2272 272 ) ( -1424 2288 336 ) we_cemetary/cemtrim2 192 16 -180.00 1 -1 0 0 0 +} +// brush 972 +{ +( -1664 2304 256 ) ( -1664 2256 256 ) ( -1472 2256 256 ) we_cemetary/fogtrunk -63 -128 90.00 1 1 0 0 0 +( -1664 2240 272 ) ( -1664 2304 272 ) ( -1472 2304 272 ) we_cemetary/fogtrunk -63 -128 90.00 1 1 0 0 0 +( -1472 2240 272 ) ( -1472 2256 256 ) ( -1664 2256 256 ) we_cemetary/fogtrunk -63 -128 90.00 1 1 0 0 0 +( -1472 2304 256 ) ( -1472 2304 272 ) ( -1664 2304 272 ) we_cemetary/fogtrunk 128 0 -180.00 1 -1 0 0 0 +( -1904 2288 272 ) ( -1888 2272 256 ) ( -1920 2304 256 ) we_cemetary/fogtrunk 192 0 -180.00 1 -1 0 0 0 +( -1408 2304 256 ) ( -1440 2272 256 ) ( -1424 2288 272 ) we_cemetary/fogtrunk 192 0 -180.00 1 -1 0 0 0 +} +// brush 973 +{ +( -1472 2304 64 ) ( -1664 2304 64 ) ( -1664 2272 64 ) we_cemetary/cemstair2 -63 0 90.00 1 1 0 0 0 +( -1472 2304 64 ) ( -1472 2304 384 ) ( -1664 2304 384 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +( -1472 2272 64 ) ( -1664 2264 80 ) ( -1472 2256 96 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +( -1472 2304 256 ) ( -1472 2240 256 ) ( -1664 2240 256 ) we_cemetary/cemstair2 -63 0 90.00 1 1 0 0 0 +( -1472 2256 144 ) ( -1664 2256 176 ) ( -1472 2256 208 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +( -1904 2288 256 ) ( -1888 2272 64 ) ( -1920 2304 64 ) we_cemetary/cemstair2 192 0 -180.00 1 -1 0 0 0 +( -1408 2304 64 ) ( -1440 2272 64 ) ( -1424 2288 256 ) we_cemetary/cemstair2 192 0 -180.00 1 -1 0 0 0 +} +// brush 974 +{ +( -1472 2304 0 ) ( -1664 2304 0 ) ( -1664 2272 0 ) we_cemetary/cemtrim2 -63 0 90.00 1 1 0 0 0 +( -1664 2272 64 ) ( -1664 2304 64 ) ( -1472 2304 64 ) we_cemetary/cemtrim2 -63 0 90.00 1 1 0 0 0 +( -1600 2272 0 ) ( -1600 2272 320 ) ( -1408 2272 320 ) we_cemetary/cemtrim2 128 0 -180.00 1 -1 0 0 0 +( -1472 2304 0 ) ( -1472 2304 320 ) ( -1664 2304 320 ) we_cemetary/cemtrim2 128 0 -180.00 1 -1 0 0 0 +( -1904 2288 64 ) ( -1888 2272 0 ) ( -1920 2304 0 ) we_cemetary/cemtrim2 192 0 -180.00 1 -1 0 0 0 +( -1408 2304 0 ) ( -1440 2272 0 ) ( -1424 2288 64 ) we_cemetary/cemtrim2 192 0 -180.00 1 -1 0 0 0 +} +// brush 975 +{ +( -1408 1856 0 ) ( -1408 2048 0 ) ( -1440 2048 0 ) we_cemetary/cemtrim2 191 0 -180.00 1 1 0 0 0 +( -1440 2048 64 ) ( -1408 2048 64 ) ( -1408 1856 64 ) we_cemetary/cemtrim2 191 0 -180.00 1 1 0 0 0 +( -1440 1920 0 ) ( -1440 1920 320 ) ( -1440 1728 320 ) we_cemetary/cemtrim2 64 0 -180.00 1 -1 0 0 0 +( -1408 1856 0 ) ( -1408 1856 320 ) ( -1408 2048 320 ) we_cemetary/cemtrim2 64 0 -180.00 1 -1 0 0 0 +( -1424 2288 64 ) ( -1440 2272 0 ) ( -1408 2304 0 ) we_cemetary/cemtrim2 128 0 0.00 1 1 0 0 0 +( -1408 1792 0 ) ( -1440 1824 0 ) ( -1424 1808 64 ) we_cemetary/cemtrim2 0 0 -180.00 1 -1 0 0 0 +} +// brush 976 +{ +( -1408 1856 64 ) ( -1408 2048 64 ) ( -1440 2048 64 ) we_cemetary/cemstair2 191 0 -180.00 1 1 0 0 0 +( -1408 1856 64 ) ( -1408 1856 384 ) ( -1408 2048 384 ) we_cemetary/cemstair2 64 0 -180.00 1 -1 0 0 0 +( -1440 1856 64 ) ( -1448 2048 80 ) ( -1456 1856 96 ) we_cemetary/cemstair2 64 0 -180.00 1 -1 0 0 0 +( -1408 1856 256 ) ( -1472 1856 256 ) ( -1472 2048 256 ) we_cemetary/cemstair2 191 0 -180.00 1 1 0 0 0 +( -1456 1856 144 ) ( -1456 2048 176 ) ( -1456 1856 208 ) we_cemetary/cemstair2 64 0 -180.00 1 -1 0 0 0 +( -1424 2288 256 ) ( -1440 2272 64 ) ( -1408 2304 64 ) we_cemetary/cemstair2 128 0 0.00 1 1 0 0 0 +( -1408 1792 64 ) ( -1440 1824 64 ) ( -1424 1808 256 ) we_cemetary/cemstair2 0 0 -180.00 1 -1 0 0 0 +} +// brush 977 +{ +( -1408 2048 256 ) ( -1456 2048 256 ) ( -1456 1856 256 ) we_cemetary/fogtrunk 191 -64 -180.00 1 1 0 0 0 +( -1472 2048 272 ) ( -1408 2048 272 ) ( -1408 1856 272 ) we_cemetary/fogtrunk 191 -64 -180.00 1 1 0 0 0 +( -1472 1856 272 ) ( -1456 1856 256 ) ( -1456 2048 256 ) we_cemetary/fogtrunk 191 -64 -180.00 1 1 0 0 0 +( -1408 1856 256 ) ( -1408 1856 272 ) ( -1408 2048 272 ) we_cemetary/fogtrunk 64 0 -180.00 1 -1 0 0 0 +( -1424 2288 272 ) ( -1440 2272 256 ) ( -1408 2304 256 ) we_cemetary/fogtrunk 128 0 0.00 1 1 0 0 0 +( -1408 1792 256 ) ( -1440 1824 256 ) ( -1424 1808 272 ) we_cemetary/fogtrunk 0 0 -180.00 1 -1 0 0 0 +} +// brush 978 +{ +( -1440 1856 272 ) ( -1440 2048 272 ) ( -1472 2048 272 ) we_cemetary/cemrunner2 63 0 -180.00 1 1 0 0 0 +( -1472 2048 336 ) ( -1440 2048 336 ) ( -1440 1856 336 ) we_cemetary/cemtrim2 159 0 -180.00 1 1 0 0 0 +( -1472 2048 272 ) ( -1472 2048 592 ) ( -1472 1856 592 ) we_cemetary/cemtrim2 64 15 -180.00 1 -1 0 0 0 +( -1408 1856 272 ) ( -1408 1856 592 ) ( -1408 2048 592 ) we_cemetary/cemtrim2 64 15 -180.00 1 -1 0 0 0 +( -1424 2288 336 ) ( -1440 2272 272 ) ( -1408 2304 272 ) we_cemetary/cemtrim2 128 15 0.00 1 1 0 0 0 +( -1408 1792 272 ) ( -1440 1824 272 ) ( -1424 1808 336 ) we_cemetary/cemtrim2 0 16 -180.00 1 -1 0 0 0 +} +// brush 979 +{ +( -1856 1824 272 ) ( -1664 1824 272 ) ( -1664 1856 272 ) we_cemetary/cemrunner2 -64 0 -90.00 1 1 0 0 0 +( -1664 1856 336 ) ( -1664 1824 336 ) ( -1856 1824 336 ) we_cemetary/cemtrim2 -97 0 -90.00 1 1 0 0 0 +( -1664 1856 272 ) ( -1664 1856 592 ) ( -1856 1856 592 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( -1856 1792 272 ) ( -1856 1792 592 ) ( -1664 1792 592 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( -1424 1808 336 ) ( -1440 1824 272 ) ( -1408 1792 272 ) we_cemetary/cemtrim2 0 15 0.00 1 1 0 0 0 +( -1920 1792 272 ) ( -1888 1824 272 ) ( -1904 1808 336 ) we_cemetary/cemtrim2 128 16 0.00 1 1 0 0 0 +} +// brush 980 +{ +( -1664 1792 256 ) ( -1664 1840 256 ) ( -1856 1840 256 ) we_cemetary/fogtrunk -64 64 -90.00 1 1 0 0 0 +( -1664 1856 272 ) ( -1664 1792 272 ) ( -1856 1792 272 ) we_cemetary/fogtrunk -64 64 -90.00 1 1 0 0 0 +( -1856 1856 272 ) ( -1856 1840 256 ) ( -1664 1840 256 ) we_cemetary/fogtrunk -64 64 -90.00 1 1 0 0 0 +( -1856 1792 256 ) ( -1856 1792 272 ) ( -1664 1792 272 ) we_cemetary/fogtrunk -64 0 0.00 1 1 0 0 0 +( -1424 1808 272 ) ( -1440 1824 256 ) ( -1408 1792 256 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +( -1920 1792 256 ) ( -1888 1824 256 ) ( -1904 1808 272 ) we_cemetary/fogtrunk 128 0 0.00 1 1 0 0 0 +} +// brush 981 +{ +( -1856 2048 272 ) ( -1888 2048 272 ) ( -1888 1856 272 ) we_cemetary/cemrunner2 0 0 0.00 1 1 0 0 0 +( -1888 1856 336 ) ( -1888 2048 336 ) ( -1856 2048 336 ) we_cemetary/cemtrim2 -32 0 0.00 1 1 0 0 0 +( -1856 1856 592 ) ( -1856 2048 592 ) ( -1856 2048 272 ) we_cemetary/cemtrim2 0 16 0.00 1 1 0 0 0 +( -1920 2048 592 ) ( -1920 1856 592 ) ( -1920 1856 272 ) we_cemetary/cemtrim2 0 16 0.00 1 1 0 0 0 +( -1920 2304 272 ) ( -1888 2272 272 ) ( -1904 2288 336 ) we_cemetary/cemtrim2 0 16 0.00 1 1 0 0 0 +( -1856 1856 272 ) ( -1888 1824 272 ) ( -1872 1840 336 ) we_cemetary/cemtrim2 0 16 0.00 1 1 0 0 0 +} +// brush 982 +{ +( -1872 1856 256 ) ( -1872 2048 256 ) ( -1920 2048 256 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +( -1920 1856 272 ) ( -1920 2048 272 ) ( -1856 2048 272 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +( -1872 2048 256 ) ( -1872 1856 256 ) ( -1856 1856 272 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +( -1920 2048 272 ) ( -1920 1856 272 ) ( -1920 1856 256 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +( -1920 2304 256 ) ( -1888 2272 256 ) ( -1904 2288 272 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +( -1856 1856 256 ) ( -1888 1824 256 ) ( -1872 1840 272 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +} +// brush 983 +{ +( -1888 2048 64 ) ( -1920 2048 64 ) ( -1920 1856 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( -1920 2048 384 ) ( -1920 1856 384 ) ( -1920 1856 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( -1872 1856 96 ) ( -1880 2048 80 ) ( -1888 1856 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( -1856 2048 256 ) ( -1856 1856 256 ) ( -1920 1856 256 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( -1872 1856 208 ) ( -1872 2048 176 ) ( -1872 1856 144 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( -1920 2304 64 ) ( -1888 2272 64 ) ( -1904 2288 256 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( -1856 1856 64 ) ( -1888 1824 64 ) ( -1872 1840 256 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +} +// brush 984 +{ +( -1888 2048 0 ) ( -1920 2048 0 ) ( -1920 1856 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( -1920 1856 64 ) ( -1920 2048 64 ) ( -1888 2048 64 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( -1888 1792 320 ) ( -1888 1984 320 ) ( -1888 1984 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( -1920 2048 320 ) ( -1920 1856 320 ) ( -1920 1856 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( -1920 2304 0 ) ( -1888 2272 0 ) ( -1904 2288 64 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( -1856 1856 0 ) ( -1888 1824 0 ) ( -1872 1840 64 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +} +// brush 985 +{ +( -1856 1792 0 ) ( -1664 1792 0 ) ( -1664 1824 0 ) we_cemetary/cemtrim2 -64 0 -90.00 1 1 0 0 0 +( -1664 1824 64 ) ( -1664 1792 64 ) ( -1856 1792 64 ) we_cemetary/cemtrim2 -64 0 -90.00 1 1 0 0 0 +( -1792 1824 0 ) ( -1792 1824 320 ) ( -1984 1824 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( -1856 1792 0 ) ( -1856 1792 320 ) ( -1664 1792 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( -1920 1792 0 ) ( -1888 1824 0 ) ( -1904 1808 64 ) we_cemetary/cemtrim2 128 0 0.00 1 1 0 0 0 +( -1728 1824 0 ) ( -1728 1760 0 ) ( -1728 1792 64 ) we_cemetary/cemtrim2 128 0 0.00 1 1 0 0 0 +} +// brush 986 +{ +( -1856 1792 0 ) ( -1664 1792 0 ) ( -1664 1824 0 ) we_cemetary/cemtrim2 -64 0 -90.00 1 1 0 0 0 +( -1664 1824 64 ) ( -1664 1792 64 ) ( -1856 1792 64 ) we_cemetary/cemtrim2 -64 0 -90.00 1 1 0 0 0 +( -1664 1824 0 ) ( -1664 1824 320 ) ( -1856 1824 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( -1856 1792 0 ) ( -1856 1792 320 ) ( -1664 1792 320 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( -1424 1808 64 ) ( -1440 1824 0 ) ( -1408 1792 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( -1600 1760 0 ) ( -1600 1824 0 ) ( -1600 1792 64 ) we_cemetary/cemtrim2 128 0 0.00 1 1 0 0 0 +} +// brush 987 +{ +( -1856 1792 64 ) ( -1664 1792 64 ) ( -1664 1824 64 ) we_cemetary/cemstair2 -64 0 -90.00 1 1 0 0 0 +( -1856 1792 64 ) ( -1856 1792 384 ) ( -1664 1792 384 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -1856 1824 64 ) ( -1664 1832 80 ) ( -1856 1840 96 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -1856 1792 256 ) ( -1856 1856 256 ) ( -1664 1856 256 ) we_cemetary/cemstair2 -64 0 -90.00 1 1 0 0 0 +( -1856 1840 144 ) ( -1664 1840 176 ) ( -1856 1840 208 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -1920 1792 64 ) ( -1888 1824 64 ) ( -1904 1808 256 ) we_cemetary/cemstair2 128 0 0.00 1 1 0 0 0 +( -1728 1824 64 ) ( -1728 1760 64 ) ( -1728 1792 256 ) we_cemetary/cemstair2 128 0 0.00 1 1 0 0 0 +} +// brush 988 +{ +( -1856 1792 64 ) ( -1664 1792 64 ) ( -1664 1824 64 ) we_cemetary/cemstair2 -64 0 -90.00 1 1 0 0 0 +( -1856 1792 64 ) ( -1856 1792 384 ) ( -1664 1792 384 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -1856 1824 64 ) ( -1664 1832 80 ) ( -1856 1840 96 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -1856 1792 256 ) ( -1856 1856 256 ) ( -1664 1856 256 ) we_cemetary/cemstair2 -64 0 -90.00 1 1 0 0 0 +( -1728 1840 144 ) ( -1536 1840 176 ) ( -1728 1840 208 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -1424 1808 256 ) ( -1440 1824 64 ) ( -1408 1792 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( -1600 1760 64 ) ( -1600 1824 64 ) ( -1600 1792 256 ) we_cemetary/cemstair2 128 0 0.00 1 1 0 0 0 +} +// brush 989 +{ +( -1664 1760 64 ) ( -1664 1792 64 ) ( -1856 1792 64 ) we_cemetary/cemstair2 -129 0 -90.00 1 1 0 0 0 +( -1664 1792 384 ) ( -1856 1792 384 ) ( -1856 1792 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -1856 1744 96 ) ( -1664 1752 80 ) ( -1856 1760 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -1664 1728 256 ) ( -1856 1728 256 ) ( -1856 1792 256 ) we_cemetary/cemstair2 -129 0 -90.00 1 1 0 0 0 +( -1760 1744 208 ) ( -1568 1744 176 ) ( -1760 1744 144 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -1600 1760 64 ) ( -1600 1824 64 ) ( -1600 1792 256 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +( -1408 1792 64 ) ( -1408 1728 64 ) ( -1408 1760 256 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +} +// brush 990 +{ +( -1664 1760 0 ) ( -1664 1792 0 ) ( -1856 1792 0 ) we_cemetary/cemtrim2 -129 0 -90.00 1 1 0 0 0 +( -1856 1792 64 ) ( -1664 1792 64 ) ( -1664 1760 64 ) we_cemetary/cemtrim2 -129 0 -90.00 1 1 0 0 0 +( -1760 1760 320 ) ( -1568 1760 320 ) ( -1568 1760 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( -1664 1792 320 ) ( -1856 1792 320 ) ( -1856 1792 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( -1600 1760 0 ) ( -1600 1824 0 ) ( -1600 1792 64 ) we_cemetary/cemtrim2 192 0 0.00 1 1 0 0 0 +( -1408 1792 0 ) ( -1408 1728 0 ) ( -1408 1760 64 ) we_cemetary/cemtrim2 192 0 0.00 1 1 0 0 0 +} +// brush 991 +{ +( -1664 1760 64 ) ( -1664 1792 64 ) ( -1856 1792 64 ) we_cemetary/cemstair2 -129 0 -90.00 1 1 0 0 0 +( -1664 1792 384 ) ( -1856 1792 384 ) ( -1856 1792 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -1856 1744 96 ) ( -1664 1752 80 ) ( -1856 1760 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -1664 1728 256 ) ( -1856 1728 256 ) ( -1856 1792 256 ) we_cemetary/cemstair2 -129 0 -90.00 1 1 0 0 0 +( -1856 1744 208 ) ( -1664 1744 176 ) ( -1856 1744 144 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -1728 1824 64 ) ( -1728 1760 64 ) ( -1728 1792 256 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +( -1920 1728 64 ) ( -1920 1760 64 ) ( -1920 1744 256 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +} +// brush 992 +{ +( -1664 1760 0 ) ( -1664 1792 0 ) ( -1856 1792 0 ) we_cemetary/cemtrim2 -129 0 -90.00 1 1 0 0 0 +( -1856 1792 64 ) ( -1664 1792 64 ) ( -1664 1760 64 ) we_cemetary/cemtrim2 -129 0 -90.00 1 1 0 0 0 +( -2048 1760 320 ) ( -1856 1760 320 ) ( -1856 1760 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( -1664 1792 320 ) ( -1856 1792 320 ) ( -1856 1792 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( -1728 1824 0 ) ( -1728 1760 0 ) ( -1728 1792 64 ) we_cemetary/cemtrim2 192 0 0.00 1 1 0 0 0 +( -1920 1728 0 ) ( -1920 1760 0 ) ( -1920 1744 64 ) we_cemetary/cemtrim2 192 0 0.00 1 1 0 0 0 +} +// brush 993 +{ +( -1856 1744 256 ) ( -1664 1744 256 ) ( -1664 1792 256 ) we_cemetary/fogtrunk -129 64 -90.00 1 1 0 0 0 +( -1856 1792 272 ) ( -1664 1792 272 ) ( -1664 1728 272 ) we_cemetary/fogtrunk -129 64 -90.00 1 1 0 0 0 +( -1664 1744 256 ) ( -1856 1744 256 ) ( -1856 1728 272 ) we_cemetary/fogtrunk -129 64 -90.00 1 1 0 0 0 +( -1664 1792 272 ) ( -1856 1792 272 ) ( -1856 1792 256 ) we_cemetary/fogtrunk -64 0 0.00 1 1 0 0 0 +( -1408 1792 256 ) ( -1408 1728 256 ) ( -1408 1760 272 ) we_cemetary/fogtrunk 192 0 0.00 1 1 0 0 0 +( -1920 1728 256 ) ( -1920 1760 256 ) ( -1920 1744 272 ) we_cemetary/fogtrunk 192 0 0.00 1 1 0 0 0 +} +// brush 994 +{ +( -1664 1728 272 ) ( -1664 1760 272 ) ( -1856 1760 272 ) we_cemetary/cemrunner2 0 0 -90.00 1 1 0 0 0 +( -1856 1760 336 ) ( -1664 1760 336 ) ( -1664 1728 336 ) we_cemetary/cemtrim2 -161 0 -90.00 1 1 0 0 0 +( -1856 1728 592 ) ( -1664 1728 592 ) ( -1664 1728 272 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( -1664 1792 592 ) ( -1856 1792 592 ) ( -1856 1792 272 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( -1408 1792 272 ) ( -1408 1728 272 ) ( -1408 1760 336 ) we_cemetary/cemtrim2 192 16 0.00 1 1 0 0 0 +( -1920 1728 272 ) ( -1920 1760 272 ) ( -1920 1744 336 ) we_cemetary/cemtrim2 192 16 0.00 1 1 0 0 0 +} +// brush 995 +{ +( -1440 2272 -32 ) ( -1888 2272 -32 ) ( -1888 1824 -32 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( -1888 1824 0 ) ( -1888 2272 0 ) ( -1440 2272 0 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( -1888 1760 0 ) ( -1440 1760 0 ) ( -1440 1760 -64 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( -1408 1824 0 ) ( -1408 2272 0 ) ( -1408 2272 -64 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( -1440 2304 0 ) ( -1888 2304 0 ) ( -1888 2304 -64 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( -1920 2272 0 ) ( -1920 1824 0 ) ( -1920 1824 -64 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +} +// brush 996 +{ +( -1440 2272 336 ) ( -1888 2272 336 ) ( -1888 1824 336 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +( -1888 1824 352 ) ( -1888 2272 352 ) ( -1440 2272 352 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +( -1888 1824 368 ) ( -1440 1824 368 ) ( -1440 1824 304 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +( -1440 1824 368 ) ( -1440 2272 368 ) ( -1440 2272 304 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +( -1440 2272 368 ) ( -1888 2272 368 ) ( -1888 2272 304 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +( -1888 2272 368 ) ( -1888 1824 368 ) ( -1888 1824 304 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +} +// brush 997 +{ +( -1600 1840 208 ) ( -1728 1840 208 ) ( -1728 1744 208 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -1728 1744 256 ) ( -1728 1840 256 ) ( -1600 1840 256 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -1728 1744 256 ) ( -1600 1744 256 ) ( -1600 1744 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -1600 1744 240 ) ( -1600 1840 240 ) ( -1600 1840 48 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +( -1600 1840 240 ) ( -1728 1840 240 ) ( -1728 1840 48 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -1728 1840 256 ) ( -1728 1744 256 ) ( -1728 1744 64 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +} +// brush 998 +{ +( -2112 1840 208 ) ( -2240 1840 208 ) ( -2240 1744 208 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +( -2240 1744 256 ) ( -2240 1840 256 ) ( -2112 1840 256 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +( -2240 1744 256 ) ( -2112 1744 256 ) ( -2112 1744 64 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +( -2112 1744 240 ) ( -2112 1840 240 ) ( -2112 1840 48 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +( -2112 1840 240 ) ( -2240 1840 240 ) ( -2240 1840 48 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +( -2240 1840 256 ) ( -2240 1744 256 ) ( -2240 1744 64 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +} +// brush 999 +{ +( -1952 2272 336 ) ( -2400 2272 336 ) ( -2400 1824 336 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +( -2400 1824 352 ) ( -2400 2272 352 ) ( -1952 2272 352 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +( -2400 1824 368 ) ( -1952 1824 368 ) ( -1952 1824 304 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +( -1952 1824 368 ) ( -1952 2272 368 ) ( -1952 2272 304 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +( -1952 2272 368 ) ( -2400 2272 368 ) ( -2400 2272 304 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +( -2400 2272 368 ) ( -2400 1824 368 ) ( -2400 1824 304 ) water/waterfloor2 0 0 0.00 1 1 0 0 0 +} +// brush 1000 +{ +( -1952 2272 -32 ) ( -2400 2272 -32 ) ( -2400 1824 -32 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( -2400 1824 0 ) ( -2400 2272 0 ) ( -1952 2272 0 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( -2400 1760 0 ) ( -1952 1760 0 ) ( -1952 1760 -64 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( -1920 1824 0 ) ( -1920 2272 0 ) ( -1920 2272 -64 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( -1952 2304 0 ) ( -2400 2304 0 ) ( -2400 2304 -64 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +( -2432 2272 0 ) ( -2432 1824 0 ) ( -2432 1824 -64 ) we_cemetary/cemtrim5 0 0 0.00 1 1 0 0 0 +} +// brush 1001 +{ +( -2176 1728 272 ) ( -2176 1760 272 ) ( -2368 1760 272 ) we_cemetary/cemrunner2 -1 0 -90.00 1 1 0 0 0 +( -2368 1760 336 ) ( -2176 1760 336 ) ( -2176 1728 336 ) we_cemetary/cemtrim2 -161 0 -90.00 1 1 0 0 0 +( -2368 1728 592 ) ( -2176 1728 592 ) ( -2176 1728 272 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( -2176 1792 592 ) ( -2368 1792 592 ) ( -2368 1792 272 ) we_cemetary/cemtrim2 -64 15 0.00 1 1 0 0 0 +( -1920 1792 272 ) ( -1920 1728 272 ) ( -1920 1760 336 ) we_cemetary/cemtrim2 192 16 0.00 1 1 0 0 0 +( -2432 1728 272 ) ( -2432 1760 272 ) ( -2432 1744 336 ) we_cemetary/cemtrim2 192 16 0.00 1 1 0 0 0 +} +// brush 1002 +{ +( -2368 1744 256 ) ( -2176 1744 256 ) ( -2176 1792 256 ) we_cemetary/fogtrunk -129 64 -90.00 1 1 0 0 0 +( -2368 1792 272 ) ( -2176 1792 272 ) ( -2176 1728 272 ) we_cemetary/fogtrunk -129 64 -90.00 1 1 0 0 0 +( -2176 1744 256 ) ( -2368 1744 256 ) ( -2368 1728 272 ) we_cemetary/fogtrunk -129 64 -90.00 1 1 0 0 0 +( -2176 1792 272 ) ( -2368 1792 272 ) ( -2368 1792 256 ) we_cemetary/fogtrunk -64 0 0.00 1 1 0 0 0 +( -1920 1792 256 ) ( -1920 1728 256 ) ( -1920 1760 272 ) we_cemetary/fogtrunk 192 0 0.00 1 1 0 0 0 +( -2432 1728 256 ) ( -2432 1760 256 ) ( -2432 1744 272 ) we_cemetary/fogtrunk 192 0 0.00 1 1 0 0 0 +} +// brush 1003 +{ +( -2176 1760 0 ) ( -2176 1792 0 ) ( -2368 1792 0 ) we_cemetary/cemtrim2 -129 0 -90.00 1 1 0 0 0 +( -2368 1792 64 ) ( -2176 1792 64 ) ( -2176 1760 64 ) we_cemetary/cemtrim2 -129 0 -90.00 1 1 0 0 0 +( -2560 1760 320 ) ( -2368 1760 320 ) ( -2368 1760 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( -2176 1792 320 ) ( -2368 1792 320 ) ( -2368 1792 0 ) we_cemetary/cemtrim2 -64 0 0.00 1 1 0 0 0 +( -2240 1824 0 ) ( -2240 1760 0 ) ( -2240 1792 64 ) we_cemetary/cemtrim2 192 0 0.00 1 1 0 0 0 +( -2432 1728 0 ) ( -2432 1760 0 ) ( -2432 1744 64 ) we_cemetary/cemtrim2 192 0 0.00 1 1 0 0 0 +} +// brush 1004 +{ +( -2176 1760 64 ) ( -2176 1792 64 ) ( -2368 1792 64 ) we_cemetary/cemstair2 -129 0 -90.00 1 1 0 0 0 +( -2176 1792 384 ) ( -2368 1792 384 ) ( -2368 1792 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -2368 1744 96 ) ( -2176 1752 80 ) ( -2368 1760 64 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -2176 1728 256 ) ( -2368 1728 256 ) ( -2368 1792 256 ) we_cemetary/cemstair2 -129 0 -90.00 1 1 0 0 0 +( -2368 1744 208 ) ( -2176 1744 176 ) ( -2368 1744 144 ) we_cemetary/cemstair2 -64 0 0.00 1 1 0 0 0 +( -2240 1824 64 ) ( -2240 1760 64 ) ( -2240 1792 256 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +( -2432 1728 64 ) ( -2432 1760 64 ) ( -2432 1744 256 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +} +// brush 1005 +{ +( -2176 1760 0 ) ( -2176 1792 0 ) ( -2368 1792 0 ) we_cemetary/cemtrim2 -129 0 -90.00 1 1 0 0 0 +( -2368 1792 64 ) ( -2176 1792 64 ) ( -2176 1760 64 ) we_cemetary/cemtrim2 -129 0 -90.00 1 1 0 0 0 +( -2272 1760 320 ) ( -2080 1760 320 ) ( -2080 1760 0 ) we_cemetary/cemtrim2 192 0 0.00 1 1 0 0 0 +( -2176 1792 320 ) ( -2368 1792 320 ) ( -2368 1792 0 ) we_cemetary/cemtrim2 192 0 0.00 1 1 0 0 0 +( -2112 1760 0 ) ( -2112 1824 0 ) ( -2112 1792 64 ) we_cemetary/cemtrim2 192 0 0.00 1 1 0 0 0 +( -1920 1792 0 ) ( -1920 1728 0 ) ( -1920 1760 64 ) we_cemetary/cemtrim2 192 0 0.00 1 1 0 0 0 +} +// brush 1006 +{ +( -2176 1760 64 ) ( -2176 1792 64 ) ( -2368 1792 64 ) we_cemetary/cemstair2 -129 0 -90.00 1 1 0 0 0 +( -2176 1792 384 ) ( -2368 1792 384 ) ( -2368 1792 64 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +( -2368 1744 96 ) ( -2176 1752 80 ) ( -2368 1760 64 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +( -2176 1728 256 ) ( -2368 1728 256 ) ( -2368 1792 256 ) we_cemetary/cemstair2 -129 0 -90.00 1 1 0 0 0 +( -2272 1744 208 ) ( -2080 1744 176 ) ( -2272 1744 144 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +( -2112 1760 64 ) ( -2112 1824 64 ) ( -2112 1792 256 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +( -1920 1792 64 ) ( -1920 1728 64 ) ( -1920 1760 256 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +} +// brush 1007 +{ +( -2368 1792 64 ) ( -2176 1792 64 ) ( -2176 1824 64 ) we_cemetary/cemstair2 -65 0 -90.00 1 1 0 0 0 +( -2368 1792 64 ) ( -2368 1792 384 ) ( -2176 1792 384 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +( -2368 1824 64 ) ( -2176 1832 80 ) ( -2368 1840 96 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +( -2368 1792 256 ) ( -2368 1856 256 ) ( -2176 1856 256 ) we_cemetary/cemstair2 -65 0 -90.00 1 1 0 0 0 +( -2240 1840 144 ) ( -2048 1840 176 ) ( -2240 1840 208 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +( -1936 1808 256 ) ( -1952 1824 64 ) ( -1920 1792 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( -2112 1760 64 ) ( -2112 1824 64 ) ( -2112 1792 256 ) we_cemetary/cemstair2 128 0 0.00 1 1 0 0 0 +} +// brush 1008 +{ +( -2368 1792 64 ) ( -2176 1792 64 ) ( -2176 1824 64 ) we_cemetary/cemstair2 -65 0 -90.00 1 1 0 0 0 +( -2368 1792 64 ) ( -2368 1792 384 ) ( -2176 1792 384 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +( -2368 1824 64 ) ( -2176 1832 80 ) ( -2368 1840 96 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +( -2368 1792 256 ) ( -2368 1856 256 ) ( -2176 1856 256 ) we_cemetary/cemstair2 -65 0 -90.00 1 1 0 0 0 +( -2368 1840 144 ) ( -2176 1840 176 ) ( -2368 1840 208 ) we_cemetary/cemstair2 192 0 0.00 1 1 0 0 0 +( -2432 1792 64 ) ( -2400 1824 64 ) ( -2416 1808 256 ) we_cemetary/cemstair2 128 0 0.00 1 1 0 0 0 +( -2240 1824 64 ) ( -2240 1760 64 ) ( -2240 1792 256 ) we_cemetary/cemstair2 128 0 0.00 1 1 0 0 0 +} +// brush 1009 +{ +( -2368 1792 0 ) ( -2176 1792 0 ) ( -2176 1824 0 ) we_cemetary/cemtrim2 -65 0 -90.00 1 1 0 0 0 +( -2176 1824 64 ) ( -2176 1792 64 ) ( -2368 1792 64 ) we_cemetary/cemtrim2 -65 0 -90.00 1 1 0 0 0 +( -2176 1824 0 ) ( -2176 1824 320 ) ( -2368 1824 320 ) we_cemetary/cemtrim2 192 0 0.00 1 1 0 0 0 +( -2368 1792 0 ) ( -2368 1792 320 ) ( -2176 1792 320 ) we_cemetary/cemtrim2 192 0 0.00 1 1 0 0 0 +( -1936 1808 64 ) ( -1952 1824 0 ) ( -1920 1792 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( -2112 1760 0 ) ( -2112 1824 0 ) ( -2112 1792 64 ) we_cemetary/cemtrim2 128 0 0.00 1 1 0 0 0 +} +// brush 1010 +{ +( -2368 1792 0 ) ( -2176 1792 0 ) ( -2176 1824 0 ) we_cemetary/cemtrim2 -65 0 -90.00 1 1 0 0 0 +( -2176 1824 64 ) ( -2176 1792 64 ) ( -2368 1792 64 ) we_cemetary/cemtrim2 -65 0 -90.00 1 1 0 0 0 +( -2304 1824 0 ) ( -2304 1824 320 ) ( -2496 1824 320 ) we_cemetary/cemtrim2 192 0 0.00 1 1 0 0 0 +( -2368 1792 0 ) ( -2368 1792 320 ) ( -2176 1792 320 ) we_cemetary/cemtrim2 192 0 0.00 1 1 0 0 0 +( -2432 1792 0 ) ( -2400 1824 0 ) ( -2416 1808 64 ) we_cemetary/cemtrim2 128 0 0.00 1 1 0 0 0 +( -2240 1824 0 ) ( -2240 1760 0 ) ( -2240 1792 64 ) we_cemetary/cemtrim2 128 0 0.00 1 1 0 0 0 +} +// brush 1011 +{ +( -2400 2048 0 ) ( -2432 2048 0 ) ( -2432 1856 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( -2432 1856 64 ) ( -2432 2048 64 ) ( -2400 2048 64 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( -2400 1792 320 ) ( -2400 1984 320 ) ( -2400 1984 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( -2432 2048 320 ) ( -2432 1856 320 ) ( -2432 1856 0 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( -2432 2304 0 ) ( -2400 2272 0 ) ( -2416 2288 64 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +( -2368 1856 0 ) ( -2400 1824 0 ) ( -2384 1840 64 ) we_cemetary/cemtrim2 0 0 0.00 1 1 0 0 0 +} +// brush 1012 +{ +( -2400 2048 64 ) ( -2432 2048 64 ) ( -2432 1856 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( -2432 2048 384 ) ( -2432 1856 384 ) ( -2432 1856 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( -2384 1856 96 ) ( -2392 2048 80 ) ( -2400 1856 64 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( -2368 2048 256 ) ( -2368 1856 256 ) ( -2432 1856 256 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( -2384 1856 208 ) ( -2384 2048 176 ) ( -2384 1856 144 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( -2432 2304 64 ) ( -2400 2272 64 ) ( -2416 2288 256 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +( -2368 1856 64 ) ( -2400 1824 64 ) ( -2384 1840 256 ) we_cemetary/cemstair2 0 0 0.00 1 1 0 0 0 +} +// brush 1013 +{ +( -2384 1856 256 ) ( -2384 2048 256 ) ( -2432 2048 256 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +( -2432 1856 272 ) ( -2432 2048 272 ) ( -2368 2048 272 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +( -2384 2048 256 ) ( -2384 1856 256 ) ( -2368 1856 272 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +( -2432 2048 272 ) ( -2432 1856 272 ) ( -2432 1856 256 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +( -2432 2304 256 ) ( -2400 2272 256 ) ( -2416 2288 272 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +( -2368 1856 256 ) ( -2400 1824 256 ) ( -2384 1840 272 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +} +// brush 1014 +{ +( -2368 2048 272 ) ( -2400 2048 272 ) ( -2400 1856 272 ) we_cemetary/cemrunner2 0 0 0.00 1 1 0 0 0 +( -2400 1856 336 ) ( -2400 2048 336 ) ( -2368 2048 336 ) we_cemetary/cemtrim2 224 0 0.00 1 1 0 0 0 +( -2368 1856 592 ) ( -2368 2048 592 ) ( -2368 2048 272 ) we_cemetary/cemtrim2 0 16 0.00 1 1 0 0 0 +( -2432 2048 592 ) ( -2432 1856 592 ) ( -2432 1856 272 ) we_cemetary/cemtrim2 0 16 0.00 1 1 0 0 0 +( -2432 2304 272 ) ( -2400 2272 272 ) ( -2416 2288 336 ) we_cemetary/cemtrim2 0 16 0.00 1 1 0 0 0 +( -2368 1856 272 ) ( -2400 1824 272 ) ( -2384 1840 336 ) we_cemetary/cemtrim2 0 16 0.00 1 1 0 0 0 +} +// brush 1015 +{ +( -2176 1792 256 ) ( -2176 1840 256 ) ( -2368 1840 256 ) we_cemetary/fogtrunk -65 -192 -90.00 1 1 0 0 0 +( -2176 1856 272 ) ( -2176 1792 272 ) ( -2368 1792 272 ) we_cemetary/fogtrunk -65 -192 -90.00 1 1 0 0 0 +( -2368 1856 272 ) ( -2368 1840 256 ) ( -2176 1840 256 ) we_cemetary/fogtrunk -65 -192 -90.00 1 1 0 0 0 +( -2368 1792 256 ) ( -2368 1792 272 ) ( -2176 1792 272 ) we_cemetary/fogtrunk 192 0 0.00 1 1 0 0 0 +( -1936 1808 272 ) ( -1952 1824 256 ) ( -1920 1792 256 ) we_cemetary/fogtrunk 0 0 0.00 1 1 0 0 0 +( -2432 1792 256 ) ( -2400 1824 256 ) ( -2416 1808 272 ) we_cemetary/fogtrunk 128 0 0.00 1 1 0 0 0 +} +// brush 1016 +{ +( -2368 1824 272 ) ( -2176 1824 272 ) ( -2176 1856 272 ) we_cemetary/cemrunner2 -65 0 -90.00 1 1 0 0 0 +( -2176 1856 336 ) ( -2176 1824 336 ) ( -2368 1824 336 ) we_cemetary/cemtrim2 -97 0 -90.00 1 1 0 0 0 +( -2176 1856 272 ) ( -2176 1856 592 ) ( -2368 1856 592 ) we_cemetary/cemtrim2 192 15 0.00 1 1 0 0 0 +( -2368 1792 272 ) ( -2368 1792 592 ) ( -2176 1792 592 ) we_cemetary/cemtrim2 192 15 0.00 1 1 0 0 0 +( -1936 1808 336 ) ( -1952 1824 272 ) ( -1920 1792 272 ) we_cemetary/cemtrim2 0 15 0.00 1 1 0 0 0 +( -2432 1792 272 ) ( -2400 1824 272 ) ( -2416 1808 336 ) we_cemetary/cemtrim2 128 16 0.00 1 1 0 0 0 +} +// brush 1017 +{ +( -1952 1856 272 ) ( -1952 2048 272 ) ( -1984 2048 272 ) we_cemetary/cemrunner2 63 0 -180.00 1 1 0 0 0 +( -1984 2048 336 ) ( -1952 2048 336 ) ( -1952 1856 336 ) we_cemetary/cemtrim2 159 0 -180.00 1 1 0 0 0 +( -1984 2048 272 ) ( -1984 2048 592 ) ( -1984 1856 592 ) we_cemetary/cemtrim2 64 15 -180.00 1 -1 0 0 0 +( -1920 1856 272 ) ( -1920 1856 592 ) ( -1920 2048 592 ) we_cemetary/cemtrim2 64 15 -180.00 1 -1 0 0 0 +( -1936 2288 336 ) ( -1952 2272 272 ) ( -1920 2304 272 ) we_cemetary/cemtrim2 128 15 0.00 1 1 0 0 0 +( -1920 1792 272 ) ( -1952 1824 272 ) ( -1936 1808 336 ) we_cemetary/cemtrim2 0 16 -180.00 1 -1 0 0 0 +} +// brush 1018 +{ +( -1920 2048 256 ) ( -1968 2048 256 ) ( -1968 1856 256 ) we_cemetary/fogtrunk 191 -64 -180.00 1 1 0 0 0 +( -1984 2048 272 ) ( -1920 2048 272 ) ( -1920 1856 272 ) we_cemetary/fogtrunk 191 -64 -180.00 1 1 0 0 0 +( -1984 1856 272 ) ( -1968 1856 256 ) ( -1968 2048 256 ) we_cemetary/fogtrunk 191 -64 -180.00 1 1 0 0 0 +( -1920 1856 256 ) ( -1920 1856 272 ) ( -1920 2048 272 ) we_cemetary/fogtrunk 64 0 -180.00 1 -1 0 0 0 +( -1936 2288 272 ) ( -1952 2272 256 ) ( -1920 2304 256 ) we_cemetary/fogtrunk 128 0 0.00 1 1 0 0 0 +( -1920 1792 256 ) ( -1952 1824 256 ) ( -1936 1808 272 ) we_cemetary/fogtrunk 0 0 -180.00 1 -1 0 0 0 +} +// brush 1019 +{ +( -1920 1856 64 ) ( -1920 2048 64 ) ( -1952 2048 64 ) we_cemetary/cemstair2 191 0 -180.00 1 1 0 0 0 +( -1920 1856 64 ) ( -1920 1856 384 ) ( -1920 2048 384 ) we_cemetary/cemstair2 64 0 -180.00 1 -1 0 0 0 +( -1952 1856 64 ) ( -1960 2048 80 ) ( -1968 1856 96 ) we_cemetary/cemstair2 64 0 -180.00 1 -1 0 0 0 +( -1920 1856 256 ) ( -1984 1856 256 ) ( -1984 2048 256 ) we_cemetary/cemstair2 191 0 -180.00 1 1 0 0 0 +( -1968 1856 144 ) ( -1968 2048 176 ) ( -1968 1856 208 ) we_cemetary/cemstair2 64 0 -180.00 1 -1 0 0 0 +( -1936 2288 256 ) ( -1952 2272 64 ) ( -1920 2304 64 ) we_cemetary/cemstair2 128 0 0.00 1 1 0 0 0 +( -1920 1792 64 ) ( -1952 1824 64 ) ( -1936 1808 256 ) we_cemetary/cemstair2 0 0 -180.00 1 -1 0 0 0 +} +// brush 1020 +{ +( -1920 1856 0 ) ( -1920 2048 0 ) ( -1952 2048 0 ) we_cemetary/cemtrim2 191 0 -180.00 1 1 0 0 0 +( -1952 2048 64 ) ( -1920 2048 64 ) ( -1920 1856 64 ) we_cemetary/cemtrim2 191 0 -180.00 1 1 0 0 0 +( -1952 1920 0 ) ( -1952 1920 320 ) ( -1952 1728 320 ) we_cemetary/cemtrim2 64 0 -180.00 1 -1 0 0 0 +( -1920 1856 0 ) ( -1920 1856 320 ) ( -1920 2048 320 ) we_cemetary/cemtrim2 64 0 -180.00 1 -1 0 0 0 +( -1936 2288 64 ) ( -1952 2272 0 ) ( -1920 2304 0 ) we_cemetary/cemtrim2 128 0 0.00 1 1 0 0 0 +( -1920 1792 0 ) ( -1952 1824 0 ) ( -1936 1808 64 ) we_cemetary/cemtrim2 0 0 -180.00 1 -1 0 0 0 +} +// brush 1021 +{ +( -1984 2304 0 ) ( -2176 2304 0 ) ( -2176 2272 0 ) we_cemetary/cemtrim2 -64 0 90.00 1 1 0 0 0 +( -2176 2272 64 ) ( -2176 2304 64 ) ( -1984 2304 64 ) we_cemetary/cemtrim2 -64 0 90.00 1 1 0 0 0 +( -2112 2272 0 ) ( -2112 2272 320 ) ( -1920 2272 320 ) we_cemetary/cemtrim2 128 0 -180.00 1 -1 0 0 0 +( -1984 2304 0 ) ( -1984 2304 320 ) ( -2176 2304 320 ) we_cemetary/cemtrim2 128 0 -180.00 1 -1 0 0 0 +( -2416 2288 64 ) ( -2400 2272 0 ) ( -2432 2304 0 ) we_cemetary/cemtrim2 192 0 -180.00 1 -1 0 0 0 +( -1920 2304 0 ) ( -1952 2272 0 ) ( -1936 2288 64 ) we_cemetary/cemtrim2 192 0 -180.00 1 -1 0 0 0 +} +// brush 1022 +{ +( -1984 2304 64 ) ( -2176 2304 64 ) ( -2176 2272 64 ) we_cemetary/cemstair2 -64 0 90.00 1 1 0 0 0 +( -1984 2304 64 ) ( -1984 2304 384 ) ( -2176 2304 384 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +( -1984 2272 64 ) ( -2176 2264 80 ) ( -1984 2256 96 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +( -1984 2304 256 ) ( -1984 2240 256 ) ( -2176 2240 256 ) we_cemetary/cemstair2 -64 0 90.00 1 1 0 0 0 +( -1984 2256 144 ) ( -2176 2256 176 ) ( -1984 2256 208 ) we_cemetary/cemstair2 128 0 -180.00 1 -1 0 0 0 +( -2416 2288 256 ) ( -2400 2272 64 ) ( -2432 2304 64 ) we_cemetary/cemstair2 192 0 -180.00 1 -1 0 0 0 +( -1920 2304 64 ) ( -1952 2272 64 ) ( -1936 2288 256 ) we_cemetary/cemstair2 192 0 -180.00 1 -1 0 0 0 +} +// brush 1023 +{ +( -2176 2304 256 ) ( -2176 2256 256 ) ( -1984 2256 256 ) we_cemetary/fogtrunk -64 -128 90.00 1 1 0 0 0 +( -2176 2240 272 ) ( -2176 2304 272 ) ( -1984 2304 272 ) we_cemetary/fogtrunk -64 -128 90.00 1 1 0 0 0 +( -1984 2240 272 ) ( -1984 2256 256 ) ( -2176 2256 256 ) we_cemetary/fogtrunk -64 -128 90.00 1 1 0 0 0 +( -1984 2304 256 ) ( -1984 2304 272 ) ( -2176 2304 272 ) we_cemetary/fogtrunk 128 0 -180.00 1 -1 0 0 0 +( -2416 2288 272 ) ( -2400 2272 256 ) ( -2432 2304 256 ) we_cemetary/fogtrunk 192 0 -180.00 1 -1 0 0 0 +( -1920 2304 256 ) ( -1952 2272 256 ) ( -1936 2288 272 ) we_cemetary/fogtrunk 192 0 -180.00 1 -1 0 0 0 +} +// brush 1024 +{ +( -1984 2272 272 ) ( -2176 2272 272 ) ( -2176 2240 272 ) we_cemetary/cemrunner2 -64 0 90.00 1 1.000122 0 0 0 +( -2176 2240 336 ) ( -2176 2272 336 ) ( -1984 2272 336 ) we_cemetary/cemtrim2 -96 0 90.00 1 1 0 0 0 +( -2176 2240 272 ) ( -2176 2240 592 ) ( -1984 2240 592 ) we_cemetary/cemtrim2 128 15 -180.00 1 -1 0 0 0 +( -1984 2304 272 ) ( -1984 2304 592 ) ( -2176 2304 592 ) we_cemetary/cemtrim2 128 15 -180.00 1 -1 0 0 0 +( -2416 2288 336 ) ( -2400 2272 272 ) ( -2432 2304 272 ) we_cemetary/cemtrim2 192 16 -180.00 1 -1 0 0 0 +( -1920 2304 272 ) ( -1952 2272 272 ) ( -1936 2288 336 ) we_cemetary/cemtrim2 192 16 -180.00 1 -1 0 0 0 +} +} +// entity 1 +{ +"origin" "-605.30 929.76 15.68" +"model" "weapon_dualuzi.tik" +"scale" "1.0" +"classname" "weapon_UziDual" +} +// entity 2 +{ +"origin" "-717.30 929.76 15.68" +"model" "weapon_uzi.tik" +"scale" "1.0" +"classname" "weapon_Uzi" +} +// entity 3 +{ +"origin" "-515.04 1069.44 25.14" +"model" "weapon_soulsucker.tik" +"scale" "1.0" +"classname" "weapon_Soulsucker" +} +// entity 4 +{ +"origin" "-752.00 1086.05 14.53" +"model" "weapon_smallshield.tik" +"scale" "1.0" +"classname" "weapon_SmallShield" +} +// entity 5 +{ +"origin" "-517.58 1190.85 15.88" +"model" "weapon_sling_gas.tik" +"scale" "1.0" +"classname" "weapon_Sling_Gas" +} +// entity 6 +{ +"origin" "-757.58 1190.85 15.88" +"model" "weapon_sling_asteroid.tik" +"scale" "1.0" +"classname" "weapon_Sling_Asteroid" +} +// entity 7 +{ +"origin" "10.42 1174.85 15.88" +"model" "weapon_sling.tik" +"scale" "1.0" +"classname" "weapon_Sling" +} +// entity 8 +{ +"origin" "-137.02 1153.86 7.85" +"model" "weapon_shotgun.tik" +"scale" "1.0" +"classname" "weapon_Shotgun" +} +// entity 9 +{ +"origin" "-237.55 1172.02 5.46" +"model" "weapon_rlauncher.tik" +"scale" "1.0" +"classname" "weapon_Rocketlauncher" +} +// entity 10 +{ +"origin" "16.14 1073.00 31.72" +"model" "weapon_largeshield.tik" +"scale" "1.0" +"classname" "weapon_LargeShield" +} +// entity 11 +{ +"origin" "-51.04 1069.44 25.14" +"model" "weapon_hornofconjuring.tik" +"scale" "1.0" +"classname" "weapon_HornOfConjuring" +} +// entity 12 +{ +"origin" "-172.47 1073.62 4.80" +"model" "weapon_gun.tik" +"scale" "1.0" +"classname" "weapon_Gun" +} +// entity 13 +{ +"origin" "-271.01 1059.41 5.79" +"model" "weapon_flashbang.tik" +"scale" "1.0" +"classname" "weapon_flashbang" +} +// entity 14 +{ +"origin" "-40.54 959.01 21.51" +"model" "weapon_flamethrower.tik" +"scale" "1.0" +"classname" "weapon_Flamethrower" +} +// entity 15 +{ +"origin" "-138.22 978.87 4.52" +"model" "weapon_cbow.tik" +"scale" "1.0" +"classname" "weapon_Crossbow" +} +// entity 16 +{ +"origin" "-284.18 959.91 16.91" +"model" "weapon_chaingun.tik" +"scale" "1.0" +"classname" "weapon_ChainGun" +} +// entity 17 +{ +"origin" "-633.51 1089.82 15.38" +"model" "weapon_firesword.tik" +"scale" "1.0" +"classname" "weapon_Sword_Fire" +} +// entity 18 +{ +"origin" "-521.51 1009.82 15.38" +"model" "weapon_elecsword.tik" +"scale" "1.0" +"classname" "weapon_Sword_Eletrical" +} +// entity 19 +{ +"origin" "-587.37 1010.40 9.88" +"model" "weapon_chainsword.tik" +"scale" "1.0" +"classname" "weapon_Sword_Chain" +} +// entity 20 +{ +"origin" "-665.51 1009.82 15.38" +"model" "weapon_sword.tik" +"scale" "1.0" +"classname" "weapon_Sword" +} +// entity 21 +{ +"origin" "-754.92 1010.55 20.21" +"model" "weapon_axe.tik" +"scale" "1.0" +"classname" "weapon_Axe" +} +// entity 22 +{ +"origin" "-1021.51 1010.48 -2.31" +"model" "item_waterampoule.tik" +"scale" "1.0" +"classname" "Item_WaterAmpoule" +} +// entity 23 +{ +"origin" "-1103.01 1011.41 5.79" +"model" "item_detonator.tik" +"scale" "1.0" +"classname" "Item_Detonator" +} +// entity 24 +{ +"origin" "-1189.85 1018.20 -0.07" +"model" "item_cop.tik" +"scale" "1.0" +"classname" "Item_CircleOfProtection" +} +// entity 25 +{ +"origin" "-1273.78 1014.20 -5.78" +"model" "item_bigwaterampoule.tik" +"scale" "1.0" +"classname" "Item_BigWaterAmpoule" +} +// entity 26 +{ +"origin" "-1658.67 1076.53 -0.22" +"model" "item_healthmush_glowing.tik" +"scale" "1.0" +"classname" "Health_MushroomGlowing" +} +// entity 27 +{ +"origin" "-1514.67 980.53 -0.22" +"model" "item_healthmush.tik" +"scale" "1.0" +"classname" "Health_Mushroom" +} +// entity 28 +{ +"origin" "-1573.85 986.20 -0.07" +"model" "item_healthvial.tik" +"scale" "1.0" +"classname" "Health_HealthVial" +} +// entity 29 +{ +"origin" "-1656.00 984.00 0.00" +"model" "item_healthplant.tik" +"scale" "1.0" +"classname" "Health_HealthPlant" +} +// entity 30 +{ +"origin" "-1721.11 980.65 -6.19" +"model" "item_healthfruit1.tik" +"scale" "1.0" +"classname" "Health_Healthfruit" +} +// entity 31 +{ +"origin" "-1780.61 983.87 3.41" +"model" "item_edenwater.tik" +"scale" "1.0" +"classname" "Health_edenwater" +} +// entity 32 +{ +"origin" "-2044.30 996.69 -0.02" +"model" "armor_shoulderpad.tik" +"scale" "1.0" +"classname" "armor_ShoulderPad" +} +// entity 33 +{ +"origin" "-2153.90 1004.06 -0.05" +"model" "armor_kneepad.tik" +"scale" "1.0" +"classname" "armor_KneePad" +} +// entity 34 +{ +"origin" "-2281.46 994.59 -0.05" +"model" "armor_armguard.tik" +"scale" "1.0" +"classname" "armor_ArmGuard" +} +// entity 35 +{ +"origin" "893.26 676.11 26.71" +"angle" "90" +"model" "claw.tik" +"scale" "1.0" +"classname" "Enemies_Claw" +} +// entity 36 +{ +"origin" "1408.00 960.00 0.00" +"angle" "90" +"model" "creeper_single.tik" +"scale" "1.0" +"classname" "Enemies_DarkCreeper_Single" +} +// entity 37 +{ +"origin" "1920.00 960.00 0.00" +"angle" "90" +"model" "creeper_double.tik" +"scale" "1.0" +"classname" "Enemies_DarkCreeper_Double" +} +// entity 38 +{ +"origin" "2432.00 1008.00 0.00" +"angle" "90" +"model" "grawlix_invisible.tik" +"scale" "1.0" +"classname" "Enemies_Grawlix_Invisible" +} +// entity 39 +{ +"origin" "2946.00 1026.00 -20.00" +"model" "gasyerass.tik" +"scale" "1.0" +"classname" "Enemies_Gasyerass_Hanging" +} +// entity 40 +{ +"origin" "3456.00 1024.00 0.00" +"angle" "90" +"model" "vmama_walking.tik" +"scale" "1.0" +"classname" "Enemies_VymishMomma_Walking" +} +// entity 41 +{ +"origin" "3960.00 936.00 0.00" +"angle" "90" +"model" "vymish_multi.tik" +"scale" "1.0" +"classname" "Enemies_Vymish_Multi" +} +// entity 42 +{ +"origin" "4488.00 952.00 0.00" +"angle" "90" +"model" "vymish_ground.tik" +"scale" "1.0" +"classname" "Enemies_Vymish_Ground" +} +// entity 43 +{ +"origin" "5000.00 952.00 0.00" +"angle" "90" +"model" "vymish_flying.tik" +"scale" "1.0" +"classname" "Enemies_Vymish_Flying" +} +// entity 44 +{ +"origin" "5000.00 2104.00 0.00" +"angle" "270" +"model" "vymish_blue.tik" +"scale" "1.0" +"classname" "Enemies_Vymish_Blue" +} +// entity 45 +{ +"origin" "4496.00 2128.00 0.00" +"angle" "270" +"model" "harvester.tik" +"scale" "1.0" +"classname" "Enemies_SoulHarvester" +} +// entity 46 +{ +"origin" "3968.00 2096.00 0.00" +"model" "suckblow.tik" +"scale" "1.0" +"classname" "Enemies_SB" +} +// entity 47 +{ +"origin" "3456.00 2160.00 0.00" +"angle" "270" +"model" "recruiter.tik" +"scale" "1.0" +"classname" "Enemies_Recruiter" +} +// entity 48 +{ +"origin" "2960.00 2112.00 0.00" +"angle" "270" +"model" "lympthorn_m.tik" +"scale" "1.0" +"classname" "Enemies_Lympthorn_male" +} +// entity 49 +{ +"origin" "2432.00 2112.00 0.00" +"angle" "270" +"model" "lympthorn_f.tik" +"scale" "1.0" +"classname" "Enemies_Lympthorn_female" +} +// entity 50 +{ +"origin" "1920.00 2160.00 0.00" +"angle" "270" +"model" "jart_fire.tik" +"scale" "1.0" +"classname" "Enemies_Jart_Fire" +} +// entity 51 +{ +"origin" "1408.00 2160.00 0.00" +"angle" "270" +"model" "jart.tik" +"scale" "1.0" +"classname" "Enemies_Jart" +} +// entity 52 +{ +"origin" "896.00 2176.00 0.00" +"angle" "270" +"model" "horde.tik" +"scale" "1.0" +"classname" "Enemies_HappyMask_HordeCreature" +} +// entity 53 +{ +"origin" "384.00 2176.00 0.00" +"angle" "270" +"model" "grawlix.tik" +"scale" "1.0" +"classname" "Enemies_Grawlix" +} +// entity 54 +{ +"origin" "-128.00 2176.00 0.00" +"angle" "270" +"model" "ghost.tik" +"scale" "1.0" +"classname" "Enemies_Ghost" +} +// entity 55 +{ +"origin" "-630.00 2170.00 0.00" +"model" "gasyerass2.tik" +"scale" "1.0" +"classname" "Enemies_Gasyerass_Ground" +} +// entity 56 +{ +"origin" "-1152.00 2176.00 0.00" +"angle" "270" +"model" "fleshbinder.tik" +"scale" "1.0" +"classname" "Enemies_FleshBinder_All" +} +// entity 57 +{ +"origin" "-1672.00 2168.00 0.00" +"angle" "270" +"model" "shgliek_evil.tik" +"scale" "1.0" +"classname" "Enemies_EvilShgliek" +} +// entity 58 +{ +"origin" "-2176.00 2176.00 0.00" +"angle" "270" +"model" "creeper.tik" +"scale" "1.0" +"classname" "Enemies_DarkCreeper" +} +// entity 59 +{ +"origin" "-2352 1568 0" +"angle" "0" +"classname" "info_player_start" +} +// entity 60 +{ +"light" "400" +"classname" "light" +"origin" "-2168 2024 136" +} +// entity 61 +{ +"classname" "func_door" +"angle" "-1" +"spawnflags" "64" +// brush 0 +{ +( -2112 1824 0 ) ( -2240 1824 0 ) ( -2240 1760 0 ) we_cemetary/cemtablet 64 64 0.00 -1 0.500000 0 0 0 +( -2240 1760 208 ) ( -2240 1824 208 ) ( -2112 1824 208 ) we_cemetary/cemtablet 64 64 0.00 -1 0.500000 0 0 0 +( -2240 1776 192 ) ( -2112 1776 192 ) ( -2112 1776 144 ) we_cemetary/cemtablet 64 0 0.00 -1 1.625000 0 0 0 +( -2112 1760 192 ) ( -2112 1824 192 ) ( -2112 1824 144 ) we_cemetary/cemtablet 64 0 0.00 -0.500000 1.625000 0 0 0 +( -2112 1808 192 ) ( -2240 1808 192 ) ( -2240 1808 144 ) we_cemetary/cemtablet 64 0 0.00 -1 1.625000 0 0 0 +( -2240 1824 192 ) ( -2240 1760 192 ) ( -2240 1760 144 ) we_cemetary/cemtablet 64 0 0.00 -0.500000 1.625000 0 0 0 +} +} +// entity 62 +{ +"origin" "-1656 2024 136" +"classname" "light" +"light" "400" +} +// entity 63 +{ +"spawnflags" "64" +"angle" "-1" +"classname" "func_door" +// brush 0 +{ +( -1600 1824 0 ) ( -1728 1824 0 ) ( -1728 1760 0 ) we_cemetary/cemtablet 64 64 0.00 -1 0.500000 0 0 0 +( -1728 1760 208 ) ( -1728 1824 208 ) ( -1600 1824 208 ) we_cemetary/cemtablet 64 64 0.00 -1 0.500000 0 0 0 +( -1728 1776 192 ) ( -1600 1776 192 ) ( -1600 1776 144 ) we_cemetary/cemtablet 64 0 0.00 -1 1.625000 0 0 0 +( -1600 1760 192 ) ( -1600 1824 192 ) ( -1600 1824 144 ) we_cemetary/cemtablet 64 0 0.00 -0.500000 1.625000 0 0 0 +( -1600 1808 192 ) ( -1728 1808 192 ) ( -1728 1808 144 ) we_cemetary/cemtablet 64 0 0.00 -1 1.625000 0 0 0 +( -1728 1824 192 ) ( -1728 1760 192 ) ( -1728 1760 144 ) we_cemetary/cemtablet 64 0 0.00 -0.500000 1.625000 0 0 0 +} +} +// entity 64 +{ +"light" "400" +"classname" "light" +"origin" "-1144 2024 136" +} +// entity 65 +{ +"classname" "func_door" +"angle" "-1" +"spawnflags" "64" +// brush 0 +{ +( -1088 1824 0 ) ( -1216 1824 0 ) ( -1216 1760 0 ) we_cemetary/cemtablet 64 64 0.00 -1 0.500000 0 0 0 +( -1216 1760 208 ) ( -1216 1824 208 ) ( -1088 1824 208 ) we_cemetary/cemtablet 64 64 0.00 -1 0.500000 0 0 0 +( -1216 1776 192 ) ( -1088 1776 192 ) ( -1088 1776 144 ) we_cemetary/cemtablet 64 0 0.00 -1 1.625000 0 0 0 +( -1088 1760 192 ) ( -1088 1824 192 ) ( -1088 1824 144 ) we_cemetary/cemtablet 64 0 0.00 -0.500000 1.625000 0 0 0 +( -1088 1808 192 ) ( -1216 1808 192 ) ( -1216 1808 144 ) we_cemetary/cemtablet 64 0 0.00 -1 1.625000 0 0 0 +( -1216 1824 192 ) ( -1216 1760 192 ) ( -1216 1760 144 ) we_cemetary/cemtablet 64 0 0.00 -0.500000 1.625000 0 0 0 +} +} +// entity 66 +{ +"origin" "-632 2024 136" +"classname" "light" +"light" "400" +} +// entity 67 +{ +"spawnflags" "64" +"angle" "-1" +"classname" "func_door" +// brush 0 +{ +( -576 1824 0 ) ( -704 1824 0 ) ( -704 1760 0 ) we_cemetary/cemtablet 64 64 0.00 -1 0.500000 0 0 0 +( -704 1760 208 ) ( -704 1824 208 ) ( -576 1824 208 ) we_cemetary/cemtablet 64 64 0.00 -1 0.500000 0 0 0 +( -704 1776 192 ) ( -576 1776 192 ) ( -576 1776 144 ) we_cemetary/cemtablet 64 0 0.00 -1 1.625000 0 0 0 +( -576 1760 192 ) ( -576 1824 192 ) ( -576 1824 144 ) we_cemetary/cemtablet 64 0 0.00 -0.500000 1.625000 0 0 0 +( -576 1808 192 ) ( -704 1808 192 ) ( -704 1808 144 ) we_cemetary/cemtablet 64 0 0.00 -1 1.625000 0 0 0 +( -704 1824 192 ) ( -704 1760 192 ) ( -704 1760 144 ) we_cemetary/cemtablet 64 0 0.00 -0.500000 1.625000 0 0 0 +} +} +// entity 68 +{ +"light" "400" +"classname" "light" +"origin" "-120 2024 136" +} +// entity 69 +{ +"classname" "func_door" +"angle" "-1" +"spawnflags" "64" +// brush 0 +{ +( -64 1824 0 ) ( -192 1824 0 ) ( -192 1760 0 ) we_cemetary/cemtablet 64 64 0.00 -1 0.500000 0 0 0 +( -192 1760 208 ) ( -192 1824 208 ) ( -64 1824 208 ) we_cemetary/cemtablet 64 64 0.00 -1 0.500000 0 0 0 +( -192 1776 192 ) ( -64 1776 192 ) ( -64 1776 144 ) we_cemetary/cemtablet 64 0 0.00 -1 1.625000 0 0 0 +( -64 1760 192 ) ( -64 1824 192 ) ( -64 1824 144 ) we_cemetary/cemtablet 64 0 0.00 -0.500000 1.625000 0 0 0 +( -64 1808 192 ) ( -192 1808 192 ) ( -192 1808 144 ) we_cemetary/cemtablet 64 0 0.00 -1 1.625000 0 0 0 +( -192 1824 192 ) ( -192 1760 192 ) ( -192 1760 144 ) we_cemetary/cemtablet 64 0 0.00 -0.500000 1.625000 0 0 0 +} +} +// entity 70 +{ +"origin" "392 2024 136" +"classname" "light" +"light" "400" +} +// entity 71 +{ +"spawnflags" "64" +"angle" "-1" +"classname" "func_door" +// brush 0 +{ +( 448 1824 0 ) ( 320 1824 0 ) ( 320 1760 0 ) we_cemetary/cemtablet 64 64 0.00 -1 0.500000 0 0 0 +( 320 1760 208 ) ( 320 1824 208 ) ( 448 1824 208 ) we_cemetary/cemtablet 64 64 0.00 -1 0.500000 0 0 0 +( 320 1776 192 ) ( 448 1776 192 ) ( 448 1776 144 ) we_cemetary/cemtablet 64 0 0.00 -1 1.625000 0 0 0 +( 448 1760 192 ) ( 448 1824 192 ) ( 448 1824 144 ) we_cemetary/cemtablet 64 0 0.00 -0.500000 1.625000 0 0 0 +( 448 1808 192 ) ( 320 1808 192 ) ( 320 1808 144 ) we_cemetary/cemtablet 64 0 0.00 -1 1.625000 0 0 0 +( 320 1824 192 ) ( 320 1760 192 ) ( 320 1760 144 ) we_cemetary/cemtablet 64 0 0.00 -0.500000 1.625000 0 0 0 +} +} +// entity 72 +{ +"light" "400" +"classname" "light" +"origin" "904 2024 136" +} +// entity 73 +{ +"classname" "func_door" +"angle" "-1" +"spawnflags" "64" +// brush 0 +{ +( 960 1824 0 ) ( 832 1824 0 ) ( 832 1760 0 ) we_cemetary/cemtablet 64 64 0.00 -1 0.500000 0 0 0 +( 832 1760 208 ) ( 832 1824 208 ) ( 960 1824 208 ) we_cemetary/cemtablet 64 64 0.00 -1 0.500000 0 0 0 +( 832 1776 192 ) ( 960 1776 192 ) ( 960 1776 144 ) we_cemetary/cemtablet 64 0 0.00 -1 1.625000 0 0 0 +( 960 1760 192 ) ( 960 1824 192 ) ( 960 1824 144 ) we_cemetary/cemtablet 64 0 0.00 -0.500000 1.625000 0 0 0 +( 960 1808 192 ) ( 832 1808 192 ) ( 832 1808 144 ) we_cemetary/cemtablet 64 0 0.00 -1 1.625000 0 0 0 +( 832 1824 192 ) ( 832 1760 192 ) ( 832 1760 144 ) we_cemetary/cemtablet 64 0 0.00 -0.500000 1.625000 0 0 0 +} +} +// entity 74 +{ +"origin" "1416 2024 136" +"classname" "light" +"light" "400" +} +// entity 75 +{ +"spawnflags" "64" +"angle" "-1" +"classname" "func_door" +// brush 0 +{ +( 1472 1824 0 ) ( 1344 1824 0 ) ( 1344 1760 0 ) we_cemetary/cemtablet 64 64 0.00 -1 0.500000 0 0 0 +( 1344 1760 208 ) ( 1344 1824 208 ) ( 1472 1824 208 ) we_cemetary/cemtablet 64 64 0.00 -1 0.500000 0 0 0 +( 1344 1776 192 ) ( 1472 1776 192 ) ( 1472 1776 144 ) we_cemetary/cemtablet 64 0 0.00 -1 1.625000 0 0 0 +( 1472 1760 192 ) ( 1472 1824 192 ) ( 1472 1824 144 ) we_cemetary/cemtablet 64 0 0.00 -0.500000 1.625000 0 0 0 +( 1472 1808 192 ) ( 1344 1808 192 ) ( 1344 1808 144 ) we_cemetary/cemtablet 64 0 0.00 -1 1.625000 0 0 0 +( 1344 1824 192 ) ( 1344 1760 192 ) ( 1344 1760 144 ) we_cemetary/cemtablet 64 0 0.00 -0.500000 1.625000 0 0 0 +} +} +// entity 76 +{ +"light" "400" +"classname" "light" +"origin" "1928 2024 136" +} +// entity 77 +{ +"classname" "func_door" +"angle" "-1" +"spawnflags" "64" +// brush 0 +{ +( 1984 1824 0 ) ( 1856 1824 0 ) ( 1856 1760 0 ) we_cemetary/cemtablet -64 64 0.00 -1 0.500000 0 0 0 +( 1856 1760 208 ) ( 1856 1824 208 ) ( 1984 1824 208 ) we_cemetary/cemtablet -64 64 0.00 -1 0.500000 0 0 0 +( 1856 1776 192 ) ( 1984 1776 192 ) ( 1984 1776 144 ) we_cemetary/cemtablet -64 0 0.00 -1 1.625000 0 0 0 +( 1984 1760 192 ) ( 1984 1824 192 ) ( 1984 1824 144 ) we_cemetary/cemtablet 64 0 0.00 -0.500000 1.625000 0 0 0 +( 1984 1808 192 ) ( 1856 1808 192 ) ( 1856 1808 144 ) we_cemetary/cemtablet -64 0 0.00 -1 1.625000 0 0 0 +( 1856 1824 192 ) ( 1856 1760 192 ) ( 1856 1760 144 ) we_cemetary/cemtablet 64 0 0.00 -0.500000 1.625000 0 0 0 +} +} +// entity 78 +{ +"origin" "2440 2024 136" +"classname" "light" +"light" "400" +} +// entity 79 +{ +"spawnflags" "64" +"angle" "-1" +"classname" "func_door" +// brush 0 +{ +( 2496 1824 0 ) ( 2368 1824 0 ) ( 2368 1760 0 ) we_cemetary/cemtablet 64 64 0.00 -1 0.500000 0 0 0 +( 2368 1760 208 ) ( 2368 1824 208 ) ( 2496 1824 208 ) we_cemetary/cemtablet 64 64 0.00 -1 0.500000 0 0 0 +( 2368 1776 192 ) ( 2496 1776 192 ) ( 2496 1776 144 ) we_cemetary/cemtablet 64 0 0.00 -1 1.625000 0 0 0 +( 2496 1760 192 ) ( 2496 1824 192 ) ( 2496 1824 144 ) we_cemetary/cemtablet 64 0 0.00 -0.500000 1.625000 0 0 0 +( 2496 1808 192 ) ( 2368 1808 192 ) ( 2368 1808 144 ) we_cemetary/cemtablet 64 0 0.00 -1 1.625000 0 0 0 +( 2368 1824 192 ) ( 2368 1760 192 ) ( 2368 1760 144 ) we_cemetary/cemtablet 64 0 0.00 -0.500000 1.625000 0 0 0 +} +} +// entity 80 +{ +"light" "400" +"classname" "light" +"origin" "2952 2024 136" +} +// entity 81 +{ +"classname" "func_door" +"angle" "-1" +"spawnflags" "64" +// brush 0 +{ +( 3008 1824 0 ) ( 2880 1824 0 ) ( 2880 1760 0 ) we_cemetary/cemtablet 64 64 0.00 -1 0.500000 0 0 0 +( 2880 1760 208 ) ( 2880 1824 208 ) ( 3008 1824 208 ) we_cemetary/cemtablet 64 64 0.00 -1 0.500000 0 0 0 +( 2880 1776 192 ) ( 3008 1776 192 ) ( 3008 1776 144 ) we_cemetary/cemtablet 64 0 0.00 -1 1.625000 0 0 0 +( 3008 1760 192 ) ( 3008 1824 192 ) ( 3008 1824 144 ) we_cemetary/cemtablet 64 0 0.00 -0.500000 1.625000 0 0 0 +( 3008 1808 192 ) ( 2880 1808 192 ) ( 2880 1808 144 ) we_cemetary/cemtablet 64 0 0.00 -1 1.625000 0 0 0 +( 2880 1824 192 ) ( 2880 1760 192 ) ( 2880 1760 144 ) we_cemetary/cemtablet 64 0 0.00 -0.500000 1.625000 0 0 0 +} +} +// entity 82 +{ +"origin" "3464 2024 136" +"classname" "light" +"light" "400" +} +// entity 83 +{ +"spawnflags" "64" +"angle" "-1" +"classname" "func_door" +// brush 0 +{ +( 3520 1824 0 ) ( 3392 1824 0 ) ( 3392 1760 0 ) we_cemetary/cemtablet 64 64 0.00 -1 0.500000 0 0 0 +( 3392 1760 208 ) ( 3392 1824 208 ) ( 3520 1824 208 ) we_cemetary/cemtablet 64 64 0.00 -1 0.500000 0 0 0 +( 3392 1776 192 ) ( 3520 1776 192 ) ( 3520 1776 144 ) we_cemetary/cemtablet 64 0 0.00 -1 1.625000 0 0 0 +( 3520 1760 192 ) ( 3520 1824 192 ) ( 3520 1824 144 ) we_cemetary/cemtablet 64 0 0.00 -0.500000 1.625000 0 0 0 +( 3520 1808 192 ) ( 3392 1808 192 ) ( 3392 1808 144 ) we_cemetary/cemtablet 64 0 0.00 -1 1.625000 0 0 0 +( 3392 1824 192 ) ( 3392 1760 192 ) ( 3392 1760 144 ) we_cemetary/cemtablet 64 0 0.00 -0.500000 1.625000 0 0 0 +} +} +// entity 84 +{ +"light" "400" +"classname" "light" +"origin" "3976 2024 136" +} +// entity 85 +{ +"classname" "func_door" +"angle" "-1" +"spawnflags" "64" +// brush 0 +{ +( 4032 1824 0 ) ( 3904 1824 0 ) ( 3904 1760 0 ) we_cemetary/cemtablet -64 64 0.00 -1 0.500000 0 0 0 +( 3904 1760 208 ) ( 3904 1824 208 ) ( 4032 1824 208 ) we_cemetary/cemtablet -64 64 0.00 -1 0.500000 0 0 0 +( 3904 1776 192 ) ( 4032 1776 192 ) ( 4032 1776 144 ) we_cemetary/cemtablet -64 0 0.00 -1 1.625000 0 0 0 +( 4032 1760 192 ) ( 4032 1824 192 ) ( 4032 1824 144 ) we_cemetary/cemtablet 64 0 0.00 -0.500000 1.625000 0 0 0 +( 4032 1808 192 ) ( 3904 1808 192 ) ( 3904 1808 144 ) we_cemetary/cemtablet -64 0 0.00 -1 1.625000 0 0 0 +( 3904 1824 192 ) ( 3904 1760 192 ) ( 3904 1760 144 ) we_cemetary/cemtablet 64 0 0.00 -0.500000 1.625000 0 0 0 +} +} +// entity 86 +{ +"origin" "4488 2024 136" +"classname" "light" +"light" "400" +} +// entity 87 +{ +"spawnflags" "64" +"angle" "-1" +"classname" "func_door" +// brush 0 +{ +( 4544 1824 0 ) ( 4416 1824 0 ) ( 4416 1760 0 ) we_cemetary/cemtablet 64 64 0.00 -1 0.500000 0 0 0 +( 4416 1760 208 ) ( 4416 1824 208 ) ( 4544 1824 208 ) we_cemetary/cemtablet 64 64 0.00 -1 0.500000 0 0 0 +( 4416 1776 192 ) ( 4544 1776 192 ) ( 4544 1776 144 ) we_cemetary/cemtablet 64 0 0.00 -1 1.625000 0 0 0 +( 4544 1760 192 ) ( 4544 1824 192 ) ( 4544 1824 144 ) we_cemetary/cemtablet 64 0 0.00 -0.500000 1.625000 0 0 0 +( 4544 1808 192 ) ( 4416 1808 192 ) ( 4416 1808 144 ) we_cemetary/cemtablet 64 0 0.00 -1 1.625000 0 0 0 +( 4416 1824 192 ) ( 4416 1760 192 ) ( 4416 1760 144 ) we_cemetary/cemtablet 64 0 0.00 -0.500000 1.625000 0 0 0 +} +} +// entity 88 +{ +"light" "400" +"classname" "light" +"origin" "5000 2024 136" +} +// entity 89 +{ +"classname" "func_door" +"angle" "-1" +"spawnflags" "64" +// brush 0 +{ +( 5056 1824 0 ) ( 4928 1824 0 ) ( 4928 1760 0 ) we_cemetary/cemtablet 64 64 0.00 -1 0.500000 0 0 0 +( 4928 1760 208 ) ( 4928 1824 208 ) ( 5056 1824 208 ) we_cemetary/cemtablet 64 64 0.00 -1 0.500000 0 0 0 +( 4928 1776 192 ) ( 5056 1776 192 ) ( 5056 1776 144 ) we_cemetary/cemtablet 64 0 0.00 -1 1.625000 0 0 0 +( 5056 1760 192 ) ( 5056 1824 192 ) ( 5056 1824 144 ) we_cemetary/cemtablet 64 0 0.00 -0.500000 1.625000 0 0 0 +( 5056 1808 192 ) ( 4928 1808 192 ) ( 4928 1808 144 ) we_cemetary/cemtablet 64 0 0.00 -1 1.625000 0 0 0 +( 4928 1824 192 ) ( 4928 1760 192 ) ( 4928 1760 144 ) we_cemetary/cemtablet 64 0 0.00 -0.500000 1.625000 0 0 0 +} +} +// entity 90 +{ +"origin" "-2168 1112 136" +"classname" "light" +"light" "400" +} +// entity 91 +{ +"spawnflags" "64" +"angle" "-1" +"classname" "func_door" +// brush 0 +{ +( -2240 1376 0 ) ( -2240 1312 0 ) ( -2112 1312 0 ) we_cemetary/cemtablet -64 -64 0.00 -1 0.500000 0 0 0 +( -2112 1312 208 ) ( -2240 1312 208 ) ( -2240 1376 208 ) we_cemetary/cemtablet -64 -64 0.00 -1 0.500000 0 0 0 +( -2112 1360 144 ) ( -2112 1360 192 ) ( -2240 1360 192 ) we_cemetary/cemtablet -64 0 0.00 -1 1.625000 0 0 0 +( -2112 1312 144 ) ( -2112 1312 192 ) ( -2112 1376 192 ) we_cemetary/cemtablet -64 0 0.00 -0.500000 1.625000 0 0 0 +( -2240 1328 144 ) ( -2240 1328 192 ) ( -2112 1328 192 ) we_cemetary/cemtablet -64 0 0.00 -1 1.625000 0 0 0 +( -2240 1376 144 ) ( -2240 1376 192 ) ( -2240 1312 192 ) we_cemetary/cemtablet -64 0 0.00 -0.500000 1.625000 0 0 0 +} +} +// entity 92 +{ +"light" "400" +"classname" "light" +"origin" "-1656 1112 136" +} +// entity 93 +{ +"classname" "func_door" +"angle" "-1" +"spawnflags" "64" +// brush 0 +{ +( -1728 1376 0 ) ( -1728 1312 0 ) ( -1600 1312 0 ) we_cemetary/cemtablet -64 -64 0.00 -1 0.500000 0 0 0 +( -1600 1312 208 ) ( -1728 1312 208 ) ( -1728 1376 208 ) we_cemetary/cemtablet -64 -64 0.00 -1 0.500000 0 0 0 +( -1600 1360 144 ) ( -1600 1360 192 ) ( -1728 1360 192 ) we_cemetary/cemtablet -64 0 0.00 -1 1.625000 0 0 0 +( -1600 1312 144 ) ( -1600 1312 192 ) ( -1600 1376 192 ) we_cemetary/cemtablet -64 0 0.00 -0.500000 1.625000 0 0 0 +( -1728 1328 144 ) ( -1728 1328 192 ) ( -1600 1328 192 ) we_cemetary/cemtablet -64 0 0.00 -1 1.625000 0 0 0 +( -1728 1376 144 ) ( -1728 1376 192 ) ( -1728 1312 192 ) we_cemetary/cemtablet -64 0 0.00 -0.500000 1.625000 0 0 0 +} +} +// entity 94 +{ +"origin" "-1144 1112 136" +"classname" "light" +"light" "400" +} +// entity 95 +{ +"spawnflags" "64" +"angle" "-1" +"classname" "func_door" +// brush 0 +{ +( -1216 1376 0 ) ( -1216 1312 0 ) ( -1088 1312 0 ) we_cemetary/cemtablet -64 -64 0.00 -1 0.500000 0 0 0 +( -1088 1312 208 ) ( -1216 1312 208 ) ( -1216 1376 208 ) we_cemetary/cemtablet -64 -64 0.00 -1 0.500000 0 0 0 +( -1088 1360 144 ) ( -1088 1360 192 ) ( -1216 1360 192 ) we_cemetary/cemtablet -64 0 0.00 -1 1.625000 0 0 0 +( -1088 1312 144 ) ( -1088 1312 192 ) ( -1088 1376 192 ) we_cemetary/cemtablet -64 0 0.00 -0.500000 1.625000 0 0 0 +( -1216 1328 144 ) ( -1216 1328 192 ) ( -1088 1328 192 ) we_cemetary/cemtablet -64 0 0.00 -1 1.625000 0 0 0 +( -1216 1376 144 ) ( -1216 1376 192 ) ( -1216 1312 192 ) we_cemetary/cemtablet -64 0 0.00 -0.500000 1.625000 0 0 0 +} +} +// entity 96 +{ +"light" "400" +"classname" "light" +"origin" "-632 1112 136" +} +// entity 97 +{ +"classname" "func_door" +"angle" "-1" +"spawnflags" "64" +// brush 0 +{ +( -704 1376 0 ) ( -704 1312 0 ) ( -576 1312 0 ) we_cemetary/cemtablet -64 -64 0.00 -1 0.500000 0 0 0 +( -576 1312 208 ) ( -704 1312 208 ) ( -704 1376 208 ) we_cemetary/cemtablet -64 -64 0.00 -1 0.500000 0 0 0 +( -576 1360 144 ) ( -576 1360 192 ) ( -704 1360 192 ) we_cemetary/cemtablet -64 0 0.00 -1 1.625000 0 0 0 +( -576 1312 144 ) ( -576 1312 192 ) ( -576 1376 192 ) we_cemetary/cemtablet -64 0 0.00 -0.500000 1.625000 0 0 0 +( -704 1328 144 ) ( -704 1328 192 ) ( -576 1328 192 ) we_cemetary/cemtablet -64 0 0.00 -1 1.625000 0 0 0 +( -704 1376 144 ) ( -704 1376 192 ) ( -704 1312 192 ) we_cemetary/cemtablet -64 0 0.00 -0.500000 1.625000 0 0 0 +} +} +// entity 98 +{ +"origin" "-120 1112 136" +"classname" "light" +"light" "400" +} +// entity 99 +{ +"spawnflags" "64" +"angle" "-1" +"classname" "func_door" +// brush 0 +{ +( -192 1376 0 ) ( -192 1312 0 ) ( -64 1312 0 ) we_cemetary/cemtablet -64 -64 0.00 -1 0.500000 0 0 0 +( -64 1312 208 ) ( -192 1312 208 ) ( -192 1376 208 ) we_cemetary/cemtablet -64 -64 0.00 -1 0.500000 0 0 0 +( -64 1360 144 ) ( -64 1360 192 ) ( -192 1360 192 ) we_cemetary/cemtablet -64 0 0.00 -1 1.625000 0 0 0 +( -64 1312 144 ) ( -64 1312 192 ) ( -64 1376 192 ) we_cemetary/cemtablet -64 0 0.00 -0.500000 1.625000 0 0 0 +( -192 1328 144 ) ( -192 1328 192 ) ( -64 1328 192 ) we_cemetary/cemtablet -64 0 0.00 -1 1.625000 0 0 0 +( -192 1376 144 ) ( -192 1376 192 ) ( -192 1312 192 ) we_cemetary/cemtablet -64 0 0.00 -0.500000 1.625000 0 0 0 +} +} +// entity 100 +{ +"light" "400" +"classname" "light" +"origin" "392 1112 136" +} +// entity 101 +{ +"classname" "func_door" +"angle" "-1" +"spawnflags" "64" +// brush 0 +{ +( 320 1376 0 ) ( 320 1312 0 ) ( 448 1312 0 ) we_cemetary/cemtablet -64 -64 0.00 -1 0.500000 0 0 0 +( 448 1312 208 ) ( 320 1312 208 ) ( 320 1376 208 ) we_cemetary/cemtablet -64 -64 0.00 -1 0.500000 0 0 0 +( 448 1360 144 ) ( 448 1360 192 ) ( 320 1360 192 ) we_cemetary/cemtablet -64 0 0.00 -1 1.625000 0 0 0 +( 448 1312 144 ) ( 448 1312 192 ) ( 448 1376 192 ) we_cemetary/cemtablet -64 0 0.00 -0.500000 1.625000 0 0 0 +( 320 1328 144 ) ( 320 1328 192 ) ( 448 1328 192 ) we_cemetary/cemtablet -64 0 0.00 -1 1.625000 0 0 0 +( 320 1376 144 ) ( 320 1376 192 ) ( 320 1312 192 ) we_cemetary/cemtablet -64 0 0.00 -0.500000 1.625000 0 0 0 +} +} +// entity 102 +{ +"origin" "904 1112 136" +"classname" "light" +"light" "400" +} +// entity 103 +{ +"spawnflags" "64" +"angle" "-1" +"classname" "func_door" +// brush 0 +{ +( 832 1376 0 ) ( 832 1312 0 ) ( 960 1312 0 ) we_cemetary/cemtablet -64 -64 0.00 -1 0.500000 0 0 0 +( 960 1312 208 ) ( 832 1312 208 ) ( 832 1376 208 ) we_cemetary/cemtablet -64 -64 0.00 -1 0.500000 0 0 0 +( 960 1360 144 ) ( 960 1360 192 ) ( 832 1360 192 ) we_cemetary/cemtablet -64 0 0.00 -1 1.625000 0 0 0 +( 960 1312 144 ) ( 960 1312 192 ) ( 960 1376 192 ) we_cemetary/cemtablet -64 0 0.00 -0.500000 1.625000 0 0 0 +( 832 1328 144 ) ( 832 1328 192 ) ( 960 1328 192 ) we_cemetary/cemtablet -64 0 0.00 -1 1.625000 0 0 0 +( 832 1376 144 ) ( 832 1376 192 ) ( 832 1312 192 ) we_cemetary/cemtablet -64 0 0.00 -0.500000 1.625000 0 0 0 +} +} +// entity 104 +{ +"light" "400" +"classname" "light" +"origin" "1416 1112 136" +} +// entity 105 +{ +"classname" "func_door" +"angle" "-1" +"spawnflags" "64" +// brush 0 +{ +( 1344 1376 0 ) ( 1344 1312 0 ) ( 1472 1312 0 ) we_cemetary/cemtablet -64 -64 0.00 -1 0.500000 0 0 0 +( 1472 1312 208 ) ( 1344 1312 208 ) ( 1344 1376 208 ) we_cemetary/cemtablet -64 -64 0.00 -1 0.500000 0 0 0 +( 1472 1360 144 ) ( 1472 1360 192 ) ( 1344 1360 192 ) we_cemetary/cemtablet -64 0 0.00 -1 1.625000 0 0 0 +( 1472 1312 144 ) ( 1472 1312 192 ) ( 1472 1376 192 ) we_cemetary/cemtablet -64 0 0.00 -0.500000 1.625000 0 0 0 +( 1344 1328 144 ) ( 1344 1328 192 ) ( 1472 1328 192 ) we_cemetary/cemtablet -64 0 0.00 -1 1.625000 0 0 0 +( 1344 1376 144 ) ( 1344 1376 192 ) ( 1344 1312 192 ) we_cemetary/cemtablet -64 0 0.00 -0.500000 1.625000 0 0 0 +} +} +// entity 106 +{ +"origin" "1928 1112 136" +"classname" "light" +"light" "400" +} +// entity 107 +{ +"spawnflags" "64" +"angle" "-1" +"classname" "func_door" +// brush 0 +{ +( 1856 1376 0 ) ( 1856 1312 0 ) ( 1984 1312 0 ) we_cemetary/cemtablet -64 -64 0.00 -1 0.500000 0 0 0 +( 1984 1312 208 ) ( 1856 1312 208 ) ( 1856 1376 208 ) we_cemetary/cemtablet -64 -64 0.00 -1 0.500000 0 0 0 +( 1984 1360 144 ) ( 1984 1360 192 ) ( 1856 1360 192 ) we_cemetary/cemtablet -64 0 0.00 -1 1.625000 0 0 0 +( 1984 1312 144 ) ( 1984 1312 192 ) ( 1984 1376 192 ) we_cemetary/cemtablet -64 0 0.00 -0.500000 1.625000 0 0 0 +( 1856 1328 144 ) ( 1856 1328 192 ) ( 1984 1328 192 ) we_cemetary/cemtablet -64 0 0.00 -1 1.625000 0 0 0 +( 1856 1376 144 ) ( 1856 1376 192 ) ( 1856 1312 192 ) we_cemetary/cemtablet -64 0 0.00 -0.500000 1.625000 0 0 0 +} +} +// entity 108 +{ +"light" "400" +"classname" "light" +"origin" "2440 1112 136" +} +// entity 109 +{ +"classname" "func_door" +"angle" "-1" +"spawnflags" "64" +// brush 0 +{ +( 2368 1376 0 ) ( 2368 1312 0 ) ( 2496 1312 0 ) we_cemetary/cemtablet -64 -64 0.00 -1 0.500000 0 0 0 +( 2496 1312 208 ) ( 2368 1312 208 ) ( 2368 1376 208 ) we_cemetary/cemtablet -64 -64 0.00 -1 0.500000 0 0 0 +( 2496 1360 144 ) ( 2496 1360 192 ) ( 2368 1360 192 ) we_cemetary/cemtablet -64 0 0.00 -1 1.625000 0 0 0 +( 2496 1312 144 ) ( 2496 1312 192 ) ( 2496 1376 192 ) we_cemetary/cemtablet -64 0 0.00 -0.500000 1.625000 0 0 0 +( 2368 1328 144 ) ( 2368 1328 192 ) ( 2496 1328 192 ) we_cemetary/cemtablet -64 0 0.00 -1 1.625000 0 0 0 +( 2368 1376 144 ) ( 2368 1376 192 ) ( 2368 1312 192 ) we_cemetary/cemtablet -64 0 0.00 -0.500000 1.625000 0 0 0 +} +} +// entity 110 +{ +"origin" "2952 1112 136" +"classname" "light" +"light" "400" +} +// entity 111 +{ +"spawnflags" "64" +"angle" "-1" +"classname" "func_door" +// brush 0 +{ +( 2880 1376 0 ) ( 2880 1312 0 ) ( 3008 1312 0 ) we_cemetary/cemtablet -64 -64 0.00 -1 0.500000 0 0 0 +( 3008 1312 208 ) ( 2880 1312 208 ) ( 2880 1376 208 ) we_cemetary/cemtablet -64 -64 0.00 -1 0.500000 0 0 0 +( 3008 1360 144 ) ( 3008 1360 192 ) ( 2880 1360 192 ) we_cemetary/cemtablet -64 0 0.00 -1 1.625000 0 0 0 +( 3008 1312 144 ) ( 3008 1312 192 ) ( 3008 1376 192 ) we_cemetary/cemtablet -64 0 0.00 -0.500000 1.625000 0 0 0 +( 2880 1328 144 ) ( 2880 1328 192 ) ( 3008 1328 192 ) we_cemetary/cemtablet -64 0 0.00 -1 1.625000 0 0 0 +( 2880 1376 144 ) ( 2880 1376 192 ) ( 2880 1312 192 ) we_cemetary/cemtablet -64 0 0.00 -0.500000 1.625000 0 0 0 +} +} +// entity 112 +{ +"light" "400" +"classname" "light" +"origin" "3464 1112 136" +} +// entity 113 +{ +"classname" "func_door" +"angle" "-1" +"spawnflags" "64" +// brush 0 +{ +( 3392 1376 0 ) ( 3392 1312 0 ) ( 3520 1312 0 ) we_cemetary/cemtablet -64 -64 0.00 -1 0.500000 0 0 0 +( 3520 1312 208 ) ( 3392 1312 208 ) ( 3392 1376 208 ) we_cemetary/cemtablet -64 -64 0.00 -1 0.500000 0 0 0 +( 3520 1360 144 ) ( 3520 1360 192 ) ( 3392 1360 192 ) we_cemetary/cemtablet -64 0 0.00 -1 1.625000 0 0 0 +( 3520 1312 144 ) ( 3520 1312 192 ) ( 3520 1376 192 ) we_cemetary/cemtablet -64 0 0.00 -0.500000 1.625000 0 0 0 +( 3392 1328 144 ) ( 3392 1328 192 ) ( 3520 1328 192 ) we_cemetary/cemtablet -64 0 0.00 -1 1.625000 0 0 0 +( 3392 1376 144 ) ( 3392 1376 192 ) ( 3392 1312 192 ) we_cemetary/cemtablet -64 0 0.00 -0.500000 1.625000 0 0 0 +} +} +// entity 114 +{ +"origin" "3976 1112 136" +"classname" "light" +"light" "400" +} +// entity 115 +{ +"spawnflags" "64" +"angle" "-1" +"classname" "func_door" +// brush 0 +{ +( 3904 1376 0 ) ( 3904 1312 0 ) ( 4032 1312 0 ) we_cemetary/cemtablet -64 -64 0.00 -1 0.500000 0 0 0 +( 4032 1312 208 ) ( 3904 1312 208 ) ( 3904 1376 208 ) we_cemetary/cemtablet -64 -64 0.00 -1 0.500000 0 0 0 +( 4032 1360 144 ) ( 4032 1360 192 ) ( 3904 1360 192 ) we_cemetary/cemtablet -64 0 0.00 -1 1.625000 0 0 0 +( 4032 1312 144 ) ( 4032 1312 192 ) ( 4032 1376 192 ) we_cemetary/cemtablet -64 0 0.00 -0.500000 1.625000 0 0 0 +( 3904 1328 144 ) ( 3904 1328 192 ) ( 4032 1328 192 ) we_cemetary/cemtablet -64 0 0.00 -1 1.625000 0 0 0 +( 3904 1376 144 ) ( 3904 1376 192 ) ( 3904 1312 192 ) we_cemetary/cemtablet -64 0 0.00 -0.500000 1.625000 0 0 0 +} +} +// entity 116 +{ +"light" "400" +"classname" "light" +"origin" "4488 1112 136" +} +// entity 117 +{ +"classname" "func_door" +"angle" "-1" +"spawnflags" "64" +// brush 0 +{ +( 4416 1376 0 ) ( 4416 1312 0 ) ( 4544 1312 0 ) we_cemetary/cemtablet -64 -64 0.00 -1 0.500000 0 0 0 +( 4544 1312 208 ) ( 4416 1312 208 ) ( 4416 1376 208 ) we_cemetary/cemtablet -64 -64 0.00 -1 0.500000 0 0 0 +( 4544 1360 144 ) ( 4544 1360 192 ) ( 4416 1360 192 ) we_cemetary/cemtablet -64 0 0.00 -1 1.625000 0 0 0 +( 4544 1312 144 ) ( 4544 1312 192 ) ( 4544 1376 192 ) we_cemetary/cemtablet -64 0 0.00 -0.500000 1.625000 0 0 0 +( 4416 1328 144 ) ( 4416 1328 192 ) ( 4544 1328 192 ) we_cemetary/cemtablet -64 0 0.00 -1 1.625000 0 0 0 +( 4416 1376 144 ) ( 4416 1376 192 ) ( 4416 1312 192 ) we_cemetary/cemtablet -64 0 0.00 -0.500000 1.625000 0 0 0 +} +} +// entity 118 +{ +"origin" "5000 1112 136" +"classname" "light" +"light" "400" +} +// entity 119 +{ +"spawnflags" "64" +"angle" "-1" +"classname" "func_door" +// brush 0 +{ +( 4928 1376 0 ) ( 4928 1312 0 ) ( 5056 1312 0 ) we_cemetary/cemtablet -64 -64 0.00 -1 0.500000 0 0 0 +( 5056 1312 208 ) ( 4928 1312 208 ) ( 4928 1376 208 ) we_cemetary/cemtablet -64 -64 0.00 -1 0.500000 0 0 0 +( 5056 1360 144 ) ( 5056 1360 192 ) ( 4928 1360 192 ) we_cemetary/cemtablet -64 0 0.00 -1 1.625000 0 0 0 +( 5056 1312 144 ) ( 5056 1312 192 ) ( 5056 1376 192 ) we_cemetary/cemtablet -64 0 0.00 -0.500000 1.625000 0 0 0 +( 4928 1328 144 ) ( 4928 1328 192 ) ( 5056 1328 192 ) we_cemetary/cemtablet -64 0 0.00 -1 1.625000 0 0 0 +( 4928 1376 144 ) ( 4928 1376 192 ) ( 4928 1312 192 ) we_cemetary/cemtablet -64 0 0.00 -0.500000 1.625000 0 0 0 +} +} +// entity 120 +{ +"_color" "0.690196 0.690196 1.000000" +"origin" "-2168 1576 136" +"classname" "light" +"light" "400" +} +// entity 121 +{ +"_color" "0.690196 0.690196 1.000000" +"light" "400" +"classname" "light" +"origin" "-1656 1576 136" +} +// entity 122 +{ +"_color" "0.690196 0.690196 1.000000" +"origin" "-1144 1576 136" +"classname" "light" +"light" "400" +} +// entity 123 +{ +"_color" "0.690196 0.690196 1.000000" +"light" "400" +"classname" "light" +"origin" "-632 1576 136" +} +// entity 124 +{ +"_color" "1.000000 1.000000 0.701961" +"origin" "-120 1576 136" +"classname" "light" +"light" "400" +} +// entity 125 +{ +"_color" "1.000000 1.000000 0.701961" +"light" "400" +"classname" "light" +"origin" "392 1576 136" +} +// entity 126 +{ +"_color" "1.000000 1.000000 0.701961" +"origin" "904 1576 136" +"classname" "light" +"light" "400" +} +// entity 127 +{ +"_color" "1.000000 1.000000 0.701961" +"light" "400" +"classname" "light" +"origin" "1416 1576 136" +} +// entity 128 +{ +"_color" "0.682353 1.000000 0.760784" +"origin" "1928 1576 136" +"classname" "light" +"light" "400" +} +// entity 129 +{ +"_color" "0.682353 1.000000 0.760784" +"light" "400" +"classname" "light" +"origin" "2440 1576 136" +} +// entity 130 +{ +"_color" "0.682353 1.000000 0.760784" +"origin" "2952 1576 136" +"classname" "light" +"light" "400" +} +// entity 131 +{ +"_color" "0.682353 1.000000 0.760784" +"light" "400" +"classname" "light" +"origin" "3464 1576 136" +} +// entity 132 +{ +"_color" "1.000000 0.827451 0.658824" +"origin" "3976 1576 136" +"classname" "light" +"light" "400" +} +// entity 133 +{ +"_color" "1.000000 0.827451 0.658824" +"light" "400" +"classname" "light" +"origin" "4488 1576 136" +} +// entity 134 +{ +"_color" "1.000000 0.827451 0.658824" +"origin" "5000 1576 136" +"classname" "light" +"light" "400" +} +// entity 135 +{ +"classname" "func_door" +"angle" "-1" +"spawnflags" "64" +// brush 0 +{ +( -352 1504 0 ) ( -352 1632 0 ) ( -416 1632 0 ) we_cemetary/cemtablet 62 80 -180.00 0.250000 -2 0 0 0 +( -416 1632 208 ) ( -352 1632 208 ) ( -352 1504 208 ) we_cemetary/cemtablet 62 80 -180.00 0.250000 -2 0 0 0 +( -400 1632 192 ) ( -400 1504 192 ) ( -400 1504 144 ) we_cemetary/cemtablet 80 0 -180.00 2 -1.625000 0 0 0 +( -416 1440 192 ) ( -352 1440 192 ) ( -352 1440 144 ) we_cemetary/cemtablet 63 127 -180.00 0.250000 -1.625000 0 0 0 +( -368 1504 192 ) ( -368 1632 192 ) ( -368 1632 144 ) we_cemetary/cemtablet 80 0 -180.00 2 -1.625000 0 0 0 +( -352 1696 192 ) ( -416 1696 192 ) ( -416 1696 144 ) we_cemetary/cemtablet 63 127 -180.00 0.250000 -1.625000 0 0 0 +} +} +// entity 136 +{ +"spawnflags" "64" +"angle" "-1" +"classname" "func_door" +// brush 0 +{ +( 1696 1504 0 ) ( 1696 1632 0 ) ( 1632 1632 0 ) we_cemetary/cemtablet 63 80 -180.00 0.250000 -2 0 0 0 +( 1632 1632 208 ) ( 1696 1632 208 ) ( 1696 1504 208 ) we_cemetary/cemtablet 63 80 -180.00 0.250000 -2 0 0 0 +( 1648 1632 192 ) ( 1648 1504 192 ) ( 1648 1504 144 ) we_cemetary/cemtablet 80 0 -180.00 2 -1.625000 0 0 0 +( 1632 1440 192 ) ( 1696 1440 192 ) ( 1696 1440 144 ) we_cemetary/cemtablet 63 127 -180.00 0.250000 -1.625000 0 0 0 +( 1680 1504 192 ) ( 1680 1632 192 ) ( 1680 1632 144 ) we_cemetary/cemtablet 80 0 -180.00 2 -1.625000 0 0 0 +( 1696 1696 192 ) ( 1632 1696 192 ) ( 1632 1696 144 ) we_cemetary/cemtablet 63 127 -180.00 0.250000 -1.625000 0 0 0 +} +} +// entity 137 +{ +"classname" "func_door" +"angle" "-1" +"spawnflags" "64" +// brush 0 +{ +( 3744 1504 0 ) ( 3744 1632 0 ) ( 3680 1632 0 ) we_cemetary/cemtablet 63 80 -180.00 0.250000 -2 0 0 0 +( 3680 1632 208 ) ( 3744 1632 208 ) ( 3744 1504 208 ) we_cemetary/cemtablet 63 80 -180.00 0.250000 -2 0 0 0 +( 3696 1632 192 ) ( 3696 1504 192 ) ( 3696 1504 144 ) we_cemetary/cemtablet 80 0 -180.00 2 -1.625000 0 0 0 +( 3680 1440 192 ) ( 3744 1440 192 ) ( 3744 1440 144 ) we_cemetary/cemtablet 63 127 -180.00 0.250000 -1.625000 0 0 0 +( 3728 1504 192 ) ( 3728 1632 192 ) ( 3728 1632 144 ) we_cemetary/cemtablet 80 0 -180.00 2 -1.625000 0 0 0 +( 3744 1696 192 ) ( 3680 1696 192 ) ( 3680 1696 144 ) we_cemetary/cemtablet 63 127 -180.00 0.250000 -1.625000 0 0 0 +} +} +// entity 138 +{ +"light" "400" +"classname" "light" +"origin" "-2648 1576 312" +"_color" "1.000000 0.968627 0.835294" +} +// entity 139 +{ +"_color" "1.000000 0.968627 0.835294" +"origin" "-2936 1576 312" +"classname" "light" +"light" "400" +} +// entity 140 +{ +"_color" "1.000000 0.968627 0.835294" +"origin" "-3208 1576 312" +"classname" "light" +"light" "400" +} +// entity 141 +{ +"light" "400" +"classname" "light" +"origin" "-3496 1576 312" +"_color" "1.000000 0.968627 0.835294" +} +// entity 142 +{ +"light" "400" +"classname" "light" +"origin" "-3736 1576 312" +"_color" "1.000000 0.968627 0.835294" +} +// entity 143 +{ +"_color" "1.000000 0.968627 0.835294" +"origin" "-6072 1592 312" +"classname" "light" +"light" "400" +} +// entity 144 +{ +"_color" "1.000000 0.968627 0.835294" +"origin" "-6120 1576 312" +"classname" "light" +"light" "400" +} +// entity 145 +{ +"light" "400" +"classname" "light" +"origin" "-7368 1576 312" +"_color" "1.000000 0.968627 0.835294" +} +// entity 146 +{ +"light" "400" +"classname" "light" +"origin" "-3992 1576 312" +"_color" "1.000000 0.968627 0.835294" +} +// entity 147 +{ +"light" "400" +"classname" "light" +"origin" "-4264 1576 312" +"_color" "1.000000 0.968627 0.835294" +} +// entity 148 +{ +"_color" "1.000000 0.968627 0.835294" +"origin" "-4552 1576 312" +"classname" "light" +"light" "400" +} +// entity 149 +{ +"_color" "1.000000 0.968627 0.835294" +"origin" "-4792 1576 312" +"classname" "light" +"light" "400" +} +// entity 150 +{ +"_color" "1.000000 0.968627 0.835294" +"origin" "-5048 1576 312" +"classname" "light" +"light" "400" +} +// entity 151 +{ +"_color" "1.000000 0.968627 0.835294" +"origin" "-5320 1576 312" +"classname" "light" +"light" "400" +} +// entity 152 +{ +"light" "400" +"classname" "light" +"origin" "-5608 1576 312" +"_color" "1.000000 0.968627 0.835294" +} +// entity 153 +{ +"light" "400" +"classname" "light" +"origin" "-5848 1576 312" +"_color" "1.000000 0.968627 0.835294" +} diff --git a/fakk/scripts/fakk.qe4 b/fakk/scripts/fakk.qe4 new file mode 100644 index 0000000..64ea3ae --- /dev/null +++ b/fakk/scripts/fakk.qe4 @@ -0,0 +1,12 @@ +{ +"texturepath" "c:/fakktools/fakk/textures/" +"entitypath" "c:/fakktools/entities/entities.def" +"modelpath" "c:/fakktools/fakk/models/*.tik" +"mapspath" "c:/fakktools/fakk/maps/example" +"rshcmd" "" +"remotebasepath" "c:/fakktools/fakk" +"basepath" "c:/fakktools/fakk" +"autosave" "c:/fakktools/fakk/maps/autosave/autosave.map" +"bsp_FastVis" "! c:\fakktools\bin\q3map -all -fast -gamedir c:/fakktools/fakk $" +"bsp_FullVis" "! c:\fakktools\bin\q3map -all -gamedir c:/fakktools/fakk $" +} \ No newline at end of file diff --git a/fakk/scripts/surfacelist.txt b/fakk/scripts/surfacelist.txt new file mode 100644 index 0000000..b87a744 --- /dev/null +++ b/fakk/scripts/surfacelist.txt @@ -0,0 +1,750 @@ +blood/bloodchains m +blood/blooddoor m +blood/bloodmetal m +blood/bloodtile m +blood/bloodtrim1 m +blood/bloodtrim2 m +blood/bloodtrim3 m +blood/bloodtrim4 m +blood/bloodwall m +blood/bloodwall1 m +blood/bloodwall2 m +blood/bloodwall3 m + +creeperpens/edenbarn w +creeperpens/edenbarn2 w +creeperpens/edenbarn3 w +creeperpens/edenbarnceil w +creeperpens/edenbarnroof w +creeperpens/edenbarnroofend w +creeperpens/edenhay o +creeperpens/edenhaybale o +creeperpens/edenhaybale2 o +creeperpens/edenhaybale3 o +creeperpens/edenwoodfloor w +creeperpens/FL_creepershit s +creeperpens/FL_pens_base d +creeperpens/fl_pens_base2 d +creeperpens/FL_pens_outside d +creeperpens/FL_shit_decal o +creeperpens/FL_shit_trans o +creeperpens/FL_street2_pens d +creeperpens/FL_street3_pens d +creeperpens/tr_grate g +creeperpens/TR_pens m +creeperpens/TR_pooshoot m +creeperpens/wl_astroid r +creeperpens/wl_astroid2 r +creeperpens/wl_barnwindow w +creeperpens/WL_basement_2 r +creeperpens/WL_basement_3 r +creeperpens/WL_basement_trans r +creeperpens/WL_dungbindoor w +creeperpens/WL_hay_trans o +creeperpens/WL_pens_insidedoor m +creeperpens/WL_pens_outsidedoor m +creeperpens/WL_pens_outsidedoorback w +creeperpens/WL_pensgate m + +eden/base m +eden/basicwall r +eden/basicwallbroke r +eden/bedtrim w +eden/blue_water +eden/blue_water_envmap +eden/CL_church r +eden/CL_edenroof m +eden/CL_edenroof2 m +eden/CL_edenroof3 r +eden/CL_edenroof4 m +eden/CL_edenroof5 m +eden/CL_redroof m +eden/creeperwall r +eden/creeperwall2 r +eden/door8 w +eden/eden_envmap1 +eden/eden_envmap1_bak +eden/eden_envmap2 +eden/eden_envmap2_bak +eden/eden_envmap2_bak2 +eden/eden_fakkhouseenvmap +eden/edenbricks r +eden/edencabinets w +eden/edencobble r +eden/edendoor m +eden/edendoor2 w +eden/edendoorwide m +eden/edenfanwall m +eden/edenfence m +eden/edenfence2 m +eden/edenfloor w +eden/edengate m +eden/edenmetal1 m +eden/edenmetal10 m +eden/edenmetal11 m +eden/edenmetal2 m +eden/edenmetal3 m +eden/edenmetal4 m +eden/edenmetal5 m +eden/edenmetal6 m +eden/edenmetal7 m +eden/edenmetal8 m +eden/edenmetal9 m +eden/edenmetalwall m +eden/edenmetalwall2 m +eden/edenmetalwall2end m +eden/edenrock r +eden/edenrockdark r +eden/edenrockmid r +eden/edenstair m +eden/edenstair2 m +eden/edentable w +eden/edentile r +eden/edenvent m +eden/edenwalltran m +eden/edenwater1 +eden/edenwriting m +eden/FL_basement r +eden/FL_basement2 r +eden/FL_chainfloor g +eden/FL_edenhouse w +eden/FL_edenhouse2 w +eden/FL_edenhouse3 w +eden/FL_edenhouse4 w +eden/FL_edenhousez w +eden/FL_grass o +eden/FL_ground d +eden/FL_groundwhite r +eden/FL_sheiekpens o +eden/FL_street1 r +eden/FL_street2 d +eden/FL_street3 d +eden/FL_street4 d +eden/FL_street5 d +eden/FL_underground r +eden/FL_underground2 r +eden/FL_woodchips o +eden/FL_yw_trans r +eden/floortile r +eden/fountain r +eden/fountainglow +eden/genmetal m +eden/genmetal_shiney m +eden/genmetal_1 m +eden/genmetal_1_shiney m +eden/genmetal_2 m +eden/genmetal_2_shiney m +eden/genmetal_3 m +eden/genmetal_3_shiney m +eden/housetrim m +eden/hybridrock +eden/ivy +eden/ivybig +eden/lt_edenlt.glow +eden/LT_edenlt1 m +eden/LT_edenlt10 m +eden/LT_edenlt10b m +eden/LT_edenlt10w m +eden/LT_edenlt11 m +eden/LT_edenlt11b m +eden/LT_edenlt11w m +eden/LT_edenlt12 m +eden/LT_edenlt12b m +eden/LT_edenlt12w m +eden/LT_edenlt13 m +eden/LT_edenlt13b m +eden/LT_edenlt13w m +eden/LT_edenlt14 m +eden/LT_edenlt14b m +eden/LT_edenlt14w m +eden/LT_edenlt15 m +eden/LT_edenlt15b m +eden/LT_edenlt15w m +eden/LT_edenlt16 m +eden/LT_edenlt16b m +eden/LT_edenlt16w m +eden/LT_edenlt17 m +eden/LT_edenlt17b m +eden/LT_edenlt17w m +eden/LT_edenlt18 m +eden/LT_edenlt18b m +eden/LT_edenlt18v m +eden/LT_edenlt18w m +eden/LT_edenlt19.glow +eden/LT_edenlt19 m +eden/LT_edenlt19b m +eden/LT_edenlt19g m +eden/LT_edenlt19lb m +eden/LT_edenlt19p m +eden/LT_edenlt19w m +eden/LT_edenlt1b m +eden/LT_edenlt1w m +eden/LT_edenlt2 m +eden/LT_edenlt20 m +eden/LT_edenlt20b m +eden/LT_edenlt20w m +eden/LT_edenlt21 m +eden/LT_edenlt21b m +eden/LT_edenlt21w m +eden/LT_edenlt22 m +eden/LT_edenlt22b m +eden/LT_edenlt22w m +eden/LT_edenlt23 m +eden/LT_edenlt23b m +eden/LT_edenlt23w m +eden/LT_edenlt24 m +eden/LT_edenlt24b m +eden/LT_edenlt24w m +eden/LT_edenlt2b m +eden/LT_edenlt2w m +eden/LT_edenlt3 m +eden/LT_edenlt3b m +eden/LT_edenlt3w m +eden/LT_edenlt4 m +eden/LT_edenlt4b m +eden/LT_edenlt4w m +eden/LT_edenlt5 m +eden/LT_edenlt5b m +eden/LT_edenlt5w m +eden/LT_edenlt6 m +eden/LT_edenlt6b m +eden/LT_edenlt6w m +eden/LT_edenlt7 m +eden/LT_edenlt7b m +eden/LT_edenlt7w m +eden/LT_edenlt8 m +eden/LT_edenlt8b m +eden/LT_edenlt8w m +eden/LT_edenlt9 m +eden/LT_edenlt9b m +eden/LT_edenlt9w m +eden/metalrib m +eden/metaltrim m +eden/nicechurchwall r +eden/ornatetopwall m +eden/ornatetrim1 m +eden/ornatewall_weathered2 m +eden/ornatewallweathered m +eden/propellorwall m +eden/pushcrate m +eden/pushcrate_glow +eden/qer_blue_water_scroll +eden/qer_edenwater1 +eden/rock r +eden/SI_training w +eden/siding m +eden/techdoor m +eden/technowall m +eden/technowall1 m +eden/technowall2 m +eden/technowall3 m +eden/technowall4 m +eden/technowall4_shiney m +eden/technowall5 m +eden/tile r +eden/toprail r +eden/TR_basement m +eden/TR_basement_2 m +eden/tr_chainlink g +eden/TR_church r +eden/TR_church_2 r +eden/TR_church_3 r +eden/TR_church_5 r +eden/TR_church_fx +eden/TR_church2_fx +eden/TR_churchtrim_4 r +eden/TR_edenwriting_glow +eden/TR_garden_tarp o +eden/TR_garden_tarp2 o +eden/TR_inside_1 r +eden/TR_laundry_1 s +eden/TR_laundry_2 s +eden/TR_laundry_3 s +eden/TR_laundry_4 s +eden/TR_laundry_5 s +eden/TR_laundry_6 s +eden/TR_market_sign w +eden/TR_metal m +eden/TR_metal2 m +eden/TR_metal3 m +eden/TR_metal4 m +eden/TR_metal5 m +eden/TR_metal6 m +eden/TR_metal7 m +eden/TR_metal8 m +eden/TR_pole m +eden/TR_redmetal m +eden/TR_redmetal2 m +eden/TR_redmetal3 m +eden/TR_redmetal4 m +eden/TR_roost_1 m +eden/TR_roost_2 m +eden/TR_roost_3 m +eden/TR_roost_4 m +eden/TR_roost_5 m +eden/TR_roost_6 m +eden/TR_roost_7 m +eden/TR_roost_8 m +eden/TR_roost_9 m +eden/TR_spiderweb1 +eden/TR_spiderweb2 +eden/TR_spiderweb3 +eden/TR_stair_1 r +eden/TR_stair_2 r +eden/TR_support m +eden/tr_trim.glow +eden/WL_arch m +eden/WL_arch1 r +eden/WL_arch1_glow +eden/WL_arch2 m +eden/WL_basement m +eden/WL_basement_1 m +eden/WL_basement_2w r +eden/WL_basement_transw r +eden/WL_basement2 m +eden/WL_basement3 m +eden/WL_basement3_glow +eden/WL_blinds +eden/WL_blinds2 +eden/WL_brick r +eden/WL_ch_back r +eden/WL_ch_back2 r +eden/WL_ch_back3 r +eden/WL_church r +eden/WL_church_1 r +eden/WL_church_2 r +eden/WL_church_2big r +eden/WL_church_3 r +eden/WL_church_detail r +eden/WL_church_detail1 r +eden/WL_church_detail2 r +eden/WL_church_door r +eden/WL_church_glass +eden/WL_church_large m +eden/WL_church_wood w +eden/WL_church_wood2 w +eden/WL_climb_slats w +eden/WL_damaged r +eden/WL_damaged2 r +eden/WL_darkmetal_1 m +eden/WL_darkmetal_2 m +eden/WL_darkmetal_3 m +eden/WL_doortops m +eden/WL_dungbindoor w +eden/WL_eden_darkstone r +eden/WL_edenbrick r +eden/WL_edendoor m +eden/WL_edendoor1 m +eden/WL_edendoor2 m +eden/WL_edendoor2_unlocked m +eden/WL_edendoor3 m +eden/WL_edenhouse r +eden/wl_edenhouse10 r +eden/WL_edenhouse2 r +eden/WL_edenhouse2w r +eden/wl_edenhouse3 r +eden/WL_edenhouse4 r +eden/WL_edenhouse5 r +eden/WL_edenhousew r +eden/WL_edenred r +eden/WL_edenred2 r +eden/WL_edenred3 r +eden/wl_edentown r +eden/wl_edentown1 r +eden/wl_edentown2 r +eden/wl_fakkhousewindow g +eden/WL_fan m +eden/WL_fan2 m +eden/WL_glass1 m +eden/WL_glass2 m +eden/WL_glass3 m +eden/WL_glass4 m +eden/WL_glass5 m +eden/WL_gold(clean) m +eden/WL_inside_1 m +eden/WL_inside_2 m +eden/WL_inside_3 m +eden/WL_inside_4 m +eden/WL_insidetrans_1 m +eden/WL_insidetrans_4 m +eden/WL_market o +eden/WL_market_door w +eden/WL_market_sides w +eden/WL_market2 o +eden/WL_market3 o +eden/WL_neweden_1 r +eden/WL_neweden_2 r +eden/WL_neweden_4 r +eden/WL_neweden_5 r +eden/WL_neweden_7 r +eden/WL_neweden_8 r +eden/WL_neweden_ivy o +eden/WL_neweden_ivycap o +eden/WL_neweden_ivyoverhang o +eden/WL_pullpit m +eden/WL_redwood w +eden/WL_rock r +eden/WL_rock2 r +eden/WL_rock3 r +eden/WL_rock4 r +eden/WL_rock5 r +eden/WL_rock9 r +eden/WL_target w +eden/WL_tarpside m +eden/WL_tarptop m +eden/WL_udoor m +eden/WL_underground1 m +eden/wl_window_fhouse.blend +eden/WL_window_fhouse m +eden/wl_window1.blend +eden/wl_window1 m +eden/wl_window1_inside.blend +eden/WL_window1_inside m +eden/wl_window2.blend +eden/WL_window2 m +eden/wl_window2_inside.blend +eden/WL_window2_inside m +eden/wl_window3.blend +eden/wl_window3 m +eden/wl_window3_inside.blend +eden/WL_window3_inside m +eden/wl_window4.blend +eden/WL_window4 m +eden/wl_window4_inside.blend +eden/WL_window4_inside m +eden/WL_winerack w +eden/WL_wood(dark) w +eden/wood w +eden/woodfloor w +eden/woodpeg w + +metals/silvermetal m + +oracle/lighttrim1 m +oracle/oraclekeys m +oracle/oraclemonitor m +oracle/oracletrim1 m +oracle/oracletrim2 m +oracle/oracletrim3 m +oracle/oracletrim3a m +oracle/oracletrim4 m +oracle/oracletrim5 m +oracle/oraclewall1 m +oracle/oraclewall2 m +oracle/oraclewall4 m +oracle/oraclewall4_ship m +oracle/oraclewall4_shipb m +oracle/oraclewall5 m +oracle/oraclewall5a m +oracle/oraclewall5b m +oracle/oraclewall5c m +oracle/oraclewall6 m +oracle/oraclewires m +oracle/oraclewiresc m + +otto/bolthead m +otto/otto_envmap1 +otto/ottocabinet m +otto/ottocabinet2 m +otto/ottocabinet3 m +otto/ottocabinet3a m +otto/ottocabinet4 m +otto/ottocontrol m +otto/ottocontrol2 m +otto/ottocontrol3 m +otto/ottocontrol4 m +otto/ottocontrol5 m +otto/ottocontrol6 m +otto/ottocontrol7 m +otto/ottocrate w +otto/ottocrate2 w +otto/ottocrate3 w +otto/ottocrate4 m +otto/ottocrate5 m +otto/ottocrate6 m +otto/ottocyl m +otto/ottofloor m +otto/ottogrnmetal m +otto/ottogrnmetal2 m +otto/ottolight m +otto/ottometal m +otto/ottopbeam w +otto/ottopipe m +otto/ottopipe2 m +otto/ottoscrew m +otto/ottoshop w +otto/ottosign1 m +otto/ottosign2 m +otto/ottosign3 m +otto/ottosign4 m +otto/ottosign5 m +otto/ottosign6 m +otto/ottosign7 m +otto/ottostair1 m +otto/ottostair2 m +otto/ottotrapdoor w +otto/ottotrim1 m +otto/ottotrim10 m +otto/ottotrim11 m +otto/ottotrim2 m +otto/ottotrim3 m +otto/ottotrim4 +otto/ottotrim5 +otto/ottotrim6 m +otto/ottotrim7 m +otto/ottotrim8 m +otto/ottotrim9 m +otto/ottowall1 m +otto/ottowall2 m +otto/ottowall3 m +otto/ottowall4 m +otto/ottowall5 m +otto/ottowall5a m + +shield/chrome_env +shield/elec_yellow1 +shield/elec_yellow2 +shield/elec_yellow3 +shield/metalfloor_wall_9b.glow +shield/metalfloor_wall_9b +shield/plasmadead +shield/plasmaFE +shield/shgen m +shield/shgen02 m +shield/shgen03 m +shield/shgen04 m +shield/shgen05 +shield/shgen06 m +shield/shgen7 +shield/shield_light.glow +shield/shield_light m +shield/specialtrim m +shield/specialtrim_pulse1 +shield/specialtrim_pulse2 +shield/technowall m +shield/technowall2 m +shield/technowall3 m +shield/technowall4 m +shield/technowall5 m + +swamps/CL_canopy(lowest) o +swamps/CL_canopy(lowest_corner) o +swamps/CL_canopy(nomask) o +swamps/CL_canopy o +swamps/CL_canopy4 o +swamps/CL_new_canopy5b o +swamps/CL_swampelev m +swamps/FL_cave d +swamps/FL_dock w +swamps/FL_hut r +swamps/FL_hut_inside w +swamps/FL_hut_inside2 w +swamps/FL_hut_moss r +swamps/FL_hut_moss2 r +swamps/FL_hut_moss3 r +swamps/FL_lilypad o +swamps/lilypad2 o +swamps/FL_lilypad_alfa o +swamps/FL_lilypad_trim o +swamps/FL_swamp_path r +swamps/FL_swamp1 o +swamps/FL_swamp10 s +swamps/FL_swamp12 s +swamps/FL_swamp13 o +swamps/FL_swamp14 s +swamps/FL_swamp15 r +swamps/FL_swamp15b s +swamps/FL_swamp16 s +swamps/FL_swamp17 d +swamps/FL_swamp2 o +swamps/FL_swamp3 o +swamps/FL_swamp4 o +swamps/FL_swamp5 o +swamps/FL_swamp6 r +swamps/FL_swamp7 r +swamps/FL_swamp8 d +swamps/FL_swampcrossover01 d +swamps/FL_swampcrossover02 r +swamps/FL_swampelev w +swamps/FL_swampwater2 +swamps/FL_swampwater3 +swamps/FL_tigerpit s +swamps/leaf_test1 o +swamps/leaf_test2 o +swamps/moss_trim w +swamps/new_canopy_lowest o +swamps/new_canopy_lowest_corner o +swamps/qer_fl_swampwater3 +swamps/swampwater +swamps/swleaf +swamps/TR_rope +swamps/TR_vinescum +swamps/wa_test2 +swamps/wa_test4 +swamps/waterfall +swamps/WL_basement2 r +swamps/WL_basement2_top r +swamps/WL_basement2_top2 r +swamps/WL_boathouse(working) w +swamps/WL_boathouse w +swamps/WL_boathouse_arch w +swamps/WL_boathouse_detail w +swamps/WL_boathouse_door w +swamps/WL_boathouse_red w +swamps/WL_boathouse2 w +swamps/WL_cave r +swamps/WL_climb_vines o +swamps/WL_climb_vinesb o +swamps/WL_faces w +swamps/WL_hut w +swamps/WL_hut_inside w +swamps/WL_hut_poletop w +swamps/WL_hut_wood w +swamps/WL_hutbed o +swamps/WL_hutdoor w +swamps/WL_hutpole w +swamps/WL_hutroof o +swamps/WL_hutroof_clean o +swamps/WL_hutroof2 o +swamps/WL_hutwindow w +swamps/WL_hutwindow_inside w +swamps/WL_inside_hut w +swamps/WL_inside_hut_tr w +swamps/WL_insidetree w +swamps/WL_mossyrock r +swamps/WL_mossyrock_tops o +swamps/WL_mossyrock_tops2 o +swamps/WL_mossyrock_tops3 r +swamps/WL_planthead o +swamps/WL_plantstem o +swamps/WL_stonewall r +swamps/WL_stonewall_moss r +swamps/WL_stonewall_sm r +swamps/WL_swampelev o +swamps/WL_swampelev_top w +swamps/WL_swampelev_top_g +swamps/WL_swampelev_top_r +swamps/WL_swampelev_toptrim w +swamps/WL_swamprock r +swamps/WL_swamprock_trans o +swamps/WL_swamptree w +swamps/WL_swamptree_moss o +swamps/WL_swamptree_moss_trim o +swamps/WL_swamptree2 w +swamps/WL_swamptree3 w +swamps/WL_swamptree3b w +swamps/WL_swamptree4(rings) w +swamps/WL_swamptree4 w +swamps/WL_topoftree w +swamps/WL_trapdoor w +swamps/WL_trapdoor_trim m +swamps/WL_wood(dark) w + +under/FL_cave_under s +under/FL_cave_under_2 s +under/FL_cave_under_trans r +under/FL_cave_under_trans2 r +under/FL_cave_under_trans3 r +under/FL_cave_under_trans4 r +under/FL_cave_under1 d +under/FL_cave_under3 r +under/FL_machines g +under/FL_machines2 g +under/FL_machines3 m +under/TR_crystal_under r +under/TR_crystal_under2 r +under/TR_crystal_under3 r +under/TR_support m +under/WL_cave_under r +under/WL_cave_under2 r +under/WL_machines m +under/WL_machines10 m +under/WL_machines2 m +under/WL_machines3 m +under/WL_machines4 m +under/WL_machines5 m +under/WL_machines6 m +under/WL_machines7 m +under/WL_machines8 m +under/WL_machines9 m + +water/waterfloor2 r +water/watermetal m +water/watermetal2 m +water/waterpillar m +water/waterpillarbase m +water/waterstatue m +water/watertile m +water/watertrim1 m +water/waterwall1 m +water/waterwall2 m + +we_cemetary/block r +we_cemetary/bluemarble r +we_cemetary/ceiling r +we_cemetary/cembase r +we_cemetary/cembroke r +we_cemetary/cemcircle r +we_cemetary/cemcircle2 r +we_cemetary/cemcolumn r +we_cemetary/cemcolumn2 r +we_cemetary/cemcolumn2b r +we_cemetary/cemdirt d +we_cemetary/cemdoor m +we_cemetary/cemdoor2 m +we_cemetary/cemfloor m +we_cemetary/cemfloor2 r +we_cemetary/cemglyph m +we_cemetary/cemmetal m +we_cemetary/cemobelisk r +we_cemetary/cemrock r +we_cemetary/cemrunner m +we_cemetary/cemrunner2 m +we_cemetary/cemstair1 r +we_cemetary/cemstair2 r +we_cemetary/cemstairtop r +we_cemetary/cemtablet m +we_cemetary/cemtrim1 m +we_cemetary/cemtrim2 m +we_cemetary/cemtrim3 m +we_cemetary/cemtrim4 m +we_cemetary/cemtrim5 r +we_cemetary/cemtrim6 r +we_cemetary/cemwall1 r +we_cemetary/cemwall10 r +we_cemetary/cemwall11 r +we_cemetary/cemwall12 r +we_cemetary/cemwall1a r +we_cemetary/cemwall1b r +we_cemetary/cemwall1broke r +we_cemetary/cemwall1c r +we_cemetary/cemwall1d r +we_cemetary/cemwall1e o +we_cemetary/cemwall1f r +we_cemetary/cemwall2 r +we_cemetary/cemwall3 r +we_cemetary/cemwall4 m +we_cemetary/cemwall5 r +we_cemetary/cemwall5top r +we_cemetary/cemwall6 r +we_cemetary/cemwall7 m +we_cemetary/cemwall8 o +we_cemetary/cemwall9 r +we_cemetary/cemwl1 m +we_cemetary/crackedbrick r +we_cemetary/FL_fogway r +we_cemetary/FL_fogway_fx +we_cemetary/FL_temple r +we_cemetary/fogdoor w +we_cemetary/fogmushtop s +we_cemetary/fogtrunk o +we_cemetary/fogtrunktop o +we_cemetary/oretrim m +we_cemetary/pillartop m +we_cemetary/sandstone r +we_cemetary/sandstone2 r +we_cemetary/statue2 m +we_cemetary/tikibase1 r +we_cemetary/tikibase2 r +we_cemetary/TR_fogway m +we_cemetary/TR_stairs r diff --git a/license.rtf b/license.rtf new file mode 100644 index 0000000..abce10b --- /dev/null +++ b/license.rtf @@ -0,0 +1,235 @@ +{\rtf1\ansi\ansicpg1252\uc1 \deff0\deflang1033\deflangfe1033{\fonttbl{\f0\froman\fcharset0\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\f28\froman\fcharset238\fprq2 Times New Roman CE;}{\f29\froman\fcharset204\fprq2 Times New Roman Cyr;} +{\f31\froman\fcharset161\fprq2 Times New Roman Greek;}{\f32\froman\fcharset162\fprq2 Times New Roman Tur;}{\f33\froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\f34\froman\fcharset178\fprq2 Times New Roman (Arabic);} +{\f35\froman\fcharset186\fprq2 Times New Roman Baltic;}}{\colortbl;\red0\green0\blue0;\red0\green0\blue255;\red0\green255\blue255;\red0\green255\blue0;\red255\green0\blue255;\red255\green0\blue0;\red255\green255\blue0;\red255\green255\blue255; +\red0\green0\blue128;\red0\green128\blue128;\red0\green128\blue0;\red128\green0\blue128;\red128\green0\blue0;\red128\green128\blue0;\red128\green128\blue128;\red192\green192\blue192;}{\stylesheet{ +\ql \li0\ri0\nowidctlpar\faauto\adjustright\rin0\lin0\itap0 \fs24\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \snext0 Normal;}{\s1\qc \li0\ri0\keepn\widctlpar +\tx0\tqc\tx4680\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\tx9360\faauto\adjustright\rin0\lin0\itap0 \b\fs22\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \sbasedon0 \snext0 heading 1;}{\*\cs10 \additive Default Paragraph Font;}{\*\cs15 \additive +\sbasedon10 footnote reference;}{\s16\qj \fi720\li0\ri0\widctlpar\tx0\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\tx9360\faauto\adjustright\rin0\lin0\itap0 \fs22\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 +\sbasedon0 \snext16 Body Text 2;}{\s17\qc \li0\ri0\widctlpar\faauto\adjustright\rin0\lin0\itap0 \b\fs22\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 \sbasedon0 \snext17 Title;}}{\info{\title ATTENTION}{\author Harry Miller}{\operator markd} +{\creatim\yr2000\mo9\dy15\hr15\min43}{\revtim\yr2000\mo9\dy15\hr15\min43}{\printim\yr1998\mo10\dy15\hr16\min36}{\version2}{\edmins4}{\nofpages7}{\nofwords3117}{\nofchars17768}{\*\company Ritual Entertainment}{\nofcharsws0}{\vern8247}} +\margl1440\margr1440\margb288 \widowctrl\ftnbj\aenddoc\aftnnar\notabind\wraptrsp\transmf\noxlattoyen\expshrtn\noultrlspc\dntblnsbdb\nospaceforul\truncatefontheight\subfontbysize\sprsbsp\wpjst\lytprtmet\hyphcaps0\horzdoc\dghspace120\dgvspace120 +\dghorigin1701\dgvorigin1984\dghshow0\dgvshow3\jcompress\viewkind4\viewscale100\nolnhtadjtbl \fet0\sectd \linex0\headery1440\footery288\sectdefaultcl {\footer \pard\plain \ql \li0\ri0\sl-240\slmult0\nowidctlpar\faauto\adjustright\rin0\lin0\itap0 +\fs24\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\fs20 +\par +\par }\pard \ql \li0\ri0\nowidctlpar\tx0\tqc\tx4680\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\tx9360\faauto\adjustright\rin0\lin0\itap0 {\fs20 Software License Agreement\tab }{\field{\*\fldinst {\fs20 PAGE }}{\fldrslt {\fs20\lang1024\langfe1024\noproof 7}}}{ +\fs20 +\par }{\fs14 08656 00001 CORP 209544.3}{\fs20 +\par }}{\*\pnseclvl1\pnucrm\pnstart1\pnindent720\pnhang{\pntxta .}}{\*\pnseclvl2\pnucltr\pnstart1\pnindent720\pnhang{\pntxta .}}{\*\pnseclvl3\pndec\pnstart1\pnindent720\pnhang{\pntxta .}}{\*\pnseclvl4\pnlcltr\pnstart1\pnindent720\pnhang{\pntxta )}} +{\*\pnseclvl5\pndec\pnstart1\pnindent720\pnhang{\pntxtb (}{\pntxta )}}{\*\pnseclvl6\pnlcltr\pnstart1\pnindent720\pnhang{\pntxtb (}{\pntxta )}}{\*\pnseclvl7\pnlcrm\pnstart1\pnindent720\pnhang{\pntxtb (}{\pntxta )}}{\*\pnseclvl8 +\pnlcltr\pnstart1\pnindent720\pnhang{\pntxtb (}{\pntxta )}}{\*\pnseclvl9\pnlcrm\pnstart1\pnindent720\pnhang{\pntxtb (}{\pntxta )}}\pard\plain \s17\qc \li0\ri0\widctlpar\faauto\adjustright\rin0\lin0\itap0 +\b\fs22\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {ATTENTION +\par }\pard\plain \qj \fi720\li0\ri0\widctlpar\faauto\adjustright\rin0\lin0\itap0 \fs24\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\fs22 +\par Here is a brief summary of certain of the terms and conditions in our Limited Software Warranty and License Agreement. You must read the full text of the agreement before using this product so that You understand all of the terms and conditions of our agr +eement regarding this product. +\par }\pard \qj \li0\ri0\widctlpar\faauto\adjustright\rin0\lin0\itap0 {\fs22 +\par WHAT IS OKAY FOR YOU TO DO: +\par +\par }\pard \qj \fi-720\li720\ri0\widctlpar\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\tx9360\faauto\adjustright\rin0\lin720\itap0 {\fs22 $\tab +Playing and enjoying the shareware and/or registered/full retail version of the game, demo and/or level editor. +\par }\pard \qj \li0\ri0\widctlpar\tx0\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\tx9360\faauto\adjustright\rin0\lin0\itap0 {\fs22 +\par }\pard \qj \fi-720\li720\ri0\widctlpar\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\tx9360\faauto\adjustright\rin0\lin720\itap0 {\fs22 $\tab +Setting up a shareware, demo, and/or registered/full retail version based server on a not-for-profit and non-commercially exploited basis. +\par }\pard \qj \li0\ri0\widctlpar\tx0\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\tx9360\faauto\adjustright\rin0\lin0\itap0 {\fs22 +\par }\pard \qj \fi-720\li720\ri0\widctlpar\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\tx9360\faauto\adjustright\rin0\lin720\itap0 {\fs22 $\tab +Playing the shareware, demo, and/or registered/full retail version of the game and/or setting up a registered/full retail version of the game using user-developed levels on a not-for-profit and non-commercially exploited bases. +\par }\pard \qj \li0\ri0\widctlpar\tx0\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\tx9360\faauto\adjustright\rin0\lin0\itap0 {\fs22 +\par WHAT IS NOT OKAY FOR YOU TO DO: +\par +\par }\pard \qj \fi-720\li720\ri0\widctlpar\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\tx9360\faauto\adjustright\rin0\lin720\itap0 {\fs22 $\tab +You cannot sell or otherwise commercially exploit or utilize the shareware, registered/full retail version, demo or level editor in any way or sell user-developed levels and/or tools. +\par }\pard \qj \li0\ri0\widctlpar\tx0\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\tx9360\faauto\adjustright\rin0\lin0\itap0 {\fs22 +\par }\pard \qj \fi-720\li720\ri0\widctlpar\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\tx9360\faauto\adjustright\rin0\lin720\itap0 {\fs22 $\tab +Commercially exploiting or otherwise utilizing any copyrighted and/or trademarked property of Ritual Entertainment or any other party contained in or associated with the shareware, demo, level editor or registered/full retail version, demo, single player + game and/or level editor, including without limitation game names, logos, graphics, characters, etc. +\par }\pard \qj \li0\ri0\widctlpar\tx0\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\tx9360\faauto\adjustright\rin0\lin0\itap0 {\fs22 +\par \sect }\sectd \linex0\headery1440\footery288\sectdefaultcl \pard\plain \s1\qc \li0\ri0\keepn\widctlpar\tqc\tx4680\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\tx9360\faauto\outlinelevel0\adjustright\rin0\lin0\itap0 +\b\fs22\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {LIMITED SOFTWARE WARRANTY AND LICENSE AGREEMENT +\par }\pard\plain \qj \li0\ri0\widctlpar\tx0\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\tx9360\faauto\adjustright\rin0\lin0\itap0 \fs24\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\fs22 +\par }\pard\plain \s16\qj \fi720\li0\ri0\widctlpar\tx0\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\tx9360\faauto\adjustright\rin0\lin0\itap0 \fs22\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 { +This LIMITED SOFTWARE WARRANTY AND LICENSE AGREEMENT (this \'93Agreement\'94), including the L +imited Warranty and other special provisions, is a legal agreement between You (either an individual or an entity) and Ritual Entertainment, Inc., a Texas corporation (the \'93Owner\'94 +), regarding this software product and the materials contained therein and re +lated thereto. Your act of downloading, installing and/or otherwise using the software constitutes Your agreement to be bound by the terms of this Agreement. If You do not agree to the terms of this Agreement cease loading or installing this product and, +if applicable, promptly return the software packaging and the accompanying materials (including any hardware, manuals, other written materials and packaging) to the place You obtained them, along with Your receipt, for a full refund. +\par }\pard\plain \qj \li0\ri0\widctlpar\tx0\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\tx9360\faauto\adjustright\rin0\lin0\itap0 \fs24\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\fs22 +\par }\pard \qj \fi720\li0\ri0\widctlpar\tx0\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\tx9360\faauto\adjustright\rin0\lin0\itap0 {\fs22\ul Grant of Limited Non-Exclusive License}{\fs22 +. (A) In the event that You are currently encountering this Agreement in conjunction with or as a result of Your downloading or otherwise installing the SOFTWARE (as defined herein), this Agreement permits You to use one (1) copy of the sof +tware program(s), in executable or object code form only, contained in the registered/full retail version of the game program entitled Heavy Metal FAKK 2 +, as contained in the disk(s) making up all or part of the registered/full retail software product, including without limitation the data files, images, level editors, death match levels, charters and screen displays (the \'93SOFTWARE\'94 +), included in this download for Your personal use on a single home or portable computer. This license also permits You to use the SOFTWARE\rquote s +level editor to create new game levels, weapons, characters and/or entities for non-commercial personal use, and to non-commercially distribute such game levels, weapons, characters, and/or entities to personal acquaintances for non-commercial use via the + Internet pursuant to subparagraph (C) below. This license does NOT authorize You to sell, lease or otherwise profit from or commercially distribute the SOFTWARE (see \'93Restrictions\'94 below). The SOFTWARE is in \'93use\'94 + on a computer when it is loaded into tempo +rary memory (i.e., RAM) or installed into the permanent memory (e.g., hard disk, CD-ROM, or other storage device) of that computer. Installation on a network server is strictly prohibited, except under a special and separate network license obtained from +Owner; this Agreement shall not serve as such necessary special network license. Installation on a network server constitutes \'93use\'94 + that must comply with the terms of this Agreement. This license is not a sale of the original SOFTWARE or any copy thereof. +\par }\pard \qj \li0\ri0\widctlpar\tx0\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\tx9360\faauto\adjustright\rin0\lin0\itap0 {\fs22 +\par }\pard \qj \fi720\li0\ri0\widctlpar\tx0\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\tx9360\faauto\adjustright\rin0\lin0\itap0 {\fs22 (B)\tab +In the event that You are currently encountering this Agreement in conjunction with or as a result of Your downloading or otherwise installing a DEMO PRODUCT (as defined herein), this Agreement permits You to use the software program(s) included in and + received solely as a result of the loaded or otherwise installed version of the demo, free standing level editor and/or shareware version of the game entitled Heavy Metal FAKK 2 +, as the case may be, for Your personal use (each such item referred to herein, individually as a \'93DEMO PRODUCT\'94 and collectively as the \'93DEMO PRODUCTS\'94 +). This license also permits You to use the level editor, as contained in and received solely as a result of the downloading or other installation or utilization of such DEMO PRODUCT, to create new + game levels, weapons, characters and/or entities for non-commercial personal use, and to non-commercially distribute such games levels, weapons, characters, and/or entities to personal acquaintances for non-commercial use via the Internet pursuant to sub +paragraph (C) below. This license does NOT authorize You to sell, lease or otherwise profit from or commercially exploit a DEMO PRODUCT (see \'93Restrictions\'94 below). A DEMO PRODUCT is in \'93use\'94 + on a computer when it is loaded into temporary memory (i.e., RAM) +or installed into the permanent memory (e.g., hard disk, CD-ROM, or other storage device) of that computer or accessed via the Internet. Installation of any DEMO PRODUCTS on a network server for profit or other commercial benefit to You or any other perso +n is strictly prohibited, except under a special and separate network license obtained from Owner; this Agreement shall not serve as such necessary special network license. Installation on a network server constitutes \'93use\'94 + that must comply with the terms of this Agreement. This license is not a sale of the original DEMO PRODUCTS or any copy thereof. +\par \sect }\sectd \sbknone\linex0\headery1440\footery288\sectdefaultcl \pard\plain \qj \fi720\li0\ri0\widctlpar\tx0\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\tx9360\faauto\adjustright\rin0\lin0\itap0 +\fs24\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\fs22 (C)\tab Subject to the terms and conditions of this Agreement, Owner grants to You the non-exclusive and limited right to create additional levels (the \'93USER LEVELS\'94 +) which are operable with the SOFTWARE or DEMO PRODUCT. You may include within the USER LEVELS certain textures and other images (the \'93Owner Images\'94) from the SOFTWARE or DEMO PRODUCT, as the case may be. You agree that the USER LEVELS wil +l not be shipped, transferred or exported into any country in violation of the U.S. Export Administration Act (or any other law governing such matters) by You or anyone at Your direction and that You will not utilize and will not authorize anyone to utili +z +e, in any other manner, the USER LEVELS in violation of any applicable law. The USER LEVELS may not be downloaded or otherwise exported or re-exported into (or to a national or resident of) any country to which the United States has embargoed goods or to +a +nyone or unto any country who/which are prohibited by applicable law, from receiving such property. You shall not rent, sell, lease, lend, offer on a pay-per-play basis or otherwise commercially exploit or commercially distribute any USER LEVELS. You are +o +nly permitted to distribute for free, without any cost or charge, the USER LEVELS to other end-users. As noted below, in the event You commercially distribute or commercially exploit any USER LEVELS or commit any other breach of this Agreement, Your licen +se, as granted in this Agreement, shall automatically terminate, without notice. IN ADDITION TO YOUR INDEMNIFICATION OBLIGATIONS AS SET FORTH BELOW, YOU HEREBY AGREE TO INDEMNIFY, DEFEND AND HOLD HARMLESS OWNER AND OWNER\rquote +S RESPECTIVE OFFICERS, EMPLOYEES, DI +RECTORS, AGENTS, LICENSEES (EXCLUDING YOU), SUBLICENSEES (EXCLUDING YOU), SUCCESSORS AND ASSIGNS FROM AND AGAINST ANY AND ALL DIRECT AND/OR INDIRECT LOSSES, LAWSUITS, DAMAGES, CAUSES OF ACTIONS AND CLAIMS RELATING TO AND/OR ARISING FROM THE USER LEVELS AN +D/OR THE DISTRIBUTION OR OTHER USE OF ANY USER LEVELS. +\par }\pard \qj \li0\ri0\widctlpar\tx0\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\tx9360\faauto\adjustright\rin0\lin0\itap0 {\fs22 +\par }\pard \qj \fi720\li0\ri0\widctlpar\tx0\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\tx9360\faauto\adjustright\rin0\lin0\itap0 {\fs22\ul Intellectual Property Ownership}{\fs22 +. Owner retains all right, title and interest to the SOFTWARE and/or DEMO PRODUCTS and any accompanying instructions or other documentation (collectively, the \'93ACCOMPANYING MATERIALS\'94 +), including, but not limited to, all copyrights, trademarks, trade secrets, trade names, proprietary rights, patents, titles, computer codes, audiovisual effects, themes, characters, character names, stories, dialog, settings, artwork, sounds + effects, musical works, and moral rights. The SOFTWARE, DEMO PRODUCTS and ACCOMPANYING MATERIALS are protected by United States copyright law and applicable copyright laws and treaties throughout the World. All rights are reserved. The SOFTWARE and ACCOM +PANYING MATERIALS may not be copied or reproduced in any manner or medium, in whole or in part, without prior written consent from Owner except as specifically provided under \'93Grant of Limited Non-Exclusive License\'94 + above. Any persons copying or reproducing all or any portion of the SOFTWARE or ACCOMPANYING MATERIALS, except as specifically provided under \'93Grant of Limited Non-Exclusive License\'94 + above, in any manner or medium, will be willfully violating the copyright laws and may be subject to civil or criminal penalties. +\par }\pard \qj \li0\ri0\widctlpar\tx0\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\tx9360\faauto\adjustright\rin0\lin0\itap0 {\fs22 +\par }\pard \qj \fi720\li0\ri0\widctlpar\tx0\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\tx9360\faauto\adjustright\rin0\lin0\itap0 {\fs22\ul SOFTWARE Backup or Archiving}{\fs22 +. After You install the SOFTWARE into the permanent memory of a computer, You may keep and use the original disk(s) and/or CD-ROM (the \'93Storage Media\'94 +) only for backup or archival purposes. You are expressly prohibited from transmitting the SOFTWARE or ACCOMPANYING MATERIALS electronically or otherwise over the Internet or through any other media or to any other party. +\par }\pard \qj \li0\ri0\widctlpar\tx0\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\tx9360\faauto\adjustright\rin0\lin0\itap0 {\fs22 +\par \sect }\sectd \sbknone\linex0\headery1440\footery288\sectdefaultcl \pard\plain \qj \fi720\li0\ri0\widctlpar\tx0\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\tx9360\faauto\adjustright\rin0\lin0\itap0 +\fs24\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\fs22\ul Restrictions}{\fs22 . Ot +her than as provided specifically in this Agreement, You are not permitted to copy or otherwise reproduce the SOFTWARE or ACCOMPANYING MATERIALS; modify or prepare derivative copies based on the SOFTWARE or ACCOMPANYING MATERIALS; distribute copies of the + +SOFTWARE or ACCOMPANYING MATERIALS by sale or other transfer of ownership; rent, lease, or lend the SOFTWARE, DEMO PRODUCTS or ACCOMPANYING MATERIALS; or to display the SOFTWARE or ACCOMPANYING MATERIALS publicly. You are expressly prohibited from selling +, leasing, charging for access to, or otherwise using for profit or commercially exploiting any USER LEVELS, level packs, add-on packs, sequels, characters or other components or items created by utilization of the SOFTWARE\rquote s or DEMO PRODUCT +\rquote s level editor +and/or based upon or related to the SOFTWARE, DEMO PRODUCT or ACCOMPANYING MATERIALS. YOU ARE NOT PERMITTED TO REVERSE ENGINEER, DECOMPILE OR DISASSEMBLE THE SOFTWARE OR ANY DEMO PRODUCT IN ANY WAY. Any copying or distribution of the SOFTWARE or ACCOMPANY +I +NG MATERIALS not specifically allowed in this Agreement is a violation of this Agreement. You may create USER LEVELS for the SOFTWARE or any DEMO PRODUCT; provided, however, that such USER LEVELS are created in accordance with the non-exclusive license se +t forth above and no USER LEVELS may be sold or otherwise commercially exploited, whether by You or by any other person or entity, but You may exchange USER LEVELS at no charge with other end-users. +\par }\pard \qj \li0\ri0\widctlpar\tx0\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\tx9360\faauto\adjustright\rin0\lin0\itap0 {\fs22 +\par }\pard \qj \fi720\li0\ri0\widctlpar\tx0\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\tx9360\faauto\adjustright\rin0\lin0\itap0 {\fs22\ul Limited Warranty and Warranty Disclaimers}{\fs22 . +\par }\pard \qj \li0\ri0\widctlpar\tx0\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\tx9360\faauto\adjustright\rin0\lin0\itap0 {\fs22 +\par }\pard \qj \fi720\li0\ri0\widctlpar\tx0\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\tx9360\faauto\adjustright\rin0\lin0\itap0 {\fs22 LIMITED WARRA +NTY. Owner warrants that the original Storage Media holding the SOFTWARE is free from defects in materials and workmanship under normal use and service for a period of ninety (90) days from the date that You downloaded the SOFTWARE. If for any reason You +f +ind defects in the Storage Media, or if You are unable to install the SOFTWARE on Your home or portable computer, You may return the SOFTWARE, ACCOMPANYING MATERIALS and all packaging related thereto to the place you purchased such products for a full ref +und or replacement thereof. This limited warranty does not apply if You have damaged the SOFTWARE by accident or abuse. +\par }\pard \qj \li0\ri0\widctlpar\tx0\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\tx9360\faauto\adjustright\rin0\lin0\itap0 {\fs22 +\par }\pard \qj \fi720\li0\ri0\widctlpar\tx0\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\tx9360\faauto\adjustright\rin0\lin0\itap0 {\fs22 CUSTOMER\rquote +S REMEDY. Your exclusive remedies, and the entire liability of Owner, shall be replacement of the SOFTWARE or DEMO PRODUCT, as +the case may be. By downloading, installing and/or otherwise using the SOFTWARE, DEMO PRODUCT or ACCOMPANYING MATERIALS, as the case may be, You hereby agree to waive any and all other remedies You may have at law or in equity. Any such remedies You may n +ot waive as a matter of public policy, You hereby assign, or shall assign as they become available, over to Owner. +\par +\par NOTWITHSTANDING ANYTHING TO THE CONTRARY IN THIS AGREEMENT, WITH RESPECT TO THE DEMO PRODUCTS, OWNER MAKES NO REPRESENTATIONS OR WARRANTIES +(EXPRESS, IMPLIED OR OTHERWISE), INCLUDING WITHOUT LIMITATION THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND/OR NON-INFRINGEMENT. THE DEMO PRODUCTS ARE PROVIDED GRATUITOUSLY TO YOU \'93AS IS\'94 + AND YOU TAKE, INSTALL, LOAD OR OTHERWISE USE SUCH DEMO PRODUCTS AT YOUR OWN RISK. OWNER HAS NO LIABILITIES ARISING FROM OR RELATED TO YOUR USE OF ANY DEMO PRODUCTS. +\par }\pard \qj \li0\ri0\widctlpar\tx0\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\tx9360\faauto\adjustright\rin0\lin0\itap0 {\fs22 +\par \sect }\sectd \sbknone\linex0\headery1440\footery288\sectdefaultcl \pard\plain \qj \fi720\li0\ri0\widctlpar\tx0\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\tx9360\faauto\adjustright\rin0\lin0\itap0 +\fs24\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\fs22\ul WARRANTY DISCLAIMERS}{\fs22 . EXCEPT FOR THE EXPRESS LIMITED WARRANTY SET FORTH ABOVE, OWNER MAKES NO WARRANTIES, E +XPRESS OR IMPLIED, ORAL OR WRITTEN, CONCERNING THE PRODUCTS REFERENCED HEREIN OR ANY COMPONENT PART THEREOF. ANY IMPLIED WARRANTIES THAT MAY BE IMPOSED BY APPLICABLE LAW ARE LIMITED IN ALL RESPECTS TO THE FULLEST EXTENT ALLOWED AND TO THE DURATION OF THE +L +IMITED WARRANTY. OWNER DOES NOT REPRESENT, WARRANT OR GUARANTEE THE QUALITY OR THE PERFORMANCE OF THE SOFTWARE, DEMO PRODUCTS OR ACCOMPANYING MATERIALS OTHER THAN AS SET FORTH IN THE ABOVE LIMITED WARRANTY. OWNER ALSO DOES NOT REPRESENT, WARRANT OR GUARAN +T +EE THAT THE SOFTWARE, DEMO PRODUCTS OR ACCOMPANYING MATERIALS CAPABILITIES WILL MEET YOUR NEEDS OR THAT THE SOFTWARE OR DEMO PRODUCTS WILL CONTINUOUSLY OPERATE, BE ERROR FREE, OR THAT PROBLEMS WILL BE CORRECTED. OWNER DOES NOT REPRESENT THAT THE SOFTWARE +OR DEMO PRODUCTS WILL OPERATE IN A MULTI-USER ENVIRONMENT. +\par }\pard \qj \li0\ri0\widctlpar\tx0\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\tx9360\faauto\adjustright\rin0\lin0\itap0 {\fs22 +\par }\pard \qj \fi720\li0\ri0\widctlpar\tx0\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\tx9360\faauto\adjustright\rin0\lin0\itap0 {\fs22 +NO ORAL OR WRITTEN INFORMATION OR ADVICE GIVEN BY OWNER, ITS DEALERS, DISTRIBUTORS, DIRECTORS, OFFICERS, EMPLOYEES, AGENTS, CONTRACTORS OR AFFILIATES SHALL CREATE ANY OTHER WARRANTY OR EXTEND OR EX +PAND THE SCOPE OF THIS WARRANTY. YOU MAY NOT RELY ON ANY SUCH INFORMATION OR ADVICE. +\par }\pard \qj \li0\ri0\widctlpar\tx0\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\tx9360\faauto\adjustright\rin0\lin0\itap0 {\fs22 +\par }\pard \qj \fi720\li0\ri0\widctlpar\tx0\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\tx9360\faauto\adjustright\rin0\lin0\itap0 {\fs22 +SOME STATES DO NOT ALLOW LIMITATIONS ON HOW LONG AN IMPLIED WARRANTY LASTS, SO THE ABOVE LIMITATION MAY NOT APPLY TO YOU. THIS LIMITED WARRANTY GIVES YOU SPECIFIC LEGAL RIGHTS AND YOU MAY ALSO HAVE OTHER RIGHTS WHICH MAY VARY FROM STATE TO STATE. +\par }\pard \qj \li0\ri0\widctlpar\tx0\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\tx9360\faauto\adjustright\rin0\lin0\itap0 {\fs22 +\par }{\fs22\ul LIABILITY LIMITATION}{\fs22 . To the maximum extent permitted by applicable law, and regardless of whether any remedy set forth herein fails of its essential purpose, +\par +\par IN NO EVENT WILL OWNER, ITS DIRECTORS, OFFICERS, EMPLOYEES, AGENTS, LICENSES (EXCLUDING YOU), SUBLICENSEES (EXCLUDING YOU) OR AFFILIATES NOR ANYONE ELSE INVOLVED IN THE DEVELOPMENT, MANUFACTURE OR DISTRIBUTION OF THE SOFTWARE, THE DEMO PRODUCTS, THE ACCOM +P +ANYING MATERIALS OR THE USER LEVELS (OTHER THAN YOU) BE LIABLE FOR ANY DAMAGES WHATSOEVER, INCLUDING WITHOUT LIMITATION, DIRECT OR INDIRECT; INCIDENTAL; OR CONSEQUENTIAL DAMAGES FOR PERSONAL INJURY, PERSONAL PROPERTY, LOSS OF BUSINESS PROFITS, BUSINESS IN +T +ERRUPTION, LOSS OF BUSINESS INFORMATION, LOSS OF TEXT OR DATA STORED IN OR USED WITH SUCH PRODUCT INCLUDING THE COST OF RECOVERING OR REPRODUCING THE TEXT OR DATA, OR ANY OTHER PECUNIARY LOSS, ARISING FROM OR OUT OF THE USE OR INABILITY TO USE THIS SOFTWA +R +E, THE DEMO PRODUCTS OR ANY USER LEVELS. THIS LIABILITY LIMITATION APPLIES EVEN IF YOU OR ANYONE ELSE HAS ADVISED OWNER OR ANY OF ITS AUTHORIZED REPRESENTATIVES OF THE POSSIBILITY OF SUCH DAMAGES. EVEN IF SUCH IS CAUSED BY, ARISES OUT OF OR RESULTS FROM T +H +E ORDINARY, STRICT, SOLE OR CONTRIBUTORY NEGLIGENCE OF OWNER OR ITS DIRECTORS, OFFICERS, EMPLOYEES, AGENTS, CONTRACTORS OR AFFILIATES. SOME STATES DO NOT ALLOW THE EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THE ABOVE LIMITATION OR +EXCLUSION MAY NOT APPLY TO YOU. +\par +\par }\pard \qj \fi720\li0\ri0\widctlpar\tx0\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\tx9360\faauto\adjustright\rin0\lin0\itap0 {\fs22\ul Product Support and Updates}{\fs22 +. This SOFTWARE is intended to be user-friendly and limited product support is provided by Owner as specified in the ACCOMPANYING MATERIALS. +\par }\pard \qj \li0\ri0\widctlpar\tx0\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\tx9360\faauto\adjustright\rin0\lin0\itap0 {\fs22 +\par }\pard \qj \fi720\li0\ri0\widctlpar\tx0\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\tx9360\faauto\adjustright\rin0\lin0\itap0 {\fs22\ul Jurisdiction}{\fs22 . TEXAS LAWS GOVERN THIS AGREEMENT, REGARDLESS OF SUCH STATE +\rquote S CHOICE OF LAW PRINCIPLES, WITH A FORUM AND VENUE OF DALLAS COUNTY, TEXAS. This Agreement may be modified only by a written instrument specifying the modification and executed by both parties. In the event that any provision of this Agre +ement shall be held to be unenforceable, such provision shall be enforced to the greatest possible extent, with the other provisions of this Agreement to remain in full force and effect. +\par }\pard \qj \li0\ri0\widctlpar\tx0\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\tx9360\faauto\adjustright\rin0\lin0\itap0 {\fs22 +\par }\pard \qj \fi720\li0\ri0\widctlpar\tx0\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\tx9360\faauto\adjustright\rin0\lin0\itap0 {\fs22\ul Entire Agreement}{\fs22 . This Agreement represents the entire agreement be +tween the parties, and supersedes any oral or written communications, proposals or prior agreements between the parties or any dealers, distributors, agents or employees. +\par }\pard \qj \li0\ri0\widctlpar\tx0\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\tx9360\faauto\adjustright\rin0\lin0\itap0 {\fs22 +\par \sect }\sectd \sbknone\linex0\headery1440\footery288\sectdefaultcl \pard\plain \qj \fi720\li0\ri0\widctlpar\tx0\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\tx9360\faauto\adjustright\rin0\lin0\itap0 +\fs24\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\fs22\ul U.S. Government Restricted Rights}{\fs22 . Each of the SOFTWARE, DEMO PROD +UCTS and the ACCOMPANYING MATERIALS is provided with RESTRICTED RIGHTS (as found in 48 C.F.R. '52.227-7013). This provision only applies if the U.S. Government or any of its entities obtains the SOFTWARE or DEMO PRODUCTS either directly or indirectly. Own +e +r created the SOFTWARE, DEMO PRODUCTS and the ACCOMPANYING MATERIALS exclusively with private funds. Additionally, information contained in the SOFTWARE, DEMO PRODUCTS and the ACCOMPANYING MATERIALS is a trade secret of Owner for all purposes of the Freed +om of Information Act or otherwise. Furthermore, the SOFTWARE and the DEMO PRODUCTS are \'93commercial computer software\'94 + subject to limited use as set forth in any contract that may be entered into between the seller and the governmental entity. Owner owns, i +n all respects, the proprietary information and proprietary data found in the SOFTWARE, DEMO PRODUCTS and the ACCOMPANYING MATERIALS. +\par }\pard \qj \li0\ri0\widctlpar\tx0\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\tx9360\faauto\adjustright\rin0\lin0\itap0 {\fs22 +\par }\pard \qj \fi720\li0\ri0\widctlpar\tx0\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\tx9360\faauto\adjustright\rin0\lin0\itap0 {\fs22 +U.S. DEPARTMENT OF DEFENSE PERSONNEL. Owner only sells this SOFTWARE, DEMO PRODUCTS and the ACCOMPANYING MATERIALS with \'93Restricted Rights\'94 + as defined in DFARS 52.227-7013 (also found at 48 C.F.R. '252.227-7013). Any U.S. Government use, duplication, or disclosure is subject to the restrictions including, but not limited to those found in the Rights in Technological Data cla +use at DFARS 52.227-7013 (48 C.F.R. '252.227-7013) that may be amended from time to time. +\par }\pard \qj \li0\ri0\widctlpar\tx0\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\tx9360\faauto\adjustright\rin0\lin0\itap0 {\fs22 +\par }\pard \qj \fi720\li0\ri0\widctlpar\tx0\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\tx9360\faauto\adjustright\rin0\lin0\itap0 {\fs22 +NON-DEPARTMENT OF DEFENSE PERSONNEL. Other governmental personnel are on notice through this Agreement that any use of the SOFTWARE, DEMO PRODUCTS and/or the ACCOMPA +NYING MATERIALS is subject to similar limitations as those stated above, including but not limited to, those stated in Commercial Computer Software -- Restricted Rights found in 48 C.F.R. '52.227-19, that may also be amended from time to time. Manufacture +r is Owner at the location listed below. +\par }\pard \qj \li0\ri0\widctlpar\tx0\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\tx9360\faauto\adjustright\rin0\lin0\itap0 {\fs22 +\par }\pard \qj \fi720\li0\ri0\widctlpar\tx0\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\tx9360\faauto\adjustright\rin0\lin0\itap0 {\fs22\ul U.S. Export Laws Prohibitions}{\fs22 +. By downloading, installing or otherwise using the SOFTWARE, DEMO PRODUCTS and/or ACCOMPANYING MATERIALS, You also agree and confirm that the SOFTWARE, DEMO PRODUCTS and/or ACCOMPANYING MATERIALS and any of the SOFTWARE\rquote s or DEMO PRODUCTS\rquote + direct products are not being and will not be transported, exported or re-exported (directly or indirectly through the Internet or otherwise) into (or to a national or resident of) any country forbidde +n to receive such SOFTWARE, DEMO PRODUCTS and/or ACCOMPANYING MATERIALS by any U.S. export laws or accompanying regulations or otherwise violate such laws or regulations, that may be amended from time to time. You also agree and confirm that the SOFTWARE, + DEMO PRODUCTS and ACCOMPANYING MATERIALS will not be used for any purpose that may be restricted by the same laws and regulations. +\par }\pard \qj \li0\ri0\widctlpar\tx0\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\tx9360\faauto\adjustright\rin0\lin0\itap0 {\fs22 +\par }\pard \qj \fi720\li0\ri0\widctlpar\tx0\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\tx9360\faauto\adjustright\rin0\lin0\itap0 {\fs22\ul Termination}{\fs22 +. This Agreement is valid until terminated. This Agreement ceases automatically (without any form of notice) if Y +ou do not comply with any Agreement provision. You can also end this Agreement by destroying the SOFTWARE and ACCOMPANYING MATERIALS or DEMO PRODUCTS, as the case may be, and all copies and reproductions of the SOFTWARE and ACCOMPANYING MATERIALS or DEMO +PRODUCTS, as the case may be, and deleting and permanently purging the SOFTWARE or DEMO PRODUCTS, as the case may be, from any client server or computer on which it has been installed. +\par }\pard \qj \li0\ri0\widctlpar\tx0\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\tx9360\faauto\adjustright\rin0\lin0\itap0 {\fs22 +\par }\pard \qj \fi720\li0\ri0\widctlpar\tx0\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\tx9360\faauto\adjustright\rin0\lin0\itap0 {\fs22\ul Program Transfer}{\fs22 . You may permanently transfer all of Your rights under + this Agreement, provided that the recipient agrees to all of the terms of this Agreement, and You agree to transfer all ACCOMPANYING MATERIALS and related documents and components and, if applicable, remove the SOFTWARE from Your computer prior thereto. +With respect to the SOFTWARE and the ACCOMPANYING MATERIALS, transferring the SOFTWARE automatically terminates Your license under this Agreement. +\par }\pard \qj \li0\ri0\widctlpar\tx0\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\tx9360\faauto\adjustright\rin0\lin0\itap0 {\fs22 +\par \sect }\sectd \sbknone\linex0\headery1440\footery288\sectdefaultcl \pard\plain \qj \fi720\li0\ri0\widctlpar\tx0\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\tx9360\faauto\adjustright\rin0\lin0\itap0 +\fs24\lang1033\langfe1033\cgrid\langnp1033\langfenp1033 {\fs22\ul Equitable Remedies.}{\fs22 + You hereby agree that if the terms of this Agreement are not specifically enforced, Owner will be irreparably damaged, and therefore You agree that Owner shall be entitled, without bond, other security, proof of damages, to appropriate equitable remedies + with respect to any breach(es) of this Agreement, in addition to any other available remedies. +\par }\pard \qj \li0\ri0\widctlpar\tx0\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\tx9360\faauto\adjustright\rin0\lin0\itap0 {\fs22 +\par }\pard \qj \fi720\li0\ri0\widctlpar\tx0\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\tx9360\faauto\adjustright\rin0\lin0\itap0 {\fs22\ul Owner.}{\fs22 + If You have any questions regarding this Agreement, the enclosed materials, or otherwise, please contact in writing: +\par }\pard \qj \li0\ri0\widctlpar\tx0\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\tx9360\faauto\adjustright\rin0\lin0\itap0 {\fs22 +\par +\par }\pard \qj \li1440\ri0\widctlpar\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\tx9360\faauto\adjustright\rin0\lin1440\itap0 {\fs22 Ritual Entertainment +\par Attn: Customer Service\tab \tab \tab \tab \tab +\par }\pard \qj \fi1440\li0\ri0\widctlpar\tx0\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\tx9360\faauto\adjustright\rin0\lin0\itap0 {\fs22 2019 North Lamar Street, Suite 220\tab \tab \tab \tab +\par Dallas, Texas 75202-1744 +\par +\par Fax: (214) 871-7390\tab \tab \tab \tab \tab +\par +\par E-mail: legal@ritual.com\tab \tab \tab +\par }\pard \qj \li0\ri0\widctlpar\tx0\tx720\tx1440\tx2160\tx2880\tx3600\tx4320\tx5040\tx5760\tx6480\tx7200\tx7920\tx8640\tx9360\faauto\adjustright\rin0\lin0\itap0 {\fs22 +\par +\par +\par +\par }{\b\fs22 Heavy Metal FAKK 2}{\fs22 , }{\b\fs22 Ritual }{\fs22 and}{\b\fs22 Ritual Entertainment }{\fs22 are trademarks of Ritual Entertainment, Inc.}{\b\fs22 +\par }{\fs22 Copyright \'a9 2000 Ritual Entertainment, Inc. All Rights Reserved. +\par +\par }{\b\fs22 Microsoft }{\fs22 and}{\b\fs22 Windows 95, Windows 98 }{\fs22 and}{\b\fs22 Windows NT}{\fs22 are registered trademarks of Microsoft Corporation. All other trademarks and trade names are properties of their respective owners. +\par +\par U.S. Government Restricted Rights +\par Manufactured in the U.S.A.}{\fs20 +\par }} \ No newline at end of file diff --git a/readme.txt b/readme.txt new file mode 100644 index 0000000..ac2c79f --- /dev/null +++ b/readme.txt @@ -0,0 +1,165 @@ +Please do not email Ritual Entertainment with questions about the tools or the +source, we do not have the resources to support the source or the utilities. +They are provided as is, and are meant for the hardcore hackers out there. + +Revision History +================ +09/17/2000 - Not all the tools properly supported the FTX format. Tools were +updated so that FTX files would not have to be re-converted back into TGA +files for the tools proper use. +09/15/2000 - Initial Release + +Heavy Metal FAKK 2 TOOLS ( Veraion 1.02 )- 09/15/2000 + +license.rtf - the license file +readme.txt - what you are reading + +bin\dlgedit.exe - the resource building utility +bin\fontgen.exe - Windows font converter utility +bin\ftxconvert.exe - Converts FTX files back into TGA +bin\lipsync.exe - generates lipsync data for wav's or mp3's +bin\lw2tan.exe - Lightwave to tan converter +bin\max2skl.exe - 3D Studio MAX 3.0 to SKL converter +bin\max2tan.exe - 3D Studio MAX 3.0 to TAN converter +bin\mcopy.exe - Handy script based copy program +bin\newq3map.exe - Map building tool using new Vis algorithm +bin\q3map.exe - Map building tool +bin\q3radiant.exe - Map Editor +bin\radiant.ini - INI file for Q3Radiant +bin\runq3radiant.bat - Batch file to run Q3Radiant +bin\tgaconvert.exe - Coverts TGA files into FTX files +bin\max2plugins\animout.dle - 3D Studio MAX 2.0 ANM exporter +bin\max2plugins\skelout.dle - 3D Studio MAX 2.0 SKL exporter +bin\max2plugins\uvout.dle - 3D Studio MAX 2.0 UV exporter +bin\max3plugins\animout.dle - 3D Studio MAX 3.0 ANM exporter +bin\max3plugins\skelout.dle - 3D Studio MAX 3.0 SKL exporter +bin\max3plugins\uvout.dle - 3D Studio MAX 3.0 UV exporter +bin\maxscripts\example.ms - example MaxScript +bin\maxscripts\exportskl.ms - MaxScript functions +bin\maxscripts\jimtest.ms - another MaxScript example +bin\Radiant plugins\Fakk2Plug.dll - Q3Radiant plugin in for FAKK 2 + +docs\AI.doc - AI overview +docs\camera documentation.doc - Camera system overview +docs\Client Side Commands.doc - Client side (cgame) command overview +docs\commands.txt - preliminary cmdlist documentation +docs\Coordinate System.doc - Coordinate systems used in FAKK 2 +docs\CVAR DOCUMENTATION.doc - Extensive CVAR documentation +docs\Description of Menus and Ingame Utils.doc - In game tools overview +docs\Dialog System.doc - Dialog system overview +docs\Dumping Demo AVI.doc - Dumping demos to AVI format overview +docs\Event Spec Documentation.doc - How to document new Events +docs\FAKK FAQ.doc - general q/a on FAKK 2 development +docs\Ghost Particle System.doc - Particle system overview +docs\Gibs.doc - How to add gibs to characters +docs\GUI Documentation.doc - GUI system overview +docs\How to Make Weapons and Ammo.doc - how to make weapons and ammo +docs\Inventory System Commands.doc - Inventory system overview +docs\Items.doc - items in Fakk 2 +docs\MAX2SKL Reference Guide.doc - MAX2SKL reference +docs\Radiant Commands.doc - Radiant documentation +docs\shader_manual_new.doc - Shader Manual +docs\Sound System.doc - Sound system overview +docs\TIKI Model System.doc - TIKI system overview +docs\Tiki QuakeEd Specs.doc - QUAKED specification for TIKI models + +entities\entities.def - combined QUAKED headers for Q3RADIANT + +fakk\maps\example\autocamera.bsp - demonstrates use of autocameras +fakk\maps\example\autosprite.bsp - demonstrates use of autosprites +fakk\maps\example\beam.bsp - demonstrates use of beams +fakk\maps\example\beam1.bsp - demonstrates use of beams +fakk\maps\example\box3.bsp - simple map +fakk\maps\example\CameraScript.bsp - demonstrates use of Scripted Cameras +fakk\maps\example\climb.bsp - demonstrates climbing on walls and ropes +fakk\maps\example\cover.bsp - demonstrates AI Cover +fakk\maps\example\door.bsp - demonstrates different doors +fakk\maps\example\doors.bsp - demonstartes more doors +fakk\maps\example\earthquake.bsp - earthquake demonstration +fakk\maps\example\explodeobject.bsp - exploding object demonstration +fakk\maps\example\exploder.bsp - exploder demonstration +fakk\maps\example\explodingwall.bsp - explodingwall demonstration +fakk\maps\example\fallingrock.bsp - falling rock demonstration +fakk\maps\example\fulcrum.bsp - fulcrum demonstration +fakk\maps\example\funcspawn.bsp - func_spawn demonstration +fakk\maps\example\gibs_and_health.bsp - gibs and health demonstration +fakk\maps\example\letterbox.bsp - letterbox demonstration +fakk\maps\example\multiexploder.bsp - multi-exploder demonstration +fakk\maps\example\patrol.bsp - AI Patrol demonstration +fakk\maps\example\pickup.bsp - Picking up Shgliek demonstration +fakk\maps\example\pushobject.bsp - Push Object demonstration +fakk\maps\example\rain.bsp - Rain and Leaves demonstration +fakk\maps\example\runthrough.bsp - func_runthrough demonstartion +fakk\maps\example\scriptgravity.bsp - Script gravity demonstration +fakk\maps\example\sinkobject.bsp - Sink Object demonstration +fakk\maps\example\teleporter.bsp - Teleporter demonstration +fakk\maps\example\useanim.bsp - UseAnim demonstration +fakk\maps\example\useobject.bsp - UseObject demonstration +fakk\maps\example\vehicle.bsp - Vehicle demonstration +fakk\maps\example\zoo.bsp - Zoo map + +fakk\scripts\fakk.qe4 - Q3Radiant setup file +fakk\scripts\surfacelist.txt - list of all textures with surface defs + +source\source\cgame - FAKK 2 CGame source + +source\source\fgame - FAKK 2 Game source + +source\source\qcommon - common files needed for above +source\source\win32 - common files needed for above + +source\utils\common - common source files for utilities +source\utils\dlgedit - source for resource editor +source\utils\fontgen - source for font generator +source\utils\ftxconvert - source for FTX converter +source\utils\lipsync - source for LIPSYNC tool +source\utils\lw2tan - source for Lightwave converter +source\utils\max2plugins - source for MAX 2 plugins +source\utils\max2skl - source for MAX skeletal converter +source\utils\max2tan - source for MAX vertex animation converter +source\utils\max3plugins - source for MAX 3 plugins +source\utils\tgaconvert - source for TGA converter + +You will need to download the 3D Studio MAX SDK in order to rebuild the +plugins. The lipsync converter does not include the header or library from +Miles since that is not re-distributable. + +Thank you and good luck, + +Scott Alden, Mark Dochtermann and Steven Peeler + +The FAKK 2 Programming Team + +--------------------------------------------------------------- + +INSTALLATION: + +The tools ships with almost no game data. As a result you will have to unpack +pak0.pk3, pak1.pk3 and pak2.pk3 in order to start building maps for the game. +You will need about 750 MB free on your hard drive to unpack these files. To do +this, drop the PK3 files on zip extraction utility like WinZip and unpack the +paks with the Folder Names option checked into the "fakk" directory of this +install. Once you have unpacked the pak files, the editor and tools will be +able to access them freely. + +In order to build maps directly from q3radiant you will need to make sure that +the file fakk.qe4 in fakk/scripts is setup properly. The file has been +configured for an installation in the c:\fakktools\ directory if this is not +the directory you installed the tools into, you will need to edit the fakk.qe4 +file. + +To run the editor, run runq3radiant.bat in the bin directory or you can +create a shortcut on your desktop by leftclick-dragging q3radiant.exe on +your desktop. Go the properties tab and add the following to the command line +(Target field): + +q3radiant.exe ..\fakk\scripts\fakk.qe4 + +LINKS: + +www.gith.net - Heavy Metal FAKK 2 editing site +www.fakkyou.com - Heavy Metal FAKK 2 page + +www.ritual.com - Ritual Entertainment's Home Page +www.ritualistic.com - #1 resource for Ritual related news +www.heavymetal.net - Official Heavy Metal site for Heavy Metal Magazine diff --git a/source/source/cgame/Linklist.h b/source/source/cgame/Linklist.h new file mode 100644 index 0000000..dc46b5c --- /dev/null +++ b/source/source/cgame/Linklist.h @@ -0,0 +1,129 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/Linklist.h $ +// $Revision:: 3 $ +// $Author:: Markd $ +// $Date:: 6/14/00 11:18a $ +// +// Copyright (C) 1997 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source is may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/Linklist.h $ +// +// 3 6/14/00 11:18a Markd +// cleaned up code using Intel compiler +// +// 2 10/05/99 2:03p Markd +// Added warning about files being in multiple projects +// +// 1 9/10/99 10:54a Jimdose +// +// 1 9/08/99 3:16p Aldie +// +// DESCRIPTION: +// +// WARNING: This file is shared between fgame, cgame and possibly the user interface. +// It is instanced in each one of these directories because of the way that SourceSafe works. +// + +#ifndef __linklist_h +#define __linklist_h +#ifdef __cplusplus +extern "C" { +#endif + + +#define NewNode(type) ((type *)Z_Malloc(sizeof(type))) + +#define LL_New(rootnode,type,next,prev) \ + { \ + (rootnode) = NewNode(type); \ + (rootnode)->prev = (rootnode); \ + (rootnode)->next = (rootnode); \ + } + +#define LL_Add(rootnode, newnode, next, prev) \ + { \ + (newnode)->next = (rootnode); \ + (newnode)->prev = (rootnode)->prev; \ + (rootnode)->prev->next = (newnode); \ + (rootnode)->prev = (newnode); \ + } +//MED +#define LL_AddFirst(rootnode, newnode, next, prev) \ + { \ + (newnode)->prev = (rootnode); \ + (newnode)->next = (rootnode)->next; \ + (rootnode)->next->prev = (newnode); \ + (rootnode)->next = (newnode); \ + } + +#define LL_Transfer(oldroot,newroot,next,prev) \ + { \ + if (oldroot->prev != oldroot) \ + { \ + oldroot->prev->next = newroot; \ + oldroot->next->prev = newroot->prev; \ + newroot->prev->next = oldroot->next; \ + newroot->prev = oldroot->prev; \ + oldroot->next = oldroot; \ + oldroot->prev = oldroot; \ + } \ + } + +#define LL_Reverse(root,type,next,prev) \ + { \ + type *newend,*trav,*tprev; \ + \ + newend = root->next; \ + for(trav = root->prev; trav != newend; trav = tprev) \ + { \ + tprev = trav->prev; \ + LL_Move(trav,newend,next,prev); \ + } \ + } + + +#define LL_Remove(node,next,prev) \ + { \ + node->prev->next = node->next; \ + node->next->prev = node->prev; \ + node->next = node; \ + node->prev = node; \ + } + +#define LL_SortedInsertion(rootnode,insertnode,next,prev,type,sortparm) \ + { \ + type *hoya; \ + \ + hoya = rootnode->next; \ + while((hoya != rootnode) && (insertnode->sortparm > hoya->sortparm)) \ + { \ + hoya = hoya->next; \ + } \ + LL_Add(hoya,insertnode,next,prev); \ + } + +#define LL_Move(node,newroot,next,prev) \ + { \ + LL_Remove(node,next,prev); \ + LL_Add(newroot,node,next,prev); \ + } + +#define LL_Empty(list,next,prev) \ + ( \ + ((list)->next == (list)) && \ + ((list)->prev == (list)) \ + ) + +#define LL_Free(list) Z_Free(list) +#define LL_Reset(list,next,prev) (list)->next = (list)->prev = (list) + +#ifdef __cplusplus +} + +#endif +#endif diff --git a/source/source/cgame/cg_beam.cpp b/source/source/cgame/cg_beam.cpp new file mode 100644 index 0000000..cba7cc1 --- /dev/null +++ b/source/source/cgame/cg_beam.cpp @@ -0,0 +1,1569 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/cgame/cg_beam.cpp $ +// $Revision:: 57 $ +// $Author:: Aldie $ +// $Date:: 7/25/00 11:30p $ +// +// Copyright (C) 1999 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/cgame/cg_beam.cpp $ +// +// 57 7/25/00 11:30p Aldie +// Made some memory changes and fixed some memory allocation bugs +// +// 56 7/18/00 4:31p Aldie +// Fix some client side multibeam stuff incase the whole group is not available +// to the client +// +// 55 6/27/00 7:16p Aldie +// Fixed it so beam emitters use alpha from entity +// +// 54 6/26/00 8:02p Aldie +// Fixed some checks for multibeams +// +// 53 6/17/00 1:54p Markd +// Added server restarted code +// +// 52 6/14/00 12:14p Markd +// more intel compiler bug fixes +// +// 51 6/08/00 3:51p Markd +// fixed unused variable warning +// +// 50 6/07/00 5:02p Aldie +// Fixed beam offset from owner bug +// +// 49 6/03/00 10:55a Markd +// Sped up tracing and debug print messages +// +// 48 5/30/00 11:00a Aldie +// Some mods for Circle of Protection powerup +// +// 47 5/16/00 6:24p Markd +// added cg_traceinfo support +// +// 46 5/06/00 3:27p Aldie +// Fix for beam emitters turning off +// +// 45 5/04/00 8:38p Aldie +// Made beam emitters work better +// +// 44 5/04/00 2:38p Aldie +// Fixed warnings +// +// 43 5/04/00 2:30p Aldie +// Fix for beam rendering tex coords +// +// 42 4/21/00 4:10p Markd +// fixed rope rendering +// +// 41 4/10/00 11:44a Markd +// fixed rope rendering +// +// 40 4/10/00 11:16a Markd +// added rope code +// +// 39 3/28/00 3:16p Aldie +// Fixed some beam problems for Pat +// +// 38 3/16/00 3:37p Aldie +// Fixed chceks for multi beam on invalid ents +// +// 37 3/01/00 1:45p Aldie +// Added some more beam functionality for beau. Added taglist to do beam +// chains. +// +// 36 2/25/00 6:19p Aldie +// Changed texture coords on beams +// +// 35 2/15/00 7:04p Aldie +// More beam rendering fixes +// +// 34 2/14/00 7:34p Aldie +// Fixed some beam rendering issues +// +// 33 2/14/00 2:31p Aldie +// Fix for the first point on multibeam rendering (ropes) +// +// 32 1/27/00 11:47a Aldie +// Made beam_t a class +// +// 31 1/26/00 5:07p Aldie +// Removed warning +// +// 30 1/25/00 3:59p Aldie +// Added warning for multibeam +// +// 29 1/24/00 6:19p Aldie +// Fixed tex coords on the beams +// +// 28 1/22/00 12:41p Jimdose +// got rid of calls to vec3() +// +// 27 1/20/00 5:26p Aldie +// Fixed some beam bugs +// +// 26 1/12/00 3:17p Aldie +// Fixed beams so that there may be multiple beams on a model +// +// 25 1/05/00 7:26p Jimdose +// made angle functions all use the same coordinate system +// AngleVectors now returns left instead of right +// no longer need to invert pitch +// +// 24 11/10/99 6:35p Aldie +// Fix to draw the entire beam for ropes +// +// 23 10/29/99 7:16p Aldie +// Updated rope stuff +// +// 22 10/26/99 2:11p Aldie +// Fix beam crash +// +// 21 10/22/99 7:18p Aldie +// Fix for model lightning +// +// 20 10/22/99 6:29p Aldie +// Fix for beams in the sky +// +// 19 10/21/99 2:51p Aldie +// Added some more beam functions +// +// 18 10/20/99 12:20p Aldie +// Cleanup and fix color bug +// +// 17 10/19/99 4:57p Aldie +// More fixes for beams +// +// 16 10/19/99 4:30p Aldie +// Added beam wave effects +// +// 15 10/19/99 12:01p Aldie +// moved a piece of code +// +// 14 10/19/99 11:57a Aldie +// Added some more beam features +// +// 13 10/18/99 1:59p Aldie +// Lots of fixes for beams and stuff +// +// 12 10/14/99 7:19p Aldie +// Fix some beam stuff +// +// 11 10/13/99 3:26p Aldie +// Various fixes for particles, beams and lensflares +// +// 10 10/08/99 5:47p Aldie +// More beam stuff +// +// 9 10/08/99 5:07p Aldie +// More beam stuff and fix for UI_CenterPrint +// +// 8 10/07/99 7:14p Aldie +// more beam stuff (woohoo!) +// +// 7 10/07/99 3:08p Aldie +// more beam fun +// +// 6 10/06/99 3:11p Aldie +// Added more docs to commands +// +// 5 10/05/99 6:01p Aldie +// Added headers +// +// DESCRIPTION: +// Beam effects + +#include "cg_local.h" +#include "vector.h" +#include "container.h" +#include "cg_commands.h" + +class beam_t : public Class + { + public: + beam_t(); + + int entity; + qhandle_t hModel; + int endtime; + Vector start, end; + float scale; + float alpha; + int flags; + int parent; + float max_offset; + float min_offset; + int numSubdivisions; + int overlap; + int beamshader; + byte shaderRGBA[4]; + int update_time; + int delay; + float life; + int numspherebeams; + float sphereradius; + int toggletime; + int toggledelay; + qboolean active; + float alphastep; + int renderfx; + str name; + }; + +beam_t::beam_t() + { + entity=0; + hModel=0; + endtime=0; + scale=0; + alpha=0; + flags=0; + parent=ENTITYNUM_NONE; + max_offset=0; + min_offset=0; + numSubdivisions=0; + overlap=0; + beamshader=0; + update_time=0; + delay=0; + life=0; + numspherebeams=0; + sphereradius=0; + toggletime=0; + toggledelay=0; + active=0; + alphastep=0; + renderfx=0; + memset( shaderRGBA, 0, 4 ); + } + +beam_t cl_beams[MAX_BEAMS]; + +static int seed = 100; + +// Recursive beam builder - I don't use it anymore +/* +void CG_BuildRenderBeam_r + ( + Vector start, + Vector end, + float angleVar, + int numSubdivisions, + int maxSubdivisions + ) + + { + if ( numSubdivisions == maxSubdivisions ) + { + return; + } + else + { + // subdivide line and call on both halves + numSubdivisions += 1; + + mid = ( p1 * 0.5 ) + ( p2 * 0.5 ); + + int seed = 100; + + mid[0] += Q_crandom( &seed ) * angleVar; + mid[1] += Q_crandom( &seed ) * angleVar; + mid[2] += Q_crandom( &seed ) * angleVar; + + CG_BuildRendererBeam( p1, mid, angleVar, numSubdivisions, maxSubdivisions, color, beamshader, scale ); + CG_BuildRendererBeam( mid, p2, angleVar, numSubdivisions, maxSubdivisions, color, beamshader, scale ); + } + } +*/ + +#define MAX_BEAM_BACKUP 6 +#define MAX_BEAM_SEGMENTS 32 + +typedef struct beamSegment_t + { + polyVert_t points[4]; + } beamSegment_t; + +typedef struct beamList_t + { + int time; + int updatetime; + int numsegments; + beamSegment_t segments[MAX_BEAM_SEGMENTS]; + } beamList_t; + +typedef struct beamEnt_t + { + int owner; + int numbeams; + int life; + int renderfx; + beamList_t beamlist[MAX_BEAM_BACKUP]; + } beamEnt_t; + +Container beamManager; + +void RemoveBeamList + ( + int owner + ) + + { + int i,num; + + num = beamManager.NumObjects(); + + for ( i=1; i<=num; i++ ) + { + beamEnt_t *be = beamManager.ObjectAt( i ); + + if ( be->owner == owner ) + { + beamManager.RemoveObjectAt( i ); + delete be; + return; + } + } + } + +beamEnt_t *FindBeamList + ( + int owner + ) + + { + int i,num; + + num = beamManager.NumObjects(); + + for ( i=1; i<=num; i++ ) + { + beamEnt_t *be = beamManager.ObjectAt( i ); + + if ( be->owner == owner ) + return be; + } + return NULL; + } + +int CreateNewBeamEntity + ( + int owner, + float life + ) + + { + beamEnt_t *be; + int i,oldest,oldest_time; + + be = FindBeamList( owner ); + + if ( !be ) + { + be = new beamEnt_t; + + if ( !be ) + cgi.Error( ERR_DROP, "Could not allocate memory for beamEnt.\n" ); + + memset ( be, 0, sizeof( beamEnt_t ) ); + memset ( be->beamlist, 0, sizeof( beamList_t ) * MAX_BEAM_BACKUP ); + be->owner = owner; + be->life = life; + + beamManager.AddObject( be ); + } + + // find the oldest beam and overwrite it. + oldest = -1; + oldest_time = 999999999; + + for ( i=0; ibeamlist[ i ].time; + + if ( !t ) + { + oldest = i; + break; + } + + if ( t < oldest_time ) + { + oldest = i; + oldest_time = t; + } + } + + // Use the oldest beam for the next beam. + be->beamlist[ oldest ].numsegments = 0; + be->beamlist[ oldest ].time = cg.time; + be->beamlist[ oldest ].updatetime = cg.time + be->life; + return oldest; + } + +void RemoveBeamEntity + ( + int owner + ) + + { + RemoveBeamList( owner ); + } + +void AddBeamSegmentToList + ( + int owner, + polyVert_t points[4], + int beamnum, + int segnum, + int renderfx + ) + + { + beamEnt_t *be; + + be = FindBeamList( owner ); + + if ( !be ) + { + cgi.DPrintf( "Could not find beam entity for owner:%d\n", owner ); + return; + } + + if ( segnum >= MAX_BEAM_SEGMENTS ) + return; + + be->renderfx = renderfx; + + // Copy the 4 points + memcpy( &be->beamlist[beamnum].segments[segnum].points, points, 4 * sizeof( polyVert_t ) ); + + // Increase the segment counter + be->beamlist[beamnum].numsegments++; + } + +void CG_AddBeamsFromList + ( + int owner, + int beamshader + ) + + { + int i,j,k,l; + float frac, fade; + beamEnt_t *be = FindBeamList( owner ); + polyVert_t newpoints[4]; + + if ( !be ) + { + return; + } + + for ( i=0; ibeamlist[i]; + + if ( !bl->time ) + continue; + + // Calculate the blend factor for fading + frac = (float)( cg.time - bl->time ) / (float)be->life; + fade = 1.0f - frac; + + if ( fade <= 0 ) + { + bl->time = 0; // RemoveBeamList( owner ); + continue; + } + + // Go through each segment and draw it with the new modulate + assert( bl->numsegments < MAX_BEAM_SEGMENTS ); + + for ( j=0; jnumsegments; j++ ) + { + memcpy( newpoints, bl->segments[j].points, 4 * sizeof( polyVert_t ) ); + + for ( k=0; k<4; k++ ) + { + for ( l=0; l<4; l++ ) + { + newpoints[k].modulate[l] = bl->segments[j].points[k].modulate[l] * fade; + } + } + + cgi.R_AddPolyToScene( beamshader, 4, newpoints, be->renderfx ); + } + } + } + +void RenderSegment + ( + Vector pt1a, + Vector pt1b, + Vector pt2a, + Vector pt2b, + byte modulate[4], + int beamshader, + int renderfx + ) + + { + int i,j; + polyVert_t points[4]; + + VectorCopy( pt1a, points[0].xyz ); + VectorCopy( pt2a, points[1].xyz ); + VectorCopy( pt2b, points[2].xyz ); + VectorCopy( pt1b, points[3].xyz ); + + points[0].st[0] = 1; points[0].st[1] = 1; + points[1].st[0] = 0; points[1].st[1] = 1; + points[2].st[0] = 0; points[2].st[1] = 0; + points[3].st[0] = 1; points[3].st[1] = 0; + + // Set the color of the verts + for ( i=0; i<4; i++ ) + { + for ( j=0; j<4; j++ ) + { + points[i].modulate[j] = modulate[j]; + } + } + + // Add a segment to the list + cgi.R_AddPolyToScene( beamshader, 4, points, renderfx ); + } + +const int MAX_SUBPOINTS=256; +static Vector subpoints[MAX_SUBPOINTS]; +static int ptctr=0; +/* +=============== +CG_Subdivide + +a, b, and c are control points. +the subdivided sequence will be: a, out1, out2, out3, c +=============== +*/ +static void CG_Subdivide( Vector a, Vector b, Vector c, Vector &out1, Vector &out2, Vector &out3 ) + { + out1 = 0.5 * (a + b); + out3 = 0.5 * (b + c); + out2 = 0.5 * (out1 + out3); + } + +void CG_MultiBeamBegin + ( + void + ) + + { + ptctr = 0; + } + +void CG_MultiBeamAddPoints + ( + vec3_t start, + vec3_t end, + int numsegments, + int flags, + float minoffset, + float maxoffset, + qboolean addstartpoint + ) + + { + Vector delta,dir,randdir; + float length; + int i; + + if ( ptctr > MAX_SUBPOINTS ) + return; + + if ( addstartpoint ) + { + subpoints[ ptctr++ ] = start; + } + + delta = Vector( end ) - Vector( start ); + length = delta.length(); + length /= numsegments; + + // get the dir of beam + dir = delta; + dir.normalize(); + + for ( i=1; i MAX_SUBPOINTS ) + return; + + randdir = Vector( crandom(), crandom(), crandom() ); + + newpt = Vector( start ) + dir * i * length; + newpt += minoffset * randdir + maxoffset * randdir; + + subpoints[ ptctr++ ] = newpt; + } + subpoints[ ptctr++ ] = end; + } + +void CG_MultiBeamEnd + ( + float scale, + int renderfx, + const char *beamshadername, + byte modulate[4], + int flags, + int owner, + float life + ) + + { + Vector prevpt,currpt; + Vector p1,p2,p3,p4,v1,v2,up,currpt1,currpt2,prevpt1,prevpt2; + qboolean prevptvalid=false; + int i,beamshader; + + beamshader = cgi.R_RegisterShader( beamshadername ); + + prevpt = subpoints[0]; + prevptvalid = false; + + for ( i=1; icurrentState.tag_num == ENTITYNUM_NONE ) + { + cgi.DPrintf( "CG_MultiBeamSubdivide : Multi beam entity does not have a child\n" ); + return; + } + pt1 = current->lerpOrigin; + + // Get pt2 + current = &cg_entities[ current->currentState.tag_num ]; + // Make sure that child is a multibeam + if ( current->currentState.eType != ET_MULTIBEAM ) + return; + + if ( current->currentState.tag_num == ENTITYNUM_NONE ) + { + cgi.DPrintf( "CG_MultiBeamSubdivide : Multi beam entity does not have a child\n" ); + return; + } + pt2 = current->lerpOrigin; + + // Get pt3 + current = &cg_entities[ current->currentState.tag_num ]; + // Make sure that child is a multibeam + if ( current->currentState.eType != ET_MULTIBEAM ) + { + return; + } + + if ( current->currentState.tag_num == ENTITYNUM_NONE ) + { + cgi.DPrintf( "CG_MultiBeamSubdivide : Multi beam entity does not have a child\n" ); + return; + } + pt3 = current->lerpOrigin; + + // First point into the subdivided points + subpoints[ptctr++] = pt1; + + while ( 1 ) + { + // Do the subdivide + CG_Subdivide( pt1, pt2, pt3, out1, out2, out3 ); + CG_Subdivide( pt1, out1, out2, out4, out5, out6 ); + + if ( ( ptctr + 4 ) > MAX_SUBPOINTS ) + break; + + // Save the points + subpoints[ptctr++] = out4; + subpoints[ptctr++] = out5; + subpoints[ptctr++] = out6; + subpoints[ptctr++] = out2; + + // end condition + if ( ( current->currentState.tag_num == ENTITYNUM_NONE ) || ( !current->currentValid ) ) + { + CG_Subdivide( out2, out3, pt3, out7, out8, out9 ); + subpoints[ptctr++] = out7; + subpoints[ptctr++] = out8; + subpoints[ptctr++] = out9; + subpoints[ptctr++] = pt3; + break; + } + + // Advance to next ent + current = &cg_entities[ current->currentState.tag_num ]; + + if ( !current->currentValid ) + { + break; + } + + // Advance the points down the line + pt1 = out2; + pt2 = pt3; + pt3 = current->lerpOrigin; + } + } + + +void CG_MultiBeam + ( + centity_t *cent + ) + + { + Vector prevpt,currpt; + entityState_t *s1; + Vector p1,p2,p3,p4,v1,v2,up,currpt1,currpt2,prevpt1,prevpt2; + const char *beamshadername; + int beamshader; + byte modulate[4]; + qboolean prevptvalid=false; + int i; + + s1 = ¢->currentState; + + // If this isn't the parent of the beam, then return + if ( !s1->surfaces[0] ) + { + return; + } + + // Subdivide up the segments + CG_MultiBeamSubdivide( cent ); + + // This is the top of the beam ent list, build up a renderer beam based on all the children + beamshadername = CG_ConfigString( CS_IMAGES + s1->surfaces[1] ); // index for shader configstring + beamshader = cgi.R_RegisterShader( beamshadername ); + //beamshader = cgi.R_RegisterShader( "" ); + for ( i=0;i<4;i++ ) + modulate[i] = cent->color[i] * 255; + + if ( ptctr < 3 ) + { + return; + } + + prevpt = subpoints[0]; + prevptvalid = false; + + for ( i=1; iscale ); + currpt2 = currpt + ( up * -s1->scale ); + + if ( !prevptvalid ) + { + prevpt1 = prevpt + up * s1->scale; + prevpt2 = prevpt + up * -s1->scale; + prevptvalid = true; + } + + RenderSegment( currpt1, currpt2, prevpt1, prevpt2, modulate, beamshader, s1->renderfx ); + + prevpt = currpt; + prevpt1 = currpt1; + prevpt2 = currpt2; + } + } + +void CG_BuildRendererBeam + ( + Vector start, + Vector end, + float angleVar, + int numSubdivisions, + byte color[4], + int beamshader, + float scale, + float overlap, + int owner, + float life, + int flags, + float startalpha, + float alphastep, + int renderfx + ) + { + Vector p1, p2, v1, v2, dir, prevpt1, prevpt2, nextpt, mid, delta, up; + int i,ii,jj; + polyVert_t points[4]; + float length; + int segnum = 0; + int beamnum = 0; + float alphafactor; + int picW; + + // Create or increment the number of beams for this owner and check to + // see if we should add a new beam + if ( flags & BEAM_PERSIST_EFFECT ) + { + beamnum = CreateNewBeamEntity( owner, life ); + if ( beamnum < 0 ) + return; + } + + // For debugging texture coords + //beamshader = cgi.R_RegisterShader( "" ); + + picW = cgi.R_GetShaderWidth( beamshader ); + + // calcluate length of beam segment + delta = end-start; + length = delta.length(); + length /= numSubdivisions; + + // get the dir of beam + dir = delta; + dir.normalize(); + + // Calculate the first up vector + v1 = start - cg.refdef.vieworg; + v2 = end - cg.refdef.vieworg; + up.CrossProduct( v1, v2 ); + up.normalize(); + + // Calculate the first points + prevpt1 = start + ( up * scale ); + prevpt2 = start + ( up * -scale ); + p1 = start; + + // go through and calculate each point of the beam and offset it by the anglevar + for ( i=1; i<=numSubdivisions; i++ ) + { + // Calculate the next point along the beam + p2 = start + ( dir * i * length ); + + // Random variance on the next point ( except if it's the last ) + if ( i != numSubdivisions ) + { + if ( flags & BEAM_WAVE_EFFECT ) + { + float phase = p2.x + p2.y; + p2.z += sin( phase + cg.time ) * angleVar; + } + else if ( flags & BEAM_USE_NOISE ) + { + p2.x += cgi.R_Noise( p2.x,p2.y,p2.z,cg.time ) * angleVar; + p2.y += cgi.R_Noise( p2.x,p2.y,p2.z,cg.time ) * angleVar; + p2.z += cgi.R_Noise( p2.x,p2.y,p2.z,cg.time ) * angleVar; + } + else + { + p2.x += Q_crandom( &seed ) * angleVar; + p2.y += Q_crandom( &seed ) * angleVar; + p2.z += Q_crandom( &seed ) * angleVar; + } + } + + // Create the up vec for the beam which is parallel to the viewplane + v1 = p1 - cg.refdef.vieworg; + v2 = p2 - cg.refdef.vieworg; + up.CrossProduct( v1, v2 ); + up.normalize(); + + // Build the quad + VectorMA( p2, scale, up, points[0].xyz ); + VectorCopy( prevpt1, points[1].xyz ); + VectorCopy( prevpt2, points[2].xyz ); + VectorMA( p2, -scale, up, points[3].xyz ); + + if ( flags & BEAM_TILESHADER ) // Tile the shader across the beam + { + float startS = ( length * ( i-1 ) ) / (float)picW; + float endS = ( length * ( i ) ) / (float)picW; + + points[0].st[0] = startS; points[0].st[1] = 1; + points[1].st[0] = endS; points[1].st[1] = 1; + points[2].st[0] = endS; points[2].st[1] = 0; + points[3].st[0] = startS; points[3].st[1] = 0; + } + else + { + points[0].st[0] = 1; points[0].st[1] = 1; + points[1].st[0] = 0; points[1].st[1] = 1; + points[2].st[0] = 0; points[2].st[1] = 0; + points[3].st[0] = 1; points[3].st[1] = 0; + } + + + if ( !alphastep ) + alphafactor = 1.0f; + else + alphafactor = startalpha + (alphastep * i); + + // Set the color of the verts + for ( ii=0; ii<4; ii++ ) + { + for ( jj=0; jj<4; jj++ ) + { + points[ii].modulate[jj] = color[jj] * alphafactor; + } + } + + if ( flags & BEAM_PERSIST_EFFECT ) + { + // Save the segment for backup for drawing faded out + AddBeamSegmentToList( owner, points, beamnum, segnum++, renderfx ); + } + else + { + // Add it to the ref + cgi.R_AddPolyToScene( beamshader, 4, points, renderfx ); + } + + + // Subtract off the overlap + if ( overlap ) + { + p2 = p2 + ( dir * -overlap ); + } + + // Save off the last point to use as the first point on the next quad + VectorMA( p2, scale, up, prevpt1 ); + VectorMA( p2, -scale, up, prevpt2 ); + p1 = p2; + } + } + +void CG_CreateModelBeam + ( + beam_t *b, + vec3_t org, + vec3_t dist, + float total_length, + vec3_t ndir, + vec3_t left, + vec3_t up + ) + + { + int tikihandle; + vec3_t mins,maxs; + int single_beam_length; + refEntity_t ent; + int count; + int j; + float factor[3]; + float t; + vec3_t angles; + int i; + + // Find the length of a single beam + tikihandle = cgi.TIKI_GetHandle( b->hModel ); + + // Calculate the bounds of the model to get it's length + cgi.CalculateBounds( tikihandle, 1.0, mins, maxs); + single_beam_length = maxs[0] - mins[0]; + + // Create the beam entity + memset (&ent, 0, sizeof(ent)); + count = 0; + + // Initialize the factors + for ( j=0; j<3; j++) + factor[j] = 0.3f * crandom(); + + t = 0; + + while ( t >= 0 && t < 1 ) + { + float dot; + vec3_t pdir; + float delta; + vec3_t distance_point; + + count++; + + // Set the origin of the current beam using the last calculated org + VectorCopy( org, ent.origin ); + + // Advance the org one beam length in the new direction ( dist is the newly calculated direction ) + for ( j=0 ; j<3 ; j++ ) + org[j] += dist[j] * ( single_beam_length - b->overlap ); + + // Offset the org by a random amount to simulate lightning + + VectorMA( org, single_beam_length * factor[2], up, org ); + VectorMA( org, single_beam_length * factor[1], left, org ); + + // Calculate (t) - how far this new point is along the overall distance + VectorSubtract( org, b->start, pdir ); + dot = DotProduct( pdir, ndir ); + t = dot/total_length; + + // Calculate point at current distance along center beam + VectorMA( b->start, total_length * t, ndir, distance_point ); + + // Allow any variations + if ( t > 0.1 && t < 0.9 ) + { + for ( j=0; j<3; j++ ) + { + delta = org[j] - distance_point[j]; + if ( delta > b->max_offset ) + { + org[j] = distance_point[j] + b->max_offset; + factor[j] = -0.3 * crandom(); + } + else if ( delta < -b->max_offset ) + { + org[j] = distance_point[j] - b->max_offset; + factor[j] = 0.3 * crandom(); + } + else + factor[j] = 0.3 * crandom(); + } + } + else // Clamp to mins + { + for ( j=0; j<3; j++ ) + { + delta = org[j] - distance_point[j]; + if ( delta > b->min_offset ) + { + org[j] -= 0.4 * single_beam_length; + factor[j] = -0.2; + } + else if ( delta < -b->min_offset ) + { + org[j] += 0.4 * single_beam_length; + factor[j] = 0.2; + } + else + factor[j] = 0; + } + } + + // Calculate the new dist vector so we can get pitch and yaw for this beam + VectorSubtract (org, ent.origin, dist); + + // Set the pitch and the yaw based off this new vector + vectoangles( dist, angles ); + + // Fill in the ent fields + ent.hModel = b->hModel; + ent.scale = b->scale; + ent.renderfx = b->renderfx; + + for( i=0; i<4; i++ ) + ent.shaderRGBA[i] = b->shaderRGBA[i]; + + VectorCopy(ent.origin, ent.oldorigin); + AnglesToAxis( angles, ent.axis ); + + // Add in this beam to the ref + cgi.R_AddRefEntityToScene( &ent ); + } + } + +void CG_AddBeams + ( + void + ) + + { + int i,ii; + beam_t *b; + vec3_t delta; + vec3_t angles; + vec3_t forward, left, up; + float length; + byte color[4]; + float fade; + + for (i=0, b=cl_beams ; ihModel || b->endtime < cg.time ) + { + // Make sure endtime is not 0, and remove the beam entirely + if ( b->endtime ) + { + RemoveBeamList( b->entity ); + b->entity = ENTITYNUM_NONE; + b->endtime = 0; + } + continue; + } + + // Fade the beam based on it's life + fade = (float)( b->endtime - cg.time ) / (float) b->life; + + for ( ii=0; ii<4; ii++ ) + color[ii] = b->shaderRGBA[ii] * fade; + + // Check to see if the beam should be toggled + if ( b->flags & BEAM_TOGGLE ) + { + if ( cg.time > b->toggletime ) + { + b->active = !b->active; + if ( b->flags & BEAM_RANDOM_TOGGLEDELAY ) + b->toggletime = cg.time + random() * b->toggledelay; + else + b->toggletime = cg.time + b->toggledelay; + } + } + + if ( !b->active ) + { + CG_AddBeamsFromList( b->entity, b->beamshader ); + continue; + } + + if ( ( b->flags & BEAM_PERSIST_EFFECT ) && ( b->update_time > cg.time ) ) + { + CG_AddBeamsFromList( b->entity, b->beamshader ); + continue; + } + + b->update_time = cg.time + b->delay; + + if ( !b->active ) + continue; + + if ( b->flags & BEAM_USEMODEL ) + { + // Calculate the direction + VectorSubtract( b->start, b->end, delta ); + + // Calculate the beam length + length = VectorLength( delta ); + + // Get the perpendicular vectors to this vector + vectoangles( delta, angles ); + AngleVectors( angles, forward, left, up ); + CG_CreateModelBeam( b, b->start, delta, length, forward, left, up ); + } + else + { + // Do a sphere effect + if ( b->flags & BEAM_SPHERE_EFFECT ) + { + int k; + + // Calculate the direction + VectorSubtract( b->start, b->end, delta ); + + // Calculate the beam length + length = VectorLength( delta ); + + for( k=0; knumspherebeams; k++ ) + { + Vector offset( crandom(), crandom(), crandom() ); + Vector start( b->start + offset * b->sphereradius ); + Vector end( b->start + offset * length ); + + CG_BuildRendererBeam( start, + end, + b->max_offset, + b->numSubdivisions, + color, + b->beamshader, + b->scale, + b->overlap, + b->entity, + b->life, + b->flags, + b->alpha, + b->alphastep, + b->renderfx + ); + + } + } + else + { + //cgi.DPrintf( "%2f %2f %2f\n", b->start[0],b->start[1],b->start[2] ); + CG_BuildRendererBeam( b->start, + b->end, + b->max_offset, + b->numSubdivisions, + color, + b->beamshader, + b->scale, + b->overlap, + b->entity, + b->life, + b->flags, + b->alpha, + b->alphastep, + b->renderfx + ); + } + if ( b->flags & BEAM_PERSIST_EFFECT ) + CG_AddBeamsFromList( b->entity, b->beamshader ); + } + } + } + +void CG_CreateBeam + ( + vec3_t start, + vec3_t dir, + int owner, + qhandle_t hModel, + float alpha, + float scale, + int flags, + float length, + int life, + qboolean create, + vec3_t endpointvec, + int min_offset, + int max_offset, + int overlap, + int numSubdivisions, + int delay, + const char *beamshadername, + byte modulate[4], + int numspherebeams, + float sphereradius, + int toggledelay, + float endalpha, + int renderfx, + const char *name + ) + + { + int i; + beam_t *b; + vec3_t end; + trace_t trace; + + // Check to see if endpoint is specified + if ( endpointvec ) + { + VectorCopy( endpointvec, end ); + } + else + { + // Trace to find the endpoint with a shot + VectorMA( start, length, dir, end ); + CG_Trace( &trace,start, vec3_origin, vec3_origin, end, 0, MASK_SHOT, false, true, "Create Beam" ); + VectorCopy( trace.endpos, end ); + } + + // If we aren't creating a beam, then search the beams for this one already active + if ( !create ) + { + for ( i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++ ) + { + if ( b->entity == owner ) + { + if ( name && b->name == name ) + { + b->endtime = cg.time + life; + b->hModel = hModel; + b->scale = scale; + b->flags = flags; + b->overlap = overlap; + b->min_offset = min_offset; + b->max_offset = max_offset; + b->alpha = alpha; + b->beamshader = cgi.R_RegisterShader( beamshadername ); + b->numSubdivisions = numSubdivisions; + b->delay = delay; + b->life = life; + b->numspherebeams = numspherebeams; + b->sphereradius = sphereradius; + b->renderfx = renderfx; + + // take the alpha from the entity if less than 1, else grab it from the client commands version + if ( alpha < 1 ) + b->shaderRGBA[ 3 ] = alpha * 255; + else + b->shaderRGBA[ 3 ] = modulate[3]; + + // Modulation based off the color + for( i=0; i<3; i++ ) + b->shaderRGBA[ i ] = modulate[ i ] * ( (float)b->shaderRGBA[3] / 255.0f ); + + b->alphastep = ( (float)( endalpha - alpha ) / (float)b->numSubdivisions ); + + VectorCopy( start, b->start ); + VectorCopy( end, b->end ); + return; + } + } + } + } + + // find a free beam + for ( i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++ ) + { + if ( b->endtime < cg.time ) + { + b->entity = owner; + b->endtime = cg.time + life; + b->hModel = hModel; + b->alpha = alpha; + b->scale = scale; + b->flags = flags; + b->overlap = overlap; + b->min_offset = min_offset; + b->max_offset = max_offset; + b->beamshader = cgi.R_RegisterShader( beamshadername ); + b->numSubdivisions = numSubdivisions; + b->delay = delay; + b->update_time = 0;//cg.time + delay; + b->life = life; + b->numspherebeams = numspherebeams; + b->sphereradius = sphereradius; + b->active = true; + b->toggledelay = toggledelay; + b->renderfx = renderfx; + b->name = name; + + // take the alpha from the entity if less than 1, else grab it from the client commands version + if ( alpha < 1 ) + b->shaderRGBA[ 3 ] = alpha * 255; + else + b->shaderRGBA[ 3 ] = modulate[ 3 ]; + + // Modulation based off the color + for( i=0; i<3; i++ ) + b->shaderRGBA[ i ] = modulate[ i ] * ( (float)b->shaderRGBA[3] / 255.0f ); + + + b->alphastep = ( (float)( endalpha - alpha ) / (float)b->numSubdivisions ); + + VectorCopy( start, b->start ); + VectorCopy( end, b->end ); + return; + } + } + return; + } + +void CG_KillBeams + ( + int entity_number + ) + + { + int i; + beam_t *b; + + for ( i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++ ) + { + if ( b->entity == entity_number ) + { + b->entity = ENTITYNUM_NONE; + b->endtime = 0; + } + } + } + +void CG_RestartBeams + ( + int timedelta + ) + + { + int i; + beam_t *b; + + for ( i=0, b=cl_beams ; i< MAX_BEAMS ; i++, b++ ) + { + if ( b->active && ( b->update_time > cg.time ) ) + { + b->endtime -= timedelta; + b->update_time -= timedelta; + if ( b->toggletime ) + b->toggletime -= timedelta; + } + } + } + + +void CG_Rope + ( + centity_t *cent + ) + + { + Vector prevpt,currpt; + entityState_t *s1; + Vector top, mid, bottom, up, v1, v2; + Vector currpt1, currpt2, prevpt1, prevpt2; + const char *beamshadername; + int beamshader; + byte modulate[4]; + float picH, length, endT; + int i,j; + polyVert_t points[4]; + + + s1 = ¢->currentState; + + top = s1->origin2; + mid = cent->lerpOrigin; + bottom = cent->lerpOrigin; + bottom.z -= s1->alpha; + + // This is the top of the beam ent list, build up a renderer beam based on all the children + beamshadername = CG_ConfigString( CS_IMAGES + s1->surfaces[0] ); // index for shader configstring + beamshader = cgi.R_RegisterShader( beamshadername ); + + picH = cgi.R_GetShaderHeight( beamshader ); + + for ( i=0;i<4;i++ ) + modulate[i] = cent->color[i] * 255; + + // Generate the up vector + v1 = top - cg.refdef.vieworg; + v2 = bottom - cg.refdef.vieworg; + + up.CrossProduct( v1, v2 ); + up.normalize(); + + // Set the color of the verts + for ( i=0; i<4; i++ ) + { + for ( j=0; j<4; j++ ) + { + points[i].modulate[j] = modulate[j]; + } + } + // set the s coordinates + points[0].st[0] = 1; + points[1].st[0] = 1; + points[2].st[0] = 0; + points[3].st[0] = 0; + + // Calculate the first points + prevpt1 = top + ( up * s1->scale ); + prevpt2 = top + ( up * -s1->scale ); + + // draw the top section + currpt1 = mid + ( up * s1->scale ); + currpt2 = mid + ( up * -s1->scale ); + + length = Vector( mid - top ).length(); + + VectorCopy( currpt1, points[0].xyz ); + VectorCopy( prevpt1, points[1].xyz ); + VectorCopy( prevpt2, points[2].xyz ); + VectorCopy( currpt2, points[3].xyz ); + + endT = length / picH; + points[0].st[1] = endT; + points[3].st[1] = endT; + points[1].st[1] = 0; + points[2].st[1] = 0; + + // Add a segment to the list + cgi.R_AddPolyToScene( beamshader, 4, points, s1->renderfx ); + + if ( s1->alpha > 0 ) + { + // draw the bottom section + prevpt1 = currpt1; + prevpt2 = currpt2; + currpt1 = bottom + ( up * s1->scale ); + currpt2 = bottom + ( up * -s1->scale ); + VectorCopy( currpt1, points[0].xyz ); + VectorCopy( prevpt1, points[1].xyz ); + VectorCopy( prevpt2, points[2].xyz ); + VectorCopy( currpt2, points[3].xyz ); + + // add on the rest of the rope + length += s1->alpha; + + // use previous T value for the start of this segment + points[1].st[1] = endT; + points[2].st[1] = endT; + endT = length / picH; + points[0].st[1] = endT; + points[3].st[1] = endT; + + // Add a segment to the list + cgi.R_AddPolyToScene( beamshader, 4, points, s1->renderfx ); + } + } diff --git a/source/source/cgame/cg_class.cpp b/source/source/cgame/cg_class.cpp new file mode 100644 index 0000000..3938f0c --- /dev/null +++ b/source/source/cgame/cg_class.cpp @@ -0,0 +1,581 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/cgame/cg_class.cpp $ +// $Revision:: 2 $ +// $Author:: Aldie $ +// $Date:: 9/10/99 5:24p $ +// +// Copyright (C) 1997 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source is may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/cgame/cg_class.cpp $ +// +// 2 9/10/99 5:24p Aldie +// Merge code +// +// 1 9/10/99 10:48a Jimdose +// +// 2 9/09/99 3:29p Aldie +// Merge +// +// 1 9/08/99 3:35p Aldie +// +// 3 7/29/99 3:32p Aldie +// Updated to new class system +// +// DESCRIPTION: +// Base class that all classes that are used in conjunction with Sin should +// be based off of. Class gives run-time type information about any class +// derived from it. This is really handy when you have a pointer to an object +// that you need to know if it supports certain behaviour. +// + +#include +#include +#include +#include "cg_class.h" +#include "cg_listener.h" +#include "../fgame/linklist.h" +#include "../qcommon/qcommon.h" +#include "cg_local.h" + +int totalmemallocated = 0; +int numclassesallocated = 0; + +static ClassDef *classlist = NULL; + +ClassDef::ClassDef() + { + this->classname = NULL; + this->classID = NULL; + this->superclass = NULL; + this->responses = NULL, + this->numEvents = 0; + this->responseLookup = NULL; + this->newInstance = NULL; + this->classSize = 0; + this->super = NULL; + this->prev = this; + this->next = this; + } + +ClassDef::ClassDef + ( + const char *classname, + const char *classID, + const char *superclass, + ResponseDef *responses, + void *( *newInstance )( void ), + int classSize + ) + + { + ClassDef *node; + + if ( classlist == NULL ) + { + classlist = new ClassDef; + } + + this->classname = classname; + this->classID = classID; + this->superclass = superclass; + this->responses = responses; + this->numEvents = 0; + this->responseLookup = NULL; + this->newInstance = newInstance; + this->classSize = classSize; + this->super = getClass( superclass ); + + // It's not uncommon for classes to not have a class id, so just set it + // to an empty string so that we're not checking for it all the time. + if ( !classID ) + { + this->classID = ""; + } + + // Check if any subclasses were initialized before their superclass + for( node = classlist->next; node != classlist; node = node->next ) + { + if ( ( node->super == NULL ) && ( !Q_stricmp( node->superclass, this->classname ) ) && + ( Q_stricmp( node->classname, "Class" ) ) ) + { + node->super = this; + } + } + + // Add to front of list + LL_Add( classlist, this, prev, next ); + } + +ClassDef::~ClassDef() + { + ClassDef *node; + + if ( classlist != this ) + { + LL_Remove( this, prev, next ); + + // Check if any subclasses were initialized before their superclass + for( node = classlist->next; node != classlist; node = node->next ) + { + if ( node->super == this ) + { + node->super = NULL; + } + } + } + else + { + // If the head of the list is deleted before the list is cleared, then we may have problems + assert( this->next == this->prev ); + } + + if ( responseLookup ) + { + delete[] responseLookup; + responseLookup = NULL; + } + } + +void ClassDef::BuildResponseList + ( + void + ) + + { + ClassDef *c; + ResponseDef *r; + int ev; + int i; + qboolean *set; + int num; + + if ( responseLookup ) + { + delete[] responseLookup; + responseLookup = NULL; + } + + num = Event::NumEventCommands(); + responseLookup = ( Response ** )new char[ sizeof( Response * ) * num ]; + memset( responseLookup, 0, sizeof( Response * ) * num ); + + set = new qboolean[ num ]; + memset( set, 0, sizeof( qboolean ) * num ); + + this->numEvents = num; + + for( c = this; c != NULL; c = c->super ) + { + r = c->responses; + if ( r ) + { + for( i = 0; r[ i ].event != NULL; i++ ) + { + ev = ( int )*r[ i ].event; + if ( !set[ ev ] ) + { + set[ ev ] = qtrue; + if ( r[ i ].response ) + { + responseLookup[ ev ] = &r[ i ].response; + } + else + { + responseLookup[ ev ] = NULL; + } + } + } + } + } + + delete[] set; + } + +void BuildEventResponses + ( + void + ) + + { + ClassDef *c; + int amount; + int numclasses; + + amount = 0; + numclasses = 0; + for( c = classlist->next; c != classlist; c = c->next ) + { + c->BuildResponseList(); + + amount += c->numEvents * sizeof( Response * ); + numclasses++; + } + + cgi.Printf( "\n------------------\nEvent system initialized:\n" + "%d classes\n%d events\n%d total memory in response list\n\n", + numclasses, Event::NumEventCommands(), amount ); + } + +ClassDef *getClassForID + ( + const char *name + ) + + { + ClassDef *c; + + for( c = classlist->next; c != classlist; c = c->next ) + { + if ( c->classID && !Q_stricmp( c->classID, name ) ) + { + return c; + } + } + + return NULL; + } + +ClassDef *getClass + ( + const char *name + ) + + { + ClassDef *c; + + for( c = classlist->next; c != classlist; c = c->next ) + { + if ( !Q_stricmp( c->classname, name ) ) + { + return c; + } + } + + return NULL; + } + +ClassDef *getClassList + ( + void + ) + + { + return classlist; + } + +void listAllClasses + ( + void + ) + + { + ClassDef *c; + + for( c = classlist->next; c != classlist; c = c->next ) + { + cgi.Printf( "%s\n", c->classname ); + } + } + +void listInheritanceOrder + ( + const char *classname + ) + + { + ClassDef *cls; + ClassDef *c; + + cls = getClass( classname ); + if ( !cls ) + { + cgi.Printf( "Unknown class: %s\n", classname ); + return; + } + for( c = cls; c != NULL; c = c->super ) + { + cgi.Printf( "%s\n", c->classname ); + } + } + +qboolean checkInheritance + ( + ClassDef *superclass, + ClassDef *subclass + ) + + { + ClassDef *c; + + for( c = subclass; c != NULL; c = c->super ) + { + if ( c == superclass ) + { + return qtrue; + } + } + return qfalse; + } + +qboolean checkInheritance + ( + ClassDef *superclass, + const char *subclass + ) + + { + ClassDef *c; + + c = getClass( subclass ); + if ( c == NULL ) + { + cgi.Printf( "Unknown class: %s\n", subclass ); + return qfalse; + } + return checkInheritance( superclass, c ); + } + +qboolean checkInheritance + ( + const char *superclass, + const char *subclass + ) + + { + ClassDef *c1; + ClassDef *c2; + + c1 = getClass( superclass ); + c2 = getClass( subclass ); + if ( c1 == NULL ) + { + cgi.Printf( "Unknown class: %s\n", superclass ); + return qfalse; + } + if ( c2 == NULL ) + { + cgi.Printf( "Unknown class: %s\n", subclass ); + return qfalse; + } + return checkInheritance( c1, c2 ); + } + +CLASS_DECLARATION( NULL, Class, NULL ) + { + { NULL, NULL } + }; + +#ifdef NDEBUG + +void * Class::operator new( size_t s ) + { + int *p; + + s += sizeof( int ); + p = ( int * )::new char[ s ]; + *p = s; + totalmemallocated += s; + numclassesallocated++; + return p + 1; + } + +void Class::operator delete( void *ptr ) + { + int *p; + + p = ( ( int * )ptr ) - 1; + totalmemallocated -= *p; + numclassesallocated--; + ::delete[]( p ); + } + +#else + +void * Class::operator new( size_t s ) + { + int *p; + + s += sizeof( int ) * 3; + p = ( int * )::new char[ s ]; + p[ 0 ] = 0x12348765; + *( int * )( ((byte *)p) + s - sizeof( int ) ) = 0x56784321; + p[ 1 ] = s; + totalmemallocated += s; + numclassesallocated++; + return p + 2; + } + +void Class::operator delete( void *ptr ) + { + int *p; + + p = ( ( int * )ptr ) - 2; + + assert( p[ 0 ] == 0x12348765 ); + assert( *( int * )( ((byte *)p) + p[ 1 ] - sizeof( int ) ) == 0x56784321 ); + + totalmemallocated -= p[ 1 ]; + numclassesallocated--; + ::delete[]( p ); + } + +#endif + +void DisplayMemoryUsage + ( + void + ) + + { + cgi.Printf( "Classes %-5d Class memory used: %d\n", numclassesallocated, totalmemallocated ); + } + +Class::Class() + { + SafePtrList = NULL; + } + +Class::~Class() + { + while( SafePtrList != NULL ) + { + SafePtrList->Clear(); + } + } + +void Class::warning + ( + const char *function, + const char *fmt, + ... + ) + + { + va_list argptr; + char text[ 1024 ]; + + va_start( argptr, fmt ); + vsprintf( text, fmt, argptr ); + va_end( argptr ); + + if ( getClassID() ) + { + cgi.Printf( "%s::%s : %s\n", getClassID(), function, text ); + } + else + { + cgi.Printf( "%s::%s : %s\n", getClassname(), function, text ); + } + } + +void Class::error + ( + const char *function, + const char *fmt, + ... + ) + + { + va_list argptr; + char text[ 1024 ]; + + va_start( argptr, fmt ); + vsprintf( text, fmt, argptr ); + va_end( argptr ); + + if ( getClassID() ) + { + cgi.Error( ERR_DROP, "%s::%s : %s\n", getClassID(), function, text ); + } + else + { + cgi.Error( ERR_DROP, "%s::%s : %s\n", getClassname(), function, text ); + } + } + +qboolean Class::inheritsFrom + ( + const char *name + ) + + { + ClassDef *c; + + c = getClass( name ); + if ( c == NULL ) + { + cgi.Printf( "Unknown class: %s\n", name ); + return qfalse; + } + return checkInheritance( c, classinfo() ); + } + +qboolean Class::isInheritedBy + ( + const char *name + ) + + { + ClassDef *c; + + c = getClass( name ); + if ( c == NULL ) + { + cgi.Printf( "Unknown class: %s\n", name ); + return qfalse; + } + return checkInheritance( classinfo(), c ); + } + +const char *Class::getClassname + ( + void + ) + + { + ClassDef *cls; + + cls = classinfo(); + return cls->classname; + } + +const char *Class::getClassID + ( + void + ) + + { + ClassDef *cls; + + cls = classinfo(); + return cls->classID; + } + +const char *Class::getSuperclass + ( + void + ) + + { + ClassDef *cls; + + cls = classinfo(); + return cls->superclass; + } + +void *Class::newInstance + ( + void + ) + + { + ClassDef *cls; + + cls = classinfo(); + return cls->newInstance(); + } diff --git a/source/source/cgame/cg_class.h b/source/source/cgame/cg_class.h new file mode 100644 index 0000000..cd10fb7 --- /dev/null +++ b/source/source/cgame/cg_class.h @@ -0,0 +1,402 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/cgame/cg_class.h $ +// $Revision:: 1 $ +// $Author:: Jimdose $ +// $Date:: 9/10/99 10:48a $ +// +// Copyright (C) 1997 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source is may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/cgame/cg_class.h $ +// +// 1 9/10/99 10:48a Jimdose +// +// 1 9/08/99 3:35p Aldie +// +// 2 7/29/99 3:32p Aldie +// Updated to new class system +// +// DESCRIPTION: +// Base class that all classes that are used in conjunction with Sin should +// be based off of. Class gives run-time type information about any class +// derived from it. This is really handy when you have a pointer to an object +// that you need to know if it supports certain behaviour. +// + +#ifndef __CG_CLASS_H__ +#define __CG_CLASS_H__ + +#include "../fgame/q_shared.h" +#include "../fgame/linklist.h" + +class Class; +class Event; + +typedef void ( Class::*Response )( Event *event ); + +template< class Type > +struct ResponseDef + { + Event *event; + void ( Type::*response )( Event *event ); + }; + +/*********************************************************************** + + ClassDef + +***********************************************************************/ + +class ClassDef + { + public: + const char *classname; + const char *classID; + const char *superclass; + void *( *newInstance )( void ); + int classSize; + ResponseDef *responses; + int numEvents; + Response **responseLookup; + ClassDef *super; + ClassDef *next; + ClassDef *prev; + + ClassDef(); + ~ClassDef(); + ClassDef( const char *classname, const char *classID, const char *superclass, + ResponseDef *responses, void *( *newInstance )( void ), int classSize ); + void BuildResponseList( void ); + }; + +/*********************************************************************** + + SafePtr + +***********************************************************************/ + +class SafePtrBase; + +class Class; + +class SafePtrBase + { + private: + void AddReference( Class *ptr ); + void RemoveReference( Class *ptr ); + + protected: + SafePtrBase *prevSafePtr; + SafePtrBase *nextSafePtr; + Class *ptr; + + public: + SafePtrBase(); + virtual ~SafePtrBase(); + void InitSafePtr( Class *newptr ); + void Clear( void ); + }; + +/*********************************************************************** + + Class + +***********************************************************************/ + +#define CLASS_DECLARATION( nameofsuperclass, nameofclass, classid ) \ + ClassDef nameofclass::ClassInfo \ + ( \ + #nameofclass, classid, #nameofsuperclass, \ + ( ResponseDef * )nameofclass::Responses, \ + nameofclass::_newInstance, sizeof( nameofclass ) \ + ); \ + void *nameofclass::_newInstance( void ) \ + { \ + return new nameofclass; \ + } \ + ClassDef *nameofclass::classinfo( void ) \ + { \ + return &( nameofclass::ClassInfo ); \ + } \ + ResponseDef nameofclass::Responses[] = + + +#define CLASS_PROTOTYPE( nameofclass ) \ + public: \ + static ClassDef ClassInfo; \ + static void *nameofclass::_newInstance( void ); \ + virtual ClassDef *nameofclass::classinfo( void ); \ + static ResponseDef nameofclass::Responses[]; + +class Class + { + private: + SafePtrBase *SafePtrList; + friend class SafePtrBase; + + public: + CLASS_PROTOTYPE( Class ); + void * operator new( size_t ); + void operator delete( void * ); + + Class(); + virtual ~Class(); + void warning( const char *function, const char *fmt, ... ); + void error( const char *function, const char *fmt, ... ); + qboolean inheritsFrom( ClassDef *c ); + qboolean inheritsFrom( const char *name ); + qboolean isInheritedBy( const char *name ); + qboolean isInheritedBy( ClassDef *c ); + const char *getClassname( void ); + const char *getClassID( void ); + const char *getSuperclass( void ); + void *newInstance( void ); + }; + +void BuildEventResponses( void ); +ClassDef *getClassForID( const char *name ); +ClassDef *getClass( const char *name ); +ClassDef *getClassList( void ); +void listAllClasses( void ); +void listInheritanceOrder( const char *classname ); +qboolean checkInheritance( ClassDef *superclass, ClassDef *subclass ); +qboolean checkInheritance( ClassDef *superclass, const char *subclass ); +qboolean checkInheritance( const char *superclass, const char *subclass ); +void DisplayMemoryUsage( void ); + +inline qboolean Class::inheritsFrom + ( + ClassDef *c + ) + + { + return checkInheritance( c, classinfo() ); + } + +inline qboolean Class::isInheritedBy + ( + ClassDef *c + ) + + { + return checkInheritance( classinfo(), c ); + } + +// The lack of a space between the ")" and "inheritsFrom" is intentional. +// It allows the macro to compile like a function call. However, this +// may cause problems in some compilers (like gcc), so we may have to +// change this to work like a normal macro with the object passed in +// as a parameter to the macro. +#define isSubclassOf( classname )inheritsFrom( &classname::ClassInfo ) +#define isSuperclassOf( classname )isInheritedBy( &classname::ClassInfo ) + +/*********************************************************************** + + SafePtr + +***********************************************************************/ + +inline SafePtrBase::SafePtrBase() + { + prevSafePtr = NULL; + nextSafePtr = NULL; + ptr = NULL; + } + +inline SafePtrBase::~SafePtrBase() + { + Clear(); + } + +inline void SafePtrBase::Clear + ( + void + ) + + { + if ( ptr ) + { + RemoveReference( ptr ); + ptr = NULL; + } + } + +inline void SafePtrBase::InitSafePtr + ( + Class *newptr + ) + + { + if ( ptr != newptr ) + { + if ( ptr ) + { + RemoveReference( ptr ); + } + + ptr = newptr; + if ( ptr == NULL ) + { + return; + } + + AddReference( ptr ); + } + } + +inline void SafePtrBase::AddReference + ( + Class *ptr + ) + + { + if ( !ptr->SafePtrList ) + { + ptr->SafePtrList = this; + LL_Reset( this, nextSafePtr, prevSafePtr ); + } + else + { + LL_Add( ptr->SafePtrList, this, nextSafePtr, prevSafePtr ); + } + } + +inline void SafePtrBase::RemoveReference + ( + Class *ptr + ) + + { + if ( ptr->SafePtrList == this ) + { + if ( ptr->SafePtrList->nextSafePtr == this ) + { + ptr->SafePtrList = NULL; + } + else + { + ptr->SafePtrList = nextSafePtr; + LL_Remove( this, nextSafePtr, prevSafePtr ); + } + } + else + { + LL_Remove( this, nextSafePtr, prevSafePtr ); + } + } + +template +class SafePtr : public SafePtrBase + { + public: + SafePtr( T* objptr = 0 ); + SafePtr( const SafePtr& obj ); + + SafePtr& operator=( const SafePtr& obj ); + SafePtr& operator=( T * const obj ); + + friend int operator==( SafePtr a, T *b ); + friend int operator!=( SafePtr a, T *b ); + friend int operator==( T *a, SafePtr b ); + friend int operator!=( T *a, SafePtr b ); + + operator T*() const; + T* operator->() const; + T& operator*() const; + }; + +template +inline SafePtr::SafePtr( T* objptr ) + { + InitSafePtr( objptr ); + } + +template +inline SafePtr::SafePtr( const SafePtr& obj ) + { + InitSafePtr( obj.ptr ); + } + +template +inline SafePtr& SafePtr::operator=( const SafePtr& obj ) + { + InitSafePtr( obj.ptr ); + return *this; + } + +template +inline SafePtr& SafePtr::operator=( T * const obj ) + { + InitSafePtr( obj ); + return *this; + } + +template +inline int operator== + ( + SafePtr a, + T* b + ) + + { + return a.ptr == b; + } + +template +inline int operator!= + ( + SafePtr a, + T* b + ) + + { + return a.ptr != b; + } + +template +inline int operator== + ( + T* a, + SafePtr b + ) + + { + return a == b.ptr; + } + +template +inline int operator!= + ( + T* a, + SafePtr b + ) + + { + return a != b.ptr; + } + +template +inline SafePtr::operator T*() const + { + return ( T * )ptr; + } + +template +inline T* SafePtr::operator->() const + { + return ( T * )ptr; + } + +template +inline T& SafePtr::operator*() const + { + return *( T * )ptr; + } + +typedef SafePtr ClassPtr; + +#endif /* class.h */ \ No newline at end of file diff --git a/source/source/cgame/cg_commands.cpp b/source/source/cgame/cg_commands.cpp new file mode 100644 index 0000000..f378384 --- /dev/null +++ b/source/source/cgame/cg_commands.cpp @@ -0,0 +1,6942 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/cgame/cg_commands.cpp $ +// $Revision:: 202 $ +// $Author:: Aldie $ +// $Date:: 8/10/00 9:26p $ +// +// Copyright (C) 1999 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/cgame/cg_commands.cpp $ +// +// 202 8/10/00 9:26p Aldie +// Fixed a lot of memory leaks on exit +// +// 201 8/10/00 4:00p Steven +// Fixed some case sensitive stuff in CacheResource. +// +// 200 7/31/00 1:30a Markd +// fixed invalid tiki handle check on temp entities +// +// 199 7/29/00 9:04p Aldie +// Added originbeamemitter +// +// 198 7/28/00 9:16p Aldie +// Changed align for parentlink +// +// 197 7/26/00 6:19p Aldie +// Added a comment +// +// 196 7/26/00 3:49p Aldie +// Fix for swipes yet again. +// +// 195 7/24/00 3:07p Aldie +// Fix for cg_effectdetail for emitters +// +// 194 7/24/00 11:52a Aldie +// Added cg_effectdetail for reducing number of effects +// +// 193 7/23/00 1:36p Aldie +// Removed time adjustment print +// +// 192 7/22/00 5:50p Markd +// added flushtikis support +// +// 191 7/22/00 5:38p Aldie +// Fix for weird cg.time values coming in +// +// 190 7/21/00 2:03p Markd +// changed detail to be on by default, not off +// +// 189 7/20/00 3:48p Aldie +// Fix for anims on tempmodels +// +// 188 7/19/00 9:52p Aldie +// Put ET_EVENTS back in. They will get sent over once, and should get +// processed once on the client. +// +// 187 7/17/00 3:26p Aldie +// Added detail command +// +// 186 7/16/00 7:08p Aldie +// Removed some unused debugging code +// +// 185 7/16/00 2:09p Aldie +// Took out some prints +// +// 184 7/16/00 11:11a Aldie +// Added some beam stuff and fixed a bug with swipes (yet again) +// +// 183 7/15/00 12:32p Aldie +// Fixed a bug for restarting tempmodels on a save game +// +// 182 7/11/00 8:17p Aldie +// Fixed emitter bug (what else), where I was accidentally removing numbers +// from the global pool when a tempent was being removed. +// +// 181 7/08/00 3:21p Aldie +// Removed some duplicate code +// +// 180 7/07/00 2:58p Markd +// fixed alias bug +// +// 179 6/27/00 7:16p Aldie +// Fixed it so beam emitters use alpha from entity +// +// 178 6/26/00 7:14p Markd +// added parentangles command +// +// 177 6/26/00 5:50p Markd +// re-did some renderfx commands, fixed anti-sb juice stuff +// +// 176 6/23/00 8:00p Aldie +// Fixed some problems with newEnt. Ugh. spawned entities in the sky were not +// inheriting renderfx. newEnt now has the right renderfx when animating so we +// get the right inheritance to tempmodels +// +// 175 6/22/00 3:13p Aldie +// Some tweaks to scaleupdown and scalemin,scalemax +// +// 174 6/21/00 6:03p Markd +// put in better bullet proofing when tiki_commands are invalid +// +// 173 6/20/00 8:04p Aldie +// Fix for axis with tempmodels +// +// 172 6/17/00 1:54p Markd +// Added server restarted code +// +// 171 6/15/00 8:21p Markd +// Added CleanupCommandManager support +// +// 170 6/15/00 7:44p Aldie +// Fix for axis on endtagtraceimpactspawn +// +// 169 6/15/00 6:54p Steven +// Fixed a looping sound issue. +// +// 168 6/14/00 8:12p Aldie +// Fix for parallel and offset along axis +// +// 167 6/14/00 12:14p Markd +// more intel compiler bug fixes +// +// 166 6/13/00 6:45p Aldie +// Added some more optimizations +// +// 165 6/13/00 1:46p Aldie +// Fixed some initialization stuff +// +// 164 6/13/00 10:57a Steven +// Moved splash stuff to cg_specialfx.cpp. +// +// 163 6/10/00 6:43p Aldie +// Fixed shadertime bug +// +// 162 6/10/00 5:52p Aldie +// Made some improvements to help speed, added tag_axis, removed notagangles +// command. Removed some unused code. Changed the method of adding +// tempmodels. +// +// 161 6/09/00 7:53p Aldie +// Added origin to playsound and fixed bouncesound and a couple other sound +// things +// +// 160 6/08/00 6:26p Aldie +// Fixed some crashbugs +// +// 159 6/07/00 9:53a Steven +// Made player splashes go twice as slow when the player is not moving. +// +// 158 6/06/00 1:59p Aldie +// Added fadein to marks +// +// 157 6/05/00 3:10p Markd +// Added has_commands check to client side command processing +// +// 156 6/05/00 3:06p Steven +// Made sure in PlaySound that current_tiki was set before trying to find a +// local alias. +// +// 155 6/04/00 6:03p Markd +// Added precise shadow support +// +// 154 6/03/00 8:19p Markd +// Added footstep code +// +// 153 6/03/00 2:07p Aldie +// Fix for HARDLINK when doing a tag emitter +// +// 152 6/03/00 10:55a Markd +// Sped up tracing and debug print messages +// +// 151 6/02/00 7:04p Aldie +// Moved the parallel check +// +// 150 6/02/00 6:52p Aldie +// Added in parallel command +// +// 149 6/01/00 7:45p Aldie +// Made it so that swipes are removed when client entities are reset. +// +// 148 6/01/00 12:20p Steven +// Improvement to splashes. +// +// 147 5/30/00 2:46p Aldie +// Fix for beam parents +// +// 146 5/25/00 5:58p Aldie +// Fix for client tempmodel animations +// +// 145 5/24/00 6:05p Markd +// fixed bug where MAX_MAP_BOUNDS was being used instead of MAP_SIZE +// +// 144 5/23/00 6:53p Aldie +// Removed scale from angles +// +// 143 5/22/00 8:02p Markd +// changed behavior of cg_debuganimwatch +// +// 142 5/22/00 6:37p Aldie +// Added originbeamspawn and fixed a velocity bug with the new tempmodels +// +// 141 5/20/00 4:42p Aldie +// Removed some unused flags and code. Fixed emitters that have parentlink or +// hardlink +// +// 140 5/20/00 11:33a Aldie +// Fix for fading on impact marks +// +// 139 5/18/00 3:32p Aldie +// Added bouncedecal +// +// 138 5/18/00 11:47a Aldie +// Added tempmodelsRealtimeEffects proc +// +// 137 5/16/00 6:24p Markd +// added cg_traceinfo support +// +// 136 5/16/00 3:40p Aldie +// Changed method of calculating physicsTime. And added physicsrate command +// +// 135 5/15/00 2:19p Aldie +// Added new tempmodel system and added player accumulated pain +// +// 133 5/09/00 1:29p Aldie +// Added lightstyles to impact marks +// +// 132 5/08/00 6:12p Markd +// Added lightstyle support for the client +// +// 131 5/06/00 5:21p Aldie +// Changed to for "dlight" command +// +// 130 5/05/00 4:30p Aldie +// Fix docs for twinkle +// +// 129 5/05/00 1:07p Aldie +// Fix for hardlink +// +// 128 5/04/00 8:38p Aldie +// Made beam emitters work better +// +// 127 5/04/00 7:45p Aldie +// Fix for hardlink +// +// 126 5/04/00 7:19p Aldie +// Added notagangles command +// +// 125 5/04/00 4:34p Aldie +// Added trail command that uses swipe code to do a trail +// +// 124 5/03/00 6:03p Aldie +// Fix for origin on physics tempmodels +// +// 123 5/02/00 7:29p Aldie +// Fix for command delay +// +// 122 5/01/00 2:42p Steven +// Improved client side caching a little bit and fixed client side aliases. +// +// 121 4/27/00 7:42p Aldie +// Added trace_count functionality for multiple spawns for tagtraceimpactmark +// and spawn +// +// 120 4/27/00 4:00p Aldie +// Removed an unused piece of code. +// +// 119 4/26/00 9:05p Markd +// Added client and cgame class commands +// +// 118 4/26/00 7:05p Aldie +// Fixed alpha bug yet again +// +// 117 4/26/00 3:07p Aldie +// Fix crashbug in swarm code +// +// 116 4/19/00 6:06p Aldie +// Fix alpha bug +// +// 115 4/19/00 5:43p Aldie +// Fix for duplicate alpha multiply +// +// 114 4/14/00 6:29p Aldie +// Removed a printf +// +// 113 4/14/00 5:54p Aldie +// Put back in fadedelay. Somewhere it accidentally got removed. +// +// 112 4/10/00 6:10p Steven +// Made it so if the render flag RF_DONT_PROCESS_COMMANDS is set that the +// client doesn't process any of this entities commands. +// +// 111 4/08/00 3:43p Aldie +// Added scale to velocity for spawntempmodels +// +// 110 4/06/00 12:12p Aldie +// Fix for CG_Emitter to use angles from the entity +// +// 109 3/31/00 4:55p Steven +// Added UseLastTraceEnd so that tracecommands could use the end point of the +// previous command. +// +// 108 3/30/00 4:22p Aldie +// Added scale to dlights and beams +// +// 107 3/28/00 5:24p Aldie +// Changed CG_Trace funcs +// +// 106 3/28/00 11:43a Aldie +// Fix scaleupdown +// +// 105 3/27/00 6:50p Aldie +// Added resolution changing for menus +// +// 104 3/27/00 1:50p Aldie +// Removed some unused code +// +// 103 3/23/00 11:09a Aldie +// Fixed a bug with the new flag changes +// +// 102 3/21/00 4:32p Aldie +// Fixed a bug with missing dlight flag +// +// 101 3/16/00 6:51p Aldie +// Added some shortcut flags for tempmodel optimization +// +// 100 3/16/00 5:09p Aldie +// Added some optimizations for tempmodels +// +// 99 3/15/00 11:01a Aldie +// Changed m_emitters to container instead of array. +// +// 98 3/14/00 3:22p Aldie +// Changed some client side emitter functionality and added func_emitter +// +// 97 3/13/00 12:24p Aldie +// Fixed some rain problems and added some functionality +// +// 96 3/13/00 10:51a Aldie +// Removed a printf +// +// 95 3/11/00 4:47p Aldie +// Fix for scaleupdown +// +// 94 3/11/00 4:06p Aldie +// Added scaleupdown code +// +// 93 3/06/00 8:07p Markd +// cleaned up unused cvar's +// +// 92 3/04/00 6:03p Aldie +// Made commandManager static +// +// 91 3/04/00 3:52p Aldie +// Fixed typo +// +// 90 3/04/00 3:51p Aldie +// Added more types for dynamic lights +// +// 89 3/04/00 2:53p Markd +// Fixed dynamic light types +// +// 88 3/04/00 2:33p Aldie +// Added lightstyle support +// +// 87 3/03/00 2:40p Aldie +// Added in tagtraceimpactsound command +// +// 86 3/01/00 5:55p Aldie +// Added alignonce flag for aligning models one time, but not every frame. Use +// if you have avelocity on a tempmodel +// +// 85 3/01/00 1:45p Aldie +// Added some more beam functionality for beau. Added taglist to do beam +// chains. +// +// 84 2/29/00 12:21p Aldie +// Added taglist to beam emitters. Allows for a list of tags to be named for a +// chain of beams +// +// 83 2/25/00 5:01p Aldie +// Changed some of the dlight stuff and added a new command +// +// 82 2/22/00 6:54p Aldie +// Added a bool to tempmodels so that they will get added at least one time to +// the ref. This is useful for getting things to show up in low framerate +// situations. +// +// 81 2/20/00 5:40p Aldie +// Fixed the twinkle command +// +// 80 2/16/00 6:55p Markd +// Added more debugging information +// +// 79 2/10/00 5:45p Aldie +// added tagtraceimpactspawn +// +// 78 2/09/00 5:38p Aldie +// removed printf +// +// 77 2/09/00 4:27p Aldie +// Fixed pause on the client emitters +// +// 76 2/07/00 4:30p Markd +// got rid of unused comments +// +// 75 2/07/00 2:47p Markd +// Added entry support to client command processor +// +// 74 2/04/00 10:50a Aldie +// Fixed beam trace +// +// 73 2/01/00 7:08p Aldie +// Added renderfx inheritance to beams +// +// 72 1/29/00 6:17p Aldie +// Added TIKI_NameForNum +// +// 71 1/29/00 10:16a Steven +// Added stop sound support in cgame. +// +// 70 1/28/00 7:16p Aldie +// Added more features to the impact decal code +// +// 69 1/27/00 4:19p Aldie +// Added a quick tagtraceimpactmark +// +// 68 1/27/00 3:20p Aldie +// Added twinkle and fixed a bug with the beams +// +// 67 1/26/00 3:34p Markd +// Added Renderfx mask for inherited entities +// +// 66 1/26/00 11:35a Aldie +// New data structures for emitters +// +// 65 1/24/00 6:19p Aldie +// Added some new commands - commanddelay and randomchance +// +// 64 1/24/00 12:50p Aldie +// Added current_entity's scale to the origin offset calculation +// +// 63 1/24/00 12:03p Aldie +// Fixed another emitter bug with align flag +// +// 62 1/22/00 6:41p Aldie +// Typo fix +// +// 61 1/22/00 1:48p Aldie +// Removed .vec3 references, fixed bouncesound and added bouncesoundonce +// +// 60 1/22/00 10:37a Aldie +// Changed default life +// +// 59 1/21/00 7:52p Aldie +// Added randvelaxis for setting velocities along the axis of the entity +// +// 58 1/20/00 5:26p Aldie +// Fixed a warning +// +// 57 1/20/00 3:23p Aldie +// Fixed a dangling else and color init for the tempmodels +// +// 56 1/20/00 2:57p Jimdose +// got rid of angmod +// +// 55 1/20/00 11:03a Markd +// Added Bouncesound but then took it out temporarily +// +// 54 1/20/00 10:38a Markd +// fixed model orientation a bit. +// +// 53 1/19/00 8:34p Markd +// Fixed GetOrientation +// +// 52 1/19/00 3:18p Aldie +// Moved cg_updateentity +// +// 51 1/18/00 3:13p Aldie +// Fix for fadedelay +// +// 50 1/15/00 2:38p Aldie +// Added fadedelay and Cachedmodellist for init command processing +// +// 49 1/12/00 7:58p Aldie +// Fix for shaderTime +// +// 48 1/12/00 4:18p Markd +// Put in extra code in ProcessCommands for better range checking +// +// 47 1/12/00 3:17p Aldie +// Fixed beams so that there may be multiple beams on a model +// +// 46 1/12/00 11:25a Markd +// added numframes == 1 protection to frame processor +// +// 45 1/05/00 7:25p Jimdose +// made angle functions all use the same coordinate system +// AngleVectors now returns left instead of right +// no longer need to invert pitch +// +// 44 12/15/99 4:19p Markd +// Fixed performance counter stuff +// +// 43 12/09/99 10:52a Jimdose +// got tags working with torso and crossblended animations +// +// 42 12/01/99 11:26a Aldie +// Couple of fixes for emitters and more ammo stuff +// +// 41 11/01/99 4:11p Jimdose +// made tags work with bone controllers +// +// 40 10/22/99 6:47p Aldie +// Fix for beams in sky +// +// 39 10/22/99 4:56p Markd +// Fixed client command processing +// +// 38 10/22/99 11:34a Aldie +// Fix for alpha from entity +// +// 37 10/22/99 10:43a Markd +// Rewrote command processor +// +// 36 10/21/99 6:17p Aldie +// Fix for randvel +// +// 35 10/21/99 2:51p Aldie +// Added some more beam functions +// +// 34 10/19/99 7:52p Markd +// Removed three part model system +// +// 33 10/19/99 11:57a Aldie +// Added some more beam features +// +// 32 10/18/99 1:59p Aldie +// Lots of fixes for beams and stuff +// +// 31 10/14/99 7:19p Aldie +// Fix some beam stuff +// +// 30 10/14/99 11:07a Aldie +// Fixed parentlink in emitter +// +// 29 10/13/99 3:26p Aldie +// Various fixes for particles, beams and lensflares +// +// 28 10/11/99 3:47p Steven +// Event documentation cleanup. +// +// 27 10/11/99 3:38p Aldie +// Fix for some command doc stuff +// +// 26 10/09/99 5:26p Markd +// Added proper portal entity support +// +// 25 10/08/99 5:47p Aldie +// More beam stuff +// +// 24 10/08/99 5:07p Aldie +// More beam stuff and fix for UI_CenterPrint +// +// 23 10/07/99 7:14p Aldie +// more beam stuff (woohoo!) +// +// 22 10/07/99 3:08p Aldie +// more beam fun +// +// 21 10/06/99 6:54p Aldie +// Fixed some stuff with tempmodel using the animatonce command +// +// 20 10/06/99 3:23p Steven +// Added a dumpevents command. +// +// 19 10/06/99 3:11p Aldie +// Added more docs to commands +// +// 18 10/05/99 6:01p Aldie +// Added headers +// +// DESCRIPTION: +// Client side command events. These are in the .TIK files and +// are processed when the animation specifies it to. + +#include "cg_commands.h" + +Container cachedModelList; + +Vector vec_zero = "0 0 0"; + +refEntity_t *current_entity = NULL; +int current_entity_number = -1; +centity_t *current_centity = NULL; +float current_scale = -1; +int current_tiki = -1; +cvar_t *cg_showtempmodels; +cvar_t *cg_showemitters; +cvar_t *cg_physics_fps; +cvar_t *cg_detail; +cvar_t *cg_effectdetail; + +Vector last_trace_end; + +void CacheResource( const char * stuff ); + +ClientGameCommandManager commandManager; + +Event EV_Client_StartBlock + ( + "(", + EV_DEFAULT, + NULL, + NULL, + "Signals the beginning of a block of commands" + ); +Event EV_Client_EndBlock + ( + ")", + EV_DEFAULT, + NULL, + NULL, + "Signals the end of a block of commands" + ); +Event EV_Client_EmitterStartOff + ( + "startoff", + EV_DEFAULT, + NULL, + NULL, + "Signals an emitter to start in the off state (no tempmodels are emitted)" + ); +Event EV_Client_SetAlpha + ( + "alpha", + EV_DEFAULT, + "f", + "alpha", + "Set the alpha of the spawned tempmodel" + ); +Event EV_Client_SetDieTouch + ( + "dietouch", + EV_DEFAULT, + NULL, + NULL, + "Set the spawned tempmodels to die when they touch a solid" + ); +Event EV_Client_SetBounceFactor + ( + "bouncefactor", + EV_DEFAULT, + "f", + "factor", + "Set the bounciness of a tempmodel when it hits a solid.\n" + "A factor > 1 will make the model bounce higher and higher on each hit" + ); +Event EV_Client_SetBounceSound + ( + "bouncesound", + EV_DEFAULT, + "sF", + "sound [delay]", + "When bouncing, what sound to play on impact and an option delay (default is 1 second) between playing this sound" + ); +Event EV_Client_SetBounceSoundOnce + ( + "bouncesoundonce", + EV_DEFAULT, + "s", + "sound", + "When bouncing, what sound to play on impact one time" + ); +Event EV_Client_SetScale + ( + "scale", + EV_DEFAULT, + "f", + "scale", + "Set the scale of a spawned tempmodel" + ); +Event EV_Client_SetScaleUpDown + ( + "scaleupdown", + EV_DEFAULT, + NULL, + NULL, + "Set the tempmodel to scale up to scale value and then down." + ); +Event EV_Client_SetScaleMin + ( + "scalemin", + EV_DEFAULT, + "f", + "scalemin", + "Set the minimum scale of a spawned tempmodel" + ); +Event EV_Client_SetScaleMax + ( + "scalemax", + EV_DEFAULT, + "f", + "scalemax", + "Set the maximum scale of a spawned tempmodel" + ); +Event EV_Client_SetModel + ( + "model", + EV_DEFAULT, + "sSSSSS", + "modelname1 modelname2 modelname3 modelname4 modelname5 modelname6", + "Set the modelname of the tempmodel. If more than 1 model is specified, it will\n" + "be randomly chosen when spawned" + ); +Event EV_Client_SetLife + ( + "life", + EV_DEFAULT, + "f", + "life", + "Set the life (in seconds) of the spawned tempmodel" + ); +Event EV_Client_SetColor + ( + "color", + EV_DEFAULT, + "fffF", + "red green blue alpha", + "Set the color (modulate) of the spawned tempmodel." + ); +Event EV_Client_SetVelocity + ( + "velocity", + EV_DEFAULT, + "f", + "forwardVelocity", + "Set the forward velocity of the spawned tempmodel" + ); +Event EV_Client_SetAngularVelocity + ( + "avelocity", + EV_DEFAULT, + "fff", + "yawVel pitchVel rollVel", + "Set the angular velocity of the spawned tempmodel" + ); +Event EV_Client_SetRandomVelocity + ( + "randvel", + EV_DEFAULT, + "SFSFSF", + "[random|crandom] xVel [random|crandom] yVel [random|crandom] zVel", + "Add a random component to the regular velocity.\n" + "If random is specified, the component will range from 0 to specified velocity.\n" + "If crandom is specified, the component will range from -specified to +specified velocity.\n" + "If neither random or crandom is specified, then the component will just be added on\n" + "without randomness.\n" + "This velocity is applied using the world axis" + ); +Event EV_Client_SetRandomVelocityAlongAxis + ( + "randvelaxis", + EV_DEFAULT, + "SFSFSF", + "[random|crandom] forwardVel [random|crandom] rightVel [random|crandom] upVel", + "Add a random component to the regular velocity.\n" + "If random is specified, the component will range from 0 to specified velocity.\n" + "If crandom is specified, the component will range from -specified to +specified velocity.\n" + "If neither random or crandom is specified, then the component will just be added on\n" + "without randomness.\n" + "This velocity is applied using the parent axis" + ); +Event EV_Client_SetAccel + ( + "accel", + EV_DEFAULT, + "fff", + "xAcc yAcc zAcc", + "Set the acceleration of the spawned tempmodel.\n" + "This acceleration is applied using the world axis" + ); +Event EV_Client_SetCount + ( + "count", + EV_DEFAULT, + "i", + "count", + "Set the number of tempmodels that are spawned\n" + "This is only used for the originspawn and tagspawn commands,\n" + "and not for emitters, use spawnrate instead" + ); +Event EV_Client_SetTraceCount + ( + "tracecount", + EV_DEFAULT, + "i", + "count", + "Set the number of traces that are done\n" + ); +Event EV_Client_SetFade + ( + "fade", + EV_DEFAULT, + NULL, + NULL, + "Set the tempmodel to fade out over it's life" + ); +Event EV_Client_SetFadeDelay + ( + "fadedelay", + EV_DEFAULT, + "f", + "time", + "Set the amount of time to delay a fade" + ); +Event EV_Client_SetFadeIn + ( + "fadein", + EV_DEFAULT, + "f", + "time", + "Set the tempmodel to fade in over the specified time" + ); +Event EV_Client_SetTwinkle + ( + "twinkle", + EV_DEFAULT, + "ffff", + "mintimeoff maxtimeoff mintimeon maxtimeon", + "Set the tempmodel to twinkle with the specified settings" + ); +Event EV_Client_SetTrail + ( + "trail", + EV_DEFAULT, + "sssf", + "shader startTag endTag life", + "Set the tempmodel to have a swipe that follows it" + ); +Event EV_Client_SetSpawnRate + ( + "spawnrate", + EV_DEFAULT, + "f", + "rate", + "Set the spawnrate of the emitter (models per second).\n" + "This is only used for emitters and not for the originspawn and tagspawn commands" + ); +Event EV_Client_SetOriginOffset + ( + "offset", + EV_DEFAULT, + "SFSFSF", + "[random|crandom] offsetX [random|crandom] offsetY [random|crandom] offsetZ", + "If random is specified, the component will range from 0 to +specified offset.\n" + "If crandom is specified, the component will range from -specified to +specified offset.\n" + "If neither random or crandom is specified, then the component will just be added on\n" + "without randomness.\n" + "This offset is applied using the world axis." + ); +Event EV_Client_SetScaleRate + ( + "scalerate", + EV_DEFAULT, + "f", + "rate", + "Set the scaling rate of the spawned tempmodel\n" + "If a negative rate is used, the model will shrink" + ); +Event EV_Client_SetCircle + ( + "circle", + EV_DEFAULT, + NULL, + NULL, + "Set the tempmodels to be spawned in a circle around the origin\n" + "This circle will be generated in the X/Y axis of the model" + ); +Event EV_Client_SetSphere + ( + "sphere", + EV_DEFAULT, + NULL, + NULL, + "Set the tempmodels to spawn in a sphere around the origin.\n" + "If sphereradius is set, the tempmodels will spawn at the radius distance from\n" + "the origin" + ); +Event EV_Client_SetInwardSphere + ( + "inwardsphere", + EV_DEFAULT, + NULL, + NULL, + "Create the tempmodels in a sphere around the origin, and adjust their\n" + "angle so they point toward the center of the sphere. This is best used with a\n" + "spehere radius and some velocity so the models look like they're heading toward the\n" + "center of the sphere." + ); +Event EV_Client_SetRadius + ( + "radius", + EV_DEFAULT, + "f", + "radius", + "Set the radius of the sphere for the inwardsphere amd sphere settings" + ); +Event EV_Client_SetSwarm + ( + "swarm", + EV_DEFAULT, + "iff", + "frequency maxspeed delta", + "Create a swarm like effect that the tempmodels follow when they are spawned\n" + "frequency is how often they change direction\n" + "maxspeed is how fast the tempmodel will move (it's randomly generated every\n" + "time the frequency is hit\n" + "delta is how much the tempmodel moves toward the origin every frame" + ); +Event EV_Client_SetWavy + ( + "wavy", + EV_DEFAULT, + "SF", + "[random|crandom] distance", + "Set the tempmodel to move in a wavy path to a maxmimun of the distance specified\n" + "If random is specified, the distance is between 0 and +specified distance\n" + "If crandom is specified, the distance is between -specified and +specified distance" + ); +Event EV_Client_SetAlign + ( + "align", + EV_DEFAULT, + NULL, + NULL, + "Align the tempmodels to the direction they are traveling" + ); +Event EV_Client_SetAlignOnce + ( + "alignonce", + EV_DEFAULT, + NULL, + NULL, + "Align the tempmodels to the direction they are traveling at the time they are initialized" + ); +Event EV_Client_SetFlickerAlpha + ( + "flicker", + EV_DEFAULT, + NULL, + NULL, + "Set the tempmodel to change it's alpha every frame. Creates a flickering effect" + ); +Event EV_Client_SetCollision + ( + "collision", + EV_DEFAULT, + "S", + "water", + "Turn on collision for the tempmodel.\n" + "If the keyword water is specified, then the tempmodel will collide with water" + ); +Event EV_Client_TagSpawn + ( + "tagspawn", + EV_DEFAULT, + "s", + "tagName", + "Spawn tempmodels from the specified tag.\n" + "This command is followed by a ( to specify a block of commands that modify the tempmodels" + ); +Event EV_Client_OriginSpawn + ( + "originspawn", + EV_DEFAULT, + NULL, + NULL, + "Spawn tempmodels from the origin.\n" + "This command is followed by a ( to specify a block of commands that modify the tempmodels" + ); +Event EV_Client_OriginBeamSpawn + ( + "originbeamspawn", + EV_DEFAULT, + NULL, + NULL, + "Spawn a beam from the origin.\n" + "This command is followed by a ( to specify a block of commands that modify the beam" + ); +Event EV_Client_OriginBeamEmitter + ( + "originbeamemitter", + EV_DEFAULT, + NULL, + NULL, + "Spawn beams from the origin.\n" + "This command is followed by a ( to specify a block of commands that modify the beam" + ); +Event EV_Client_TagEmitter + ( + "tagemitter", + EV_DEFAULT, + "ss", + "tagName emitterName", + "Create an emitter that spawns tempmodels from the specified tag.\n" + "This command is followed by a ( to specify a block of commands that modify the tempmodels" + ); +Event EV_Client_OriginEmitter + ( + "originemitter", + EV_DEFAULT, + "s", + "emitterName", + "Create an emitter that spawns tempmodels from the origin.\n" + "This command is followed by a ( to specify a block of commands that modify the tempmodels" + ); +Event EV_Client_EmitterOn + ( + "emitteron", + EV_DEFAULT, + "s", + "emitterName", + "Turn the specified emitter on" + ); +Event EV_Client_EmitterOff + ( + "emitteroff", + EV_DEFAULT, + "s", + "emitterName", + "Turn the specified emitter off" + ); +Event EV_Client_Sound + ( + "sound", + EV_DEFAULT, + "sIFF", + "soundName channel volume min_distance", + "Play the specified sound" + ); +Event EV_Client_StopSound + ( + "stopsound", + EV_DEFAULT, + "i", + "channel", + "Stops the sound on the specified channel." + ); +Event EV_Client_LoopSound + ( + "loopsound", + EV_DEFAULT, + "sFF", + "soundName volume min_distance", + "Play the specifed sound as a looping sound" + ); +Event EV_Client_Cache + ( + "cache", + EV_DEFAULT, + "s", + "resourceName", + "Cache the specified resource" + ); +Event EV_Client_AliasCache + ( + "aliascache", + EV_DEFAULT, + "ssSSSSSS", + "alias realPath arg1 arg2 arg3 arg4 arg5 arg6", + "Create an alias to the specified path and cache the resource" + ); +Event EV_Client_Alias + ( + "alias", + EV_DEFAULT, + "ssSSSSSS", + "alias realPath arg1 arg2 arg3 arg4 arg5 arg6", + "Create an alias to the specified path" + ); +Event EV_Client_Footstep + ( + "footstep", + EV_DEFAULT, + NULL, + NULL, + "Play a footstep sound that is appropriate to the surface we are currently stepping on" + ); +Event EV_Client_Client + ( + "client", + EV_DEFAULT, + "SSSSSS", + "arg1 arg2 arg3 arg4 arg5 arg6", + "Execute the specified command arg string" + ); +Event EV_Client_OriginDynamicLight + ( + "origindlight", + EV_DEFAULT, + "fffffSS", + "red green blue intensity life type1 type2", + "Spawn a dynamic light from the origin of the model\n" + "The red,green,blue parms are the color of the light\n" + "The intensity is the radius of the light\n" + "type is the type of light to create (lensflare,viewlensflare,additive)" + ); +Event EV_Client_TagDynamicLight + ( + "tagdlight", + EV_DEFAULT, + "sfffffSS", + "tagName red green blue intensity life type1 type2", + "Spawn a dynamic light from the specified tag\n" + "The red,green,blue parms are the color of the light\n" + "The intensity is the radius of the light\n" + "type is the type of light to create (lensflare,viewlensflare,additive)" + ); +Event EV_Client_DynamicLight + ( + "dlight", + EV_DEFAULT, + "ffffSS", + "red green blue intensity type1 type2", + "This makes the emitter itself a dynamic light" + "The red,green,blue parms are the color of the light\n" + "The intensity is the radius of the light\n" + "type is the type of light to create (lensflare,viewlensflare,additive)" + ); +Event EV_Client_SetEntityColor + ( + "entcolor", + EV_DEFAULT, + "fffF", + "red green blue alpha", + "Set the color(modulate) of this entity" + ); +Event EV_Client_SetTexAnimTime + ( + "texanimtime", + EV_DEFAULT, + "f", + "time", + "Set the texture animation speed" + ); +Event EV_Client_SetGlobalFade + ( + "globalfade", + EV_DEFAULT, + "S", + "[in|out]", + "Set the tempmodels to globally fade in or out together" + ); +Event EV_Client_SetParentLink + ( + "parentlink", + EV_DEFAULT, + NULL, + NULL, + "Set the tempmodels linked to the parent, so they move with the parent model" + ); +Event EV_Client_SetHardLink + ( + "hardlink", + EV_DEFAULT, + NULL, + NULL, + "Set the tempmodels linked to the model they are spawned from, so they move with it" + ); +Event EV_Client_SetRandomRoll + ( + "randomroll", + EV_DEFAULT, + NULL, + NULL, + "Set the tempmodels so they pick a random roll value every frame" + ); +Event EV_Client_ParentAngles + ( + "parentangles", + EV_DEFAULT, + NULL, + NULL, + "Set the tempmodels angles to that of its parent" + ); +Event EV_Client_SetAngles + ( + "angles", + EV_DEFAULT, + "SFSFSF", + "[random|crandom] pitch [random|crandom] yaw [random|crandom] roll", + "If random is specified, the component will range from 0 to +specified value.\n" + "If crandom is specified, the component will range from -specified to +specified value.\n" + "If neither random or crandom is specified, then the component will be just set\n" + "without randomness." + ); +Event EV_Client_Swipe + ( + "swipe", + EV_DEFAULT, + "V", + "origin", + "Do a swipe and add it on to the swipe rendering list." + ); +Event EV_Client_SwipeOn + ( + "swipeon", + EV_DEFAULT, + "ssff", + "shader startTagName endTagNamelife life", + "Signal the start of a swipe from the current tag" + ); +Event EV_Client_SwipeOff + ( + "swipeoff", + EV_DEFAULT, + NULL, + NULL, + "Signal the end of a swipe" + ); +Event EV_Client_BeginTagBeamEmitter + ( + "tagbeamemitter", + EV_DEFAULT, + "sss", + "tagstart tagend name", + "Create a beam emitter that uses 2 tags to determine it's start and end position" + ); +Event EV_Client_BeginTagBeamSpawn + ( + "tagbeamspawn", + EV_DEFAULT, + "sf", + "tagstart name", + "Create a beam emitter that uses the tag to determine it's starting position." + ); +Event EV_Client_AnimateOnce + ( + "animateonce", + EV_DEFAULT, + NULL, + NULL, + "Set a tempmodel to animate once and then get removed" + ); +Event EV_Client_SetAnim + ( + "anim", + EV_DEFAULT, + "s", + "animation", + "Set a tempmodel the the specified animation" + ); +Event EV_Client_SetSubdivisions + ( + "numsegments", + EV_DEFAULT, + "i", + "numsegments", + "Set the number of segments in a beam" + ); +Event EV_Client_SetMinOffset + ( + "minoffset", + EV_DEFAULT, + "f", + "minoffset", + "Set the minimum offset from center in a beam" + ); +Event EV_Client_SetMaxOffset + ( + "maxoffset", + EV_DEFAULT, + "f", + "maxoffset", + "Set the maximum offset from center in a beam" + ); +Event EV_Client_SetBeamShader + ( + "beamshader", + EV_DEFAULT, + "s", + "shadername", + "Set the shader to use for the beam" + ); +Event EV_Client_SetBeamLength + ( + "beamlength", + EV_DEFAULT, + "f", + "length", + "Set the length of the beam or trace length (for decals)" + ); +Event EV_Client_SetBeamDelay + ( + "beamdelay", + EV_DEFAULT, + "SF", + "[random] delay", + "Set the delay time between creating new beams.\n" + "If the keyword random is specified, the delay between beams will occur randomly between 0 and the time specified" + ); +Event EV_Client_SetBeamToggleDelay + ( + "beamtoggledelay", + EV_DEFAULT, + "SF", + "[random] delay", + "Set a delay between toggling the beams on and off.\n" + "If the keyword random is specified, the delay between toggling will occur randomly between 0 and the time specified" + ); +Event EV_Client_SetBeamPersist + ( + "beampersist", + EV_DEFAULT, + NULL, + NULL, + "Make the beams persist instead of blinking out" + ); +Event EV_Client_SetBeamOffsetEndpoints + ( + "beam_offset_endpoints", + EV_DEFAULT, + NULL, + NULL, + "Make the beams endpoints offset to reduce the bunching up effect" + ); +Event EV_Client_BeamSphere + ( + "beamsphere", + EV_DEFAULT, + "i", + "count", + "Create a sphere shaped beam effect from the origin. Count is the number of beams" + ); +Event EV_Client_Spread + ( + "spread", + EV_DEFAULT, + "ff", + "spreadx spready", + "Add a random variance in the spawned beam in the forward direction by the amound specified in spreadx and spready" + ); +Event EV_Client_UseLastTraceEnd + ( + "uselasttraceend", + EV_DEFAULT, + NULL, + NULL, + "Makes this trace command use the end results of the last trace command" + ); +Event EV_Client_OffsetAlongAxis + ( + "offsetalongaxis", + EV_DEFAULT, + "SfSfSf", + "[crandom|random] offsetx [crandom|random] offsety [crandom|random] offsetz", + "If random is specified, the component will range from 0 to specified offset.\n" + "If crandom is specified, the component will range from -specified to +specified offset.\n" + "If neither random or crandom is specified, then the component will just be added on\n" + "without randomness.\n" + "This offset is applied using the model's local axis" + ); +Event EV_Client_SetEndAlpha + ( + "endalpha", + EV_DEFAULT, + "f", + "alpha", + "Set the alpha of the beam's endpoint" + ); +Event EV_Client_RandomChance + ( + "randomchance", + EV_DEFAULT, + "fSSSSSS", + "percentage [arg1] [arg2] [arg3] [arg4] [arg5] [arg6]", + "Set the percentage chance that command will occur" + ); +Event EV_Client_CommandDelay + ( + "commanddelay", + EV_DEFAULT, + "fiSSSSSS", + "time commandnumber [arg1] [arg2] [arg3] [arg4] [arg5] [arg6]", + "Set the time delay between this command getting executed. This requires a command number to be assigned here.\n" + "This is internally used to keep track of the commands this entity executes and will resolve naming conflicts." + ); +Event EV_Client_TagTraceImpactSound + ( + "tagtraceimpactsound", + EV_DEFAULT, + "si", + "tagname maxlength", + "Perform a trace from the specified tag to the maxlength and play a sound at that position" + ); +Event EV_Client_TagTraceImpactSpawn + ( + "tagtraceimpactspawn", + EV_DEFAULT, + "s", + "tagname", + "Perform a trace from the specified tag to the maxlength and spawn the specified model there." + ); +Event EV_Client_TagTraceImpactMark + ( + "tagtraceimpactmark", + EV_DEFAULT, + "sI", + "tagname temporary", + "Perform a trace from the specified tag to the maxlength and put the shader as a decal on the surface it hits\n" + "temporary = specify 1 for a temporary mark that only appears for a short time, 0 for a decal that stays aroung longer (default is 0)\n" + ); +Event EV_Client_BounceDecal + ( + "bouncedecal", + EV_DEFAULT, + "iI", + "maxamount temporary", + "Put a mark when the tempmodel bounces and hits a surface\n" + "maxamount = Max amount of decals to make when bouncing\n" + "temporary = specify 1 for a temporary mark that only appears for a short time, 0 for a decal that stays aroung longer (default is 0)\n" + ); +Event EV_Client_SetDecalRadius + ( + "decalradius", + EV_DEFAULT, + "f", + "radius", + "Set the radius of the decal" + ); +Event EV_Client_SetDecalOrientation + ( + "orientation", + EV_DEFAULT, + "f", + "degrees", + "Set the degrees to orient the decal. Specify 'random' to use a random orientation" + ); +Event EV_Client_SetDecalShader + ( + "decalshader", + EV_DEFAULT, + "s", + "shadername", + "Set the shader to use for the impact decal" + ); +Event EV_Client_SetTraceLength + ( + "tracelength", + EV_DEFAULT, + "f", + "length", + "Set the length of the trace for the decal" + ); +Event EV_Client_TraceSpawn + ( + "tracespawn", + EV_DEFAULT, + "s", + "modelname", + "Spawn the specified model when the trace hits a solid object" + ); +Event EV_Client_TagList + ( + "taglist", + EV_DEFAULT, + "ssSSSSSS", + "arg1 arg2 arg3 arg4 arg5 arg6 arg7 arg8", + "Set the tag list to create a beam that travels between all the tags" + ); +Event EV_Client_Lightstyle + ( + "lightstyle", + EV_DEFAULT, + "s", + "nameOfImage", + "Set a lightstyle to determine the color of this tempmodel, the image\n" + "specified is used to determine the look of the light style" + ); +Event EV_Client_DuplicateCount + ( + "duplicatecount", + EV_DEFAULT, + "i", + "num", + "Set a duplication number for the tempmodels" + ); +Event EV_Client_PhysicsRate + ( + "physicsrate", + EV_DEFAULT, + "s", + "rate", + "Set the rate (in updates per second) for the tempmodel's physics to be updated" + ); +Event EV_Client_Parallel + ( + "parallel", + EV_DEFAULT, + NULL, + NULL, + "Set tempmodel to be parallel to the viewer" + ); +Event EV_Client_Detail + ( + "detail", + EV_DEFAULT, + NULL, + NULL, + "Set emitter/tempmodel to be detail. Which can be turned off by detail" + ); +Event EV_Client_Print + ( + "print", + EV_DEFAULT, + "s", + "string", + "Prints a string." + ); + +CLASS_DECLARATION( Listener, ClientGameCommandManager, NULL ) + { + { &EV_Client_StartBlock, StartBlock }, + { &EV_Client_EndBlock, EndBlock }, + { &EV_Client_EmitterStartOff, EmitterStartOff }, + { &EV_Client_OriginSpawn, BeginOriginSpawn }, + { &EV_Client_OriginBeamSpawn, BeginOriginBeamSpawn }, + { &EV_Client_OriginBeamEmitter, BeginOriginBeamEmitter }, + { &EV_Client_TagSpawn, BeginTagSpawn }, + { &EV_Client_TagEmitter, BeginTagEmitter }, + { &EV_Client_BeginTagBeamEmitter, BeginTagBeamEmitter }, + { &EV_Client_BeginTagBeamSpawn, BeginTagBeamSpawn }, + { &EV_Client_OriginEmitter, BeginOriginEmitter }, + { &EV_Client_EmitterOn, EmitterOn }, + { &EV_Client_EmitterOff, EmitterOff }, + { &EV_Client_SetAlpha, SetAlpha }, + { &EV_Client_SetDieTouch, SetDieTouch }, + { &EV_Client_SetBounceFactor, SetBounceFactor }, + { &EV_Client_SetBounceSound, SetBounceSound }, + { &EV_Client_SetBounceSoundOnce, SetBounceSoundOnce }, + { &EV_Client_SetScale, SetScale }, + { &EV_Client_SetScaleUpDown, SetScaleUpDown }, + { &EV_Client_SetScaleMin, SetScaleMin }, + { &EV_Client_SetScaleMax, SetScaleMax }, + { &EV_Client_SetModel, SetModel }, + { &EV_Client_SetLife, SetLife }, + { &EV_Client_SetColor, SetColor }, + { &EV_Client_SetVelocity, SetVelocity }, + { &EV_Client_SetAngularVelocity, SetAngularVelocity }, + { &EV_Client_SetRandomVelocity, SetRandomVelocity }, + { &EV_Client_SetRandomVelocityAlongAxis, SetRandomVelocityAlongAxis }, + { &EV_Client_SetAccel, SetAccel }, + { &EV_Client_SetCount, SetCount }, + { &EV_Client_SetTraceCount, SetTraceCount }, + { &EV_Client_SetFade, SetFade }, + { &EV_Client_SetFadeDelay, SetFadeDelay }, + { &EV_Client_SetFadeIn, SetFadeIn }, + { &EV_Client_SetTwinkle, SetTwinkle }, + { &EV_Client_SetTrail, SetTrail }, + { &EV_Client_SetSpawnRate, SetSpawnRate }, + { &EV_Client_SetScaleRate, SetScaleRate }, + { &EV_Client_SetOriginOffset, SetOriginOffset }, + { &EV_Client_SetSphere, SetSphere }, + { &EV_Client_SetCircle, SetCircle }, + { &EV_Client_SetInwardSphere, SetInwardSphere }, + { &EV_Client_SetRadius, SetRadius }, + { &EV_Client_SetWavy, SetWavy }, + { &EV_Client_SetSwarm, SetSwarm }, + { &EV_Client_SetAlign, SetAlign }, + { &EV_Client_SetAlignOnce, SetAlignOnce }, + { &EV_Client_SetCollision, SetCollision }, + { &EV_Client_SetFlickerAlpha, SetFlickerAlpha }, + { &EV_Client_Sound, Sound }, + { &EV_Client_StopSound, StopSound }, + { &EV_Client_LoopSound, LoopSound }, + { &EV_Client_Cache, Cache }, + { &EV_Client_AliasCache, AliasCache }, + { &EV_Client_Alias, Alias }, + { &EV_Client_Footstep, Footstep }, + { &EV_Client_Client, Client }, + { &EV_Client_TagDynamicLight, TagDynamicLight }, + { &EV_Client_OriginDynamicLight, OriginDynamicLight }, + { &EV_Client_DynamicLight, DynamicLight }, + { &EV_Client_SetEntityColor, SetEntityColor }, + { &EV_Client_SetGlobalFade, SetGlobalFade }, + { &EV_Client_SetParentLink, SetParentLink }, + { &EV_Client_SetHardLink, SetHardLink }, + { &EV_Client_SetRandomRoll, SetRandomRoll }, + { &EV_Client_SetAngles, SetAngles }, + { &EV_Client_ParentAngles, ParentAngles }, + { &EV_Client_Swipe, Swipe }, + { &EV_Client_SwipeOn, SwipeOn }, + { &EV_Client_SwipeOff, SwipeOff }, + { &EV_Client_SetAnim, SetAnim }, + { &EV_Client_AnimateOnce, AnimateOnce }, + { &EV_Client_SetSubdivisions, SetSubdivisions }, + { &EV_Client_SetMinOffset, SetMinOffset }, + { &EV_Client_SetMaxOffset, SetMaxOffset }, + { &EV_Client_SetBeamShader, SetShader }, + { &EV_Client_SetBeamLength, SetLength }, + { &EV_Client_SetDecalShader, SetShader }, + { &EV_Client_SetTraceLength, SetLength }, + { &EV_Client_SetBeamDelay, SetBeamDelay }, + { &EV_Client_SetBeamToggleDelay, SetBeamToggleDelay }, + { &EV_Client_SetBeamPersist, SetBeamPersist }, + { &EV_Client_SetBeamOffsetEndpoints, SetBeamOffsetEndpoints }, + { &EV_Client_BeamSphere, SetBeamSphere }, + { &EV_Client_Spread, SetSpread }, + { &EV_Client_UseLastTraceEnd, SetUseLastTraceEnd }, + { &EV_Client_OffsetAlongAxis, SetOffsetAlongAxis }, + { &EV_Client_SetEndAlpha, SetEndAlpha }, + { &EV_Client_RandomChance, RandomChance }, + { &EV_Client_CommandDelay, CommandDelay }, + { &EV_Client_TagTraceImpactMark, BeginTagTraceImpactMark }, + { &EV_Client_BounceDecal, SetBounceDecal }, + { &EV_Client_SetDecalRadius, SetDecalRadius }, + { &EV_Client_SetDecalOrientation, SetDecalOrientation }, + { &EV_Client_TagTraceImpactSpawn, BeginTagTraceImpactSpawn }, + { &EV_Client_TagTraceImpactSound, TagTraceImpactSound }, + { &EV_Client_TagList, TagList }, + { &EV_Client_Lightstyle, SetLightstyle }, + { &EV_Client_DuplicateCount, SetDuplicateCount }, + { &EV_Client_PhysicsRate, SetPhysicsRate }, + { &EV_Client_Parallel, SetParallel }, + { &EV_Client_Detail, SetDetail }, + { &EV_Client_Print, Print }, + { NULL, NULL } + }; + +static int DLightNameToNum + ( + str s + ) + + { + if ( !s.icmp( "normal" ) ) + return 0; + else if ( !s.icmp( "lensflare" ) ) + return lensflare; + else if ( !s.icmp( "viewlensflare" ) ) + return viewlensflare; + else if ( !s.icmp( "additive" ) ) + return additive; + else + return 0; + } + +float RandomizeRange + ( + float start, + float end + ) + + { + float t; + + if ( start > end ) + { + return start; + } + + t = start + ( ( end - start ) * random() ); + return t; + } + +//============= +//ClientGameCommandManager +//============= +ClientGameCommandManager::ClientGameCommandManager + ( + ) + + { + m_seed = 0; + + InitializeTempModels(); + InitializeEmitters(); + } + +void ClientGameCommandManager::Print + ( + Event *ev + ) + + { + if ( current_entity ) + cgi.DPrintf( "%d:%s\n", current_entity->entityNumber, ev->GetString( 1 ) ); + } + +//=============== +// CommandDelay +//=============== +void ClientGameCommandManager::CommandDelay + ( + Event *ev + ) + + { + int i; + int delay; + Event *ev1; + + delay = ev->GetFloat( 1 ) * 1000; + if ( current_entity ) + { + commandtime_t *ct = m_command_time_manager.GetLastCommandTime( current_entity->entityNumber, ev->GetInteger( 2 ) ); + + if ( !ct->last_command_time ) + { + ct->last_command_time = cg.time + delay; + return; + } + + if ( ct->last_command_time > cg.time ) + return; + else + ct->last_command_time = cg.time + delay; + } + else + { + warning( "CCM:CommandDelay", "Cannot perform command delay on spawned tempmodels" ); + } + + ev1 = new Event( ev->GetString( 3 ) ); + + for ( i=4; i<=ev->NumArgs(); i++ ) + { + ev1->AddToken( ev->GetToken( i ) ); + } + ProcessEvent( ev1 ); + } + +//=============== +// RandomChance +//=============== +void ClientGameCommandManager::RandomChance + ( + Event *ev + ) + + { + int i; + float percentage = ev->GetFloat( 1 ); + + if ( ( random() < percentage ) && ( ev->NumArgs() >= 2 ) ) + { + Event *ev1; + + ev1 = new Event( ev->GetString( 2 ) ); + + for ( i=3; i<=ev->NumArgs(); i++ ) + { + ev1->AddToken( ev->GetToken( i ) ); + } + ProcessEvent( ev1 ); + } + } +//=============== +// SetDetail +//=============== +void ClientGameCommandManager::SetDetail + ( + Event *ev + ) + + { + m_spawnthing->cgd.flags |= T_DETAIL; + } + +//=============== +// SetDecalRadius +//=============== +void ClientGameCommandManager::SetDecalRadius + ( + Event *ev + ) + + { + m_spawnthing->cgd.decal_radius = ev->GetFloat( 1 ); + } + +//=============== +// SetDecalOrientation +//=============== +void ClientGameCommandManager::SetDecalOrientation + ( + Event *ev + ) + + { + str deg; + + deg = ev->GetString( 1 ); + + if ( !deg.icmp( "random" ) ) + m_spawnthing->cgd.decal_orientation = random() * 360; + else + m_spawnthing->cgd.decal_orientation = ev->GetFloat( 1 ); + } + +//=============== +// SetBounceDecal +//=============== +void ClientGameCommandManager::SetBounceDecal + ( + Event *ev + ) + { + m_spawnthing->cgd.flags2 |= T2_BOUNCE_DECAL; + if ( ev->NumArgs() > 1 ) + { + m_spawnthing->cgd.maxbouncecount = ev->GetInteger( 1 ); + + if ( ev->NumArgs() > 2 ) + { + qboolean b = ev->GetBoolean( 2 ); + if ( b ) + { + m_spawnthing->cgd.flags2 |= T2_TEMPORARY_DECAL; + } + } + } + } + +//=============== +// BeginTagTraceImpactMark +//=============== +void ClientGameCommandManager::BeginTagTraceImpactMark + ( + Event *ev + ) + { + // Setup ending function + endblockfcn = EndTagTraceImpactMark; + m_spawnthing = InitializeSpawnthing( &m_localemitter ); + + // Get the tagname and orientation + m_spawnthing->tagname = ev->GetString( 1 ); + GetOrientation( m_spawnthing->tagname, m_spawnthing ); + + if ( ev->NumArgs() > 2 ) + { + if ( ev->GetBoolean( 2 ) ) + { + m_spawnthing->cgd.flags2 |= T2_TEMPORARY_DECAL; + } + } + } + +//=============== +// EndTagTraceImpactMark +//=============== +void ClientGameCommandManager::EndTagTraceImpactMark + ( + void + ) + + { + Vector end; + trace_t trace; + int i; + + for ( i=0; itrace_count; i++ ) + { + if ( m_spawnthing->use_last_trace_end ) + { + end = last_trace_end; + } + else + { + end = m_spawnthing->cgd.origin + m_spawnthing->forward * m_spawnthing->length + + m_spawnthing->right * crandom() * m_spawnthing->spreadx + + m_spawnthing->up * crandom() * m_spawnthing->spready; + last_trace_end = end; + } + + // Do the trace to get the endpoint + CG_Trace( &trace, m_spawnthing->cgd.origin, vec_zero, vec_zero, end, ENTITYNUM_NONE, MASK_SHOT, false, true, "EndTagTraceImpactMark" ); + + if ( ( trace.fraction != 1.0f ) && !( trace.surfaceFlags & SURF_SKY ) && ( trace.entityNum == ENTITYNUM_WORLD ) ) + { + qhandle_t shader = cgi.R_RegisterShader( m_spawnthing->cgd.shadername ); + + CG_ImpactMark( shader, + trace.endpos, + trace.plane.normal, + m_spawnthing->cgd.decal_orientation, + (float)m_spawnthing->cgd.color[0]/255.0f, + (float)m_spawnthing->cgd.color[1]/255.0f, + (float)m_spawnthing->cgd.color[2]/255.0f, + m_spawnthing->cgd.alpha, + m_spawnthing->cgd.flags & T_FADE, + m_spawnthing->cgd.decal_radius, + m_spawnthing->cgd.flags2 & T2_TEMPORARY_DECAL, + m_spawnthing->cgd.lightstyle, + m_spawnthing->cgd.flags & T_FADEIN); + } + } + } + +//=============== +// BeginTagTraceImpactSpawn +//=============== +void ClientGameCommandManager::BeginTagTraceImpactSpawn + ( + Event *ev + ) + { + // Setup ending function + endblockfcn = EndTagTraceImpactSpawn; + m_spawnthing = InitializeSpawnthing( &m_localemitter ); + + // Get the tagname and orientation + m_spawnthing->tagname = ev->GetString( 1 ); + GetOrientation( m_spawnthing->tagname, m_spawnthing ); + } + +//=============== +// EndTagTraceImpactSpawn +//=============== +void ClientGameCommandManager::EndTagTraceImpactSpawn + ( + void + ) + + { + Vector end,dir,org,f,r,u; + trace_t trace; + int i; + + org = m_spawnthing->cgd.origin; + f = m_spawnthing->forward; + r = m_spawnthing->right; + u = m_spawnthing->up; + + for ( i=0; itrace_count; i++ ) + { + if ( m_spawnthing->use_last_trace_end ) + { + end = last_trace_end; + } + else + { + end = org + f * m_spawnthing->length + + r * crandom() * m_spawnthing->spreadx + + u * crandom() * m_spawnthing->spready; + + last_trace_end = end; + } + + // Do the trace to get the endpoint + CG_Trace( &trace, org, vec_zero, vec_zero, end, ENTITYNUM_NONE, MASK_SHOT, false, true, "EndTagTraceImpactSpawn" ); + + if ( ( trace.fraction != 1.0f ) && !( trace.surfaceFlags & SURF_SKY ) && ( trace.entityNum == ENTITYNUM_WORLD ) ) + { + dir = trace.endpos - m_spawnthing->cgd.origin; + dir.normalize(); + + m_spawnthing->forward = trace.plane.normal; + VectorCopy( m_spawnthing->forward, m_spawnthing->tag_axis[0] ); + m_spawnthing->cgd.origin = trace.endpos; + SpawnTempModel( m_spawnthing->count ); + } + } + } + +//=============== +// EndTagTraceImpactSound +//=============== +void ClientGameCommandManager::TagTraceImpactSound + ( + Event *ev + ) + + { + float maxlength; + Vector end; + trace_t trace; + + maxlength = ev->GetFloat( 1 ); + end = m_spawnthing->cgd.origin + m_spawnthing->forward * maxlength; + + // Do the trace to get the endpoint + CG_Trace( &trace, m_spawnthing->cgd.origin, vec_zero, vec_zero, end, ENTITYNUM_NONE, MASK_SHOT, false, true, "EndTagTraceImpactSound" ); + + if ( ( trace.fraction != 1.0f ) && !( trace.surfaceFlags & SURF_SKY ) && ( trace.entityNum == ENTITYNUM_WORLD ) ) + { + PlaySound( ev->GetString( 2 ), &trace.endpos ); + } + } + +//=============== +// SetDuplicateCount +//=============== +void ClientGameCommandManager::SetDuplicateCount + ( + Event *ev + ) + + { + m_spawnthing->cgd.duplicateCount = ev->GetInteger( 1 ); + } + +//=============== +// SetParallel +//=============== +void ClientGameCommandManager::SetParallel + ( + Event *ev + ) + + { + m_spawnthing->cgd.flags2 |= T2_PARALLEL; + } + +//=============== +// PhysicsRate +//=============== +void ClientGameCommandManager::SetPhysicsRate + ( + Event *ev + ) + + { + str rate; + + rate = ev->GetString( 1 ); + + if ( !rate.icmp( rate, "every" ) ) + m_spawnthing->cgd.flags2 |= T2_PHYSICS_EVERYFRAME; + else + m_spawnthing->cgd.physicsRate = atof( rate ); + } + +//=============== +// SetLightstyle +//=============== +void ClientGameCommandManager::SetLightstyle + ( + Event *ev + ) + + { + m_spawnthing->cgd.lightstyle = CG_RegisterLightStyle( ev->GetString( 1 ) ); + } + +//=============== +// SetBeamSphere +//=============== +void ClientGameCommandManager::SetBeamSphere + ( + Event *ev + ) + + { + m_spawnthing->numspherebeams = ev->GetInteger( 1 ); + m_spawnthing->beamflags = BEAM_SPHERE_EFFECT; + } + +//=============== +// SetBeamSpread +//=============== +void ClientGameCommandManager::SetSpread + ( + Event *ev + ) + + { + m_spawnthing->spreadx = ev->GetFloat( 1 ); + m_spawnthing->spready = ev->GetFloat( 2 ); + } + +//=============== +// SetUseLastTraceEnd +//=============== +void ClientGameCommandManager::SetUseLastTraceEnd + ( + Event *ev + ) + + { + m_spawnthing->use_last_trace_end = qtrue; + } + +//=============== +// SetSubdivisions +//=============== +void ClientGameCommandManager::SetSubdivisions + ( + Event *ev + ) + + { + m_spawnthing->numSubdivisions = ev->GetInteger( 1 ); + } + +//=============== +// SetBeamPersist +//=============== +void ClientGameCommandManager::SetBeamPersist + ( + Event *ev + ) + + { + m_spawnthing->beamflags |= BEAM_PERSIST_EFFECT; + } + +//=============== +// SetBeamOffsetEndponts +//=============== +void ClientGameCommandManager::SetBeamOffsetEndpoints + ( + Event *ev + ) + + { + m_spawnthing->beamflags |= BEAM_OFFSET_ENDPOINTS; + } + +//=============== +// SetBeamDelay +//=============== +void ClientGameCommandManager::SetBeamDelay + ( + Event *ev + ) + + { + if ( ev->NumArgs() > 1 ) + { + str r = ev->GetString( 1 ); + if ( r.icmp( "random" ) ) + m_spawnthing->beamflags |= BEAM_RANDOM_DELAY; + m_spawnthing->delay = ev->GetFloat( 2 ) * 1000.0f; + } + else + { + m_spawnthing->delay = ev->GetFloat( 1 ) * 1000.0f; + } + } + +//=============== +// SetBeamToggleDelay +//=============== +void ClientGameCommandManager::SetBeamToggleDelay + ( + Event *ev + ) + + { + m_spawnthing->beamflags |= BEAM_TOGGLE; + if ( ev->NumArgs() > 1 ) + { + str r = ev->GetString( 1 ); + if ( !r.icmp( "random" ) ) + m_spawnthing->beamflags |= BEAM_RANDOM_TOGGLEDELAY; + + m_spawnthing->toggledelay = ev->GetFloat( 2 ) * 1000.0f; + } + else + { + m_spawnthing->toggledelay = ev->GetFloat( 1 ) * 1000.0f; + } + } + +//=============== +// SetBeamLength +//=============== +void ClientGameCommandManager::SetLength + ( + Event *ev + ) + + { + m_spawnthing->length = ev->GetFloat( 1 ); + } + +//=============== +// SetShader +//=============== +void ClientGameCommandManager::SetShader + ( + Event *ev + ) + + { + m_spawnthing->cgd.shadername = ev->GetString( 1 ); + } + +//=============== +// SetMinOffset +//=============== +void ClientGameCommandManager::SetMinOffset + ( + Event *ev + ) + + { + m_spawnthing->min_offset = ev->GetInteger( 1 ); + } + +//=============== +// SetSubdivisions +//=============== +void ClientGameCommandManager::SetMaxOffset + ( + Event *ev + ) + + { + m_spawnthing->max_offset = ev->GetInteger( 1 ); + } + +//=============== +// SetAnim +//=============== +void ClientGameCommandManager::SetAnim + ( + Event *ev + ) + + { + m_spawnthing->animName = ev->GetString( 1 ); + } + +//=============== +// AnimateOnce +//=============== +void ClientGameCommandManager::AnimateOnce + ( + Event *ev + ) + + { + m_spawnthing->cgd.flags |= T_ANIMATEONCE; + } + +//=============== +// EmitterStartOff +//=============== +void ClientGameCommandManager::EmitterStartOff + ( + Event *ev + ) + + { + m_spawnthing->startoff = qtrue; + } + +//=============== +// StartBlock +//=============== +void ClientGameCommandManager::StartBlock + ( + Event *ev + ) + + { + // Make sure there are no more args on this line, because + // they will be lost + if ( ev->NumArgs() > 1 ) + cgi.DPrintf( "CCM::StartBlock : Invalid commands on start block '{'\n" ); + } + +//=============== +// EndBlock +//=============== +void ClientGameCommandManager::EndBlock + ( + Event *ev + ) + + { + // Make sure there are no more args on this line, because + // they will be lost + + if ( ev->NumArgs() > 1 ) + cgi.DPrintf( "CCM::StartBlock : Invalid commands on start block '{'\n" ); + + if ( endblockfcn ) + ( this->*endblockfcn)( ) ; + + endblockfcn = NULL; + } + +//============= +//SetSwarm +//============= +void ClientGameCommandManager::SetSwarm + ( + Event *ev + ) + + { + m_spawnthing->cgd.swarmfreq = ev->GetInteger( 1 ); + m_spawnthing->cgd.swarmmaxspeed = ev->GetFloat( 2 ); + m_spawnthing->cgd.swarmdelta = ev->GetFloat( 3 ); + m_spawnthing->cgd.flags |= T_SWARM; + } + + +//============= +//SetWavy +//============= +void ClientGameCommandManager::SetWavy + ( + Event *ev + ) + + { + str wave; + + wave = ev->GetString( 1 ); + if ( wave == "crandom" ) + { + m_spawnthing->cgd.wave = crandom() * ev->GetFloat( 2 ); + } + else if ( wave == "random" ) + { + m_spawnthing->cgd.wave = random() * ev->GetFloat( 2); + } + else + { + m_spawnthing->cgd.wave = atof( wave.c_str() ); + } + m_spawnthing->cgd.flags |= T_WAVE; + } + +//============= +//SetCircle +//============= +void ClientGameCommandManager::SetCircle + ( + Event *ev + ) + + { + m_spawnthing->cgd.flags |= T_CIRCLE; + } + +//============= +//SetSphere +//============= +void ClientGameCommandManager::SetSphere + ( + Event *ev + ) + + { + m_spawnthing->cgd.flags |= T_SPHERE; + } + +//============= +//SetSphere +//============= +void ClientGameCommandManager::SetRadius + ( + Event *ev + ) + + { + m_spawnthing->sphereRadius = ev->GetFloat( 1 ); + } + +//============= +//SetInwardSphere +//============= +void ClientGameCommandManager::SetInwardSphere + ( + Event *ev + ) + + { + m_spawnthing->cgd.flags |= T_INWARDSPHERE; + m_spawnthing->sphereRadius = ev->GetFloat( 1 ); + } + +//============= +//SetAlign +//============= +void ClientGameCommandManager::SetAlign + ( + Event *ev + ) + + { + m_spawnthing->cgd.flags |= T_ALIGN; + } + +//============= +//SetAlignOnce +//============= +void ClientGameCommandManager::SetAlignOnce + ( + Event *ev + ) + + { + m_spawnthing->cgd.flags |= T_ALIGNONCE; + } + +//============= +//SetRandomRoll +//============= +void ClientGameCommandManager::SetRandomRoll + ( + Event *ev + ) + + { + m_spawnthing->cgd.flags |= T_RANDOMROLL; + } + +//============= +//SetCollision +//============= +void ClientGameCommandManager::SetCollision + ( + Event *ev + ) + + { + str mask; + + m_spawnthing->cgd.flags |= T_COLLISION; + m_spawnthing->cgd.collisionmask = ( CONTENTS_SOLID ); + + if ( ev->NumArgs() > 1 ) + { + mask = ev->GetString( 1 ); + + if ( mask == "water" ) + { + m_spawnthing->cgd.collisionmask = ( CONTENTS_SOLID|CONTENTS_WATER ); + } + } + } + +//============= +//SetFlickerAlpha +//============= +void ClientGameCommandManager::SetFlickerAlpha + ( + Event *ev + ) + + { + m_spawnthing->cgd.flags |= T_FLICKERALPHA; + } + +//============= +//SetEndAlpha +//============= +void ClientGameCommandManager::SetEndAlpha + ( + Event *ev + ) + + { + m_spawnthing->endalpha = ev->GetFloat( 1 ); + } + + +//============= +//SetOffsetAlongAxis +//============= +void ClientGameCommandManager::SetOffsetAlongAxis + ( + Event *ev + ) + + { + int i = 1; + int j = 0; + + while ( j < 3 ) + { + str org; + + org = ev->GetString( i++ ); + if ( org == "crandom" ) + { + m_spawnthing->randaxis[ j ] = CRANDOM; + m_spawnthing->axis_offset[j++] = ev->GetFloat( i++ ); + } + else if ( org == "random" ) + { + m_spawnthing->randaxis[ j ] = RANDOM; + m_spawnthing->axis_offset[j++] = ev->GetFloat( i++ ); + } + else + { + m_spawnthing->randaxis[ j ] = NOT_RANDOM; + m_spawnthing->axis_offset[j++] = atof( org.c_str() ); + } + } + } + +//============= +//SetOriginOffset +//============= +void ClientGameCommandManager::SetOriginOffset + ( + Event *ev + ) + + { + int i = 1; + int j = 0; + + while ( j < 3 ) + { + str org; + + org = ev->GetString( i++ ); + if ( org == "crandom" ) + { + m_spawnthing->randorg[ j ] = CRANDOM; + m_spawnthing->origin_offset[j++] = ev->GetFloat( i++ ); + } + else if ( org == "random" ) + { + m_spawnthing->randorg[ j ] = RANDOM; + m_spawnthing->origin_offset[j++] = ev->GetFloat( i++ ); + } + else + { + m_spawnthing->randorg[ j ] = NOT_RANDOM; + m_spawnthing->origin_offset[j++] = atof( org.c_str() ); + } + } + } + +//============= +//SetAlpha +//============= +void ClientGameCommandManager::SetAlpha + ( + Event *ev + ) + + { + m_spawnthing->cgd.alpha = ev->GetFloat( 1 ); + } + +//============= +//SetDieTouch +//============= +void ClientGameCommandManager::SetDieTouch + ( + Event *ev + ) + + { + m_spawnthing->cgd.flags |= T_DIETOUCH; + } + +//============= +//SetBounceFactor +//============= +void ClientGameCommandManager::SetBounceFactor + ( + Event *ev + ) + + { + m_spawnthing->cgd.bouncefactor = ev->GetFloat( 1 ); + m_spawnthing->cgd.flags |= T_COLLISION; + m_spawnthing->cgd.collisionmask = ( CONTENTS_SOLID ); + } + +//============= +//SetBounceSound +//============= +void ClientGameCommandManager::SetBounceSound + ( + Event *ev + ) + + { + m_spawnthing->cgd.bouncesound = ev->GetString( 1 ); + + if ( ev->NumArgs() == 2 ) + m_spawnthing->cgd.bouncesound_delay = ev->GetFloat( 1 ) * 1000; + + m_spawnthing->cgd.flags |= T_BOUNCESOUND; + } + +//============= +//SetBounceSoundOnce +//============= +void ClientGameCommandManager::SetBounceSoundOnce + ( + Event *ev + ) + + { + m_spawnthing->cgd.flags |= T_BOUNCESOUNDONCE; + SetBounceSound( ev ); + } + +//============= +//SetScale +//============= +void ClientGameCommandManager::SetScale + ( + Event *ev + ) + + { + m_spawnthing->cgd.scale = ev->GetFloat( 1 ); + } + +//============= +//SetScaleUpDown +//============= +void ClientGameCommandManager::SetScaleUpDown + ( + Event *ev + ) + + { + m_spawnthing->cgd.flags |= T_SCALEUPDOWN; + } + +//============= +//SetScaleMin +//============= +void ClientGameCommandManager::SetScaleMin + ( + Event *ev + ) + + { + m_spawnthing->cgd.flags |= T_RANDSCALE; + m_spawnthing->cgd.scalemin = ev->GetFloat( 1 ); + } + +//============= +//SetScaleMax +//============= +void ClientGameCommandManager::SetScaleMax + ( + Event *ev + ) + + { + m_spawnthing->cgd.flags |= T_RANDSCALE; + m_spawnthing->cgd.scalemax = ev->GetFloat( 1 ); + } + +//============= +//SetScaleRate +//============= +void ClientGameCommandManager::SetScaleRate + ( + Event *ev + ) + + { + m_spawnthing->cgd.scaleRate = ev->GetFloat( 1 ); + } + +//============= +//SetFade +//============= +void ClientGameCommandManager::SetFade + ( + Event *ev + ) + + { + m_spawnthing->cgd.flags |= T_FADE; + } + +//============= +//SetFadeDelay +//============= +void ClientGameCommandManager::SetFadeDelay + ( + Event *ev + ) + + { + m_spawnthing->cgd.fadedelay = ev->GetFloat( 1 ) * 1000; + m_spawnthing->cgd.flags |= T_FADE; + } + +//============= +//SetFadeIn +//============= +void ClientGameCommandManager::SetFadeIn + ( + Event *ev + ) + + { + m_spawnthing->cgd.flags |= T_FADEIN; + + if ( ev->NumArgs() > 0 ) + m_spawnthing->cgd.fadeintime = ev->GetFloat( 1 ) * 1000; + } + +//============= +//SetTwinkle +//============= +void ClientGameCommandManager::SetTwinkle + ( + Event *ev + ) + + { + m_spawnthing->cgd.flags |= T_TWINKLE; + m_spawnthing->cgd.min_twinkletimeoff = ev->GetFloat( 1 ) * 1000; + m_spawnthing->cgd.max_twinkletimeoff = ev->GetFloat( 2 ) * 1000; + m_spawnthing->cgd.min_twinkletimeon = ev->GetFloat( 3 ) * 1000; + m_spawnthing->cgd.max_twinkletimeon = ev->GetFloat( 4 ) * 1000; + } + +//============= +//SetSwipe +//============= +void ClientGameCommandManager::SetTrail + ( + Event *ev + ) + + { + m_spawnthing->cgd.flags2 |= T2_TRAIL; + m_spawnthing->cgd.swipe_shader = ev->GetString( 1 ); + m_spawnthing->cgd.swipe_tag_start = ev->GetString( 2 ); + m_spawnthing->cgd.swipe_tag_end = ev->GetString( 3 ); + m_spawnthing->cgd.swipe_life = ev->GetFloat( 4 ); + } + + +//============= +//SetSpawnRate +//============= +void ClientGameCommandManager::SetSpawnRate + ( + Event *ev + ) + + { + m_spawnthing->spawnRate = ( 1.0f / ev->GetFloat( 1 ) ) * 1000; + } + +//============= +//SetParentLink +//============= +void ClientGameCommandManager::SetParentLink + ( + Event *ev + ) + + { + m_spawnthing->cgd.flags |= T_PARENTLINK; + } + +//============= +//SetHardLink +//============= +void ClientGameCommandManager::SetHardLink + ( + Event *ev + ) + + { + m_spawnthing->cgd.flags |= T_HARDLINK; + m_spawnthing->cgd.parent = current_entity_number; + + if ( current_entity ) + m_spawnthing->cgd.origin = m_spawnthing->cgd.origin - current_entity->origin; + } + +//============= +//SetColor +//============= +void ClientGameCommandManager::SetColor + ( + Event *ev + ) + + { + m_spawnthing->cgd.color[0] = ev->GetFloat( 1 ) * 0xff; + m_spawnthing->cgd.color[1] = ev->GetFloat( 2 ) * 0xff; + m_spawnthing->cgd.color[2] = ev->GetFloat( 3 ) * 0xff; + + if ( ev->NumArgs() == 4 ) + { + m_spawnthing->cgd.color[3] = ev->GetFloat( 4 ) * 0xff; + m_spawnthing->cgd.alpha = ev->GetFloat( 4 ); + } + + } + +//============= +//SetEntityColor +//============= +void ClientGameCommandManager::SetEntityColor + ( + Event *ev + ) + + { + if ( current_centity ) + { + current_centity->client_color[0] = ev->GetFloat( 1 ); + current_centity->client_color[1] = ev->GetFloat( 2 ); + current_centity->client_color[2] = ev->GetFloat( 3 ); + if ( ev->NumArgs() == 4 ) + current_centity->client_color[3] = ev->GetFloat( 4 ); + } + } + +//============= +//SetGlobalFade +//============= +void ClientGameCommandManager::SetGlobalFade + ( + Event *ev + ) + + { + str mode; + + mode = ev->GetString( 1 ); + + if ( mode == "in" ) + m_spawnthing->cgd.flags |= T_GLOBALFADEIN; + else if ( mode == "out" ) + m_spawnthing->cgd.flags |= T_GLOBALFADEOUT; + else + cgi.DPrintf( "Illegal globalfade parm: %s\n", mode.c_str() ); + } + +//============= +//SetRandomVelocity +//============= +void ClientGameCommandManager::SetRandomVelocity + ( + Event *ev + ) + + { + int i = 1; + int j = 0; + Vector randval; + str vel; + + if ( ev->NumArgs() < 3 ) + { + warning( "ClientGameCommandManager::SetRandomVelocity", "Expecting at least 3 args for command randvel" ); + } + + while ( j < 3 ) + { + vel = ev->GetString( i++ ); + if ( vel == "crandom" ) + { + m_spawnthing->randvel[ j ] = CRANDOM; + m_spawnthing->velocityVariation[j++] = ev->GetFloat( i++ ); + } + else if ( vel == "random" ) + { + m_spawnthing->randvel[ j ] = RANDOM; + m_spawnthing->velocityVariation[j++] = ev->GetFloat( i++ ); + } + else + { + m_spawnthing->randvel[ j ] = NOT_RANDOM; + m_spawnthing->velocityVariation[j++] = atof( vel.c_str() ); + } + } + + m_spawnthing->cgd.flags2 |= T2_MOVE; + } + +//============= +//SetRandomVelocityAlongAxis +//============= +void ClientGameCommandManager::SetRandomVelocityAlongAxis + ( + Event *ev + ) + + { + m_spawnthing->cgd.flags |= T_RANDVELAXIS; + SetRandomVelocity( ev ); + } + + +//============= +//SetVelocity +//============= +void ClientGameCommandManager::SetVelocity + ( + Event *ev + ) + + { + m_spawnthing->forwardVelocity = ev->GetFloat( 1 ); + m_spawnthing->cgd.flags2 |= T2_MOVE; + } + +//============= +//SetAngularVelocity +//============= +void ClientGameCommandManager::SetAngularVelocity + ( + Event *ev + ) + + { + int i = 1; + int j = 0; + Vector randval; + str vel; + + if ( ev->NumArgs() < 3 ) + { + warning( "ClientGameCommandManager::SetAngularVelocity", "Expecting at least 3 args for command randvel" ); + } + + while ( j < 3 ) + { + vel = ev->GetString( i++ ); + if ( vel == "crandom" ) + { + m_spawnthing->randavel[ j ] = CRANDOM; + m_spawnthing->cgd.avelocity[j++] = ev->GetFloat( i++ ); + } + else if ( vel == "random" ) + { + m_spawnthing->randavel[ j ] = RANDOM; + m_spawnthing->cgd.avelocity[j++] = ev->GetFloat( i++ ); + } + else + { + m_spawnthing->randavel[ j ] = NOT_RANDOM; + m_spawnthing->cgd.avelocity[j++] = atof( vel.c_str() ); + } + } + + m_spawnthing->cgd.flags2 |= T2_AMOVE; + } + +//============= +//SetAngles +//============= +void ClientGameCommandManager::SetAngles + ( + Event *ev + ) + + { + int i = 1; + int j = 0; + Vector randval; + str vel; + + if ( ev->NumArgs() < 3 ) + { + warning( "ClientGameCommandManager::SetAngles", "Expecting at least 3 args for command randvel" ); + } + + while ( j < 3 ) + { + vel = ev->GetString( i++ ); + if ( vel == "crandom" ) + { + m_spawnthing->randangles[ j ] = CRANDOM; + m_spawnthing->cgd.angles[j++] = ev->GetFloat( i++ ); + } + else if ( vel == "random" ) + { + m_spawnthing->randangles[ j ] = RANDOM; + m_spawnthing->cgd.angles[j++] = ev->GetFloat( i++ ); + } + else + { + m_spawnthing->randangles[ j ] = NOT_RANDOM; + m_spawnthing->cgd.angles[j++] = atof( vel.c_str() ); + } + } + // Set the tag axis + m_spawnthing->cgd.flags |= T_ANGLES; + } + +//============= +//ParentAngles +//============= +void ClientGameCommandManager::ParentAngles + ( + Event *ev + ) + + { + if ( current_centity ) + { + m_spawnthing->cgd.angles = Vector( current_centity->currentState.angles ); + } + m_spawnthing->cgd.flags |= T_ANGLES; + } + +//============= +//SetAccel +//============= +void ClientGameCommandManager::SetAccel + ( + Event *ev + ) + + { + m_spawnthing->cgd.accel[0] = ev->GetFloat( 1 ); + m_spawnthing->cgd.accel[1] = ev->GetFloat( 2 ); + m_spawnthing->cgd.accel[2] = ev->GetFloat( 3 ); + + m_spawnthing->cgd.flags2 |= T2_ACCEL; + } + +//============= +//SetCount +//============= +void ClientGameCommandManager::SetCount + ( + Event *ev + ) + + { + m_spawnthing->count = ev->GetInteger( 1 ); + } + +//============= +//SetTraceCount +//============= +void ClientGameCommandManager::SetTraceCount + ( + Event *ev + ) + + { + m_spawnthing->trace_count = ev->GetInteger( 1 ); + } + +//============= +//SetLife +//============= +void ClientGameCommandManager::SetLife + ( + Event *ev + ) + + { + str life; + + life = ev->GetString( 1 ); + + if ( !life.icmp( "autocalc" ) ) + m_spawnthing->cgd.flags |= T_AUTOCALCLIFE; + else + m_spawnthing->cgd.life = atof( life ) * 1000; + } + +//============= +//SetModel +//============= +void ClientGameCommandManager::SetModel + ( + Event *ev + ) + + { + int i; + int num = ev->NumArgs(); + + for ( i=1; i<=num; i++ ) + { + str s_arg( ev->GetString( i ) ); + m_spawnthing->m_modellist.AddObject( s_arg ); + CacheResource( ev->GetString( i ) ); + } + } + +//============= +//TagList +//============= +void ClientGameCommandManager::TagList + ( + Event *ev + ) + + { + int i; + int num = ev->NumArgs(); + + if ( num < 2 ) + { + warning( "CCG::TagList", "Invalid number of tags specified in taglist. Minimum set of tags is 2.\n" ); + return; + } + + for ( i=1; i<=num; i++ ) + { + str s_arg( ev->GetString( i ) ); + m_spawnthing->m_taglist.AddObject( s_arg ); + } + } + +//============= +//InitializeSpawnthing +//============= +spawnthing_t *ClientGameCommandManager::InitializeSpawnthing + ( + spawnthing_t *sp + ) + + { + int i; + + // Initalize m_spawnthing - these can be overidden with other commands + sp->m_modellist.ClearObjectList(); + AxisClear( sp->axis ); + AxisClear( sp->tag_axis ); + + sp->startoff = qfalse; + sp->velocityVariation = Vector( 0,0,0 ); + sp->origin_offset = Vector( 0,0,0 ); + sp->axis_offset = Vector( 0,0,0 ); + sp->forwardVelocity = 0; + sp->count = 1; + sp->trace_count = 1; + sp->delay = 0; + sp->beamflags = 0; + sp->length = 1000; + sp->max_offset = 0; + sp->min_offset = 0; + sp->numSubdivisions = 1; + sp->overlap = 0; + sp->startoff = 0; + sp->numspherebeams = 0; + sp->spreadx = 0; + sp->spready = 0; + sp->use_last_trace_end = qfalse; + sp->endalpha = 1.0f; + sp->sphereRadius = 0; + sp->spawnRate = 1.0f/10.0f; + sp->touchfcn = NULL; + sp->forward = Vector( 1,0,0 ); + sp->right = Vector( 0,1,0 ); + sp->up = Vector( 0,0,1 ); + + sp->cgd.scale = 1.0f; + sp->cgd.createTime = cg.time; + sp->cgd.life = EMITTER_DEFAULT_LIFE; + sp->cgd.avelocity = Vector( 0,0,0 ); + sp->cgd.accel = Vector( 0,0,0 ); + sp->cgd.origin = Vector( 0,0,0 ); + sp->cgd.oldorigin = Vector( 0,0,0 ); + sp->cgd.angles = Vector( 0,0,0 ); + sp->cgd.alpha = 1.0f; + sp->cgd.scalemin = 0; + sp->cgd.scalemax = 999999.0f; + sp->cgd.scaleRate = 0; + sp->cgd.bouncefactor = 1.0f; + sp->cgd.bouncesound = ""; + sp->cgd.bouncesound_delay = 1000; + sp->cgd.bouncecount = 0; + sp->cgd.maxbouncecount = 3; + sp->cgd.flags = 0; + sp->cgd.flags2 = 0; + sp->cgd.duplicateCount = 0; + sp->cgd.wave = 0; + sp->cgd.swarmfreq = 0; + sp->cgd.swarmdelta = 0; + sp->cgd.swarmmaxspeed = 0; + sp->cgd.fadeintime = 0; + sp->cgd.fadedelay = 0; + sp->cgd.lightIntensity = 0; + sp->cgd.lightType = 0; + sp->cgd.collisionmask = CONTENTS_SOLID; + sp->cgd.parent = -1; + sp->cgd.tikihandle = -1; + sp->cgd.lightstyle = -1; + sp->cgd.physicsRate = 10; + sp->cgd.shadername = "beamshader"; + sp->cgd.decal_orientation = 0; + sp->cgd.decal_radius = 10; + sp->cgd.max_twinkletimeoff = 0; + sp->cgd.min_twinkletimeoff = 0; + sp->cgd.max_twinkletimeon = 0; + sp->cgd.min_twinkletimeon = 0; + sp->cgd.swipe_life = 0; + + for ( i=0; i<3; i++ ) + { + sp->dcolor[i] = 1.0f; + sp->randvel[i] = NOT_RANDOM; + sp->randorg[i] = NOT_RANDOM; + sp->randavel[i] = NOT_RANDOM; + sp->randangles[i] = NOT_RANDOM; + sp->randaxis[i] = NOT_RANDOM; + sp->cgd.color[i] = 0xff; + } + + sp->cgd.color[3] = 255; + + return sp; + } + +//================== +//GetEmitterByName +//================== +spawnthing_t *ClientGameCommandManager::GetEmitterByName + ( + str name + ) + + { + int i; + for ( i=1; i<=m_emitters.NumObjects(); i++ ) + { + spawnthing_t *st = m_emitters.ObjectAt( i ); + if ( st->emittername == name ) + { + return st; + } + } + return NULL; + } + +//================== +//CreateNewEmitter +//================== +spawnthing_t *ClientGameCommandManager::CreateNewEmitter + ( + str name + ) + + { + spawnthing_t *st; + + st = new spawnthing_t; + + // Init the emitter and set the internal pointer at it + InitializeSpawnthing( st ); + + // Set the emitter's name + st->emittername = name; + + // Store it in the container + m_emitters.AddObject( st ); + + return st; + } + +//================== +//CreateNewEmitter +//================== +spawnthing_t *ClientGameCommandManager::CreateNewEmitter + ( + void + ) + + { + return CreateNewEmitter( "" ); + } + +//=============== +//BeginOriginSpawn +//=============== +void ClientGameCommandManager::BeginOriginSpawn + ( + Event *ev + ) + + { + if ( !current_entity ) + { + cgi.DPrintf( "ClientGameCommandManager::BeginOriginSpawn : Illegal use of \"originspawn\"\n" ); + return; + } + + // Setup ending function + endblockfcn = EndOriginSpawn; + + // Init the thing we are going to spawn + m_spawnthing = InitializeSpawnthing( &m_localemitter ); + + // Set the origin based on the entity's origin + m_spawnthing->cgd.origin = current_entity->origin; + + // Set the axis based on the entity's axis + m_spawnthing->forward = current_entity->axis[0]; + m_spawnthing->right = current_entity->axis[1]; + m_spawnthing->up = current_entity->axis[2]; + } + +//=============== +// EndOriginSpawn +//=============== +void ClientGameCommandManager::EndOriginSpawn + ( + void + ) + + { + // Okay we should have a valid spawnthing, let's create a render entity + SpawnTempModel( m_spawnthing->count ); + } + +//=============== +//UpdateSpawnThing +//=============== +void ClientGameCommandManager::UpdateSpawnThing + ( + spawnthing_t *ep + ) + + { + int i; + orientation_t orientation; + + VectorCopy( current_entity->origin, ep->cgd.origin ); + + for ( i = 0 ; i < 3 ; i++ ) + { + VectorMA( ep->cgd.origin, orientation.origin[i], current_entity->axis[i], ep->cgd.origin ); + } + + MatrixMultiply( orientation.axis, current_entity->axis, ep->axis ); + + // Set the axis based on the tag's axis + ep->forward = ep->axis[0]; + ep->right = ep->axis[1]; + ep->up = ep->axis[2]; + } + +//=============== +//BeginTagEmitter +//=============== +void ClientGameCommandManager::BeginTagEmitter + ( + Event *ev + ) + + { + // Setup ending function + endblockfcn = EndTagEmitter; + + // Init the emitter + m_spawnthing = CreateNewEmitter(); + if( !m_spawnthing ) + { + return; + } + + // Get the tagname and orientation + m_spawnthing->tagname = ev->GetString( 1 ); + + if ( !m_spawnthing->tagname.length() ) + warning( "CCM::BeginTagEmitter", "Tagname not specified for tagemitter in model: '%s'\n", cgi.TIKI_NameForNum( current_tiki ) ); + + m_spawnthing->emittername = ev->GetString( 2 ); + if ( !m_spawnthing->emittername.length() ) + warning( "CCM::BeginTagEmitter", "Emittername not specified for tagemitter in model: '%s'\n", cgi.TIKI_NameForNum( current_tiki ) ); + + m_spawnthing->cgd.tikihandle = current_tiki; + } + +//=============== +// EndTagEmitter +//=============== +void ClientGameCommandManager::EndTagEmitter + ( + void + ) + + { + endblockfcn = NULL; + } + +//=============== +//BeginTagBeamEmitter +//=============== +void ClientGameCommandManager::BeginTagBeamEmitter + ( + Event *ev + ) + + { + // Setup ending function + endblockfcn = EndTagBeamEmitter; + + // Init the emitter + m_spawnthing = CreateNewEmitter(); + if( !m_spawnthing ) + { + return; + } + + m_spawnthing->cgd.flags |= T_BEAMTHING; + + // Get the tagname and orientation + + m_spawnthing->startTag = ev->GetString( 1 ); + + if ( m_spawnthing->startTag == "USE_TAGLIST" ) + { + if ( ev->NumArgs() == 2 ) + m_spawnthing->emittername = ev->GetString( 2 ); + } + else + { + if ( ev->NumArgs() == 3 ) + { + m_spawnthing->endTag = ev->GetString( 2 ); + m_spawnthing->emittername = ev->GetString( 3 ); + } + else if ( ev->NumArgs() == 2 ) + { + m_spawnthing->emittername = ev->GetString( 2 ); + } + } + + m_spawnthing->cgd.tikihandle = current_tiki; + } + +//=============== +// EndTagBeamEmitter +//=============== +void ClientGameCommandManager::EndTagBeamEmitter + ( + void + ) + + { + endblockfcn = NULL; + } + +//=============== +//BeginOriginEmitter +//=============== +void ClientGameCommandManager::BeginOriginEmitter + ( + Event *ev + ) + + { + // Setup ending function + endblockfcn = EndOriginEmitter; + + // Init the emitter + m_spawnthing = CreateNewEmitter(); + if( !m_spawnthing ) + { + return; + } + + // Get the emitter's name + m_spawnthing->emittername = ev->GetString( 1 ); + + if ( !m_spawnthing->emittername.length() ) + warning( "CCM::BeginOriginEmitter", "Emittername not specified for originemitter in model: '%s'\n", cgi.TIKI_NameForNum( current_tiki ) ); + + m_spawnthing->cgd.tikihandle = current_tiki; + } + +//=============== +//EndOriginEmitter +//=============== +void ClientGameCommandManager::EndOriginEmitter + ( + void + ) + + { + endblockfcn = NULL; + } + + +//=============== +//BeginOriginBeamEmitter +//=============== +void ClientGameCommandManager::BeginOriginBeamEmitter + ( + Event *ev + ) + + { + // Setup ending function + endblockfcn = EndOriginBeamEmitter; + + // Init the emitter + m_spawnthing = CreateNewEmitter(); + if( !m_spawnthing ) + { + return; + } + + // Get the emitter's name + m_spawnthing->emittername = ev->GetString( 1 ); + + if ( !m_spawnthing->emittername.length() ) + warning( "CCM::BeginOriginEmitter", "Emittername not specified for originemitter in model: '%s'\n", cgi.TIKI_NameForNum( current_tiki ) ); + + m_spawnthing->cgd.tikihandle = current_tiki; + m_spawnthing->cgd.flags |= T_BEAMTHING; + } + +//=============== +//EndOriginBeamEmitter +//=============== +void ClientGameCommandManager::EndOriginBeamEmitter + ( + void + ) + + { + endblockfcn = NULL; + } + +//=============== +//GetOrientation - Calculates the orientation of a tag +//=============== +void ClientGameCommandManager::GetOrientation + ( + str tagname, + spawnthing_t *sp + ) + + { + int i; + orientation_t or; + int tagnum; + + assert( current_entity ); + assert( current_tiki != -1 ); + + if ( !current_entity || ( current_tiki == -1 ) ) + { + return; + } + + tagnum = cgi.Tag_NumForName( current_tiki, tagname.c_str() ); + + if ( tagnum == -1 ) + { + warning( "ClientGameCommandManager::GetOrientation : Tagname %s does not exist", tagname.c_str() ); + return; + } + + or = cgi.Tag_LerpedOrientation( current_tiki, current_entity, tagnum ); + + VectorCopy( current_entity->origin, sp->cgd.origin ); + + for ( i = 0 ; i < 3 ; i++ ) + { + VectorMA( sp->cgd.origin, or.origin[i], current_entity->axis[i], sp->cgd.origin ); + } + + MatrixMultiply( or.axis, current_entity->axis, sp->axis ); + + // Set the axis based on the tag's axis + sp->forward = sp->axis[0]; + sp->right = sp->axis[1]; + sp->up = sp->axis[2]; + + // If angles are not set, then use the angles from the tag + if ( !( sp->cgd.flags & T_ANGLES ) ) + sp->cgd.angles = sp->forward.toAngles(); + + AxisCopy( sp->axis, sp->tag_axis ); + } + +//=============== +//BeginTagSpawn +//=============== +void ClientGameCommandManager::BeginTagSpawn + ( + Event *ev + ) + + { + str tagname; + + // Setup ending function + endblockfcn = EndTagSpawn; + + // Init the thing we are going to spawn + m_spawnthing = InitializeSpawnthing( &m_localemitter ); + + // Get the tagname and orientation + tagname = ev->GetString( 1 ); + GetOrientation( tagname, m_spawnthing ); + } + +//=============== +// EndTagSpawn +//=============== +void ClientGameCommandManager::EndTagSpawn + ( + void + ) + + { + // Okay we should have a valid spawnthing, let's create a render entity + SpawnTempModel( m_spawnthing->count ); + } + +//=============== +//BeginTagBeamShoot +//=============== +void ClientGameCommandManager::BeginTagBeamSpawn + ( + Event *ev + ) + + { + str tagname; + + // Setup ending function + endblockfcn = EndTagBeamSpawn; + + // Init the thing we are going to spawn + m_spawnthing = InitializeSpawnthing( &m_localemitter ); + + // Get the tagname and orientation + tagname = ev->GetString( 1 ); + GetOrientation( tagname, m_spawnthing ); + } + +//=============== +// EndTagSpawn +//=============== +void ClientGameCommandManager::EndTagBeamSpawn + ( + void + ) + + { + // Okay we should have a valid spawnthing, let's create the beam now + int i; + int renderfx; + Vector end; + trace_t trace; + float scale=1.0f; + + if ( current_entity ) + { + scale = current_entity->scale; + } + + for ( i=0; i<3; i++ ) + { + if ( m_spawnthing->randaxis[i] == RANDOM ) + m_spawnthing->cgd.origin += Vector( m_spawnthing->tag_axis[i] ) * m_spawnthing->axis_offset[i] * random(); + else if ( m_spawnthing->randaxis[i] == CRANDOM ) + m_spawnthing->cgd.origin += Vector( m_spawnthing->tag_axis[i] ) * m_spawnthing->axis_offset[i] * crandom(); + else + m_spawnthing->cgd.origin += Vector( m_spawnthing->tag_axis[i] ) * m_spawnthing->axis_offset[i]; + } + + if ( m_spawnthing->use_last_trace_end ) + { + end = last_trace_end; + } + else + { + end = m_spawnthing->cgd.origin + m_spawnthing->forward * m_spawnthing->length + + m_spawnthing->right * crandom() * m_spawnthing->spreadx + + m_spawnthing->up * crandom() * m_spawnthing->spready; + last_trace_end = end; + } + + + CG_Trace( &trace, m_spawnthing->cgd.origin, vec_zero, vec_zero, end, ENTITYNUM_NONE, MASK_SHOT, qfalse, qtrue, "EndTagBeamSpawn" ); + + if ( current_entity ) + renderfx = ( current_entity->renderfx & ~( RF_FLAGS_NOT_INHERITED | RF_LIGHTING_ORIGIN ) ); + else + renderfx = 0; + + CG_CreateBeam( m_spawnthing->cgd.origin, + vec_zero, + current_entity_number, + 1, + m_spawnthing->cgd.alpha, + m_spawnthing->cgd.scale * scale, + (m_spawnthing->beamflags | BEAM_LIGHTNING_EFFECT), + m_spawnthing->length, + m_spawnthing->cgd.life, + qfalse, + trace.endpos, + m_spawnthing->min_offset, + m_spawnthing->max_offset, + m_spawnthing->overlap, + m_spawnthing->numSubdivisions, + m_spawnthing->delay, + m_spawnthing->cgd.shadername, + m_spawnthing->cgd.color, + m_spawnthing->numspherebeams, + m_spawnthing->sphereRadius, + m_spawnthing->toggledelay, + m_spawnthing->endalpha, + renderfx, + m_spawnthing->emittername + ); + } + +//=============== +//BeginOriginBeamSpawn +//=============== +void ClientGameCommandManager::BeginOriginBeamSpawn + ( + Event *ev + ) + + { + // Setup ending function + endblockfcn = EndOriginBeamSpawn; + + // Init the emitter + m_spawnthing = CreateNewEmitter(); + if( !m_spawnthing ) + { + return; + } + + // Set the origin based on the entity's origin + m_spawnthing->cgd.origin = current_entity->origin; + + // Set the axis based on the entity's axis + m_spawnthing->forward = current_entity->axis[0]; + m_spawnthing->right = current_entity->axis[1]; + m_spawnthing->up = current_entity->axis[2]; + } + +//=============== +// EndOriginBeamSpawn +//=============== +void ClientGameCommandManager::EndOriginBeamSpawn + ( + void + ) + + { + // Okay we should have a valid spawnthing, let's create the beam now + int i,renderfx,c,count; + Vector end; + trace_t trace; + float scale=1.0f; + + if ( current_entity ) + { + scale = current_entity->scale; + } + + count = m_spawnthing->count * cg_effectdetail->value; + + for ( c=0; c<=count; c++ ) + { + Vector angles; + + for ( i=0; i<3; i++ ) + { + // Randomize angles or set absolute + if ( m_spawnthing->randangles[i] == RANDOM ) + angles[i] = random() * m_spawnthing->cgd.angles[i]; + else if ( m_spawnthing->randangles[i] == CRANDOM ) + angles[i] = crandom() * m_spawnthing->cgd.angles[i]; + else + angles[i] = m_spawnthing->cgd.angles[i]; + + if ( m_spawnthing->randaxis[i] == RANDOM ) + m_spawnthing->cgd.origin += Vector( m_spawnthing->tag_axis[i] ) * m_spawnthing->axis_offset[i] * random(); + else if ( m_spawnthing->randaxis[i] == CRANDOM ) + m_spawnthing->cgd.origin += Vector( m_spawnthing->tag_axis[i] ) * m_spawnthing->axis_offset[i] * crandom(); + else + m_spawnthing->cgd.origin += Vector( m_spawnthing->tag_axis[i] ) * m_spawnthing->axis_offset[i]; + } + + AnglesToAxis( angles, m_spawnthing->axis ); + m_spawnthing->forward = m_spawnthing->axis[0]; + m_spawnthing->right = m_spawnthing->axis[1]; + m_spawnthing->up = m_spawnthing->axis[2]; + + end = m_spawnthing->cgd.origin + m_spawnthing->forward * m_spawnthing->length + + m_spawnthing->right * crandom() * m_spawnthing->spreadx + + m_spawnthing->up * crandom() * m_spawnthing->spready; + + CG_Trace( &trace, m_spawnthing->cgd.origin, vec_zero, vec_zero, end, ENTITYNUM_NONE, MASK_SHOT, qfalse, qtrue, "EndOriginBeamSpawn" ); + + if ( current_entity ) + renderfx = ( current_entity->renderfx & ~( RF_FLAGS_NOT_INHERITED | RF_LIGHTING_ORIGIN ) ); + else + renderfx = 0; + + CG_CreateBeam( m_spawnthing->cgd.origin, + vec_zero, + current_entity_number, + 1, + m_spawnthing->cgd.alpha, + m_spawnthing->cgd.scale * scale, + (m_spawnthing->beamflags | BEAM_LIGHTNING_EFFECT), + m_spawnthing->length, + m_spawnthing->cgd.life, + qtrue, + trace.endpos, + m_spawnthing->min_offset, + m_spawnthing->max_offset, + m_spawnthing->overlap, + m_spawnthing->numSubdivisions, + m_spawnthing->delay, + m_spawnthing->cgd.shadername, + m_spawnthing->cgd.color, + m_spawnthing->numspherebeams, + m_spawnthing->sphereRadius, + m_spawnthing->toggledelay, + m_spawnthing->endalpha, + renderfx, + m_spawnthing->emittername + ); + } + } + +//============= +//AllocateTempModel +//============= +ctempmodel_t *ClientGameCommandManager::AllocateTempModel + ( + void + ) + + { + ctempmodel_t *p; + + if ( !m_free_tempmodels ) + { + // no free entities, so free the one at the end of the chain + // remove the oldest active entity + FreeTempModel( m_active_tempmodels.prev ); + } + + p = m_free_tempmodels; + m_free_tempmodels = m_free_tempmodels->next; + + // link into the active list + p->next = m_active_tempmodels.next; + p->prev = &m_active_tempmodels; + m_active_tempmodels.next->prev = p; + m_active_tempmodels.next = p; + + return p; + } + +//=============== +//FreeTempModel +//=============== +void ClientGameCommandManager::FreeTempModel + ( + ctempmodel_t *p + ) + + { + if ( !p->prev ) + { + cgi.Error( ERR_DROP, "CCM::FreeTempModel: not active" ); + } + + RemoveClientEntity( p->number, p->cgd.tikihandle, NULL, p ); + + // remove from the doubly linked active list + p->prev->next = p->next; + p->next->prev = p->prev; + + // the free list is only singly linked + p->next = m_free_tempmodels; + m_free_tempmodels = p; + } + +void ClientGameCommandManager::ResetTempModels + ( + void + ) + + { + // Go through all the active tempmodels and free them + ctempmodel_t *p,*next; + + p = m_active_tempmodels.prev; + for ( ; p != &m_active_tempmodels; p = next ) + { + next = p->prev; + FreeTempModel( p ); + } + } + +//============= +//InitializeTempModels +//============= +void ClientGameCommandManager::InitializeTempModels + ( + void + ) + + { + int i; + + m_numtempmodels = MAX_TEMPMODELS; + + m_active_tempmodels.next = &m_active_tempmodels; + m_active_tempmodels.prev = &m_active_tempmodels; + + m_free_tempmodels = &m_tempmodels[0]; + + for ( i=0 ; icgd.swarmfreq == 0 ) + return; + + // If the frequency is hit, set a new velocity + if ( !( rand() % p->cgd.swarmfreq ) ) + { + p->cgd.velocity.x = crandom() * p->cgd.swarmmaxspeed; + p->cgd.velocity.y = crandom() * p->cgd.swarmmaxspeed; + p->cgd.velocity.z = crandom() * p->cgd.swarmmaxspeed; + } + + // Try to move toward the origin by the specified delta + if ( p->cgd.origin.x < p->cgd.parentOrigin.x ) + p->cgd.velocity.x += p->cgd.swarmdelta; + else + p->cgd.velocity.x -= p->cgd.swarmdelta; + + if ( p->cgd.origin.y < p->cgd.parentOrigin.y ) + p->cgd.velocity.y += p->cgd.swarmdelta; + else + p->cgd.velocity.y -= p->cgd.swarmdelta; + + if ( p->cgd.origin.z < p->cgd.parentOrigin.z ) + p->cgd.velocity.z += p->cgd.swarmdelta; + else + p->cgd.velocity.z -= p->cgd.swarmdelta; + } + +void ClientGameCommandManager::OtherTempModelEffects + ( + ctempmodel_t *p, + Vector origin, + refEntity_t *newEnt + ) + + { + vec3_t axis[3]; + + if ( p->number != -1 ) + { + // Set the axis + AnglesToAxis( p->cgd.angles, axis ); + + current_scale = newEnt->scale; + current_entity = newEnt; + current_tiki = p->cgd.tikihandle; + current_entity_number = p->number; + + // Update any emitters that are active on this tempmodel + UpdateEmitter( p->cgd.tikihandle, axis, p->number, p->cgd.parent, origin ); + + // Add in trails for this tempmodel + if ( p->cgd.flags2 & T2_TRAIL ) + { + Event *ev = new Event( EV_Client_Swipe ); + ev->AddVector( origin ); + commandManager.ProcessEvent( ev ); + } + + current_entity_number = -1; + current_tiki = -1; + current_entity = NULL; + current_scale = -1; + } + } + +//=============== +//AnimateTempModel - animate temp models +//=============== +void ClientGameCommandManager::AnimateTempModel + ( + ctempmodel_t *p, + Vector origin, + refEntity_t *newEnt + ) + + { + int numframes; + int deltatime; + int frametime; + + // This code is for animating tempmodels that are spawned from the client side + + if ( p->cgd.tikihandle < 0 ) + return; + + // Calc frame stuff + frametime = 1000.0f * cgi.Frame_Time( p->cgd.tikihandle, p->ent.anim, 0 ); + deltatime = cg.time - p->lastAnimTime; + numframes = cgi.Anim_NumFrames( p->cgd.tikihandle, p->ent.anim ); + + if ( !p->addedOnce ) + { + // Process entry commands + CG_ProcessEntityCommands( p->cgd.tikihandle, TIKI_FRAME_CMD_ENTRY, p->ent.anim, -1, &p->ent, NULL ); + } + + if ( numframes < 2 ) + return; + + // Go through all the frames, and process any commands associated with the tempmodel as well + while( deltatime >= frametime ) + { + deltatime -= frametime; + p->lastAnimTime += frametime; + p->ent.oldanim = p->ent.anim; + p->ent.oldframe = p->ent.frame; + p->ent.frame = ( p->ent.frame + 1 ) % numframes; + CG_ProcessEntityCommands( p->cgd.tikihandle, p->ent.frame, p->ent.anim, -1, &p->ent, NULL ); + } + + p->ent.backlerp = 1.0f - ( ( float )deltatime / ( float )frametime ); + } + +qboolean ClientGameCommandManager::TempModelRealtimeEffects + ( + ctempmodel_t *p, + float ftime, + float dtime, + float scale + ) + + { + float fade,fadein; + byte tempColor[4]; + + if ( p->cgd.flags & ( T_FADE|T_SCALEUPDOWN ) ) + { + fade = 1.0f - ( float )( p->aliveTime - p->cgd.fadedelay ) / ( float )( p->cgd.life - p->cgd.fadedelay ); + + // Clamp the fade + if ( fade > 1 ) + fade = 1; + if ( fade < 0 ) + fade = 0; + } + else + { + fade = 1.0f; + } + + dtime = ( cg.time - p->cgd.createTime ); + + // Calculate fade in value + if ( p->cgd.flags & T_FADEIN ) + fadein = dtime / (float)p->cgd.fadeintime; + else + fadein = 0; + + // Convert dtime to seconds + dtime *= 0.001; + + // Do the scale animation + if ( ftime && p->cgd.scaleRate ) + p->ent.scale += p->ent.scale * ( p->cgd.scaleRate * ftime ); + + if ( p->cgd.flags & T_SCALEUPDOWN ) + { + p->ent.scale = p->cgd.scale * sin( ( fade ) * M_PI ); + + if ( p->ent.scale < p->cgd.scalemin ) + p->ent.scale = p->cgd.scalemin; + if ( p->ent.scale > p->cgd.scalemax ) + p->ent.scale = p->cgd.scalemax; + } + + if ( p->cgd.lightstyle >= 0 ) + { + int i; + float color[4]; + CG_LightStyleColor( p->cgd.lightstyle, dtime * 1000, color ); + for ( i=0; i<4; i++ ) + tempColor[i] = color[i] * 255; + } + else + { + memcpy( tempColor, p->cgd.color, 4 ); + } + + if ( p->cgd.flags & T_TWINKLE ) + { + // See if we should toggle the twinkle + if ( cg.time > p->twinkleTime ) + { + // If off, turn it on + if ( p->cgd.flags & T_TWINKLE_OFF ) + { + p->cgd.flags &= ~T_TWINKLE_OFF; + p->twinkleTime = cg.time + p->cgd.min_twinkletimeon + random() * p->cgd.max_twinkletimeon; + } + else + { + p->cgd.flags |= T_TWINKLE_OFF; + p->twinkleTime = cg.time + p->cgd.min_twinkletimeoff + random() * p->cgd.max_twinkletimeoff; + } + } + + if ( p->cgd.flags & T_TWINKLE_OFF ) + memset( tempColor, 0, 4 ); + } + + if ( p->cgd.flags & T_FADEIN && ( fadein < 1 ) ) // Do the fadein effect + { + p->ent.shaderRGBA[0] = (int)( tempColor[0] * ( fadein * p->cgd.alpha ) ); + p->ent.shaderRGBA[1] = (int)( tempColor[1] * ( fadein * p->cgd.alpha ) ); + p->ent.shaderRGBA[2] = (int)( tempColor[2] * ( fadein * p->cgd.alpha ) ); + p->ent.shaderRGBA[3] = (int)( tempColor[3] * ( fadein * p->cgd.alpha ) ); + } + else if ( p->cgd.flags & T_FADE ) // Do a fadeout effect + { + p->ent.shaderRGBA[0] = ( tempColor[0] * ( fade * p->cgd.alpha ) ); + p->ent.shaderRGBA[1] = ( tempColor[1] * ( fade * p->cgd.alpha ) ); + p->ent.shaderRGBA[2] = ( tempColor[2] * ( fade * p->cgd.alpha ) ); + p->ent.shaderRGBA[3] = ( tempColor[3] * ( fade * p->cgd.alpha ) ); + } + else + { + p->ent.shaderRGBA[0] = tempColor[0] * p->cgd.alpha; + p->ent.shaderRGBA[1] = tempColor[1] * p->cgd.alpha; + p->ent.shaderRGBA[2] = tempColor[2] * p->cgd.alpha; + p->ent.shaderRGBA[3] = tempColor[3] * p->cgd.alpha; + } + + if ( p->cgd.flags & T_FLICKERALPHA ) + { + float random = random(); + + if ( p->cgd.flags & (T_FADE|T_FADEIN) ) + { + p->ent.shaderRGBA[0] *= random; + p->ent.shaderRGBA[1] *= random; + p->ent.shaderRGBA[2] *= random; + p->ent.shaderRGBA[3] *= random; + } + else + { + p->ent.shaderRGBA[0] = p->cgd.color[0] * random; + p->ent.shaderRGBA[1] = p->cgd.color[1] * random; + p->ent.shaderRGBA[2] = p->cgd.color[2] * random; + p->ent.shaderRGBA[3] = p->cgd.color[3] * random; + } + } + + // Check for completely faded out model + if ( fade <= 0 && p->addedOnce ) + { + return false; + } + + // Check for completely scaled out model + if ( ( p->ent.scale <= 0 && p->addedOnce ) && !( p->cgd.flags & T_SCALEUPDOWN ) ) + { + return false; + } + + // Do swarming flies effects + if ( p->cgd.flags & T_SWARM ) + { + UpdateSwarm( p ); + } + + return true; + } + +qboolean ClientGameCommandManager::TempModelPhysics + ( + ctempmodel_t *p, + float ftime, + float time2, + float scale + ) + + { + int dtime; + Vector parentOrigin(0,0,0); + Vector parentAngles(0,0,0); + Vector tempangles; + trace_t trace; + float dot; + + VectorCopy( p->ent.origin, p->lastEnt.origin ); + AxisCopy( p->ent.axis, p->lastEnt.axis ); + + dtime = ( cg.time - p->cgd.createTime ); + + // Save oldorigin + p->cgd.oldorigin = p->cgd.origin; + + // Update the orign and the angles based on velocities first + if ( p->cgd.flags2 & (T2_MOVE|T2_ACCEL) ) + { + p->cgd.origin = p->cgd.origin + ( p->cgd.velocity * ftime * scale ) + ( time2 * p->cgd.accel ); + } + + // If linked to the parent or hardlinked, get the parent's origin + if ( ( p->cgd.flags & ( T_PARENTLINK | T_HARDLINK ) ) && ( p->cgd.parent != ENTITYNUM_NONE ) ) + { + centity_t *pc; + pc = &cg_entities[ p->cgd.parent ]; + + if ( pc->currentValid ) + { + refEntity_t *e; + + e = cgi.R_GetRenderEntity( p->cgd.parent ); + + if ( !e ) + return false; + + parentOrigin = e->origin; + vectoangles( e->axis[0], parentAngles ); + } + else + { + return false; + } + } + + // Align the object along it's traveling vector + if ( p->cgd.flags & T_ALIGN ) + { + p->cgd.angles = p->cgd.velocity.toAngles(); + parentAngles = vec_zero; + } + + if ( p->cgd.flags & T_RANDOMROLL ) + { + p->cgd.angles[ROLL] = random() * 360; + } + + // Update the angles based on angular velocity + if ( p->cgd.flags2 & T2_AMOVE ) + p->cgd.angles = p->cgd.angles + ( ftime * p->cgd.avelocity ); + + // Mod the angles if needed + p->cgd.angles[0] = AngleMod( p->cgd.angles[0] ); + p->cgd.angles[1] = AngleMod( p->cgd.angles[1] ); + p->cgd.angles[2] = AngleMod( p->cgd.angles[2] ); + + // Add in parent angles + tempangles = p->cgd.angles + parentAngles; + + // Convert to axis + if ( ( p->cgd.flags & ( T_ALIGN|T_RANDOMROLL|T_PARENTLINK|T_HARDLINK|T_ANGLES ) ) || ( p->cgd.flags2 & T2_AMOVE ) ) + { + AnglesToAxis( tempangles, p->ent.axis ); + } + + // Only do real collision if necessary + if ( p->cgd.flags & T_COLLISION ) + { + // trace a line from previous position to new position + CG_Trace( &trace, p->cgd.oldorigin, NULL, NULL, p->cgd.origin, -1, p->cgd.collisionmask, qfalse, qfalse, "Collision" ); + } + else + { + // Fake it out so it never collides + trace.fraction = 1.0; + } + + // Check for collision + if ( trace.fraction == 1.0 ) + { + // Acceleration of velocity + if ( p->cgd.flags2 & T2_ACCEL ) + p->cgd.velocity = p->cgd.velocity + ftime * p->cgd.accel; + } + else + { + if ( p->touchfcn ) + { + p->touchfcn( p, &trace ); + } + + if ( p->cgd.flags & T_DIETOUCH ) + return false; + + Vector normal; + + // Set the origin + p->cgd.origin = trace.endpos; + + if ( + ( p->cgd.flags2 & T2_BOUNCE_DECAL ) && + ( p->cgd.bouncecount < p->cgd.maxbouncecount ) + ) + { + // Put down a bounce decal + qhandle_t shader = cgi.R_RegisterShader( p->cgd.shadername ); + + CG_ImpactMark( shader, + trace.endpos, + trace.plane.normal, + p->cgd.decal_orientation, + (float)p->cgd.color[0]/255.0f, + (float)p->cgd.color[1]/255.0f, + (float)p->cgd.color[2]/255.0f, + p->cgd.alpha, + p->cgd.flags & T_FADE, + p->cgd.decal_radius, + p->cgd.flags2 & T2_TEMPORARY_DECAL, + p->cgd.lightstyle, + p->cgd.flags & T_FADEIN + ); + + p->cgd.bouncecount++; + } + + // calculate the bounce + normal = trace.plane.normal; + + // reflect the velocity on the trace plane + if ( p->cgd.flags2 & T2_ACCEL ) + p->cgd.velocity = p->cgd.velocity + ftime*trace.fraction * p->cgd.accel; + + dot = p->cgd.velocity * normal; + p->cgd.velocity = p->cgd.velocity + ( ( -2*dot ) * normal ); + p->cgd.velocity *= p->cgd.bouncefactor; + + // check for stop + if ( trace.plane.normal[2] > 0 && p->cgd.velocity[2] < 40 ) + { + p->cgd.velocity = Vector( 0,0,0 ); + p->cgd.avelocity = Vector( 0,0,0 ); + p->cgd.flags &= ~T_WAVE; + } + else + { + if ( p->cgd.flags & T_BOUNCESOUNDONCE ) + { + vec3_t org; + VectorCopy( p->cgd.origin, org ); + PlaySound( p->cgd.bouncesound, &org ); + p->cgd.flags &= ~(T_BOUNCESOUNDONCE|T_BOUNCESOUND); + } + else if ( ( p->cgd.flags & T_BOUNCESOUND ) && ( p->next_bouncesound_time < cg.time ) ) + { + vec3_t org; + VectorCopy( p->cgd.origin, org ); + PlaySound( p->cgd.bouncesound, &org ); + p->next_bouncesound_time = cg.time + p->cgd.bouncesound_delay; + } + } + } + + // copy over origin + VectorCopy( p->cgd.origin, p->ent.origin ); + + // Add in a waviness + if ( p->cgd.flags & T_WAVE ) + { + Vector add = p->perp * sin( dtime ) * p->cgd.wave; + VectorAdd( p->ent.origin, add, p->ent.origin ); + } + + // Add in parent's origin if linked + if ( p->cgd.flags & ( T_PARENTLINK | T_HARDLINK ) ) + VectorAdd( p->ent.origin, parentOrigin, p->ent.origin ); + + if ( !p->lastEntValid ) + { + // Make the lastEnt valid, by setting it to p->ent and setting the origin to the tempmodel's oldorigin + p->lastEnt = p->ent; + VectorCopy( p->cgd.oldorigin, p->lastEnt.origin ); + p->lastEntValid = true; + } + + return true; + } + +qboolean ClientGameCommandManager::LerpTempModel + ( + refEntity_t *newEnt, + ctempmodel_t *p, + float frac + ) + + { + int i,j; + + // If the tempmodel is parentlinked, then we need to get the origin of the parent and + // add it to the tempmodel's origin + if ( p->cgd.flags & (T_PARENTLINK|T_HARDLINK) ) + { + centity_t *pc; + Vector parentOrigin; + + // Lerp the tempmodel's local origin + for( i=0; i<3; i++ ) + { + newEnt->origin[i] = p->cgd.oldorigin[i] + frac * ( p->cgd.origin[i] - p->cgd.oldorigin[i] ); + } + + // Find the parent entity + pc = &cg_entities[ p->cgd.parent ]; + + if ( pc->currentValid ) + { + refEntity_t *e; + + e = cgi.R_GetRenderEntity( p->cgd.parent ); + + if ( !e ) + return false; + + parentOrigin = e->origin; + } + else + { + return false; + } + + // Add the parent ent's origin to the local origin + VectorAdd( newEnt->origin, parentOrigin, newEnt->origin ); + } + else + { + if ( p->cgd.flags2 & (T2_MOVE|T2_ACCEL) ) + { + // Lerp the ent's origin + for( i=0; i<3; i++ ) + { + newEnt->origin[i] = p->lastEnt.origin[i] + frac * ( p->ent.origin[i] - p->lastEnt.origin[i] ); + } + } + } + + if ( p->cgd.flags2 & T2_PARALLEL ) + { + Vector v1 = p->cgd.origin - cg.refdef.vieworg; + vectoangles( v1, p->cgd.angles ); + AnglesToAxis( p->cgd.angles, newEnt->axis ); + } + else if ( ( p->cgd.flags & ( T_ALIGN|T_RANDOMROLL|T_PARENTLINK|T_HARDLINK ) ) || ( p->cgd.flags2 & T2_AMOVE ) ) + { + // Lerp axis + for ( i=0; i<3; i++ ) + { + for ( j=0; j<3; j++ ) + { + newEnt->axis[i][j] = p->lastEnt.axis[i][j] + frac * ( p->ent.axis[i][j] - p->lastEnt.axis[i][j] ); + } + } + } + + return true; + } + + +static int lastFrameTime=0; + +//=============== +//AddTempModels - Update and add tempmodels to the ref +//=============== +#define TOO_MUCH_TIME_PASSED 500 +void ClientGameCommandManager::AddTempModels + ( + void + ) + + { + ctempmodel_t *p, *next; + int count=0; // Tempmodel count + int frameTime; + float effectTime, effectTime2; + int mstime=0; + float ftime=0; + float time2=0; + float scale=1.0f; + float lerpfrac=0; + int physics_rate=0; + qboolean ret; + refEntity_t newEnt; + + // To counteract cg.time going backwards + if ( lastFrameTime ) + { + if ( ( cg.time < lastFrameTime ) || ( cg.time - lastFrameTime > TOO_MUCH_TIME_PASSED ) ) + { + p = m_active_tempmodels.prev; + for ( ; p != &m_active_tempmodels; p = next ) + { + next = p->prev; + p->lastPhysicsTime = cg.time; + } + lastFrameTime = cg.time; + return; + } + } + + if ( lastFrameTime != 0 ) + frameTime = cg.time - lastFrameTime; + else + frameTime = 0; + + + if ( paused->integer ) + { + lastFrameTime = 0; + } + else + { + lastFrameTime = cg.time; + } + + memset( &newEnt, 0, sizeof( newEnt ) ); + // Set this frame time for the next one + effectTime = ( float )frameTime / 1000.0f; + effectTime2 = effectTime * effectTime; + + // If there is a current entity, it's scale is used as a factor + if ( current_entity ) + scale = current_entity->scale; + + // Go through all the temp models and run the physics if necessary, + // then add them to the ref + p = m_active_tempmodels.prev; + for ( ; p != &m_active_tempmodels; p = next ) + { + // grab next now, so if the local entity is freed we still have it + next = p->prev; + + if ( ( p->cgd.flags & T_DETAIL ) && !cg_detail->integer ) + { + FreeTempModel( p ); + continue; + } + + current_tiki = p->cgd.tikihandle; + + TempModelRealtimeEffects( p, effectTime, effectTime2, scale ); + + if ( p->lastPhysicsTime ) + { + mstime = cg.time - p->lastPhysicsTime; + + // Check for physics + physics_rate = 1000 / p->cgd.physicsRate; // Physics rate in milliseconds + + // Avoid large jumps in time + if ( mstime > physics_rate * 2 ) + { + mstime = physics_rate; + } + + if ( ( mstime >= physics_rate ) || ( p->cgd.flags2 & T2_PHYSICS_EVERYFRAME ) ) + { + ftime = mstime / 1000.0f; + time2 = ftime * ftime; + ret = TempModelPhysics( p, ftime, time2, scale ); + + if ( !ret ) + { + FreeTempModel( p ); + continue; + } + + p->lastPhysicsTime = cg.time; + } + } + + // Calculate the lerp value based on the time passed since last physics time of this tempmodel + lerpfrac = (float)( cg.time - p->lastPhysicsTime ) / (float)physics_rate; + + // Clamp + if ( lerpfrac > 1 ) + lerpfrac = 1; + if ( lerpfrac < 0 ) + lerpfrac = 0; + + // Increment the time this tempmodel has been alive + p->aliveTime += frameTime; + + // Dead, and free up the tempmodel + if ( p->aliveTime >= p->cgd.life && p->addedOnce ) + { + FreeTempModel( p ); + continue; + } + + // Run physics if the lastEnt is not valid to get a valid lerp + if ( !p->lastEntValid ) + { + float t,t2; + t = physics_rate / 1000.0f; + t2 = t * t; + + ret = TempModelPhysics( p, t, t2, scale ); + if ( !ret ) + { + FreeTempModel( p ); + continue; + } + + lerpfrac = 0; + p->lastPhysicsTime = cg.time; + } + + // clear out the new entity and initialize it + // this will become the current_entity if anything is spawned off it + + newEnt.scale = p->ent.scale; + memcpy( newEnt.shaderRGBA, p->ent.shaderRGBA, 4 ); + AxisCopy( p->ent.axis, newEnt.axis ); + VectorCopy( p->ent.origin, newEnt.origin ); + + // Lerp the tempmodel + if ( !LerpTempModel( &newEnt, p, lerpfrac ) ) + { + FreeTempModel( p ); + continue; + } + + // Animate and do trails (swipes) + newEnt.renderfx = p->ent.renderfx; + newEnt.hModel = p->ent.hModel; + newEnt.reType = p->ent.reType; + newEnt.shaderTime = p->ent.shaderTime; + + AnimateTempModel( p, newEnt.origin, &newEnt ); + + newEnt.anim = p->ent.anim; + newEnt.frame = p->ent.frame; + newEnt.oldanim = p->ent.oldanim; + newEnt.oldframe = p->ent.oldframe; + newEnt.backlerp = p->ent.backlerp; + + OtherTempModelEffects( p, newEnt.origin, &newEnt ); + + // Add to the ref + if ( p->cgd.flags & T_DLIGHT ) + { + // Tempmodel is a Dynamic Light + cgi.R_AddLightToScene( p->cgd.origin, + p->cgd.lightIntensity * scale, + (float)p->cgd.color[0]/255.0f, + (float)p->cgd.color[1]/255.0f, + (float)p->cgd.color[2]/255.0f, + p->cgd.lightType + ); + } + else if( p->ent.reType == RT_SPRITE ) + cgi.R_AddRefSpriteToScene( &newEnt ); // Sprite + else + cgi.R_AddRefEntityToScene( &newEnt ); // Model + + // Set the added once flag so we can delete it later + p->addedOnce = qtrue; + + // Local tempmodel count stat + count++; + current_tiki = -1; + } + + + // stats + if ( cg_showtempmodels->integer ) + { + cgi.DPrintf( "TC:%i\n", count ); + } + } + +//================= +//SpawnTempModel +//================= +void ClientGameCommandManager::SpawnTempModel + ( + int count, + spawnthing_t *sp + ) + { + m_spawnthing = sp; + SpawnTempModel( count ); + } + +//================= +//SpawnTempModel +//================= +void ClientGameCommandManager::SpawnTempModel + ( + int mcount, + int timeAlive + ) + + { + int i; + ctempmodel_t *p; + refEntity_t ent; + int count; + float current_entity_scale=1.0f; + Vector newForward; + + if ( current_entity ) + { + current_entity_scale = current_entity->scale; + } + else + { + current_entity_scale = 1.0f; + } + + if ( current_scale > 0 ) + current_entity_scale *= current_scale; + + if ( mcount > 1 ) + mcount *= cg_effectdetail->value; + + if ( mcount < 1 ) + mcount = 1; + + for ( count = 0; count < mcount; count++ ) + { + p = AllocateTempModel(); + + if (!p) + { + cgi.DPrintf( "Out of tempmodels\n" ); + return; + } + + memset( &ent, 0, sizeof( refEntity_t ) ); + memset( &p->lastEnt, 0, sizeof( refEntity_t ) ); + + // Copy over the common data block + p->cgd = m_spawnthing->cgd; + + // Copy over the vectors to the axis + VectorCopy( m_spawnthing->forward, m_spawnthing->axis[0] ); + VectorCopy( m_spawnthing->right, m_spawnthing->axis[1] ); + VectorCopy( m_spawnthing->up, m_spawnthing->axis[2] ); + + // newForward may be changed by spehere or circle + newForward = m_spawnthing->forward; + + // Set up the origin of the tempmodel + if ( m_spawnthing->cgd.flags & T_SPHERE ) + { + // Create a random forward vector so the particles burst out in a sphere + newForward = Vector( crandom(), crandom(), crandom() ); + } + else if ( m_spawnthing->cgd.flags & T_CIRCLE ) + { + if ( m_spawnthing->sphereRadius != 0 ) // Offset by the radius + { + Vector dst; + // Create a circular shaped burst around the up vector + float angle = ( ( float ) count / ( float ) m_spawnthing->count ) * 360;// * M_PI * 2; + + Vector end = m_spawnthing->forward * m_spawnthing->sphereRadius * current_entity_scale; + RotatePointAroundVector( dst, m_spawnthing->up, end, angle ); + + VectorAdd ( dst, m_spawnthing->cgd.origin, p->cgd.origin ); + newForward = p->cgd.origin - m_spawnthing->cgd.origin; + newForward.normalize(); + } + } + else if ( m_spawnthing->cgd.flags & T_INWARDSPHERE ) + { + // Project the origin along a random ray, and set the forward + // vector pointing back to the origin + Vector dir, end; + + dir = Vector( crandom(), crandom(), crandom() ); + + end = m_spawnthing->cgd.origin + dir * m_spawnthing->sphereRadius * current_entity_scale; + VectorCopy ( end, p->cgd.origin ); + newForward = dir * -1; + } + else if ( m_spawnthing->sphereRadius != 0 ) // Offset in a spherical pattern + { + Vector dir, end; + + dir = Vector( crandom(), crandom(), crandom() ); + + dir.normalize(); + + end = m_spawnthing->cgd.origin + dir * m_spawnthing->sphereRadius * current_entity_scale; + VectorCopy ( end, p->cgd.origin ); + newForward = dir; + } + else + { + VectorCopy ( m_spawnthing->cgd.origin, p->cgd.origin ); + } + + // Randomize the origin based on offsets + for ( i=0; i<3; i++ ) + { + if ( m_spawnthing->randorg[i] == RANDOM ) + p->cgd.origin[i] += random() * m_spawnthing->origin_offset[i] * current_entity_scale; + else if ( m_spawnthing->randorg[i] == CRANDOM ) + p->cgd.origin[i] += crandom() * m_spawnthing->origin_offset[i] * current_entity_scale; + else + p->cgd.origin[i] += m_spawnthing->origin_offset[i] * current_entity_scale; + } + + p->cgd.oldorigin = p->cgd.origin; + p->modelname = m_spawnthing->GetModel(); + p->addedOnce = qfalse; + p->lastEntValid = qfalse; + + if ( p->modelname.length() ) + ent.hModel = cgi.R_RegisterModel( p->modelname.c_str() ); + + // Initialize the refEntity + ent.oldframe = ent.frame; + ent.shaderTime = cg.time / 1000.0f; + + // Get the tikihandle + p->cgd.tikihandle = cgi.TIKI_GetHandle( ent.hModel ); + + // Set the reftype based on the modelname + if ( p->modelname == "*beam" ) + { + ent.reType = RT_BEAM; + ent.customShader = cgi.R_RegisterShader( "beamshader" ); + } + else if ( strstr( p->modelname, ".spr" ) ) + { + ent.reType = RT_SPRITE; + } + else + { + ent.reType = RT_MODEL; + } + + // Set the animation + if ( m_spawnthing->animName.length() && ( p->cgd.tikihandle > 0 ) ) + { + ent.anim = cgi.Anim_Random( p->cgd.tikihandle, m_spawnthing->animName ); + } + else if ( ent.reType == RT_MODEL && ( p->cgd.tikihandle > 0 ) ) + { + ent.anim = cgi.Anim_Random( p->cgd.tikihandle, "idle" ); + } + + // Randomize the scale + if ( m_spawnthing->cgd.flags & T_RANDSCALE ) // Check for random scale + { + ent.scale = RandomizeRange( m_spawnthing->cgd.scalemin, m_spawnthing->cgd.scalemax ); + p->cgd.scale = ent.scale; + } + else + { + ent.scale = m_spawnthing->cgd.scale; + } + + ent.scale *= current_entity_scale; + + // CURRENT ENTITY INFLUENCES ON THE TEMPMODELS HAPPEN HERE + // copy over the renderfx from the current_entity, but only the flags we want + if ( current_entity ) + { + // explicitly add RF_LIGHTING ORIGIN and RF_SHADOWPLANE because we don't want those on dynamic objects + ent.renderfx |= ( current_entity->renderfx & ~( RF_FLAGS_NOT_INHERITED | RF_LIGHTING_ORIGIN ) ); + } + + // Set up modulation for constant color + for ( i=0; i<4; i++ ) + { + p->cgd.color[i] = ent.shaderRGBA[i] = m_spawnthing->cgd.color[i]; + } + + // Apply the alpha from the current_entity to the tempmodel + if ( current_entity ) + { + float ealpha; + + ealpha = ( float )current_entity->shaderRGBA[3] / 255.0f; + + if ( ealpha != 1.0 ) + { + // pre-multiply the alpha from the entity + for ( i=0; i<4; i++ ) + { + p->cgd.color[i] = ent.shaderRGBA[i] = ent.shaderRGBA[i] * ealpha; + } + } + } + + p->ent = ent; + p->lastEnt = ent; + p->number = -1; + + // If createTime is specified, the use it. Otherwise use the createTime from the spawnthing. + if ( timeAlive > 0 ) + p->aliveTime = timeAlive; + else + p->aliveTime = 0; + + // If animateonce is set, set the life = to the length of the anim + if ( ( m_spawnthing->cgd.flags & T_ANIMATEONCE ) && ( p->ent.anim > 0 ) ) + { + p->cgd.life = cgi.Anim_Time( p->cgd.tikihandle, p->ent.anim ) * 1000.0f; + } + else + { + p->cgd.life = m_spawnthing->cgd.life; + } + + p->lastAnimTime = p->cgd.createTime; + p->lastPhysicsTime = p->cgd.createTime; + p->killTime = cg.time + p->cgd.life; // The time the tempmodel will die + p->seed = m_seed++; // For use with randomizations + p->cgd.velocity = Vector( 0,0,0 ); // Zero out the velocity + p->touchfcn = m_spawnthing->touchfcn; // Set up the touchfunction + p->perp.x = crandom(); // Create a random perp vector for waves + p->perp.y = crandom(); + p->perp.z = 0; + p->next_bouncesound_time = 0; // Init the next bouncesound time + + if ( p->cgd.flags & T_TWINKLE ) + if ( random() > 0.5f ) + p->cgd.flags |= T_TWINKLE_OFF; + + if ( p->cgd.flags2 & T2_TRAIL ) + { + // Assign a global number to this entity from the command_time_manager + // Tempmodels with trails need their own unique number. + p->number = m_command_time_manager.AssignNumber(); + p->cgd.flags |= T_ASSIGNED_NUMBER; + int oldnum = current_entity_number; + centity_t *oldcent = current_centity; + current_centity = NULL; + current_entity_number = p->number; + + Event *swipeEv = new Event( EV_Client_SwipeOn ); + swipeEv->AddString( p->cgd.swipe_shader ); + swipeEv->AddString( p->cgd.swipe_tag_start ); + swipeEv->AddString( p->cgd.swipe_tag_end ); + swipeEv->AddFloat( p->cgd.swipe_life ); + + commandManager.ProcessEvent( swipeEv ); + + current_centity = oldcent; + current_entity_number = oldnum; + } + + // Check to see if this tiki has any emitters bound to it and update it's number. This is + // used for updating emitters that are attached to tempmodels. + if ( p->cgd.tikihandle >= 0 ) + { + for ( i=1; i<=m_emitters.NumObjects(); i++ ) + { + spawnthing_t *st = m_emitters.ObjectAt( i ); + + if ( st->cgd.tikihandle == p->cgd.tikihandle ) + { + // Assign this tempmodel a number if he doesn't already have one + if ( p->number == -1 ) + p->number = st->AssignNumber(); + + st->GetEmitTime( p->number ); + } + } + } + + + for ( i=0; i<3; i++ ) + { + // Randomize avelocity or set absolute + if ( m_spawnthing->randavel[i] == RANDOM ) + p->cgd.avelocity[i] = m_spawnthing->cgd.avelocity[i] * random() * current_entity_scale; + else if ( m_spawnthing->randavel[i] == CRANDOM ) + p->cgd.avelocity[i] = m_spawnthing->cgd.avelocity[i] * crandom() * current_entity_scale; + else + p->cgd.avelocity[i] = m_spawnthing->cgd.avelocity[i] * current_entity_scale; + + // Randomize angles or set absolute + if ( m_spawnthing->randangles[i] == RANDOM ) + p->cgd.angles[i] = random() * m_spawnthing->cgd.angles[i]; + else if ( m_spawnthing->randangles[i] == CRANDOM ) + p->cgd.angles[i] = crandom() * m_spawnthing->cgd.angles[i]; + else + p->cgd.angles[i] = m_spawnthing->cgd.angles[i]; + } + + // If forward velocity is set, just use that otherwise use random variation of the velocity + if ( m_spawnthing->forwardVelocity != 0 ) + { + for ( i=0; i<3; i++ ) + { + p->cgd.velocity[i] = newForward[i] * m_spawnthing->forwardVelocity * current_entity_scale; + } + } + + if ( p->cgd.flags2 & T2_PARALLEL ) + { + Vector v1 = p->cgd.origin - cg.refdef.vieworg; + vectoangles( v1, p->cgd.angles ); + } + + AnglesToAxis( p->cgd.angles, m_spawnthing->axis ); + AxisCopy( m_spawnthing->axis, p->ent.axis ); + + // Random velocities along axis or world axis + for ( i=0; i<3; i++ ) + { + if ( m_spawnthing->randvel[i] == RANDOM ) + { + if ( m_spawnthing->cgd.flags & T_RANDVELAXIS ) + p->cgd.velocity += Vector( m_spawnthing->tag_axis[i] ) * m_spawnthing->velocityVariation[i] * random() * current_entity_scale; + else + p->cgd.velocity[i] += m_spawnthing->velocityVariation[i] * random() * current_entity_scale; + } + else if ( m_spawnthing->randvel[i] == CRANDOM ) + { + if ( m_spawnthing->cgd.flags & T_RANDVELAXIS ) + p->cgd.velocity += Vector( m_spawnthing->tag_axis[i] ) * m_spawnthing->velocityVariation[i] * crandom() * current_entity_scale; + else + p->cgd.velocity[i] += m_spawnthing->velocityVariation[i] * crandom() * current_entity_scale; + } + else + { + if ( m_spawnthing->cgd.flags & T_RANDVELAXIS ) + p->cgd.velocity += Vector( m_spawnthing->tag_axis[i] ) * m_spawnthing->velocityVariation[i] * current_entity_scale; + else + p->cgd.velocity[i] += m_spawnthing->velocityVariation[i] * current_entity_scale; + } + } + + // If align flag is set, adjust the angles to the direction of velocity + if ( p->cgd.flags & ( T_ALIGN|T_ALIGNONCE ) ) + { + p->cgd.angles = p->cgd.velocity.toAngles(); + } + + // Random offsets along axis + for ( i=0; i<3; i++ ) + { + if ( p->cgd.flags2 & T2_PARALLEL ) + { + if ( m_spawnthing->randaxis[i] == RANDOM ) + p->cgd.origin += Vector( m_spawnthing->axis[i] ) * m_spawnthing->axis_offset[i] * random() * current_entity_scale; + else if ( m_spawnthing->randaxis[i] == CRANDOM ) + p->cgd.origin += Vector( m_spawnthing->axis[i] ) * m_spawnthing->axis_offset[i] * crandom() * current_entity_scale; + else + p->cgd.origin += Vector( m_spawnthing->axis[i] ) * m_spawnthing->axis_offset[i] * current_entity_scale; + } + else + { + if ( m_spawnthing->randaxis[i] == RANDOM ) + p->cgd.origin += Vector( m_spawnthing->tag_axis[i] ) * m_spawnthing->axis_offset[i] * random() * current_entity_scale; + else if ( m_spawnthing->randaxis[i] == CRANDOM ) + p->cgd.origin += Vector( m_spawnthing->tag_axis[i] ) * m_spawnthing->axis_offset[i] * crandom() * current_entity_scale; + else + p->cgd.origin += Vector( m_spawnthing->tag_axis[i] ) * m_spawnthing->axis_offset[i] * current_entity_scale; + } + } + + // Calculate one tick of velocity based on time alive ( passed in ) + p->cgd.origin = p->cgd.origin + ( p->cgd.velocity * ( (float)p->aliveTime/1000.0f ) * current_entity_scale ); + + if ( p->cgd.flags & T_AUTOCALCLIFE ) + { + Vector end,delta; + float length,speed; + vec3_t axis[3]; + trace_t trace; + + AnglesToAxis( p->cgd.angles, axis ); + + end = p->cgd.origin + Vector( axis[0] ) * MAP_SIZE; + CG_Trace( &trace, p->cgd.origin, vec_zero, vec_zero, end, ENTITYNUM_NONE, CONTENTS_SOLID|CONTENTS_WATER, qfalse, qfalse, "AutoCalcLife" ); + + delta = trace.endpos - p->cgd.origin; + length = delta.length(); + speed = p->cgd.velocity.length(); + + p->cgd.life = ( length / speed ) * 1000.0f; + } + + // global fading is based on the number of animations in the current_entity's animation + if ( current_entity ) + { + if ( m_spawnthing->cgd.flags & (T_GLOBALFADEIN|T_GLOBALFADEOUT) ) + { + int numframes = cgi.Anim_NumFrames( current_tiki, current_entity->anim ); + + p->cgd.alpha = (float)current_entity->frame / (float)numframes; + + if ( m_spawnthing->cgd.flags & T_GLOBALFADEOUT ) + { + p->cgd.alpha = 1.0f - p->cgd.alpha; + } + } + } + } + } + +//=============== +//EmitterOn +//=============== +void ClientGameCommandManager::EmitterOn + ( + Event *ev + ) + + { + int i; + str name; + + name = ev->GetString( 1 ); + + for ( i=1; i<=m_emitters.NumObjects(); i++ ) + { + spawnthing_t *st = m_emitters.ObjectAt( i ); + + if ( st->emittername == name ) + { + emittertime_t *et; + + et = st->GetEmitTime( current_entity_number ); + + et->active = qtrue; + et->last_emit_time = cg.time; + et->lerp_emitter = qfalse; + } + } + } + +//=============== +//EmitterOff +//=============== +void ClientGameCommandManager::EmitterOff + ( + Event *ev + ) + + { + int i; + str name; + + name = ev->GetString( 1 ); + + for ( i=1; i<=m_emitters.NumObjects(); i++ ) + { + spawnthing_t *st = m_emitters.ObjectAt( i ); + + if ( st->emittername == name ) + { + emittertime_t *et; + + et = st->GetEmitTime( current_entity_number ); + et->active = qfalse; + + if ( st->cgd.flags & T_BEAMTHING ) + { + // Kill any active beams emitted from this thing + CG_KillBeams( current_entity_number ); + } + } + } + } + +//=============== +// Sound +//=============== +void ClientGameCommandManager::PlaySound + ( + str sound_name, + vec3_t *origin, + int channel, + float volume, + float min_distance + ) + + { + const char *name = NULL; + str random_alias; + + // Get the real sound to play + if ( current_tiki >= 0 ) + name = cgi.TIKI_Alias_FindRandom( current_tiki, sound_name.c_str() ); + + if ( !name ) + name = cgi.Alias_FindRandom( sound_name.c_str() ); + + if ( !name ) + name = sound_name.c_str(); + + if ( origin ) + cgi.S_StartSound( *origin, current_entity_number, channel, cgi.S_RegisterSound( name ), volume, min_distance ); + else + cgi.S_StartSound( NULL, current_entity_number, channel, cgi.S_RegisterSound( name ), volume, min_distance ); + } + +//=============== +// Sound +//=============== +void ClientGameCommandManager::Sound + ( + Event *ev + ) + + { + int channel = CHAN_AUTO; + str sound_name; + float volume = -1.0; + float min_distance = -1.0; + + if (ev->NumArgs() < 1) + return; + + // Get all of the parameters + + sound_name = ev->GetString( 1 ); + + if (ev->NumArgs() > 1) + channel = ev->GetInteger( 2 ); + + if (ev->NumArgs() > 2) + volume = ev->GetFloat( 3 ); + + if (ev->NumArgs() > 3) + min_distance = ev->GetFloat( 4 ); + + // play the sound + if ( current_entity ) + { + PlaySound( sound_name, ¤t_entity->origin, channel, volume, min_distance ); + } + else + { + PlaySound( sound_name, NULL, channel, volume, min_distance ); + } + } + +//=============== +// StopSound +//=============== +void ClientGameCommandManager::StopSound + ( + Event *ev + ) + + { + int channel; + + if (ev->NumArgs() > 0) + channel = ev->GetInteger( 1 ); + else + return; + + cgi.S_StopSound( current_entity_number, channel ); + } + +//=============== +// LoopSound +//=============== +void ClientGameCommandManager::LoopSound + ( + Event *ev + ) + + { + str sound_name; + float volume = -1.0; + float min_dist = -1.0; + const char *name = NULL; + + if ( !current_centity ) + { + cgi.DPrintf( "CCM::LoopSound : LoopSound in %s without current_centity\n", cgi.TIKI_NameForNum( current_tiki ) ); + return; + } + + if ( ev->NumArgs() < 1 ) + return; + + sound_name = ev->GetString( 1 ); + + if ( ev->NumArgs() > 1 ) + volume = ev->GetFloat( 2 ); + + if ( ev->NumArgs() > 2 ) + min_dist = ev->GetFloat( 3 ); + + // Get the real sound to play + + name = cgi.TIKI_Alias_FindRandom( current_tiki, sound_name.c_str() ); + + if ( !name ) + name = cgi.Alias_FindRandom( sound_name.c_str() ); + + if ( !name ) + name = sound_name.c_str(); + + current_centity->tikiLoopSound = cgi.S_RegisterSound( name ); + current_centity->tikiLoopSoundVolume = volume; + current_centity->tikiLoopSoundMinDist = min_dist; + } + +//=============== +// CacheResource +//=============== +void CacheResource + ( + const char * stuff + ) + + { + str real_stuff; + + if ( !stuff ) + return; + + real_stuff = stuff; + real_stuff.tolower(); + + if ( strstr( real_stuff.c_str(), ".wav" ) ) + { + cgi.S_RegisterSound( real_stuff.c_str() ); + } + else if ( strstr( real_stuff.c_str(), ".mp3" ) ) + { + cgi.S_RegisterSound( real_stuff.c_str() ); + } + else if ( strstr( real_stuff.c_str(), ".tik" ) ) + { + int hModel = cgi.R_RegisterModel( real_stuff.c_str() ); + cachedModelList.AddUniqueObject( hModel ); + } + else if ( strstr( real_stuff.c_str(), ".spr" ) ) + { + cgi.R_RegisterShader( real_stuff.c_str() ); + } + } + +//=============== +//Cache +//=============== +void ClientGameCommandManager::Cache + ( + Event *ev + ) + + { + if ( ev->NumArgs() < 1 ) + return; + + CacheResource( ev->GetString( 1 ) ); + } + +//=============== +// AliasResource +//=============== +void AliasResource + ( + int tikihandle, + const char * alias, + const char * realname, + const char * parameters + ) + { + if ( tikihandle >= 0 ) + { + cgi.TIKI_Alias_Add( tikihandle, alias, realname, parameters ); + } + else + { + cgi.Alias_Add( alias, realname, parameters ); + } + } + +//=============== +//AliasCache +//=============== +void ClientGameCommandManager::AliasCache + ( + Event *ev + ) + + { + int i; + char parmbuffer[ 512 ]; // this holds the parameters to be passed into the alias command + + if (ev->NumArgs() < 2) + return; + + // alias is in argument 1 + // real path is argument 2 + // any additional parameters are in arguments 3-n + + parmbuffer[ 0 ] = 0; + + for( i = 3; i <= ev->NumArgs(); i++ ) + { + strcat( parmbuffer, ev->GetToken( i ) ); + strcat( parmbuffer, " " ); + } + + AliasResource( current_tiki, ev->GetString( 1 ), ev->GetString( 2 ), parmbuffer ); + CacheResource( ev->GetString( 2 ) ); + } + +//=============== +//Alias +//=============== +void ClientGameCommandManager::Alias + ( + Event *ev + ) + + { + int i; + char parmbuffer[ 512 ]; // this holds the parameters to be passed into the alias command + + if (ev->NumArgs() < 2) + return; + + // alias is in argument 1 + // real path is argument 2 + // any additional parameters are in arguments 3-n + + parmbuffer[ 0 ] = 0; + + for( i = 3; i <= ev->NumArgs(); i++ ) + { + strcat( parmbuffer, ev->GetToken( i ) ); + strcat( parmbuffer, " " ); + } + + AliasResource( current_tiki, ev->GetString( 1 ), ev->GetString( 2 ), parmbuffer ); + } + +//=============== +//Footstep +//=============== +void ClientGameCommandManager::Footstep + ( + Event *ev + ) + + { + float volume; + + if ( ev->NumArgs() > 0 ) + { + volume = ev->GetFloat( 1 ); + } + else + { + volume = 1.0f; + } + + if ( current_centity ) + { + CG_Footstep( current_centity, volume ); + } + } + + + +//=============== +//Client +//=============== +void ClientGameCommandManager::Client + ( + Event *ev + ) + + { + Event *event; + const char * eventname; + int i; + + // see if it was a dummy command + if ( ev->NumArgs() < 1 ) + return; + + eventname = ev->GetString( 1 ); + event = new Event( eventname ); + + for( i = 2; i <= ev->NumArgs(); i++ ) + { + event->AddToken( ev->GetToken( i ) ); + } + ProcessEvent( event ); + } + +//=============== +//TagDynamicLight +//=============== +void ClientGameCommandManager::TagDynamicLight + ( + Event *ev + ) + + { + str tagname; + + // Spawn a single tempmodel that is a dynamic light + m_spawnthing = InitializeSpawnthing( &m_localemitter ); + + tagname = ev->GetString( 1 ); + GetOrientation( tagname, m_spawnthing ); + + m_spawnthing->cgd.flags |= T_DLIGHT; + m_spawnthing->cgd.color[0] = ev->GetFloat( 2 ) * 255; + m_spawnthing->cgd.color[1] = ev->GetFloat( 3 ) * 255; + m_spawnthing->cgd.color[2] = ev->GetFloat( 4 ) * 255; + m_spawnthing->cgd.color[3] = 255; + m_spawnthing->cgd.lightIntensity = ev->GetFloat( 5 ); + m_spawnthing->cgd.life = ev->GetFloat( 6 ) * 1000; + if ( ev->NumArgs() > 6 ) + { + m_spawnthing->cgd.lightType |= DLightNameToNum( ev->GetString( 7 ) ); + if ( ev->NumArgs() > 7 ) + m_spawnthing->cgd.lightType |= DLightNameToNum( ev->GetString( 8 ) ); + } + else + { + m_spawnthing->cgd.lightType = 0; + } + SpawnTempModel( 1, m_spawnthing ); + } + +//=============== +//OriginDynamicLight +//=============== +void ClientGameCommandManager::OriginDynamicLight + ( + Event *ev + ) + + { + str tagname; + + if ( !current_entity ) + { + cgi.DPrintf( "ClientGameCommandManager::OriginDynamicLight : Illegal use of \"origindlight\"\n" ); + return; + } + + // Spawn a single tempmodel that is a dynamic light + m_spawnthing = InitializeSpawnthing( &m_localemitter ); + + m_spawnthing->cgd.origin = current_entity->origin; + m_spawnthing->cgd.flags |= T_DLIGHT; + m_spawnthing->cgd.color[0] = ev->GetFloat( 1 ) * 255; + m_spawnthing->cgd.color[1] = ev->GetFloat( 2 ) * 255; + m_spawnthing->cgd.color[2] = ev->GetFloat( 3 ) * 255; + m_spawnthing->cgd.color[3] = 255; + m_spawnthing->cgd.lightIntensity = ev->GetFloat( 4 ); + m_spawnthing->cgd.life = ev->GetFloat( 5 ) * 1000; + if ( ev->NumArgs() > 5 ) + { + m_spawnthing->cgd.lightType |= DLightNameToNum( ev->GetString( 6 ) ); + if ( ev->NumArgs() > 6 ) + m_spawnthing->cgd.lightType |= DLightNameToNum( ev->GetString( 7 ) ); + } + else + { + m_spawnthing->cgd.lightType = 0; + } + SpawnTempModel( 1, m_spawnthing ); + } + + +//=============== +//DynamicLight +//=============== +void ClientGameCommandManager::DynamicLight + ( + Event *ev + ) + + { + str tagname; + + // The emitter itself has a dynamic light + m_spawnthing->cgd.flags |= T_DLIGHT; + m_spawnthing->dcolor[0] = ev->GetFloat( 1 ); + m_spawnthing->dcolor[1] = ev->GetFloat( 2 ); + m_spawnthing->dcolor[2] = ev->GetFloat( 3 ); + m_spawnthing->cgd.lightIntensity = ev->GetFloat( 4 ); + if ( ev->NumArgs() > 4 ) + { + m_spawnthing->cgd.lightType |= ( dlighttype_t )ev->GetInteger( 5 ); + if ( ev->NumArgs() > 5 ) + m_spawnthing->cgd.lightType |= DLightNameToNum( ev->GetString( 6 ) ); + } + else + { + m_spawnthing->cgd.lightType = 0; + } + } + +static int emittercount=0; + +//=============== +//UpdateBeam +//=============== +void ClientGameCommandManager::UpdateBeam + ( + int tikihandle, + int entity_number, + spawnthing_t *beamthing + ) + { + Vector start, end; + int renderfx; + qboolean addstartpoint; + float scale,alpha; + emittertime_t *et; + + et = beamthing->GetEmitTime( entity_number ); + + if ( !et->active ) + return; + + if ( current_entity ) + { + renderfx = ( current_entity->renderfx & ~( RF_FLAGS_NOT_INHERITED | RF_LIGHTING_ORIGIN ) ); + scale = current_entity->scale; + alpha = ( float )current_entity->shaderRGBA[3] / 255.0f; + } + else + { + renderfx = 0; + scale = 1.0f; + alpha = 1.0f; + } + + if ( beamthing->startTag == "USE_TAGLIST" ) + { + int i, count; + str startTag, endTag; + Vector dir; + + count = beamthing->m_taglist.NumObjects(); + + if ( !count ) + return; + + startTag = beamthing->m_taglist.ObjectAt( 1 ); + GetOrientation( startTag, beamthing ); + start = beamthing->cgd.origin; + if ( beamthing->beamflags & BEAM_OFFSET_ENDPOINTS ) + { + dir = Vector( crandom(), crandom(), crandom() ); + start += ( crandom() * beamthing->min_offset * dir ) + ( crandom() * beamthing->max_offset * dir ); + } + + CG_MultiBeamBegin(); + addstartpoint = qtrue; + + for( i=2; i<=count; i++ ) + { + str s; + + s = va( "%d", i ); + + endTag = beamthing->m_taglist.ObjectAt( i ); + + GetOrientation( endTag, beamthing ); + end = beamthing->cgd.origin; + + if ( beamthing->beamflags & BEAM_OFFSET_ENDPOINTS ) + { + dir = Vector( crandom(), crandom(), crandom() ); + end += ( crandom() * beamthing->min_offset * dir ) + ( crandom() * beamthing->max_offset * dir ); + } + + CG_MultiBeamAddPoints( start, + end, + beamthing->numSubdivisions, + beamthing->beamflags, + beamthing->min_offset, + beamthing->max_offset, + addstartpoint + ); + + addstartpoint = qfalse; + startTag = endTag; + start = end; + } + + byte newcolor[4]; + + newcolor[0] = beamthing->cgd.color[0] * alpha; + newcolor[1] = beamthing->cgd.color[1] * alpha; + newcolor[2] = beamthing->cgd.color[2] * alpha; + newcolor[3] = beamthing->cgd.color[3] * alpha; + + CG_MultiBeamEnd( beamthing->cgd.scale * scale, + renderfx, + beamthing->cgd.shadername, + newcolor, + beamthing->beamflags, + entity_number, + beamthing->cgd.life ); + } + else + { + if ( beamthing->startTag.length() ) + { + // Use a dummy sp to get the orientation + GetOrientation( beamthing->startTag, beamthing ); + start = beamthing->cgd.origin; + } + else + { + start = beamthing->cgd.origin; + } + + if ( beamthing->endTag.length() ) + { + // Use a dummy sp to get the orientation + GetOrientation( beamthing->endTag, beamthing ); + end = beamthing->cgd.origin; + } + else + { + end = start + beamthing->forward * beamthing->length; + } + + CG_CreateBeam( start, + vec_zero, + entity_number, + 1, + beamthing->cgd.alpha * alpha, + beamthing->cgd.scale * scale, + (beamthing->beamflags|BEAM_LIGHTNING_EFFECT), + beamthing->length, + beamthing->cgd.life, + qfalse, + end, + beamthing->min_offset, + beamthing->max_offset, + beamthing->overlap, + beamthing->numSubdivisions, + beamthing->delay, + beamthing->cgd.shadername, + beamthing->cgd.color, + beamthing->numspherebeams, + beamthing->sphereRadius, + beamthing->toggledelay, + beamthing->endalpha, + renderfx, + beamthing->emittername + ); + } + } + + +//=============== +//UpdateEmitter +//=============== +void ClientGameCommandManager::UpdateEmitter + ( + int tikihandle, + vec3_t axis[3], + int entity_number, + int parent_number, + Vector entity_origin + ) + + { + int parent,lastparent,i; + emittertime_t *et=NULL; + centity_t *pc; + int count=0; + float scale=1.0f; + + if ( current_entity ) + scale = current_entity->scale; + + // Find the emitter associated with this model + for ( i=1; i<=m_emitters.NumObjects(); i++ ) + { + m_spawnthing = m_emitters.ObjectAt( i ); + + if ( m_spawnthing->cgd.tikihandle != tikihandle ) + { + continue; + } + + et = m_spawnthing->GetEmitTime( entity_number ); + + if ( !et->active ) + continue; + + if ( ( m_spawnthing->cgd.flags & T_DETAIL ) && !cg_detail->integer ) + { + et->last_emit_time = 0; + continue; + } + + // Set the default origin (spawn from the parent's origin) + VectorCopy( entity_origin, m_spawnthing->cgd.origin ); + + if ( m_spawnthing->cgd.flags & T_BEAMTHING ) + { + if ( m_spawnthing->cgd.flags & T_ANGLES ) + { + vec3_t axis[3]; + + AnglesToAxis( m_spawnthing->cgd.angles, axis ); + + m_spawnthing->forward = axis[0]; + m_spawnthing->right = axis[1]; + m_spawnthing->up = axis[2]; + } + + UpdateBeam( tikihandle, entity_number, m_spawnthing ); + continue; + } + if ( m_spawnthing->tagname.length() ) + { + // Set the axis and origin based on the tag's axis and origin + GetOrientation( m_spawnthing->tagname, m_spawnthing ); + } + else if ( axis ) + { + // Set the axis based on the entity's axis. + m_spawnthing->forward = axis[0]; + m_spawnthing->right = axis[1]; + m_spawnthing->up = axis[2]; + } + else + { + m_spawnthing->forward = Vector( 1,0,0 ); + m_spawnthing->right = Vector( 0,1,0 ); + m_spawnthing->up = Vector( 0,0,1 ); + } + + // If we are HARDLINKed then subtract off the parent's origin + if ( m_spawnthing->cgd.flags & T_HARDLINK ) + { + m_spawnthing->cgd.parent = entity_number; + m_spawnthing->cgd.origin -= entity_origin; + } + else if ( m_spawnthing->cgd.flags & T_PARENTLINK ) + { + lastparent = ENTITYNUM_NONE; + + parent = parent_number; + + // Find the topmost parent + while ( parent != ENTITYNUM_NONE ) + { + pc = &cg_entities[ parent ]; + lastparent = parent; + parent = pc->currentState.parent; + } + + // The lastparent is the "real" parent + if ( lastparent != ENTITYNUM_NONE) + { + pc = &cg_entities[ lastparent ]; + + m_spawnthing->cgd.origin -= pc->lerpOrigin; + m_spawnthing->cgd.parent = lastparent; + } + } + + m_spawnthing->cgd.createTime = cg.time; + m_spawnthing->cgd.parentOrigin = Vector( entity_origin ); + + if ( m_spawnthing->cgd.flags & T_DLIGHT ) + { + cgi.R_AddLightToScene( m_spawnthing->cgd.origin, + m_spawnthing->cgd.lightIntensity * scale, + m_spawnthing->dcolor[0], + m_spawnthing->dcolor[1], + m_spawnthing->dcolor[2], + m_spawnthing->cgd.lightType + ); + continue; + } + + Vector save_origin = m_spawnthing->cgd.origin; + Vector delta = m_spawnthing->cgd.origin - et->oldorigin; + + if ( m_spawnthing->spawnRate < 0 ) + { + warning( "ClientGameCommandManager::UpdateEmitter", "Invalid spawnrate (negative)" ); + continue; + } + + if ( paused->integer ) + { + et->last_emit_time = 0; + } + else if ( ( et->last_emit_time > 0 ) && ( m_spawnthing->spawnRate ) ) + { + int dtime = cg.time - et->last_emit_time; + float lerp, lerpfrac; + + if ( et->last_emit_time > cg.time ) + et->last_emit_time = cg.time; + + count = dtime / ( m_spawnthing->spawnRate * ( 1.0f / cg_effectdetail->value ) ); + + // This is kind of a nasty bit of code. If the count is 1, just spawn + // a single tempmodel, if it's greater than 1, then spawn the number + // of tempmodels over a period of time, and adjust their create times + // accordingly. Also lerp the origins so they appear where they are + // supposed to. This helps smoothing out low frame rate situations + // where this is only get called a few times a second, but the spawn + // rate is high, and it will look a lot smoother. + if ( !count ) + { + continue; + } + else if ( count == 1 ) + { + SpawnTempModel( 1 ); + et->last_emit_time = cg.time; + } + else + { + lerpfrac = 1.0f / (float)count; + + lerp = 0; + while ( dtime > ( m_spawnthing->spawnRate * ( 1.0f / cg_effectdetail->value ) ) ) + { + et->last_emit_time = cg.time; + + dtime -= m_spawnthing->spawnRate * ( 1.0f / cg_effectdetail->value ); + + if ( et->lerp_emitter ) + m_spawnthing->cgd.origin = et->oldorigin + ( delta * lerp ); + + SpawnTempModel( 1, dtime ); + + lerp += lerpfrac; + } + } + } + else + { + et->last_emit_time = cg.time; + } + + if ( cg_showemitters->integer ) + { + if ( count ) + cgi.DPrintf( "%d:%s:%d tempmodels emitted\n", entity_number, m_spawnthing->emittername.c_str(), count ); + } + + // Since we have an oldorigin, now we can do lerping + m_spawnthing->cgd.origin = save_origin; + et->oldorigin = save_origin; + et->lerp_emitter = qtrue; + } + } + +//=============== +// RemoveClientEntity - Removes an entity from being +// updated if it has emitters attached +//=============== +void ClientGameCommandManager::RemoveClientEntity + ( + int number, + int tikihandle, + centity_t *cent, + ctempmodel_t *p + ) + + { + int i; + + // Kill the emitters if they are attached to this tiki + if ( number != -1 ) + { + for ( i=1; i<=m_emitters.NumObjects(); i++ ) + { + spawnthing_t *st = m_emitters.ObjectAt( i ); + + if ( st->cgd.tikihandle == tikihandle ) + { + st->RemoveEntity( number ); + } + } + } + + // Turn off any swiping for this entity number + int oldnum = current_entity_number; + centity_t *oldcent = current_centity; + + current_centity = cent; + current_entity_number = number; + ProcessEvent( EV_Client_SwipeOff ); + current_entity_number = oldnum; + current_centity = oldcent; + + // If this tempmodel was assigned a temporary number then remove it from the command_time_manager + if ( p && p->cgd.flags & T_ASSIGNED_NUMBER ) + { + m_command_time_manager.RemoveEntity( number ); + } + } + +//=============== +// FreeAllTempModels +//=============== +void ClientGameCommandManager::FreeAllTempModels + ( + void + ) + + { + ctempmodel_t *p, *next; + + // Go through all the temp models and run the physics if necessary, + // then add them to the ref + p = m_active_tempmodels.prev; + for ( ; p != &m_active_tempmodels; p = next ) + { + // grab next now, so if the local entity is freed we still have it + next = p->prev; + FreeTempModel( p ); + } + } + +//=============== +// RestartAllEmitters +//=============== +void ClientGameCommandManager::RestartAllEmitters + ( + int timedelta + ) + + { + int i; + + for( i = 1; i <= m_emitters.NumObjects(); i++ ) + { + spawnthing_t *st = m_emitters.ObjectAt( i ); + + if ( st->cgd.createTime > cg.time ) + { + st->cgd.createTime -= timedelta; + st->lastTime -= timedelta; + } + } + } + +//=============== +// FreeAllEmitters +//=============== +void ClientGameCommandManager::FreeAllEmitters + ( + void + ) + + { + m_emitters.ClearObjectList(); + } + +//=============== +//CG_RestartCommandManager +//=============== +void CG_RestartCommandManager + ( + int timedelta + ) + + { + commandManager.FreeAllTempModels(); + commandManager.RestartAllEmitters( timedelta ); + } + + +//=============== +//CG_FlushCommandManager +//=============== +void CG_FlushCommandManager + ( + void + ) + + { + commandManager.FreeAllTempModels(); + commandManager.FreeAllEmitters(); + } + + +void ProcessInitCommands + ( + int tikihandle + ) + + { + int i, j, num_args; + + // Process all the client side init commands + if ( tikihandle >= 0 ) + { + tiki_cmd_t tikicmds; + + if ( cgi.InitCommands( tikihandle, &tikicmds ) ) + { + for ( i = 0; i < tikicmds.num_cmds; i++ ) + { + Event *ev; + + num_args = tikicmds.cmds[ i ].num_args; + + // Create the event and Process it. + ev = new Event( tikicmds.cmds[ i ].args[ 0 ] ); + + for ( j=1; jAddToken( tikicmds.cmds[ i ].args[ j ] ); + + current_tiki = tikihandle; + commandManager.ProcessEvent( ev ); + current_tiki = -1; + } + } + } + } + +//================= +//CG_ProcessInitCommands +//================= +void CG_ProcessInitCommands + ( + int tikihandle + ) + + { + int i; + + ProcessInitCommands( tikihandle ); + // If any models were cached in this TIKI, then we have to Process their INIT commands too + + for( i=1; i<=cachedModelList.NumObjects(); i++ ) + { + int tikihandle; + int hModel = cachedModelList.ObjectAt( i ); + tikihandle = cgi.TIKI_GetHandle( hModel ); + ProcessInitCommands( tikihandle ); + } + + cachedModelList.ClearObjectList(); + } + +//================= +//CG_UpdateEntity +//================= +void CG_UpdateEntity + ( + int tikihandle, + refEntity_t *ent, + centity_t *cent + ) + { + // Check to see if this model has any emitters + current_entity = ent; + current_tiki = tikihandle; + + if ( cent->currentState.parent != ENTITYNUM_NONE ) + { + commandManager.UpdateEmitter( tikihandle, ent->axis, cent->currentState.number, cent->currentState.parent, ent->origin ); + } + else + { + commandManager.UpdateEmitter( tikihandle, ent->axis, cent->currentState.number, cent->currentState.parent, cent->lerpOrigin ); + } + current_entity = NULL; + current_tiki = -1; + } + +extern "C" + { + void CG_AnimationDebugMessage( int number, const char *fmt, ... ); + } + +//================= +//CG_ProcessEntityCommands +//================= +void CG_ProcessEntityCommands + ( + int tikihandle, + int frame, + int anim, + int entnum, + refEntity_t *ent, + centity_t *cent + ) + { + int i,j; + int num_args; + + tiki_cmd_t tikicmds; + + if ( cgi.Frame_Commands( tikihandle, anim, frame, &tikicmds ) ) + { + current_entity = ent; + current_centity = cent; + current_entity_number = entnum; + current_tiki = tikihandle; + CG_AnimationDebugMessage( entnum, "Processing Ent Commands: Entity: %3d Anim:#(%i) Frame:#(%i)\n", anim, frame ); + + for ( i = 0; i < tikicmds.num_cmds; i++ ) + { + Event *ev; + + num_args = tikicmds.cmds[ i ].num_args; + + if ( num_args > 0 ) + { + // Create the event and Process it. + ev = new Event( tikicmds.cmds[ i ].args[ 0 ] ); + + for ( j=1; jAddToken( tikicmds.cmds[ i ].args[ j ] ); + } + + commandManager.ProcessEvent( ev ); + } + } + + current_tiki = -1; + current_entity_number = -1; + current_entity = NULL; + current_centity = NULL; + } + } + +//================= +//CG_ClientCommandDebugMessage +//================= +void CG_ClientCommandDebugMessage + ( + centity_t *cent, + const char *fmt, + ... + ) + { +#ifndef NDEBUG + if ( cg_debugAnim->integer ) + { + va_list argptr; + char msg[1024]; + + va_start (argptr,fmt); + vsprintf (msg,fmt,argptr); + va_end (argptr); + + if ( ( !cg_debugAnimWatch->integer ) || ( ( cg_debugAnimWatch->integer - 1 ) == cent->currentState.number ) ) + { + if ( cg_debugAnim->integer == 2 ) + { + cgi.DebugPrintf( msg ); + } + else + { + cgi.Printf( msg ); + } + } + } +#endif + } + + +//================= +//CG_ClientCommands +//================= +void CG_ClientCommands + ( + int tikihandle, + int new_frame, + int new_anim, + animstate_t *state, + refEntity_t *ent, + centity_t *cent + ) + + { + int anim; + int frame; + + if ( tikihandle < 0 ) + return; + + if ( paused->integer ) + return; + + if ( cent->currentState.eFlags & EF_DONT_PROCESS_COMMANDS ) + return; + + assert( cent ); + + // don't do anything if the frame is illegal + if ( ( new_frame < 0 ) || ( new_frame >= state->numframes ) ) + return; + +#if 0 +#ifndef NDEBUG + CG_ClientCommandDebugMessage( + cent, + "Client Commands: cg.time %d checking Entity %d anim %d frame %d\n", + cg.time, + cent->currentState.number, + new_anim, + new_frame + ); +#endif +#endif + + anim = state->last_cmd_anim - 1; + frame = state->last_cmd_frame; + + // if we had a last anim and it it wasn't same as ours then + // we need to run any exit commands from the last animation + if ( ( anim != new_anim ) && ( anim >= 0 ) ) + { + // play the exit command + CG_ProcessEntityCommands( tikihandle, TIKI_FRAME_CMD_EXIT, anim, cent->currentState.number, ent, cent ); +#ifndef NDEBUG + CG_ClientCommandDebugMessage( + cent, + "Client Commands: Entity %d Exiting Anim: %s\n", + cent->currentState.number, + cgi.Anim_NameForNum( tikihandle, anim ) + ); +#endif + frame = 0; + + // Reset the tiki looping sound if changing animation + cent->tikiLoopSound = NULL; + } + + if ( state->has_commands ) + { + // if we are entering a new animation, than + // we need to run any entry commands for the new animation + if ( anim != new_anim ) + { + // play the exit command + CG_ProcessEntityCommands( tikihandle, TIKI_FRAME_CMD_ENTRY, new_anim, cent->currentState.number, ent, cent ); +#ifndef NDEBUG + CG_ClientCommandDebugMessage( + cent, + "Client Commands: Entity %d Entering Anim: %s\n", + cent->currentState.number, + cgi.Anim_NameForNum( tikihandle, new_anim ) + ); +#endif + } + + if ( state->driven ) + { + // make sure we process this frame if we are on a new frame + // although this is a hack, it guarantees that the frame will be processed + // below. + frame %= state->numframes; + if ( frame < new_frame ) + frame = new_frame; + } + else + { + // + // we need to catch up on the frames we haven't played yet + // + if ( ( new_frame != ( frame - 1 ) ) && ( state->numframes > 1 ) ) + { + // and frame number so that it wraps properly + frame %= state->numframes; + + // lerp to one minus the current frame + while ( frame != new_frame ) + { +#ifndef NDEBUG + CG_ClientCommandDebugMessage( + cent, + "Client Commands: cg.time %d Catching up Entity: %d Anim: %s frame: %d numframes: %d\n", + cg.time, + cent->currentState.number, + cgi.Anim_NameForNum( tikihandle, new_anim ), + frame, + state->numframes + ); +#endif + state->last_cmd_time = cg.time + TIKI_FRAME_CMD_MAXFRAMERATE; + CG_ProcessEntityCommands( tikihandle, frame, new_anim, cent->currentState.number, ent, cent ); + frame = ( frame + 1 ) % state->numframes; + } + } + } + + // + // handle the single frame and every frame case + // + if ( + ( frame == new_frame ) || + ( + ( cg.time > state->last_cmd_time ) && + ( cent->currentState.eFlags & EF_EVERYFRAME ) + ) + ) + { +#ifndef NDEBUG + CG_ClientCommandDebugMessage( + cent, + "Client Commands: cg.time %d Processing Entity: %d Anim: %s frame: %d numframes: %d\n", + cg.time, + cent->currentState.number, + cgi.Anim_NameForNum( tikihandle, new_anim ), + new_frame, + state->numframes + ); +#endif + state->last_cmd_time = cg.time + TIKI_FRAME_CMD_MAXFRAMERATE; + CG_ProcessEntityCommands( tikihandle, new_frame, new_anim, cent->currentState.number, ent, cent ); + } + } + + if ( cent->clientFlags & CF_UPDATESWIPE ) + { + current_entity = ent; + current_centity = cent; + current_entity_number = cent->currentState.number; + current_tiki = tikihandle; + + commandManager.ProcessEvent( EV_Client_Swipe ); + + current_tiki = -1; + current_entity_number = -1; + current_entity = NULL; + current_centity = NULL; + } + + state->last_cmd_anim = new_anim + 1; + state->last_cmd_frame = new_frame + 1; + } + +//=============== +//CG_AddTempModels +//=============== +void CG_AddTempModels + ( + void + ) + + { + commandManager.AddTempModels(); + } + +//=============== +//CG_InitializeCommandManager +//=============== +void CG_InitializeCommandManager + ( + void + ) + + { + cg_showtempmodels = cgi.Cvar_Get( "cg_showtempmodels", "0", 0 ); + cg_showemitters = cgi.Cvar_Get( "cg_showemitters", "0", 0 ); + cg_physics_fps = cgi.Cvar_Get( "cg_physics_fps", "10", CVAR_ARCHIVE ); + cg_detail = cgi.Cvar_Get( "detail", "1", CVAR_ARCHIVE ); + cg_effectdetail = cgi.Cvar_Get( "cg_effectdetail", "1", CVAR_ARCHIVE ); + + commandManager.InitializeTempModels(); + commandManager.InitializeEmitters(); + CG_InitTestEmitter(); + CG_InitializeClientEmitters(); + } + +void CG_ResetTempModels + ( + void + ) + + { + commandManager.ResetTempModels(); + lastFrameTime = cg.time; + } + +//=============== +//CG_RemoveClientEntity +//=============== +void CG_RemoveClientEntity + ( + int number, + int tikihandle, + centity_t *cent + ) + + { + commandManager.RemoveClientEntity( number, tikihandle, cent ); + + // Remove the beam list associated with this entity + RemoveBeamList( number ); + } + +//================= +//CG_Command_ProcessFile +//================= +qboolean CG_Command_ProcessFile( const char * filename, qboolean quiet ) + { + char *buffer; + const char *bufstart; + char com_token[MAX_STRING_CHARS]; + + if ( cgi.FS_ReadFile( filename, ( void ** )&buffer, quiet ) == -1 ) + { + return qfalse; + } + + if ( !quiet ) + cgi.DPrintf( "CG_Command_ProcessFile: %s\n", filename ); + + // we are not setting up for a tiki + current_tiki = -1; + + bufstart = buffer; + + while ( 1 ) + { + Event *ev; + + // grab each line as we go + strcpy( com_token, COM_ParseExt( &buffer, qtrue ) ); + if (!com_token[0]) + break; + + if ( + !strcmpi( com_token, "end" ) || + !strcmpi( com_token, "server" ) + ) + { + // skip the line + while( 1 ) + { + strcpy( com_token, COM_ParseExt( &buffer, qfalse ) ); + if (!com_token[0]) + break; + } + continue; + } + + // Create the event + ev = new Event( com_token ); + + // get the rest of the line + while( 1 ) + { + strcpy( com_token, COM_ParseExt( &buffer, qfalse ) ); + if (!com_token[0]) + break; + + ev->AddToken( com_token ); + } + commandManager.ProcessEvent( ev ); + } + cgi.FS_FreeFile( ( void * )bufstart ); + + return qtrue; + } + + +//=========================== +//CG_ConsoleCommand Functions +//=========================== +void CG_EventList_f( void ) + { + const char *mask; + + mask = NULL; + if ( cgi.Argc() > 1 ) + { + mask = cgi.Argv( 1 ); + } + Event::ListCommands( mask ); + } + +void CG_EventHelp_f( void ) + { + const char *mask; + + mask = NULL; + if ( cgi.Argc() > 1 ) + { + mask = cgi.Argv( 1 ); + } + Event::ListDocumentation( mask ); + } + +void CG_DumpEventHelp_f( void ) + { + const char *mask; + + mask = NULL; + if ( cgi.Argc() > 1 ) + { + mask = cgi.Argv( 1 ); + } + Event::ListDocumentation( mask, true ); + } + +void CG_PendingEvents_f( void ) + { + const char *mask; + + mask = NULL; + if ( cgi.Argc() > 1 ) + { + mask = cgi.Argv( 1 ); + } + Event::PendingEvents( mask ); + } + +void CG_ClassList_f( void ) + { + listAllClasses(); + } + +void CG_ClassTree_f( void ) + { + if ( cgi.Argc() > 1 ) + { + listInheritanceOrder( cgi.Argv( 1 ) ); + } + else + { + cgi.Printf( "Syntax: cg_classtree [classname].\n" ); + } + } + +void CG_ClassEvents_f( void ) + { + if ( cgi.Argc() > 1 ) + { + ClassEvents( cgi.Argv( 1 ) ); + } + else + { + Com_Printf( "Syntax: cg_classevents [classname].\n" ); + } + } + +void CG_DumpClassEvents_f( void ) + { + if ( cgi.Argc() > 1 ) + { + ClassEvents( cgi.Argv( 1 ), qtrue ); + } + else + { + Com_Printf( "Syntax: cg_dumpclassevents [classname].\n" ); + } + } + +void CG_DumpAllClasses_f( void ) + { + DumpAllClasses(); + } + +#define throw_assert assert ( 0 ), throw + +EmitterLoader emitterLoader; + +Event EV_EmitterLoader_Emitter + ( + "emitter", + EV_DEFAULT, + "s", + "emittername", + "Create a new emitter" + ); + +CLASS_DECLARATION( Listener, EmitterLoader, NULL ) + { + { &EV_EmitterLoader_Emitter, Emitter }, + { NULL, NULL } + }; + +EmitterLoader::EmitterLoader + ( + ) + + { + emitterActive = false; + } + +void EmitterLoader::Emitter + ( + Event *ev + ) + + { + spawnthing_t *st; + + st = commandManager.CreateNewEmitter( ev->GetString( 1 ) ); + + if ( st ) + { + emitterActive = true; + commandManager.SetSpawnthing( st ); + } + } + +void EmitterLoader::ProcessEmitter + ( + Script &script + ) + + { + str token; + + while ( script.TokenAvailable ( true ) ) + { + Event *ev = NULL; + + token = script.GetToken ( true ); + + if ( !str::cmp( "}", token ) ) + break; + + ev = new Event ( token ); + + while ( script.TokenAvailable ( false ) ) + ev->AddToken ( script.GetToken ( false ) ); + + if ( emitterActive ) + { + commandManager.ProcessEvent( ev ); + } + } + + commandManager.SetSpawnthing( NULL ); + emitterActive = NULL; + } + +bool EmitterLoader::Load + ( + Script &script + ) + + { + str token; + str errortext; + + try + { + while ( script.TokenAvailable ( true ) ) + { + Event *ev = NULL; + + token = script.GetToken ( true ); + + if ( !str::cmp( "{", token ) ) + { + ProcessEmitter( script ); + } + else if ( !token.length () || !ValidEvent ( token ) ) + { + throw_assert "invalid token"; + } + else + { + ev = new Event ( token ); + + while ( script.TokenAvailable ( false ) ) + ev->AddToken ( script.GetToken ( false ) ); + + ProcessEvent ( ev ); + } + } + } + catch ( const char *s ) + { + cgi.DPrintf ( "emitter: error on line %d: %s\n", script.GetLineNumber (), s ); + return false; + } + + return true; + } + +void CG_InitializeClientEmitters + ( + void + ) + + { + Script script; + + Com_Printf ( "Loading client emitters...\n" ); + script.LoadFile ( "global/emitters.scr" ); + emitterLoader.Load ( script ); + } + +void CG_Emitter + ( + centity_t *cent + ) + + { + spawnthing_t *emitter; + float dtime; + emittertime_t *et; + vec3_t mins, maxs; + + emitter = commandManager.GetEmitterByName( CG_ConfigString( CS_IMAGES + cent->currentState.tag_num ) ); + + if ( emitter ) + { + vec3_t axis[3]; + cgi.R_ModelBounds( cgs.inlineDrawModel[cent->currentState.modelindex], mins, maxs ); + + emitter->cgd.origin[0] = cent->lerpOrigin[0] + mins[0] + ( random() * ( maxs[0] - mins[0] ) ); + emitter->cgd.origin[1] = cent->lerpOrigin[1] + mins[1] + ( random() * ( maxs[1] - mins[1] ) ); + emitter->cgd.origin[2] = cent->lerpOrigin[2] + maxs[2]; + emitter->cgd.parentOrigin = Vector( cent->lerpOrigin ); + emitter->cgd.parentOrigin[2] = cent->lerpOrigin[2] + maxs[2]; + emitter->cgd.parentMins = mins; + emitter->cgd.parentMaxs = maxs; + + AnglesToAxis( cent->lerpAngles, axis ); + emitter->forward = axis[0]; + emitter->right = axis[1]; + emitter->up = axis[2]; + + // Update the emitter time and spawn the tempmodels + et = emitter->GetEmitTime( cent->currentState.number ); + + if ( et->last_emit_time > 0 ) + { + dtime = cg.time - et->last_emit_time; + while ( dtime > emitter->spawnRate ) + { + dtime -= emitter->spawnRate; + commandManager.SpawnTempModel( 1, emitter ); + et->last_emit_time = cg.time; + } + } + } + } + + +void ClientGameCommandManager::CGEvent + ( + centity_t *cent + ) + + { + str modelname; + vec3_t axis[3]; + int tikihandle; + + tikihandle = cgs.model_tiki[cent->currentState.modelindex]; + + if ( tikihandle == -1 ) + return; + + CG_EntityEffects( cent ); + + modelname = cgi.TIKI_NameForNum( tikihandle ); + m_spawnthing = InitializeSpawnthing( &m_localemitter ); + + AnglesToAxis( cent->lerpAngles, axis ); + m_spawnthing->cgd.angles = cent->lerpAngles; + m_spawnthing->forward = axis[0]; + m_spawnthing->right = axis[1]; + m_spawnthing->up = axis[2]; + m_spawnthing->cgd.origin = cent->lerpOrigin; + m_spawnthing->cgd.scale = cent->currentState.scale; + m_spawnthing->cgd.alpha = cent->currentState.alpha; + + m_spawnthing->cgd.color[0] = cent->color[0] * 255; + m_spawnthing->cgd.color[1] = cent->color[1] * 255; + m_spawnthing->cgd.color[2] = cent->color[2] * 255; + m_spawnthing->cgd.color[3] = cent->color[3] * 255; + + Event *ev; + ev = new Event( "model" ); + ev->AddString( modelname ); + ProcessEvent( ev ); + + ev = new Event( "anim" ); + ev->AddString( "idle" ); + ProcessEvent( ev ); + + SpawnTempModel( 1 ); + } + +void CG_Event + ( + centity_t *cent + ) + + { + commandManager.CGEvent( cent ); + } diff --git a/source/source/cgame/cg_commands.h b/source/source/cgame/cg_commands.h new file mode 100644 index 0000000..b4a8ec0 --- /dev/null +++ b/source/source/cgame/cg_commands.h @@ -0,0 +1,1061 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/cgame/cg_commands.h $ +// $Revision:: 75 $ +// $Author:: Aldie $ +// $Date:: 7/29/00 9:04p $ +// +// Copyright (C) 1998 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/cgame/cg_commands.h $ +// +// 75 7/29/00 9:04p Aldie +// Added originbeamemitter +// +// 74 7/25/00 11:30p Aldie +// Made some memory changes and fixed some memory allocation bugs +// +// 73 7/22/00 5:50p Markd +// added flushtikis support +// +// 72 7/19/00 9:52p Aldie +// Put ET_EVENTS back in. They will get sent over once, and should get +// processed once on the client. +// +// 71 7/17/00 3:26p Aldie +// Added detail command +// +// 70 7/15/00 12:32p Aldie +// Fixed a bug for restarting tempmodels on a save game +// +// 69 7/11/00 9:57p Aldie +// Removed assertion +// +// 68 7/11/00 8:17p Aldie +// Fixed emitter bug (what else), where I was accidentally removing numbers +// from the global pool when a tempent was being removed. +// +// 67 6/27/00 2:34p Markd +// clear out swipes when restarting +// +// 66 6/26/00 7:14p Markd +// added parentangles command +// +// 65 6/17/00 1:54p Markd +// Added server restarted code +// +// 64 6/15/00 8:21p Markd +// Added CleanupCommandManager support +// +// 63 6/14/00 12:14p Markd +// more intel compiler bug fixes +// +// 62 6/10/00 5:52p Aldie +// Made some improvements to help speed, added tag_axis, removed notagangles +// command. Removed some unused code. Changed the method of adding +// tempmodels. +// +// 61 6/09/00 7:53p Aldie +// Added origin to playsound and fixed bouncesound and a couple other sound +// things +// +// 60 6/03/00 8:19p Markd +// Added footstep code +// +// 59 6/02/00 6:52p Aldie +// Added in parallel command +// +// 58 6/01/00 7:45p Aldie +// Made it so that swipes are removed when client entities are reset. +// +// 57 5/30/00 2:47p Aldie +// Fix for animateTempModel() +// +// 56 5/22/00 6:38p Aldie +// Added originbeamspawn +// +// 55 5/20/00 4:42p Aldie +// Removed some unused flags and code. Fixed emitters that have parentlink or +// hardlink +// +// 54 5/18/00 3:32p Aldie +// Added bouncedecal +// +// 53 5/18/00 11:47a Aldie +// Added tempmodelsRealtimeEffects proc +// +// 52 5/16/00 3:40p Aldie +// Changed method of calculating physicsTime. And added physicsrate command +// +// 51 5/15/00 2:19p Aldie +// Added new tempmodel system and added player accumulated pain +// +// 49 5/04/00 7:46p Aldie +// Added tagnoangles command +// +// 48 5/04/00 4:34p Aldie +// Added trail command that uses swipe code to do a trail +// +// 47 4/27/00 7:42p Aldie +// Added trace_count functionality for multiple spawns for tagtraceimpactmark +// and spawn +// +// 46 3/31/00 4:56p Steven +// Added UseLastTraceEnd so that tracecommands could use the end point of the +// previous command. +// +// 45 3/27/00 1:50p Aldie +// Removed some unused code +// +// 44 3/16/00 6:51p Aldie +// Added some shortcut flags for tempmodel optimization +// +// 43 3/16/00 5:09p Aldie +// Added some optimizations for tempmodels +// +// 42 3/15/00 11:01a Aldie +// Changed m_emitters to container instead of array. +// +// 41 3/14/00 3:22p Aldie +// Changed some client side emitter functionality and added func_emitter +// +// 40 3/13/00 1:54p Aldie +// Fixes for rain +// +// 39 3/11/00 4:47p Aldie +// Fix for scaleupdown +// +// 38 3/11/00 4:06p Aldie +// Added scaleupdown code +// +// 37 3/04/00 6:03p Aldie +// Made commandManager static +// +// 36 3/04/00 2:53p Markd +// Fixed dynamic light types +// +// 35 3/04/00 2:33p Aldie +// Added lightstyle support +// +// 34 3/03/00 2:40p Aldie +// Added in tagtraceimpactsound command +// +// 33 3/01/00 5:55p Aldie +// Added alignonce flag for aligning models one time, but not every frame. Use +// if you have avelocity on a tempmodel +// +// 32 2/29/00 12:22p Aldie +// Added taglist to beam emitters. Allows for a list of tags to be named for a +// chain of beams +// +// 31 2/25/00 5:01p Aldie +// Changed some of the dlight stuff and added a new command +// +// 30 2/22/00 6:54p Aldie +// Added a bool to tempmodels so that they will get added at least one time to +// the ref. This is useful for getting things to show up in low framerate +// situations. +// +// 29 2/20/00 5:40p Aldie +// Fixed the twinkle command +// +// 28 2/11/00 3:22p Aldie +// Changed swipe code a bit, and added cg_hidetempmodels cvar. +// +// 27 2/10/00 5:45p Aldie +// added tagtraceimpactspawn +// +// 26 2/09/00 4:27p Aldie +// Fixed pause on the client emitters +// +// 25 2/07/00 7:38p Aldie +// Fixed swiping, also various weapons fixes for sword and for sling +// +// 24 1/29/00 10:16a Steven +// Added stop sound support in cgame. +// +// 23 1/28/00 7:16p Aldie +// Added more features to the impact decal code +// +// 22 1/27/00 4:20p Aldie +// Added tagtraceimpactmark +// +// 21 1/27/00 3:21p Aldie +// Added twinkle +// +// 20 1/26/00 11:35a Aldie +// New data structures for emitters +// +// 19 1/24/00 7:42p Aldie +// Removed assertion +// +// 18 1/24/00 6:19p Aldie +// Added some new commands - commanddelay and randomchance +// +// 17 1/22/00 1:48p Aldie +// Removed .vec3 references, fixed bouncesound and added bouncesoundonce +// +// 16 1/22/00 10:37a Aldie +// Changed default life +// +// 15 1/21/00 7:53p Aldie +// Added randvelaxis command +// +// 14 1/20/00 11:03a Markd +// Added Bouncesound but then took it out temporarily +// +// 13 1/15/00 2:39p Aldie +// Added fadedelay and Cachedmodellist for init command processing +// +// 12 10/29/99 7:16p Aldie +// Updated rope stuff +// +// 11 10/19/99 11:57a Aldie +// Added some more beam features +// +// 10 10/13/99 3:26p Aldie +// Various fixes for particles, beams and lensflares +// +// 9 10/11/99 3:38p Aldie +// Fix for some command doc stuff +// +// 8 10/08/99 5:07p Aldie +// More beam stuff and fix for UI_CenterPrint +// +// 7 10/07/99 7:14p Aldie +// More beam stuff +// +// 6 10/07/99 3:08p Aldie +// more beam fun +// +// 5 10/06/99 6:55p Aldie +// Fix some problems with the animateonce command +// +// 4 10/06/99 3:11p Aldie +// Added more docs to commands +// +// 3 10/05/99 6:01p Aldie +// Added headers +// +// DESCRIPTION: +// client side entity commands + +/* +The cg_command system is used for a variety of different functions, but mostly it is +used for spawning client side temp models. Either through the use of emitters or +commands that are tied to various frames of animation. + +The ctempmodel_t class is the data structure for all of the static tempmodels. +These are updated every frame and refEntity and refSprite data is created and added +to the renderer for drawing. + +The spawnthing_t is the intermediate data holder. When the TIKI file is processed +the spawnthing_t is cleared out and values are assigned based on the commands issued. + +cg_common_data is a list of common data elements that are the same in the ctempmodel_t and +the spawhthing_t + +After the m_spawnthing is filled in, 1 or more ctempmodel_t structures are spawned. + +The ClientCommandManager is the listener that process all of the commands in the +TIKI file, similar to ScriptMaster in the server game dll. + +*/ + +#ifndef __CG_COMMANDS_H__ +#define __CG_COMMANDS_H__ + +#include "cg_local.h" +#include "listener.h" +#include "script.h" +#include "vector.h" +#include "../qcommon/qcommon.h" + +#define EMITTER_DEFAULT_LIFE 1000 +#define MAX_EMITTERS 32 +#define MAX_SWIPES 32 + +#define T_RANDSCALE (1<<0) +#define T_SCALEANIM (1<<1) +#define T_SPHERE (1<<2) +#define T_INWARDSPHERE (1<<3) +#define T_CIRCLE (1<<4) +#define T_FADE (1<<5) +#define T_DIETOUCH (1<<6) +#define T_ANGLES (1<<7) +#define T_WAVE (1<<8) +#define T_SWARM (1<<9) +#define T_ALIGN (1<<10) +#define T_COLLISION (1<<11) +#define T_FLICKERALPHA (1<<12) +#define T_DLIGHT (1<<13) +#define T_FADEIN (1<<14) +#define T_GLOBALFADEIN (1<<15) +#define T_GLOBALFADEOUT (1<<16) +#define T_PARENTLINK (1<<17) +#define T_RANDOMROLL (1<<18) +#define T_HARDLINK (1<<19) +#define T_ANIMATEONCE (1<<20) +#define T_BEAMTHING (1<<21) +#define T_RANDVELAXIS (1<<22) +#define T_BOUNCESOUND (1<<23) +#define T_BOUNCESOUNDONCE (1<<24) +#define T_TWINKLE (1<<25) +#define T_TWINKLE_OFF (1<<26) +#define T_ALIGNONCE (1<<27) +#define T_SCALEUPDOWN (1<<28) +#define T_AUTOCALCLIFE (1<<29) +#define T_ASSIGNED_NUMBER (1<<30) +#define T_DETAIL (1<<31) + +#define T2_MOVE (1<<0) +#define T2_AMOVE (1<<1) +#define T2_ACCEL (1<<2) +#define T2_TRAIL (1<<3) +#define T2_PHYSICS_EVERYFRAME (1<<4) +#define T2_TEMPORARY_DECAL (1<<5) +#define T2_BOUNCE_DECAL (1<<6) +#define T2_PARALLEL (1<<7) + +typedef enum { NOT_RANDOM, RANDOM, CRANDOM } randtype_t; + +class cg_common_data : public Class + { + public: + cg_common_data(); + + int life; + int createTime; + Vector origin; + Vector oldorigin; + Vector accel; + Vector angles; + Vector velocity; + Vector avelocity; + Vector parentOrigin; + Vector parentMins; + Vector parentMaxs; + byte color[4]; + float alpha; + float scaleRate; + float scalemin; + float scalemax; + float bouncefactor; + float wave; + int duplicateCount; + int bouncecount; + int maxbouncecount; + str bouncesound; + int bouncesound_delay; + int flags; + int flags2; + int tikihandle; + int swarmfreq; + float swarmmaxspeed; + float swarmdelta; + float lightIntensity; + int lightType; + int fadeintime; + int fadedelay; + int parent; + int collisionmask; + int min_twinkletimeoff; + int max_twinkletimeoff; + int min_twinkletimeon; + int max_twinkletimeon; + int lightstyle; + int physicsRate; + float scale; + str swipe_shader; + str swipe_tag_start; + str swipe_tag_end; + str shadername; + float swipe_life; + + float decal_orientation; + float decal_radius; + }; + +inline cg_common_data::cg_common_data() + { + int i; + + bouncesound_delay =0; + life =0; + createTime =0; + wave =0; + alpha =0; + fadedelay =0; + lightIntensity =0; + lightType =(dlighttype_t)0; + bouncefactor =0; + bouncecount =0; + maxbouncecount =0; + scaleRate =0; + scale =1; + scalemin =0; + scalemax =0; + swarmfreq =0; + swarmmaxspeed =0; + swarmdelta =0; + flags =0; + flags2 =0; + duplicateCount =0; + fadeintime =0; + parent =0; + tikihandle =0; + collisionmask =0; + min_twinkletimeoff =0; + max_twinkletimeoff =0; + min_twinkletimeon =0; + max_twinkletimeoff =0; + lightstyle =-1; + physicsRate =10; + + for (i=0;i<4;i++) + { + color[i] = 0; + } + } + +class ctempmodel_t : public Class + { + public: + ctempmodel_t(); + + class ctempmodel_t *next; + class ctempmodel_t *prev; + + cg_common_data cgd; + str modelname; + + refEntity_t lastEnt; + refEntity_t ent; + + int number; + int lastAnimTime; + int lastPhysicsTime; + int killTime; + int next_bouncesound_time; + Vector perp; + int seed; + int twinkleTime; + int aliveTime; + qboolean addedOnce; + qboolean lastEntValid; + + void (*touchfcn)( ctempmodel_t *ct, trace_t *trace ); + }; + +inline ctempmodel_t::ctempmodel_t() + { + number =0; + lastPhysicsTime =0; + lastAnimTime =0; + killTime =0; + next_bouncesound_time =0; + seed =0; + twinkleTime =0; + aliveTime =0; + addedOnce =qfalse; + lastEntValid =qfalse; + } + +#define LIFE_SWIPE 1 +#define MAX_SWIPE_POINTS 64 + +struct swipepoint_t + { + vec3_t points[2]; + float time; + }; + +class swipething_t : public Class + { + public: + qboolean enabled; + str tagname_start; + str tagname_end; + int entitynum; + float startcolor[4]; + float endcolor[4]; + swipepoint_t swipepoints[MAX_SWIPE_POINTS]; + swipepoint_t cntPoint; + int num_live_swipes; + int first_swipe; + float life; + qhandle_t shader; + void Init (); + }; + +inline void swipething_t::Init () + { + int i; + + enabled = qfalse; + tagname_start = ""; + tagname_end = ""; + entitynum = -1; + + for ( i=0; i < 4; i++ ) + { + startcolor[i] = 1.f; + endcolor[i] = 0.f; + } + + for ( i=0; i < MAX_SWIPE_POINTS; i++ ) + { + VectorSet ( swipepoints[i].points[0], 0.f, 0.f, 0.f ); + VectorSet ( swipepoints[i].points[1], 0.f, 0.f, 0.f ); + swipepoints[i].time = 0.f; + } + + num_live_swipes = 0; + first_swipe = 0; + } + +// Enttracker is used to keep track of client side tempmodels. They are assigned +// a number from a pool of 256. +class enttracker_t : public Class + { + public: + enttracker_t(); + int AssignNumber( void ); + + + protected: + qboolean usedNumbers[256]; + virtual void RemoveEntity( int entnum ); + + }; + +inline enttracker_t::enttracker_t + ( + ) + + { + memset( usedNumbers, 0, sizeof( usedNumbers ) ); + } + +inline void enttracker_t::RemoveEntity + ( + int entnum + ) + + { + // If the entnum is a magic number, then clear out the usedNumber field, so that it + // may be reused for this emitter. + + if ( entnum >= MAGIC_UNUSED_NUMBER ) + { + entnum -= MAGIC_UNUSED_NUMBER; + + assert( entnum >= 0 ); + assert( entnum < 256 ); + + usedNumbers[ entnum ] = qfalse; + } + } + +inline int enttracker_t::AssignNumber + ( + void + ) + + { + int i; + + // These numbers are used for client side tempmodels that are emitters themselves. + // Since they don't have real entity_numbers, they must be assigned a MAGIC number + // so we can keep track of the last time that the model emitted something. + + // Search for a number that is not used + for ( i=0; i<256; i++ ) + { + if ( !usedNumbers[i] ) + { + usedNumbers[i] = qtrue; + return MAGIC_UNUSED_NUMBER + i; + } + } + + return -1; + } + +class emittertime_t : public Class + { + public: + int entity_number; + int last_emit_time; + Vector oldorigin; + qboolean active; + qboolean lerp_emitter; + }; + +// emitterthing_t is used to keep track of the last time and emitter was updated +// for a particular entity number. It inherits from the enttracker_t so it can +// manage client side tempmodels +class emitterthing_t : public enttracker_t + { + protected: + Container m_emittertimes; // A list of entity numbers and the last time they emitted + + public: + emittertime_t *GetEmitTime( int entnum ); + virtual void RemoveEntity( int entnum ); + qboolean startoff; + + }; + +inline void emitterthing_t::RemoveEntity + ( + int entnum + ) + + { + int num,count; + emittertime_t *et; + + if ( entnum == -1 ) + return; + + count = m_emittertimes.NumObjects(); + + for ( num=count; num>=1; num-- ) + { + et = m_emittertimes.ObjectAt( num ); + if ( et->entity_number == entnum ) + { + m_emittertimes.RemoveObjectAt( num ); + delete et; + } + } + + enttracker_t::RemoveEntity( entnum ); + } + +inline emittertime_t *emitterthing_t::GetEmitTime + ( + int entnum + ) + + { + int num, count; + emittertime_t *et; + + count = m_emittertimes.NumObjects(); + + for ( num=1; num<=count; num++ ) + { + et = m_emittertimes.ObjectAt( num ); + if ( et->entity_number == entnum ) + { + return et; + } + } + + // Add a new entry if we didn't find it already + et = new emittertime_t; + et->entity_number = entnum; + et->last_emit_time = cg.time; + et->lerp_emitter = qfalse; + + if ( this->startoff ) + { + et->active = qfalse; + } + else + { + et->active = qtrue; + } + + m_emittertimes.AddObject( et ); + + return et; + } + +class commandtime_t : public Class + { + public: + int entity_number; + int command_number; + int last_command_time; + }; + +// This class is used for keeping track of the last time an entity executed a particular +// command. A command number must be assigned externally by the user +class commandthing_t : public enttracker_t + { + + Container m_commandtimes; // A list of entity numbers and the last time they executed a command + + public: + commandtime_t *GetLastCommandTime( int entnum, int commandnum ); + virtual void RemoveEntity( int entnum ); + }; + +inline void commandthing_t::RemoveEntity + ( + int entnum + ) + + { + int num,count; + commandtime_t *ct; + + count = m_commandtimes.NumObjects(); + + for ( num=count; num>=1; num-- ) + { + ct = m_commandtimes.ObjectAt( num ); + if ( ct->entity_number == entnum ) + { + m_commandtimes.RemoveObjectAt( num ); + } + } + + enttracker_t::RemoveEntity( entnum ); + } + +inline commandtime_t *commandthing_t::GetLastCommandTime + ( + int entnum, + int commandnum + ) + + { + int num, count; + commandtime_t *ct; + + // Search for this entity number + count = m_commandtimes.NumObjects(); + + for ( num=1; num<=count; num++ ) + { + ct = m_commandtimes.ObjectAt( num ); + if ( ( ct->entity_number == entnum ) && ( ct->command_number == commandnum ) ) + { + return ct; + } + } + + // Add a new entry if we didn't find it + ct = new commandtime_t; + ct->entity_number = entnum; + ct->command_number = commandnum; + ct->last_command_time = 0; + + m_commandtimes.AddObject( ct ); + + return ct; + } + +class spawnthing_t : public emitterthing_t + { + public: + Container m_modellist; // A list of models that should be spawned from the emitter + Container m_taglist; // A list of tags to create beams + + cg_common_data cgd; + + Vector origin_offset; + Vector axis_offset; + Vector velocityVariation; + Vector forward; + Vector right; + Vector up; + vec3_t axis[3]; + vec3_t tag_axis[3]; + randtype_t randvel[3]; + randtype_t randorg[3]; + randtype_t randavel[3]; + randtype_t randangles[3]; + randtype_t randaxis[3]; + float forwardVelocity; + float sphereRadius; + float spawnRate; + int lastTime; + int count; + int trace_count; + str tagname; + str emittername; + str animName; + float dcolor[3]; + qboolean dlight; + + // beam stuff also impact trace stuff + str startTag; + str endTag; + float length; + float min_offset; + float max_offset; + float overlap; + float numSubdivisions; + float delay; + float toggledelay; + int beamflags; + int numspherebeams; + float endalpha; + float spreadx; + float spready; + qboolean use_last_trace_end; + + void (*touchfcn)( ctempmodel_t *ct, trace_t *trace ); + str GetModel( void ); + void SetModel( str model ); + }; + +inline void spawnthing_t::SetModel + ( + str model + ) + + { + m_modellist.ClearObjectList(); + m_modellist.AddObject( model ); + } + +inline str spawnthing_t::GetModel + ( + void + ) + + { + int num, index; + + num = m_modellist.NumObjects(); + + if ( !num ) + { + return ""; + } + + index = ( num * random() ) + 1; + + if ( index > num ) + index = num; + + return m_modellist.ObjectAt( index ); + } + +// Keeps track of beams that are created by entities that need their positions updated every frame +class beamthing_t : public emitterthing_t + { + public: + str beamname; + str shadername; + str startTag; + str endTag; + int numSubdivisions; + int tikihandle; + float alpha; + float scale; + int flags; + float length; + int life; + float min_offset; + float max_offset; + float overlap; + int delay; + byte modulate[4]; + }; + +#define MAX_TEMPMODELS 1024 +#define MAX_BEAMS 128 + +class ClientGameCommandManager : public Listener + { + private: + spawnthing_t m_localemitter; // local emitter used by animation commands + ctempmodel_t m_active_tempmodels; + ctempmodel_t *m_free_tempmodels; + ctempmodel_t m_tempmodels[MAX_TEMPMODELS]; + spawnthing_t *m_spawnthing; + Container m_emitters; // Global emitters set up by client commands + int m_numtempmodels; // number of tempmodels + int m_seed; + commandthing_t m_command_time_manager; // Keeps track of entity numbers and the last time + // they executed particular commands + + void (ClientGameCommandManager::*endblockfcn)( void ); + ctempmodel_t *AllocateTempModel( void ); + qboolean TempModelPhysics( ctempmodel_t *p, float ftime, float time2, float scale ); + qboolean TempModelRealtimeEffects( ctempmodel_t *p, float ftime, float time2, float scale ); + qboolean LerpTempModel( refEntity_t *newEnt, ctempmodel_t *p, float frac ); + void Print( Event *ev ); + void StartBlock( Event *ev ); + void EndBlock( Event *ev ); + void UpdateSpawnThing( spawnthing_t *ep ); + void EmitterStartOff( Event *ev ); + void SetAlpha( Event *ev ); + void SetDieTouch( Event *ev ); + void SetBounceFactor( Event *ev ); + void SetBounceSound( Event *ev ); + void SetBounceSoundOnce( Event *ev ); + void SetModel( Event *ev ); + void SetLife( Event *ev ); + void SetColor( Event *ev ); + void SetColorRange( Event *ev ); + void SetLightstyle( Event *ev ); + void SetDuplicateCount( Event *ev ); + void SetVelocity( Event *ev ); + void SetAngularVelocity( Event *ev ); + void SetCount( Event *ev ); + void SetTraceCount( Event *ev ); + void SetScale( Event *ev ); + void SetScaleUpDown( Event *ev ); + void SetScaleMin( Event *ev ); + void SetScaleMax( Event *ev ); + void SetScaleRate( Event *ev ); + void SetRandomVelocity( Event *ev ); + void SetRandomVelocityAlongAxis( Event *ev ); + void SetAccel( Event *ev ); + void SetFade( Event *ev ); + void SetFadeDelay( Event *ev ); + void SetSpawnRate( Event *ev ); + void SetOriginOffset( Event *ev ); + void SetOffsetAlongAxis( Event *ev ); + void SetCircle( Event *ev ); + void SetSphere( Event *ev ); + void SetInwardSphere( Event *ev ); + void SetWavy( Event *ev ); + void SetRandomRoll( Event *ev ); + void SetSwarm( Event *ev ); + void SetAlign( Event *ev ); + void SetAlignOnce( Event *ev ); + void SetCollision( Event *ev ); + void SetFlickerAlpha( Event *ev ); + void SetFadeIn( Event *ev ); + void SetEntityColor( Event *ev ); + void SetGlobalFade( Event *ev ); + void SetRadius( Event *ev ); + void SetParentLink( Event *ev ); + void SetHardLink( Event *ev ); + void SetAngles( Event *ev ); + void ParentAngles( Event *ev ); + void SetTwinkle( Event *ev ); + void SetTrail( Event *ev ); + void SetPhysicsRate( Event *ev ); + void SetBounceDecal( Event *ev ); + void UpdateSwarm( ctempmodel_t *p ); + void SpawnTempModel( int count, int timealive=0 ); + void FreeTempModel( ctempmodel_t *le ); + void BeginOriginSpawn( Event *ev ); + void EndOriginSpawn( void ); + void BeginOriginBeamSpawn( Event *ev ); + void EndOriginBeamSpawn( void ); + void BeginOriginBeamEmitter( Event *ev ); + void EndOriginBeamEmitter( void ); + void BeginTagSpawn( Event *ev ); + void EndTagSpawn( void ); + void BeginTagBeamSpawn( Event *ev ); + void EndTagBeamSpawn( void ); + void BeginTagEmitter( Event *ev ); + void EndTagEmitter( void ); + void BeginOriginEmitter( Event *ev ); + void EndOriginEmitter( void ); + void BeginTagBeamEmitter( Event *ev ); + void EndTagBeamEmitter( void ); + void EmitterOn( Event *ev ); + void EmitterOff( Event *ev ); + void RainTouch( Event *ev ); + void Sound( Event *ev ); + void StopSound( Event *ev ); + void LoopSound( Event *ev ); + void Cache( Event *ev ); + void AliasCache( Event *ev ); + void Alias( Event *ev ); + void Client( Event *ev ); + void TagDynamicLight( Event *ev ); + void OriginDynamicLight( Event *ev ); + void DynamicLight( Event *ev ); + void GetOrientation( str tagname, spawnthing_t *sp ); + void AnimateTempModel( ctempmodel_t *ent, Vector origin, refEntity_t *newEnt ); + void OtherTempModelEffects( ctempmodel_t *p, Vector origin, refEntity_t *newEnt ); + void Swipe( Event *ev ); + void SwipeOn ( Event *ev ); + void SwipeOff ( Event *ev ); + void AnimateOnce( Event *ev ); + void SetAnim( Event *ev ); + void BeginTagTraceImpactMark( Event *ev ); + void EndTagTraceImpactMark( void ); + void BeginTagTraceImpactSpawn( Event *ev ); + void EndTagTraceImpactSpawn( void ); + void SetDecalRadius( Event *ev ); + void SetDecalOrientation( Event *ev ); + void TagList( Event *ev ); + void TagTraceImpactSound( Event *ev ); + void SetParallel( Event *ev ); + void Footstep( Event *ev ); + void SetDetail( Event *ev ); + + // Beam stuff + void SetSubdivisions( Event *ev ); + void SetMinOffset( Event *ev ); + void SetMaxOffset( Event *ev ); + void SetShader( Event *ev ); + void SetLength( Event *ev ); + void SetBeamDelay( Event *ev ); + void SetBeamToggleDelay( Event *ev ); + void SetBeamPersist( Event *ev ); + void SetBeamOffsetEndpoints( Event *ev ); + void SetBeamSphere( Event *ev ); + void SetSpread( Event *ev ); + void SetUseLastTraceEnd( Event *ev ); + void SetEndAlpha( Event *ev ); + + void RandomChance( Event *ev ); + void CommandDelay( Event *ev ); + public: + CLASS_PROTOTYPE( ClientGameCommandManager ); + + ClientGameCommandManager(); + void AddTempModels( void ); + void UpdateEmitter( int tikihandle, vec3_t axis[3], int entity_number, int parent_number, Vector entity_origin ); + void UpdateBeam( int tikihandle, int entity_number, spawnthing_t *beamthing ); + void PlaySound( str sound_name, vec3_t *origin=NULL, int channel = CHAN_AUTO, float volume = -1, float min_distance = -1 ); + + spawnthing_t *InitializeSpawnthing( spawnthing_t *ep ); + void SpawnTempModel( int count, class spawnthing_t *sp ); + void FreeAllTempModels( void ); + void RestartAllEmitters( int timedelta ); + void FreeAllEmitters( void ); + + void InitializeTempModels( void ); + void InitializeEmitters( void ); + void RemoveClientEntity( int number, int tikihandle, centity_t *cent, ctempmodel_t *p=NULL ); + void TestEmitter( void ); + void UpdateTestEmitter( void ); + void SetTestEmitterValues( void ); + void DumpEmitter( void ); + void ClearSwipes( void ); + void ResetTempModels( void ); + inline void SetSpawnthing( spawnthing_t *st ){ m_spawnthing = st; }; + spawnthing_t *CreateNewEmitter( str emittername ); + spawnthing_t *CreateNewEmitter( void ); + spawnthing_t *GetEmitterByName( str emittername ); + void CGEvent( centity_t *cent ); + }; + +class EmitterLoader : public Listener + { + private: + bool emitterActive; + + public: + CLASS_PROTOTYPE ( EmitterLoader ); + + EmitterLoader(); + bool Load( Script & ); + void ProcessEmitter( Script & ); + void Emitter( Event *ev ); + }; + +extern ClientGameCommandManager commandManager; + +#endif // __CG_COMMANDS_H__ + diff --git a/source/source/cgame/cg_consolecmds.c b/source/source/cgame/cg_consolecmds.c new file mode 100644 index 0000000..a04893c --- /dev/null +++ b/source/source/cgame/cg_consolecmds.c @@ -0,0 +1,314 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/cgame/cg_consolecmds.c $ +// $Revision:: 9 $ +// $Author:: Markd $ +// $Date:: 7/22/00 5:50p $ +// +// Copyright (C) 1998 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/cgame/cg_consolecmds.c $ +// +// 9 7/22/00 5:50p Markd +// added flushtikis support +// +// 8 4/26/00 9:05p Markd +// Added client and cgame class commands +// +// 7 10/18/99 1:59p Aldie +// Lots of fixes for beams and stuff +// +// 6 10/13/99 3:26p Aldie +// Various fixes for particles, beams and lensflares +// +// 5 10/06/99 3:23p Steven +// Added a dumpevents command. +// +// 4 10/05/99 6:01p Aldie +// Added headers +// +// DESCRIPTION: +// text commands typed in at the local console, or executed by a key binding + +#include "cg_local.h" + +void CG_TargetCommand_f( void ); + +/* +================= +CG_SizeUp_f + +Keybinding command +================= +*/ +static void CG_SizeUp_f (void) { + cgi.Cvar_Set("viewsize", va("%i",(int)(cg_viewsize->integer+10))); +} + + +/* +================= +CG_SizeDown_f + +Keybinding command +================= +*/ +static void CG_SizeDown_f (void) { + cgi.Cvar_Set("viewsize", va("%i",(int)(cg_viewsize->integer-10))); +} + + +/* +============= +CG_Viewpos_f + +Debugging command to print the current position +============= +*/ +static void CG_Viewpos_f (void) { + cgi.Printf("(%i %i %i) : %i\n", (int)cg.refdef.vieworg[0], + (int)cg.refdef.vieworg[1], (int)cg.refdef.vieworg[2], + (int)cg.refdefViewAngles[YAW]); +} + +#if 0 +static void CG_ScoresDown_f( void ) { + // don't constantly send requests, or we would overflow + if ( cg.showScores && cg.scoresRequestTime + 2000 > cg.time ) { + return; + } + cg.scoresRequestTime = cg.time; + cgi.SendClientCommand( "score" ); + + if ( !cg.showScores ) { + // don't display anything until first score returns + cg.showScores = qtrue; + cg.numScores = 0; + } +} + +static void CG_ScoresUp_f( void ) { + cg.showScores = qfalse; + cg.scoreFadeTime = cg.time; +} + +static void CG_InfoDown_f( void ) { + cg.showInformation = qtrue; +} + +static void CG_InfoUp_f( void ) { + cg.showInformation = qfalse; +} + + +/* +============================================================================= + + MODEL TESTING + +The viewthing and gun positioning tools from Q2 have been integrated and +enhanced into a single model testing facility. + +Model viewing can begin with either "testmodel " or "testgun ". + +The names must be the full pathname after the basedir, like +"models/weapons/v_launch/tris.md3" or "players/male/tris.md3" + +Testmodel will create a fake entity 100 units in front of the current view +position, directly facing the viewer. It will remain immobile, so you can +move around it to view it from different angles. + +Testgun will cause the model to follow the player around and supress the real +view weapon model. The default frame 0 of most guns is completely off screen, +so you will probably have to cycle a couple frames to see it. + +"nextframe", "prevframe", "nextskin", and "prevskin" commands will change the +frame or skin of the testmodel. These are bound to F5, F6, F7, and F8 in +q3default.cfg. + +Note that none of the model testing features update while the game is paused, so +it may be convenient to test with deathmatch set to 1 so that bringing down the +console doesn't pause the game. + +============================================================================= +*/ + +/* +================= +CG_TestModel_f + +Creates an entity in front of the current position, which +can then be moved around +================= +*/ +void CG_TestModel_f (void) { + vec3_t angles; + + memset( &cg.testModelEntity, 0, sizeof(cg.testModelEntity) ); + if ( cgi.Argc() < 2 ) { + return; + } + + Q_strncpyz (cg.testModelName, cgi.Argv( 1 ), MAX_QPATH ); + cg.testModelEntity.hModel = cgi.R_RegisterModel( cg.testModelName ); + + if ( cgi.Argc() == 3 ) { + cg.testModelEntity.backlerp = atof( cgi.Argv( 2 ) ); + cg.testModelEntity.frame = 1; + cg.testModelEntity.oldframe = 0; + } + if (! cg.testModelEntity.hModel ) { + cgi.Printf( "Can't register model\n" ); + return; + } + + VectorMA( cg.refdef.vieworg, 100, cg.refdef.viewaxis[0], cg.testModelEntity.origin ); + + angles[PITCH] = 0; + angles[YAW] = 180 + cg.refdefViewAngles[1]; + angles[ROLL] = 0; + + AnglesToAxis( angles, cg.testModelEntity.axis ); + cg.testGun = qfalse; +} + +void CG_TestModelNextFrame_f (void) { + cg.testModelEntity.frame++; + cgi.Printf( "frame %i\n", cg.testModelEntity.frame ); +} + +void CG_TestModelPrevFrame_f (void) { + cg.testModelEntity.frame--; + cgi.Printf( "frame %i\n", cg.testModelEntity.frame ); +} + +void CG_TestModelNextSkin_f (void) { + cg.testModelEntity.skinNum++; + cgi.Printf( "skin %i\n", cg.testModelEntity.skinNum ); +} + +void CG_TestModelPrevSkin_f (void) { + cg.testModelEntity.skinNum--; + if ( cg.testModelEntity.skinNum < 0 ) { + cg.testModelEntity.skinNum = 0; + } + cgi.Printf( "skin %i\n", cg.testModelEntity.skinNum ); +} + +void CG_AddTestModel (void) { + // re-register the model, because the level may have changed + cg.testModelEntity.hModel = cgi.R_RegisterModel( cg.testModelName ); + if (! cg.testModelEntity.hModel ) { + cgi.Printf ("Can't register model\n"); + return; + } + cgi.R_AddRefEntityToScene( &cg.testModelEntity ); +} + + +#endif + +/* +================= +CG_FlushModels_f +================= +*/ +void CG_FlushModels_f( void ) + { + int i; + + // clear any tiki handles to bad values + memset( &cgs.model_tiki, -1, sizeof( cgs.model_tiki ) ); + + // reset all emitters + CG_FlushCommandManager(); + + // flush all the tikis + cgi.FlushAll(); + + // go through all the models and process them + for ( i = CS_MODELS ; i < MAX_MODELS ; i++ ) + { + CG_ProcessConfigString( i ); + } + } + + + +typedef struct { + char *cmd; + void (*function)(void); +} consoleCommand_t; + +static consoleCommand_t commands[] = { +// { "testmodel", CG_TestModel_f }, +// { "nextframe", CG_TestModelNextFrame_f }, +// { "prevframe", CG_TestModelPrevFrame_f }, +// { "nextskin", CG_TestModelNextSkin_f }, +// { "prevskin", CG_TestModelPrevSkin_f }, + { "viewpos", CG_Viewpos_f }, +// { "+scores", CG_ScoresDown_f }, +// { "-scores", CG_ScoresUp_f }, +// { "+info", CG_InfoDown_f }, +// { "-info", CG_InfoUp_f }, + { "sizeup", CG_SizeUp_f }, + { "sizedown", CG_SizeDown_f }, + { "cg_eventlist", CG_EventList_f }, + { "cg_eventhelp", CG_EventHelp_f }, + { "cg_dumpevents", CG_DumpEventHelp_f }, + { "cg_pendingevents", CG_PendingEvents_f }, + { "cg_classlist", CG_ClassList_f }, + { "cg_classtree", CG_ClassTree_f }, + { "cg_classevents", CG_ClassEvents_f }, + { "cg_dumpclassevents", CG_DumpClassEvents_f }, + { "cg_dumpallclasses", CG_DumpAllClasses_f }, + { "testemitter", CG_TestEmitter_f }, + { "dumpemitter", CG_DumpEmitter_f }, + { "flushtikis", CG_FlushModels_f } +}; + + +/* +================= +CG_ConsoleCommand + +The string has been tokenized and can be retrieved with +Cmd_Argc() / Cmd_Argv() +================= +*/ +qboolean CG_ConsoleCommand( void ) { + const char *cmd; + int i; + + cmd = cgi.Argv(0); + + for ( i = 0 ; i < sizeof( commands ) / sizeof( commands[0] ) ; i++ ) { + if ( !Q_stricmp( cmd, commands[i].cmd ) ) { + commands[i].function(); + return qtrue; + } + } + + return qfalse; +} + + +/* +================= +CG_InitConsoleCommands + +Let the client system know about all of our commands +so it can perform tab completion +================= +*/ +void CG_InitConsoleCommands( void ) { + int i; + + for ( i = 0 ; i < sizeof( commands ) / sizeof( commands[0] ) ; i++ ) { + cgi.AddCommand( commands[i].cmd ); + } +} diff --git a/source/source/cgame/cg_container.h b/source/source/cgame/cg_container.h new file mode 100644 index 0000000..6911d8a --- /dev/null +++ b/source/source/cgame/cg_container.h @@ -0,0 +1,381 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/cgame/cg_container.h $ +// $Revision:: 2 $ +// $Author:: Aldie $ +// $Date:: 9/10/99 5:24p $ +// +// Copyright (C) 1997 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source is may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/cgame/cg_container.h $ +// +// 2 9/10/99 5:24p Aldie +// Merge code +// +// 1 9/10/99 10:48a Jimdose +// +// 2 9/09/99 3:30p Aldie +// Merge +// +// 1 9/08/99 3:35p Aldie +// +// DESCRIPTION: +// Base class for a dynamic array. Allows adding, removing, index of, +// and finding of entries with specified value. Originally created for +// cataloging entities, but pointers to objects that may be removed at +// any time are bad to keep around, so only entity numbers should be +// used in the future. +// + +#ifndef __CONTAINER_H__ +#define __CONTAINER_H__ + +#include + +template< class Type > +class Container + { + private: + Type *objlist; + int numobjects; + int maxobjects; + + public: + Container(); + ~Container(); + void FreeObjectList( void ); + void ClearObjectList( void ); + int NumObjects( void ); + void Resize( int maxelements ); + void SetObjectAt( int index, Type& obj ); + int AddObject( Type& obj ); + int AddUniqueObject( Type& obj ); + void AddObjectAt( int index, Type& obj ); + int IndexOfObject( Type& obj ); + qboolean ObjectInList( Type& obj ); + Type& ObjectAt( int index ); + Type *AddressOfObjectAt( int index ); + void RemoveObjectAt( int index ); + void RemoveObject( Type& obj ); + void Sort( int ( __cdecl *compare )( const void *elem1, const void *elem2 ) ); + }; + +template< class Type > +Container::Container() + { + objlist = NULL; + FreeObjectList(); + } + +template< class Type > +Container::~Container() + { + FreeObjectList(); + } + +template< class Type > +void Container::FreeObjectList + ( + void + ) + + { + if ( objlist ) + { + delete[] objlist; + } + objlist = NULL; + numobjects = 0; + maxobjects = 0; + } + +template< class Type > +void Container::ClearObjectList + ( + void + ) + + { + // only delete the list if we have objects in it + if ( objlist && numobjects ) + { + delete[] objlist; + objlist = new Type[ maxobjects ]; + numobjects = 0; + } + } + +template< class Type > +int Container::NumObjects + ( + void + ) + + { + return numobjects; + } + +template< class Type > +void Container::Resize + ( + int maxelements + ) + + { + Type *temp; + int i; + + assert( maxelements >= 0 ); + + if ( maxelements <= 0 ) + { + FreeObjectList(); + return; + } + + if ( !objlist ) + { + maxobjects = maxelements; + objlist = new Type[ maxobjects ]; + } + else + { + temp = objlist; + maxobjects = maxelements; + if ( maxobjects < numobjects ) + { + maxobjects = numobjects; + } + + objlist = new Type[ maxobjects ]; + for( i = 0; i < numobjects; i++ ) + { + objlist[ i ] = temp[ i ]; + } + delete[] temp; + } + } + +template< class Type > +void Container::SetObjectAt + ( + int index, + Type& obj + ) + + { + if ( ( index <= 0 ) || ( index > numobjects ) ) + { + gi.Error( ERR_DROP, "Container::SetObjectAt : index out of range" ); + } + + objlist[ index - 1 ] = obj; + } + +template< class Type > +int Container::AddObject + ( + Type& obj + ) + + { + if ( !objlist ) + { + Resize( 10 ); + } + + if ( numobjects == maxobjects ) + { + Resize( maxobjects * 2 ); + } + + objlist[ numobjects ] = obj; + numobjects++; + + return numobjects; + } + +template< class Type > +int Container::AddUniqueObject + ( + Type& obj + ) + + { + int index; + + index = IndexOfObject( obj ); + if ( !index ) + index = AddObject( obj ); + return index; + } + +template< class Type > +void Container::AddObjectAt + ( + int index, + Type& obj + ) + + { + // + // this should only be used when reconstructing a list that has to be identical to the original + // + if ( index > maxobjects ) + { + Resize( index ); + } + if ( index > numobjects ) + { + numobjects = index; + } + SetObjectAt( index, obj ); + } + +template< class Type > +int Container::IndexOfObject + ( + Type& obj + ) + + { + int i; + + for( i = 0; i < numobjects; i++ ) + { + if ( objlist[ i ] == obj ) + { + return i + 1; + } + } + + return 0; + } + +template< class Type > +qboolean Container::ObjectInList + ( + Type& obj + ) + + { + if ( !IndexOfObject( obj ) ) + { + return false; + } + + return true; + } + +template< class Type > +Type& Container::ObjectAt + ( + int index + ) + + { + if ( ( index <= 0 ) || ( index > numobjects ) ) + { + cgi.Error( ERR_DROP, "Container::ObjectAt : index out of range" ); + } + + return objlist[ index - 1 ]; + } + +template< class Type > +Type * Container::AddressOfObjectAt + ( + int index + ) + + { + // + // this should only be used when reconstructing a list that has to be identical to the original + // + if ( index > maxobjects ) + { + cgi.Error( ERR_DROP, "Container::AddressOfObjectAt : index is greater than maxobjects" ); + } + if ( index > numobjects ) + { + numobjects = index; + } + return &objlist[ index - 1 ]; + } + +template< class Type > +void Container::RemoveObjectAt + ( + int index + ) + + { + int i; + + if ( !objlist ) + { + cgi.Printf( "Container::RemoveObjectAt : Empty list\n" ); + return; + } + + if ( ( index <= 0 ) || ( index > numobjects ) ) + { + cgi.Error( ERR_DROP, "Container::RemoveObjectAt : index out of range" ); + return; + } + + i = index - 1; + numobjects--; + for( i = index - 1; i < numobjects; i++ ) + { + objlist[ i ] = objlist[ i + 1 ]; + } + } + +template< class Type > +void Container::RemoveObject + ( + Type& obj + ) + + { + int index; + + index = IndexOfObject( obj ); + if ( !index ) + { + gi.DPrintf( "Container::RemoveObject : Object not in list\n" ); + return; + } + + RemoveObjectAt( index ); + } + +template< class Type > +void Container::Sort + ( + int ( __cdecl *compare )( const void *elem1, const void *elem2 ) + ) + + { + if ( !objlist ) + { + gi.DPrintf( "Container::RemoveObjectAt : Empty list\n" ); + return; + } + + qsort( ( void * )objlist, ( size_t )numobjects, sizeof( Type ), compare ); + } + +// +// Exported templated classes must be explicitly instantiated +// +#ifdef EXPORT_TEMPLATE +template class Container; +#endif + +#endif /* container.h */ \ No newline at end of file diff --git a/source/source/cgame/cg_drawtools.cpp b/source/source/cgame/cg_drawtools.cpp new file mode 100644 index 0000000..f2f50b4 --- /dev/null +++ b/source/source/cgame/cg_drawtools.cpp @@ -0,0 +1,363 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/cgame/cg_drawtools.cpp $ +// $Revision:: 8 $ +// $Author:: Markd $ +// $Date:: 7/27/00 11:35p $ +// +// Copyright (C) 1998 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/cgame/cg_drawtools.cpp $ +// +// 8 7/27/00 11:35p Markd +// got rid of DrawDisconnect +// +// 7 7/10/00 11:54p Markd +// added exit level code +// +// 6 6/14/00 12:14p Markd +// more intel compiler bug fixes +// +// 5 6/09/00 10:27a Markd +// got lagometer and CG_2D operations functioning +// +// 4 12/11/99 5:51p Markd +// First wave of bug fixes after q3a gold merge +// +// 3 10/05/99 6:01p Aldie +// Added headers +// +// DESCRIPTION: +// Some tools used to drawing 2d stuff + +#include "cg_local.h" + +/* +================ +CG_AdjustFrom640 + +Adjusted for resolution and screen aspect ratio +================ +*/ +void CG_AdjustFrom640( float *x, float *y, float *w, float *h ) { +#if 0 + // adjust for wide screens + if ( cgs.glconfig.vidWidth * 480 > cgs.glconfig.vidHeight * 640 ) { + *x += 0.5 * ( cgs.glconfig.vidWidth - ( cgs.glconfig.vidHeight * 640 / 480 ) ); + } +#endif + // scale for screen sizes + *x *= cgs.screenXScale; + *y *= cgs.screenYScale; + *w *= cgs.screenXScale; + *h *= cgs.screenYScale; +} + +/* +============= +CG_TileClearBox + +This repeats a 64*64 tile graphic to fill the screen around a sized down +refresh window. +============= +*/ +void CG_TileClearBox( int x, int y, int w, int h, qhandle_t hShader ) { + float s1, t1, s2, t2; + + s1 = x/64.0; + t1 = y/64.0; + s2 = (x+w)/64.0; + t2 = (y+h)/64.0; + cgi.R_DrawStretchPic( x, y, w, h, s1, t1, s2, t2, hShader ); +} + + + +/* +============== +CG_TileClear + +Clear around a sized down screen +============== +*/ +void CG_TileClear( void ) { + int top, bottom, left, right; + int w, h; + + w = cgs.glconfig.vidWidth; + h = cgs.glconfig.vidHeight; + + if ( cg.refdef.x == 0 && cg.refdef.y == 0 && + cg.refdef.width == w && cg.refdef.height == h ) { + return; // full screen rendering + } + + top = cg.refdef.y; + bottom = top + cg.refdef.height-1; + left = cg.refdef.x; + right = left + cg.refdef.width-1; + + // clear above view screen + CG_TileClearBox( 0, 0, w, top, cgs.media.backTileShader ); + + // clear below view screen + CG_TileClearBox( 0, bottom, w, h - bottom, cgs.media.backTileShader ); + + // clear left of view screen + CG_TileClearBox( 0, top, left, bottom - top + 1, cgs.media.backTileShader ); + + // clear right of view screen + CG_TileClearBox( right, top, w - right, bottom - top + 1, cgs.media.backTileShader ); +} + + +/* +=============================================================================== + +LAGOMETER + +=============================================================================== +*/ + +#define LAG_SAMPLES 128 + + +typedef struct { + int frameSamples[LAG_SAMPLES]; + int frameCount; + int snapshotFlags[LAG_SAMPLES]; + int snapshotSamples[LAG_SAMPLES]; + int snapshotCount; +} lagometer_t; + +lagometer_t lagometer; + +/* +============== +CG_AddLagometerFrameInfo + +Adds the current interpolate / extrapolate bar for this frame +============== +*/ +void CG_AddLagometerFrameInfo( void ) { + int offset; + + offset = cg.time - cg.latestSnapshotTime; + lagometer.frameSamples[ lagometer.frameCount & ( LAG_SAMPLES - 1) ] = offset; + lagometer.frameCount++; +} + +/* +============== +CG_AddLagometerSnapshotInfo + +Each time a snapshot is received, log its ping time and +the number of snapshots that were dropped before it. + +Pass NULL for a dropped packet. +============== +*/ +void CG_AddLagometerSnapshotInfo( snapshot_t *snap ) { + // dropped packet + if ( !snap ) { + lagometer.snapshotSamples[ lagometer.snapshotCount & ( LAG_SAMPLES - 1) ] = -1; + lagometer.snapshotCount++; + return; + } + + // add this snapshot's info + lagometer.snapshotSamples[ lagometer.snapshotCount & ( LAG_SAMPLES - 1) ] = snap->ping; + lagometer.snapshotFlags[ lagometer.snapshotCount & ( LAG_SAMPLES - 1) ] = snap->snapFlags; + lagometer.snapshotCount++; +} + +/* +============== +CG_DrawDisconnect +============== +*/ +void CG_DrawDisconnect( void ) { + float x, y; + int cmdNum; + usercmd_t cmd; + + // draw the phone jack if we are completely past our buffers + cmdNum = cgi.GetCurrentCmdNumber() - CMD_BACKUP + 1; + cgi.GetUserCmd( cmdNum, &cmd ); + if ( !cg.snap || cmd.serverTime <= cg.snap->ps.commandTime + || cmd.serverTime > cg.time ) { // special check for map_restart + return; + } + + // blink it + if ( ( cg.time >> 9 ) & 1 ) { + return; + } + + x = 640 - 48; + y = 480 - 48; + + cgi.R_DrawStretchPic( x, y, 48, 48, 0, 0, 1, 1, cgi.R_RegisterShader("gfx/2d/net.tga" ) ); +} + + +#define MAX_LAGOMETER_PING 900 +#define MAX_LAGOMETER_RANGE 300 + +/* +============== +CG_DrawLagometer +============== +*/ +void CG_DrawLagometer( void ) { + int a, x, y, i; + float v; + float ax, ay, aw, ah, mid, range; + int color; + float vscale; + + if ( !cg_lagometer->integer ) { + // don't draw the disconnect icon in single player + //CG_DrawDisconnect(); + return; + } + + // + // draw the graph + // + x = 640 - 48; + y = 480 - 48; + + cgi.R_SetColor( NULL ); + cgi.R_DrawStretchPic( x, y, 48, 48, 0, 0, 1, 1, cgs.media.lagometerShader ); + + ax = x; + ay = y; + aw = 48; + ah = 48; + CG_AdjustFrom640( &ax, &ay, &aw, &ah ); + + color = -1; + range = ah / 3; + mid = ay + range; + + vscale = range / MAX_LAGOMETER_RANGE; + + // draw the frame interpoalte / extrapolate graph + for ( a = 0 ; a < aw ; a++ ) { + i = ( lagometer.frameCount - 1 - a ) & (LAG_SAMPLES - 1); + v = lagometer.frameSamples[i]; + v *= vscale; + if ( v > 0 ) { + if ( color != 1 ) { + color = 1; + cgi.R_SetColor( g_color_table[ColorIndex(COLOR_YELLOW)] ); + } + if ( v > range ) { + v = range; + } + cgi.R_DrawBox( ax + aw - a, mid - v, 1, v ); + } else if ( v < 0 ) { + if ( color != 2 ) { + color = 2; + cgi.R_SetColor( g_color_table[ColorIndex(COLOR_BLUE)] ); + } + v = -v; + if ( v > range ) { + v = range; + } + cgi.R_DrawBox( ax + aw - a, mid, 1, v ); + } + } + + // draw the snapshot latency / drop graph + range = ah / 2; + vscale = range / MAX_LAGOMETER_PING; + + for ( a = 0 ; a < aw ; a++ ) { + i = ( lagometer.snapshotCount - 1 - a ) & (LAG_SAMPLES - 1); + v = lagometer.snapshotSamples[i]; + if ( v > 0 ) { + if ( lagometer.snapshotFlags[i] & SNAPFLAG_RATE_DELAYED ) { + if ( color != 5 ) { + color = 5; // YELLOW for rate delay + cgi.R_SetColor( g_color_table[ColorIndex(COLOR_YELLOW)] ); + } + } else { + if ( color != 3 ) { + color = 3; + cgi.R_SetColor( g_color_table[ColorIndex(COLOR_GREEN)] ); + } + } + v = v * vscale; + if ( v > range ) { + v = range; + } + cgi.R_DrawBox( ax + aw - a, ay + ah - v, 1, v ); + } else if ( v < 0 ) { + if ( color != 4 ) { + color = 4; // RED for dropped snapshots + cgi.R_SetColor( g_color_table[ColorIndex(COLOR_RED)] ); + } + cgi.R_DrawBox( ax + aw - a, ay + ah - range, 1, range ); + } + } + + cgi.R_SetColor( NULL ); + + CG_DrawDisconnect(); +} + +/* +============== +CG_DrawIcons +============== +*/ +void CG_DrawIcons( void ) + { + qhandle_t handle; + float x,y,w,h; + + if ( paused->integer ) + { + handle = cgs.media.pausedShader; + } + else + { + if ( cg.predicted_player_state.pm_flags & PMF_LEVELEXIT ) + { + // blink it + if ( ( cg.time >> 9 ) & 1 ) + { + return; + } + handle = cgs.media.levelExitShader; + } + else + { + return; + } + } + w = cgi.R_GetShaderWidth( handle ); + h = cgi.R_GetShaderHeight( handle ); + x = w / 4; + y = cgs.glconfig.vidHeight - ( 1.25f * h ); + + cgi.R_SetColor( colorWhite ); + cgi.R_DrawStretchPic( x, y, w, h, 0, 0, 1, 1, handle ); + } + +/* +============== +CG_Draw2D +============== +*/ +void CG_Draw2D( void ) + { + CG_DrawIcons(); + CG_DrawLagometer(); + } diff --git a/source/source/cgame/cg_ents.c b/source/source/cgame/cg_ents.c new file mode 100644 index 0000000..2d8ac79 --- /dev/null +++ b/source/source/cgame/cg_ents.c @@ -0,0 +1,925 @@ +// cg_ents.c -- present snapshot entities, happens every single frame + +#include "cg_local.h" + +/* +========================================================================== + +FUNCTIONS CALLED EACH FRAME + +========================================================================== +*/ + +/* +====================== +CG_SetEntitySoundPosition +====================== +*/ +void CG_SetEntitySoundPosition( centity_t *cent ) + { + vec3_t origin; + + if ( cent->currentState.solid == SOLID_BMODEL ) + { + float *v; + vec3_t vel; + + v = cgs.inlineModelMidpoints[ cent->currentState.modelindex ]; + VectorAdd( cent->lerpOrigin, v, origin ); + + vel[0] = 0.0; + vel[1] = 0.0; + vel[2] = 0.0; + + cgi.S_UpdateEntity( cent->currentState.number, origin, vel, qfalse ); + } + else + { + if ( cent && cg.snap && cent->currentState.parent == cg.snap->ps.clientNum ) + { + vec3_t origin; + vec3_t velocity; + + origin[0] = 0; + origin[1] = 0; + origin[2] = 0; + + velocity[0] = 0; + velocity[1] = 0; + velocity[2] = 0; + + cgi.S_UpdateEntity( cent->currentState.number, origin, velocity, qtrue ); + } + else + { + CG_GetOrigin( cent, origin ); + cgi.S_UpdateEntity( cent->currentState.number, origin, cent->currentState.pos.trDelta, qfalse ); + } + } + } + +/* +================== +CG_EntityEffects + +Add continuous entity effects, like local entity emission and lighting +================== +*/ +void CG_EntityEffects( centity_t *cent ) + { + // initialize with the client colors + cent->color[ 0 ] = cent->client_color[ 0 ]; + cent->color[ 1 ] = cent->client_color[ 1 ]; + cent->color[ 2 ] = cent->client_color[ 2 ]; + cent->color[ 3 ] = cent->client_color[ 3 ]; + + if ( cent->currentState.constantLight != 0xffffff ) + { + int style; + unsigned cl; + float i, r, g, b; + + cl = cent->currentState.constantLight; + style = ( cl & 255 ); + r = ( float )style / 255.0f; + g = ( float )( ( cl >> 8 ) & 255 ) / 255.0f; + b = ( float )( ( cl >> 16 ) & 255 ) / 255.0f; + i = ( ( cl >> 24 ) & 255 ) * CONSTANTLIGHT_RADIUS_SCALE; + if ( cent->currentState.renderfx & RF_LIGHTSTYLE_DLIGHT ) + { + float color[ 4 ]; + + CG_LightStyleColor( style, cg.time, color, qfalse ); + r = color[ 0 ]; + g = color[ 1 ]; + b = color[ 2 ]; + i *= color[ 3 ]; + } + if ( i ) + { + int flags; + + flags = 0; + if ( cent->currentState.renderfx & RF_LENSFLARE ) + { + flags |= lensflare; + } + else if ( cent->currentState.renderfx & RF_VIEWLENSFLARE ) + { + flags |= viewlensflare; + } + if ( cent->currentState.renderfx & RF_ADDITIVE_DLIGHT ) + { + flags |= additive; + } + cgi.R_AddLightToScene( cent->lerpOrigin, i, r, g, b, flags ); + } + if ( r < cent->color[ 0 ] ) + cent->color[ 0 ] = r; + if ( g < cent->color[ 1 ] ) + cent->color[ 1 ] = g; + if ( b < cent->color[ 2 ] ) + cent->color[ 2 ] = b; + } + } + +/* +================== +CG_General +================== +*/ +void CG_General( centity_t *cent ) { + refEntity_t ent; + entityState_t *s1; + int i; + int tikihandle; + + s1 = ¢->currentState; + + // add loop sound + if ( s1->loopSound ) + { + cgi.S_AddLoopingSound( cent->lerpOrigin, vec3_origin, cgs.sound_precache[s1->loopSound], s1->loopSoundVolume, s1->loopSoundMinDist ); + } + if ( cent->tikiLoopSound ) + cgi.S_AddLoopingSound( cent->lerpOrigin, vec3_origin, cent->tikiLoopSound, cent->tikiLoopSoundVolume, cent->tikiLoopSoundMinDist ); + + // if set to invisible, skip + if (!s1->modelindex) { + return; + } + + memset (&ent, 0, sizeof(ent)); + + // set frame + + ent.frame = s1->frame; + ent.oldframe = ent.frame; + ent.backlerp = 0; + ent.uselegs = qtrue; + + VectorCopy( cent->lerpOrigin, ent.origin); + VectorCopy( cent->lerpOrigin, ent.oldorigin); + + // set skin + ent.skinNum = s1->skinNum; + ent.customSkin = 0; + + ent.hModel = cgs.model_draw[s1->modelindex]; + + // set surfaces + memcpy( ent.surfaces, s1->surfaces, MAX_MODEL_SURFACES ); + + // Modulation based off the color + for( i=0; i<3; i++ ) + ent.shaderRGBA[ i ] = cent->color[ i ] * 255; + + // take the alpha from the entity if less than 1, else grab it from the client commands version + if ( s1->alpha < 1 ) + { + ent.shaderRGBA[ 3 ] = s1->alpha * 255; + } + else + { + ent.shaderRGBA[ 3 ] = cent->color[ 3 ] * 255; + } + + // convert angles to axis + AnglesToAxis( cent->lerpAngles, ent.axis ); + + // Interpolated state variables + if ( cent->interpolate ) + { + ent.scale = s1->scale + cg.frameInterpolation * ( cent->nextState.scale - cent->currentState.scale ); + } + else + { + ent.scale = s1->scale; + } + // set the entity number + ent.entityNumber = s1->number; + + // copy shader specific data + ent.shader_data[ 0 ] = s1->tag_num; + ent.shader_data[ 1 ] = s1->skinNum; + ent.renderfx |= s1->renderfx; + + if ( ent.renderfx & RF_SKYORIGIN ) + { + memcpy( cg.sky_axis, ent.axis, sizeof( cg.sky_axis ) ); + VectorCopy( ent.origin, cg.sky_origin ); + } + + tikihandle = cgs.model_tiki[ s1->modelindex ]; + if ( tikihandle >= 0 ) + { + // update any emitter's... + CG_UpdateEntity( tikihandle, &ent, cent ); + } + + if ( s1->eFlags & ( EF_LEFT_TARGETED | EF_RIGHT_TARGETED ) ) + { + CG_EntityTargeted( tikihandle, cent, &ent ); + } + + // add to refresh list + if ( !( ent.renderfx & RF_DONTDRAW ) ) + cgi.R_AddRefEntityToScene (&ent); +} + +/* +================== +CG_Speaker + +Speaker entities can automatically play sounds +================== +*/ +void CG_Speaker( centity_t *cent ) + { + if ( ! cent->currentState.clientNum ) // FIXME: use something other than clientNum... + { + return; // not auto triggering + } + + if ( cg.time < cent->miscTime ) + { + return; + } + + // FIXME + //cgi.S_StartSound (NULL, cent->currentState.number, CHAN_ITEM, cgs.sound_precache[cent->currentState.eventParm] ); + + // ent->s.frame = ent->wait * 10; + // ent->s.clientNum = ent->random * 10; + cent->miscTime = cg.time + cent->currentState.frame * 100 + cent->currentState.clientNum * 100 * crandom(); + } + + +/* +=============== +CG_Mover +=============== +*/ +void CG_Mover( centity_t *cent ) { + refEntity_t ent; + entityState_t *s1; + + s1 = ¢->currentState; + + // create the render entity + memset (&ent, 0, sizeof(ent)); + VectorCopy( cent->lerpOrigin, ent.origin); + VectorCopy( cent->lerpOrigin, ent.oldorigin); + AnglesToAxis( cent->lerpAngles, ent.axis ); + + ent.renderfx &= ~RF_SHADOW; + + // flicker between two skins (FIXME?) + ent.skinNum = ( cg.time >> 6 ) & 1; + + // get the model, either as a bmodel or a modelindex + if ( s1->solid == SOLID_BMODEL ) { + ent.hModel = cgs.inlineDrawModel[s1->modelindex]; + } else { + ent.hModel = cgs.model_draw[s1->modelindex]; + } + + // add to refresh list + cgi.R_AddRefEntityToScene(&ent); +} + +/* +=============== +CG_Sprite +=============== +*/ +void CG_Sprite( centity_t *cent ) + { + refEntity_t ent; + entityState_t *s1; + int i; + + s1 = ¢->currentState; + + memset( &ent, 0, sizeof( refEntity_t ) ); + + if ( s1->parent != ENTITYNUM_NONE ) + { + refEntity_t *parent; + int tikihandle; + + parent = cgi.R_GetRenderEntity( s1->parent ); + + if ( !parent ) + { + cgi.DPrintf( "CG_Sprite: Could not find parent entity\n" ); + return; + } + + tikihandle = cgi.TIKI_GetHandle( parent->hModel ); + CG_AttachEntity( &ent, parent, tikihandle, s1->tag_num & TAG_MASK, s1->attach_use_angles, s1->attach_offset ); + } + else + { + VectorCopy( cent->lerpOrigin, ent.origin); + VectorCopy( cent->lerpOrigin, ent.oldorigin); + } + + ent.hModel = cgs.model_draw[s1->modelindex]; + + // Modulation based off the color + for( i=0; i<3; i++ ) + ent.shaderRGBA[ i ] = cent->color[ i ] * 255; + + // take the alpha from the entity if less than 1, else grab it from the client commands version + if ( s1->alpha < 1 ) + ent.shaderRGBA[ 3 ] = s1->alpha * 255; + else + ent.shaderRGBA[ 3 ] = cent->color[ 3 ] * 255; + + ent.renderfx |= s1->renderfx; + + // convert angles to axis + AnglesToAxis( cent->lerpAngles, ent.axis ); + + // Interpolated state variables + if ( cent->interpolate ) + { + ent.scale = s1->scale + cg.frameInterpolation * ( cent->nextState.scale - cent->currentState.scale ); + } + else + { + ent.scale = s1->scale; + } + + // add to refresh list + if ( !( cent->currentState.renderfx & RF_DONTDRAW ) ) + cgi.R_AddRefSpriteToScene( &ent ); + } + +/* +================== +CG_Item +================== +*/ +void CG_Item( centity_t *cent ) + { + entityState_t *es; + int thandle; + float radius, scale; + float frac; + vec3_t mins, maxs, mid, start, save; + polyVert_t verts[4]; + + es = ¢->currentState; + + // if set to invisible, skip + if ( !es->modelindex || ( es->parent != ENTITYNUM_NONE ) || ( es->renderfx & RF_DONTDRAW ) ) + { + return; + } + + // autorotate + VectorCopy( cg.autoAngles, cent->lerpAngles ); + + thandle = cgs.model_tiki[ es->modelindex ]; + if ( thandle == -1 ) + return; + + radius = cgi.R_ModelRadius( cgs.model_draw[ es->modelindex ] ) * 0.5f * es->scale; + cgi.R_ModelBounds( cgs.model_draw[ es->modelindex ], mins, maxs ); + VectorAdd( mins, maxs, mid ); + VectorScale( mid, 0.5f * es->scale, mid ); + + // offset the model from the ground + cent->lerpOrigin[ 2 ] += radius; + + // save off the center of the model for the rings + VectorCopy( cent->lerpOrigin, save ); + + // items bob up and down continuously + scale = 0.005 + es->number * 0.00001; + cent->lerpOrigin[2] += ( radius * 0.2f ) + cos( ( cg.time + 1000 ) * scale ) * ( radius * 0.2f ); + + // offset the origin to the centroid + cent->lerpOrigin[0] -= + mid[0] * cg.autoAxis[0][0] + + mid[1] * cg.autoAxis[1][0] + + mid[2] * cg.autoAxis[2][0]; + cent->lerpOrigin[1] -= + mid[0] * cg.autoAxis[0][1] + + mid[1] * cg.autoAxis[1][1] + + mid[2] * cg.autoAxis[2][1]; + + cent->lerpOrigin[2] -= + mid[0] * cg.autoAxis[0][2] + + mid[1] * cg.autoAxis[1][2] + + mid[2] * cg.autoAxis[2][2]; + + scale *= 0.5f; + + frac = cos( ( cg.time + 1000 ) * scale ) * radius; + VectorCopy( save, start ); + start[ 2 ] += frac; + frac = 1.5f * ( radius - fabs( frac * 0.5f ) ); + + // add the item rings + VectorCopy( start, verts[ 0 ].xyz ); + verts[ 0 ].xyz[ 0 ] -= frac; + verts[ 0 ].xyz[ 1 ] -= frac; + verts[ 0 ].st[0] = 0; + verts[ 0 ].st[1] = 0; + verts[ 0 ].modulate[0] = 255; + verts[ 0 ].modulate[1] = 255; + verts[ 0 ].modulate[2] = 255; + verts[ 0 ].modulate[3] = 255; + + VectorCopy( start, verts[ 1 ].xyz ); + verts[ 1 ].xyz[ 0 ] -= frac; + verts[ 1 ].xyz[ 1 ] += frac; + verts[ 1 ].st[0] = 0; + verts[ 1 ].st[1] = 1; + verts[ 1 ].modulate[0] = 255; + verts[ 1 ].modulate[1] = 255; + verts[ 1 ].modulate[2] = 255; + verts[ 1 ].modulate[3] = 255; + + VectorCopy( start, verts[ 2 ].xyz ); + verts[ 2 ].xyz[ 0 ] += frac; + verts[ 2 ].xyz[ 1 ] += frac; + verts[ 2 ].st[0] = 1; + verts[ 2 ].st[1] = 1; + verts[ 2 ].modulate[0] = 255; + verts[ 2 ].modulate[1] = 255; + verts[ 2 ].modulate[2] = 255; + verts[ 2 ].modulate[3] = 255; + + VectorCopy( start, verts[ 3 ].xyz ); + verts[ 3 ].xyz[ 0 ] += frac; + verts[ 3 ].xyz[ 1 ] -= frac; + verts[ 3 ].st[0] = 1; + verts[ 3 ].st[1] = 0; + verts[ 3 ].modulate[0] = 255; + verts[ 3 ].modulate[1] = 255; + verts[ 3 ].modulate[2] = 255; + verts[ 3 ].modulate[3] = 255; + + cgi.R_AddPolyToScene( cgs.media.itemRingShader, 4, verts, 0 ); + + frac = cos( ( cg.time + 1000 ) * scale + DEG2RAD( 180 ) ) * radius; + VectorCopy( save, start ); + start[ 2 ] += frac; + frac = 1.5f * ( radius - fabs( frac * 0.5f ) ); + + VectorCopy( start, verts[ 0 ].xyz ); + verts[ 0 ].xyz[ 0 ] -= frac; + verts[ 0 ].xyz[ 1 ] -= frac; + + VectorCopy( start, verts[ 1 ].xyz ); + verts[ 1 ].xyz[ 0 ] -= frac; + verts[ 1 ].xyz[ 1 ] += frac; + + VectorCopy( start, verts[ 2 ].xyz ); + verts[ 2 ].xyz[ 0 ] += frac; + verts[ 2 ].xyz[ 1 ] += frac; + + VectorCopy( start, verts[ 3 ].xyz ); + verts[ 3 ].xyz[ 0 ] += frac; + verts[ 3 ].xyz[ 1 ] -= frac; + + cgi.R_AddPolyToScene( cgs.media.itemRingShader, 4, verts, 0 ); + + } + + +/* +=============== +CG_Beam +=============== +*/ +void CG_Beam( centity_t *cent ) { + entityState_t *s1; + vec3_t vz={0,0,0},origin={0,0,0}; + byte modulate[4]; + int i; + + s1 = ¢->currentState; + + for ( i=0;i<4;i++ ) + modulate[i] = cent->color[i] * 255; + + if ( s1->torso_anim != ENTITYNUM_NONE ) + { + refEntity_t *parent; + parent = cgi.R_GetRenderEntity( s1->torso_anim ); + + if ( !parent ) + { + cgi.DPrintf( "CG_Beam: Could not find parent entity\n" ); + return; + } + + VectorAdd( s1->origin, parent->origin, origin ); + } + else + { + VectorCopy( s1->origin, origin ); + } + + CG_CreateBeam( origin, // start + vz, // dir ( auto calculated by using origin2-origin ) + s1->number, // owner number + cgs.model_draw[s1->modelindex], //hModel + s1->alpha, // alpha + s1->scale, // scale + s1->skinNum, // flags + 0, // length ( auto calculated ) + PKT_TO_BEAM_PARM( s1->surfaces[0] ) * 1000, // life + qfalse, // don't always create the beam, just update it + s1->origin2, // endpoint + s1->bone_angles[0][0], // min offset + s1->bone_angles[0][1], // max offset + PKT_TO_BEAM_PARM( s1->surfaces[3] ), // overlap + s1->surfaces[4], // subdivisions + PKT_TO_BEAM_PARM( s1->surfaces[5] ) * 1000, // delay + CG_ConfigString( CS_IMAGES + s1->tag_num ), // index for shader configstring + modulate, // modulate color + s1->surfaces[6], // num sphere beams + PKT_TO_BEAM_PARM( s1->surfaces[7] ), // sphere radius + PKT_TO_BEAM_PARM( s1->surfaces[8] ), // toggle delay + PKT_TO_BEAM_PARM( s1->surfaces[9] ), // end alpha + s1->renderfx, + "" + ); +} + + +void CG_Decal + ( + centity_t *cent + ) + + { + qhandle_t shader; + vec3_t dir; + entityState_t *s1; + + s1 = ¢->currentState; + + shader = cgi.R_RegisterShader( CG_ConfigString( CS_IMAGES + s1->tag_num ) ); + ByteToDir( s1->surfaces[0], dir ); + CG_ImpactMark( shader, + s1->origin, + dir, + s1->angles[2], + cent->color[0], + cent->color[1], + cent->color[2], + cent->color[3], + qtrue, + s1->scale, + qfalse, + -1, + qfalse); + } + +/* +=============== +CG_Portal +=============== +*/ +void CG_Portal( centity_t *cent ) + { + refEntity_t ent; + entityState_t *s1; + + s1 = ¢->currentState; + + // create the render entity + memset (&ent, 0, sizeof(ent)); + VectorCopy( cent->lerpOrigin, ent.origin ); + VectorCopy( s1->origin2, ent.oldorigin ); + AnglesToAxis( cent->currentState.angles, ent.axis ); + + // negating this tends to get the directions like they want + // we really should have a camera roll value + VectorSubtract( vec3_origin, ent.axis[1], ent.axis[1] ); + VectorSubtract( vec3_origin, ent.axis[2], ent.axis[2] ); + + ent.reType = RT_PORTALSURFACE; + ent.frame = s1->frame; // rotation speed + ent.skinNum = s1->clientNum/256.0 * 360; // roll offset + + // add to refresh list + cgi.R_AddRefEntityToScene(&ent); + } + + +/* +========================= +CG_AdjustPositionForMover +========================= +*/ +void CG_AdjustPositionForMover( const vec3_t in, int moverNum, int fromTime, int toTime, vec3_t out ) { + centity_t *cent; + vec3_t oldOrigin, origin, deltaOrigin; + vec3_t oldAngles, angles; + + if ( moverNum == ENTITYNUM_NONE ) { + VectorCopy( in, out ); + return; + } + + cent = &cg_entities[ moverNum ]; + + if ( cent->currentState.pos.trType == TR_LERP ) { + int i; + + if ( cent->interpolate ) + { + // we calculate lerpOrigin so we have always have the latest info. It is possible to call this before lerpOrigin + // is updated by AddEntities + for ( i=0; i<3; i++ ) + { + cent->lerpOrigin[i] = cent->currentState.origin[i] + + cg.frameInterpolation * ( cent->nextState.origin[i] - cent->currentState.origin[i] ); + } + } + for ( i=0; i<3; i++ ) + { + out[ i ] = in[ i ] + ( cent->lerpOrigin[i] - cent->currentState.origin[i] ); + } + return; + + } else if ( cent->currentState.eType != ET_MOVER ) { + VectorCopy( in, out ); + return; + } + + EvaluateTrajectory( ¢->currentState.pos, fromTime, oldOrigin ); + EvaluateTrajectory( ¢->currentState.apos, fromTime, oldAngles ); + + EvaluateTrajectory( ¢->currentState.pos, toTime, origin ); + EvaluateTrajectory( ¢->currentState.apos, toTime, angles ); + + VectorSubtract( origin, oldOrigin, deltaOrigin ); + + VectorAdd( in, deltaOrigin, out ); + + // FIXME: origin change when on a rotating object +} + + +/* +=============== +CG_CalcEntityLerpPositions + +=============== +*/ +void CG_CalcEntityLerpPositions( centity_t *cent ) { + int i; + float f; + + f = cg.frameInterpolation; + + if ( cg.snap->ps.pm_type < PM_DEAD ) + { + if ( cent->currentState.number == cg.snap->ps.clientNum ) + { + // if the player, take position from prediction + VectorCopy( cg.predicted_player_state.origin, cent->lerpOrigin ); + for ( i=0; i<3; i++ ) { + cent->lerpAngles[i] = LerpAngle( cent->currentState.angles[i], cent->nextState.angles[i], f ); + } + + return; + } + } + + if ( cent->currentState.pos.trType == TR_LERP ) { + float quat[ 4 ]; + float mat[ 3 ][ 3 ]; + + if ( !cent->interpolate ) { + VectorCopy( cent->currentState.angles, cent->lerpAngles ); + VectorCopy( cent->currentState.origin, cent->lerpOrigin ); + return; + } + + // it would be an internal error to find an entity that interpolates without + // a snapshot ahead of the current one + if ( cg.nextSnap == NULL ) { + cgi.Error( ERR_DROP, "CG_AddCEntity: cg.nextSnap == NULL" ); + } + + for ( i=0; i<3; i++ ) { + cent->lerpOrigin[i] = cent->currentState.origin[i] + + f * ( cent->nextState.origin[i] - cent->currentState.origin[i] ); + } + + if ( !memcmp( cent->currentState.angles, cent->nextState.angles, sizeof( vec3_t ) ) ) { + VectorCopy( cent->currentState.angles, cent->lerpAngles ); + } else { + // use spherical interpolation using quaternions so that bound objects + // rotate properly without gimble lock. + SlerpQuaternion( cent->currentState.quat, cent->nextState.quat, f, quat ); + QuatToMat( quat, mat ); + MatrixToEulerAngles( mat, cent->lerpAngles ); + } + } else if ( cent->interpolate && cent->currentState.pos.trType == TR_INTERPOLATE ) { + // if the entity has a valid next state, interpolate a value between the frames + // unless it is a mover with a known start and stop + vec3_t current, next; + + // it would be an internal error to find an entity that interpolates without + // a snapshot ahead of the current one + if ( cg.nextSnap == NULL ) { + cgi.Error( ERR_DROP, "CG_AddCEntity: cg.nextSnap == NULL" ); + } + + // this will linearize a sine or parabolic curve, but it is important + // to not extrapolate player positions if more recent data is available + EvaluateTrajectory( ¢->currentState.pos, cg.snap->serverTime, current ); + EvaluateTrajectory( ¢->nextState.pos, cg.nextSnap->serverTime, next ); + + cent->lerpOrigin[0] = current[0] + f * ( next[0] - current[0] ); + cent->lerpOrigin[1] = current[1] + f * ( next[1] - current[1] ); + cent->lerpOrigin[2] = current[2] + f * ( next[2] - current[2] ); + + EvaluateTrajectory( ¢->currentState.apos, cg.snap->serverTime, current ); + EvaluateTrajectory( ¢->nextState.apos, cg.nextSnap->serverTime, next ); + + // Lerp legs, torso, and head angles + for ( i=0; i<3; i++ ) { + cent->lerpAngles[i] = LerpAngle( current[i], next[i], f ); + } + } else { + // just use the current frame and evaluate as best we can + EvaluateTrajectory( ¢->currentState.pos, cg.time, cent->lerpOrigin ); + EvaluateTrajectory( ¢->currentState.apos, cg.time, cent->lerpAngles ); + + // adjust for riding a mover + CG_AdjustPositionForMover( cent->lerpOrigin, cent->currentState.groundEntityNum, + cg.snap->serverTime, cg.time, cent->lerpOrigin ); + } +} + +/* +=============== +CG_AddCEntity + +=============== +*/ +void CG_AddCEntity( centity_t *cent ) +{ + // event-only entities will have been dealt with already + if ( cent->currentState.eType >= ET_EVENTS ) { + return; + } + + // calculate the current origin + CG_CalcEntityLerpPositions( cent ); + + // add automatic effects + CG_EntityEffects( cent ); + + CG_SetEntitySoundPosition( cent ); + + switch ( cent->currentState.eType ) { + default: + cgi.Error( ERR_DROP, "Bad entity type: %i\n", cent->currentState.eType ); + break; + case ET_PLAYER: + CG_Player( cent ); + // intentional fallthrough + case ET_MODELANIM: + CG_Splash( cent ); + CG_ModelAnim( cent ); + break; + case ET_ITEM: + CG_Item( cent ); + CG_ModelAnim( cent ); + break; + case ET_GENERAL: + CG_General( cent ); + break; + case ET_MOVER: + CG_Mover( cent ); + break; + case ET_BEAM: + CG_Beam( cent ); + break; + case ET_ROPE: // skip + CG_Rope( cent ); + break; + case ET_MULTIBEAM: // skip + break; + case ET_SPRITE: + CG_Sprite( cent ); + break; + case ET_PORTAL: + CG_Portal( cent ); + break; + case ET_RAIN: + case ET_EMITTER: + CG_Emitter( cent ); + break; + case ET_DECAL: + CG_Decal( cent ); + break; + } + } + +/* +=============== +CG_AddPacketEntities + +=============== +*/ +void CG_AddPacketEntities( void ) { + int num; + centity_t *cent; +// playerState_t *ps; + + // the auto-rotating items will all have the same axis + cg.autoAngles[0] = 0; + cg.autoAngles[1] = ( cg.time & 2047 ) * 360 / 2048.0; + cg.autoAngles[2] = 0; + + cg.autoAnglesSlow[0] = 0; + cg.autoAnglesSlow[1] = ( cg.time & 4095 ) * 360 / 4096.0f; + cg.autoAnglesSlow[2] = 0; + + cg.autoAnglesFast[0] = 0; + cg.autoAnglesFast[1] = ( cg.time & 1023 ) * 360 / 1024.0f; + cg.autoAnglesFast[2] = 0; + + AnglesToAxis( cg.autoAngles, cg.autoAxis ); + AnglesToAxis( cg.autoAnglesSlow, cg.autoAxisSlow ); + AnglesToAxis( cg.autoAnglesFast, cg.autoAxisFast ); + + // generate and add the entity from the playerstate + //ps = &cg.predicted_player_state; + //PlayerStateToEntityState( ps, &cg_entities[ ps->clientNum ].currentState ); + //CG_AddCEntity( &cg_entities[ ps->clientNum ] ); + + // add each entity sent over by the server + for ( num = 0 ; num < cg.snap->numEntities ; num++ ) { + cent = &cg_entities[ cg.snap->entities[ num ].number ]; + CG_AddCEntity( cent ); + } + + // Add in the multibeams at the end + for ( num = 0 ; num < cg.snap->numEntities ; num++ ) { + cent = &cg_entities[ cg.snap->entities[ num ].number ]; + if ( cent->currentState.eType == ET_MULTIBEAM ) + CG_MultiBeam( cent ); + } + +} + +void CG_GetOrigin( centity_t *cent, vec3_t origin ) + { + if ( cent->currentState.parent == ENTITYNUM_NONE ) + { + VectorCopy( cent->lerpOrigin, origin ); + } + else + { + int i; + orientation_t or; + refEntity_t *parent; + int tikihandle; + + parent = cgi.R_GetRenderEntity( cent->currentState.parent ); + + if ( !parent ) + { + cgi.DPrintf( "CG_GetOrigin: Could not find parent entity\n" ); + return; + } + + tikihandle = cgi.TIKI_GetHandle( parent->hModel ); + + // lerp the tag + if ( r_lerpmodels->integer ) + { + or = cgi.Tag_LerpedOrientation( tikihandle, parent, cent->currentState.tag_num ); + } + else + { + //FIXME + // doesn't handle torso animations + or = cgi.Tag_Orientation( tikihandle, parent->anim, parent->frame, cent->currentState.tag_num, parent->scale, + parent->bone_tag, parent->bone_quat ); + } + + VectorCopy( parent->origin, origin ); + + for ( i = 0 ; i < 3 ; i++ ) + { + VectorMA( origin, or.origin[i], parent->axis[i], origin ); + } + } + } + diff --git a/source/source/cgame/cg_event.c b/source/source/cgame/cg_event.c new file mode 100644 index 0000000..c24b2e5 --- /dev/null +++ b/source/source/cgame/cg_event.c @@ -0,0 +1,35 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/cgame/cg_event.c $ +// $Revision:: 4 $ +// $Author:: Aldie $ +// $Date:: 10/05/99 6:01p $ +// +// Copyright (C) 1998 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/cgame/cg_event.c $ +// +// 4 10/05/99 6:01p Aldie +// Added headers +// +// DESCRIPTION: +// handle entity events at snapshot or playerstate transitions + +#include "cg_local.h" + + +/* +============== +CG_EntityEvent + +An entity has an event value +============== +*/ + +void CG_EntityEvent( centity_t *cent, vec3_t position ) + { + } diff --git a/source/source/cgame/cg_lightstyles.cpp b/source/source/cgame/cg_lightstyles.cpp new file mode 100644 index 0000000..340d0ae --- /dev/null +++ b/source/source/cgame/cg_lightstyles.cpp @@ -0,0 +1,640 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/cgame/cg_lightstyles.cpp $ +// $Revision:: 7 $ +// $Author:: Markd $ +// $Date:: 6/14/00 12:14p $ +// +// Copyright (C) 1998 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/cgame/cg_lightstyles.cpp $ +// +// 7 6/14/00 12:14p Markd +// more intel compiler bug fixes +// +// 6 5/09/00 1:33p Markd +// added some lightstyle utilities to SetLightStyle +// +// 5 5/08/00 6:12p Markd +// Added lightstyle support for the client +// +// 4 3/04/00 1:35p Markd +// fixed lerping bug with lightstyles +// +// 3 3/04/00 12:23p Markd +// Fixed some lightstyle bugs +// +// 2 3/04/00 11:45a Markd +// Added light style support and malloc and free to the cgame +// +// 1 3/04/00 11:02a Markd +// +// DESCRIPTION: +// light style code + +#include "cg_local.h" + +/* +=================================================================== + +LIGHT STYLE CODE + +=================================================================== +*/ + +#define MAX_LIGHTSTYLE_LENGTH 128 +#define MAX_LIGHTSTYLE_NAME_LENGTH 64 + +typedef struct + { + char name[ MAX_LIGHTSTYLE_NAME_LENGTH ]; + qboolean hasalpha; + int length; + float map[ MAX_LIGHTSTYLE_LENGTH ][ 4 ]; + } clightstyle_t; + +clightstyle_t cg_lightstyle[ MAX_LIGHTSTYLES * 2 ]; + +/* +================ +CG_LightStyleColor +================ +*/ +qboolean CG_LightStyleColor( int style, int realtime, float color[4], qboolean clamp ) + { + clightstyle_t *ls; + int i, time; + float frac; + qboolean at_end; + + time = realtime / 50; + frac = ( realtime - ( time * 50.0f ) ) / 50.0f; + memset( color, 0, sizeof( color ) ); + if ( ( style < 0 ) || ( style >= ( MAX_LIGHTSTYLES * 2 ) ) ) + { + cgi.DPrintf ("CG_LightStyleColor: style out of range.\n"); + return qtrue; + } + + ls = &cg_lightstyle[ style ]; + + if ( !ls->length ) + { + cgi.DPrintf ("CG_LightStyleColor: style %d has zero length.\n", style); + return qtrue; + } + + // by default we are not at the end + at_end = qfalse; + if ( clamp ) + { + if ( time >= ls->length ) + { + time = ls->length - 1; + at_end = qtrue; + } + } + else + { + time %= ls->length; + } + + // + // only lerp if we are before the end + // + if ( time == ls->length - 1 ) + { + memcpy( color, ls->map[ time ], 4 * sizeof( ls->map[ time ][ 0 ] ) ); + } + else + { + for( i = 0; i < 4; i++ ) + { + color[ i ] = ls->map[ time ][ i ] + frac * ( ls->map[ time + 1 ][ i ] - ls->map[ time ][ i ] ); + } + } + + if ( !ls->hasalpha ) + color[ 3 ] = 1; + + return at_end; + } + +/* +============= +LoadTGA +============= +*/ +static qboolean LoadTGA(const char * name, byte ** pic, int *width, int *height, qboolean * hasalpha ) + { + int columns, rows, numPixels; + byte *pixbuf; + int row, column; + byte *buf_p; + byte *buffer; + TargaHeader targa_header; + byte *targa_rgba; + byte targa_palette[ 256 * 4 ]; + int i; + + *pic = NULL; + *hasalpha = false; + + // + // load the file + // + cgi.FS_ReadFile(name, (void **)&buffer, qtrue); + if (!buffer) + { + cgi.DPrintf( "TGA File not found: %s\n", name ); + return false; + } + + buf_p = buffer; + + targa_header.id_length = *buf_p++; + targa_header.colormap_type = *buf_p++; + targa_header.image_type = *buf_p++; + + targa_header.colormap_index = LittleShort ( *((short *)buf_p) ); + buf_p += 2; + targa_header.colormap_length = LittleShort ( *((short *)buf_p) ); + buf_p += 2; + targa_header.colormap_size = *buf_p++ / 8; + targa_header.x_origin = LittleShort ( *((short *)buf_p) ); + buf_p += 2; + targa_header.y_origin = LittleShort ( *((short *)buf_p) ); + buf_p += 2; + targa_header.width = LittleShort ( *((short *)buf_p) ); + buf_p += 2; + targa_header.height = LittleShort ( *((short *)buf_p) ); + buf_p += 2; + targa_header.pixel_size = *buf_p++; + targa_header.attributes = *buf_p++; + + if (targa_header.image_type!=1 + && targa_header.image_type!=2 + && targa_header.image_type!=10) + { + cgi.DPrintf("LoadTGA: Only type 1, 2 and 10 targa RGB images supported\n"); + return false; + } + + if ( (targa_header.colormap_type !=0 && targa_header.colormap_type !=1) + || (targa_header.pixel_size!=32 && targa_header.pixel_size!=24 && targa_header.pixel_size!=8)) + { + cgi.DPrintf("LoadTGA: Only 24, 32 and colormap images supported (no colormaps)\n"); + return false; + } + + columns = targa_header.width; + rows = targa_header.height; + numPixels = columns * rows; + + if (width) + *width = columns; + if (height) + *height = rows; + + targa_rgba = ( byte * )cgi.Malloc( numPixels * 4 ); + *pic = targa_rgba; + + if (targa_header.id_length != 0) + buf_p += targa_header.id_length; // skip TARGA image comment + + for (i=0;i=0; row--) + { + pixbuf = targa_rgba + row*columns; + for(column=0; column=0; row--) { + pixbuf = targa_rgba + row*columns*4; + for(column=0; column=0; row--) { + pixbuf = targa_rgba + row*columns*4; + for(column=0; column0) + row--; + else + goto breakOut; + pixbuf = targa_rgba + row*columns*4; + } + } + } + else { // non run-length packet + for(j=0;j0) + row--; + else + goto breakOut; + pixbuf = targa_rgba + row*columns*4; + } + } + } + } + breakOut:; + } + } + cgi.FS_FreeFile( buffer ); + return true; + } + +void createLightstyleFromTGA( int num, const char *filename ) + { + byte *data=0; + int i, j, width, height; + qboolean hasalpha; + + if (!LoadTGA(filename, &data, &width, &height, &hasalpha)) + { + return; + } + + if ( width > MAX_LIGHTSTYLE_LENGTH ) + { + cgi.DPrintf("createLightstyleFromTGA: Light style too large, truncating.\n",filename); + width = MAX_LIGHTSTYLE_LENGTH; + } + + strncpy( cg_lightstyle[ num ].name, filename, MAX_LIGHTSTYLE_NAME_LENGTH ); + cg_lightstyle[ num ].hasalpha = hasalpha; + cg_lightstyle[ num ].length = width; + + for( i = 0; i < width; i++ ) + { + for ( j = 0; j < 4; j++ ) + { + cg_lightstyle[ num ].map[ i ][ j ] = ( float )data[ ( i * 4 ) + j ] / 255.0f; + } + } + + if ( data ) + cgi.Free( data ); + } + +void CG_SetLightStyle( int num, const char *s ) + { + char *r, *g, *b, *a; + int j, k, n, len; + float t; + + if ( ( num < 0 ) || ( num >= ( MAX_LIGHTSTYLES * 2 ) ) ) + { + cgi.DPrintf ("CG_SetLightStyle: num out of range.\n"); + return; + } + + len = strlen( s ); + + if ( !strcmpi( &s[ len - 4 ], ".tga" ) ) + { + createLightstyleFromTGA( num, s ); + return; + } + + if ( !s ) + return; + + r = strchr( s, 'R' ); + g = strchr( s, 'G' ); + b = strchr( s, 'B' ); + a = strchr( s, 'A' ); + + n = 0; + if (r) + n++; + if (g) + n++; + if (b) + n++; + if (a) + n++; + if (!n) + n++; + + if (!a) + cg_lightstyle[ num ].hasalpha = false; + else + cg_lightstyle[ num ].hasalpha = true; + + j = strlen (s) / n; + if (j >= MAX_LIGHTSTYLE_LENGTH) + { + cgi.DPrintf ( "svc_lightstyle length=%i", j); + j = MAX_LIGHTSTYLE_LENGTH - 1; + } + + if ( !r && !g && !b && !a ) + { + cg_lightstyle[ num ].length = j; + for( k = 0; k < j; k++ ) + { + t = ( float )( s[ k ] - 'a' ) * 127.5f / 12.5; + if ( t > 255 ) + { + t = 255.0f; + } + cg_lightstyle[ num ].map[ k ][ 0 ] = t / 255.0f; + cg_lightstyle[ num ].map[ k ][ 1 ] = t / 255.0f; + cg_lightstyle[ num ].map[ k ][ 2 ] = t / 255.0f; + cg_lightstyle[ num ].map[ k ][ 3 ] = 1; + } + } + else + { + n = 0; + // red + k = 0; + t = 0; + if ( r ) + { + r++; + while( ( r[ k ] >= 'a' ) && ( r[ k ] <= 'z' ) ) + { + t = ( float )( r[ k ] - 'a' ) * 127.5f / 12.5; + if ( t > 255 ) + { + t = 255.0f; + } + cg_lightstyle[ num ].map[ k ][ 0 ] = t / 255.0f; + k++; + } + n = k; + } + while( k < MAX_LIGHTSTYLE_LENGTH ) + { + cg_lightstyle[ num ].map[ k++ ][ 0 ] = t / 255.0f; + } + + // green + k = 0; + t = 0; + if ( g ) + { + g++; + while( ( g[ k ] >= 'a' ) && ( g[ k ] <= 'z' ) ) + { + t = ( float )( g[ k ] - 'a' ) * 127.5f / 12.5; + if ( t > 255 ) + { + t = 255.0f; + } + cg_lightstyle[ num ].map[ k ][ 1 ] = t / 255.0f; + k++; + } + n = max( n, k ); + } + while( k < MAX_LIGHTSTYLE_LENGTH ) + { + cg_lightstyle[ num ].map[ k++ ][ 1 ] = t / 255.0f; + } + + // blue + k = 0; + t = 0; + if ( b ) + { + b++; + while( ( b[ k ] >= 'a' ) && ( b[ k ] <= 'z' ) ) + { + t = ( float )( b[ k ] - 'a' ) * 127.5f / 12.5; + if ( t > 255 ) + { + t = 255.0f; + } + cg_lightstyle[ num ].map[ k ][ 2 ] = t / 255.0f; + k++; + } + n = max( n, k ); + } + while( k < MAX_LIGHTSTYLE_LENGTH ) + { + cg_lightstyle[ num ].map[ k++ ][ 2 ] = t / 255.0f; + } + + // alpha + k = 0; + t = 255; + if ( a ) + { + a++; + while( ( a[ k ] >= 'a' ) && ( a[ k ] <= 'z' ) ) + { + t = ( float )( a[ k ] - 'a' ) * 127.5f / 25; + if ( t > 255 ) + { + t = 255.0f; + } + cg_lightstyle[ num ].map[ k ][ 3 ] = t / 255.0f; + k++; + } + n = max( n, k ); + } + while( k < MAX_LIGHTSTYLE_LENGTH ) + { + cg_lightstyle[ num ].map[ k++ ][ 3 ] = t / 255.0f; + } + + cg_lightstyle[ num ].length = n; + } + } + +/* +================ +CG_GetLightStyle +================ +*/ +int CG_GetLightStyle( const char * name ) + { + int i; + + for( i = MAX_LIGHTSTYLES; i < MAX_LIGHTSTYLES * 2; i++ ) + { + if ( !strcmpi( cg_lightstyle[ i ].name, name ) ) + { + return i; + } + } + return -1; + } + +/* +================ +CG_GetFreeLightStyle +================ +*/ +int CG_GetFreeLightStyle( void ) + { + int i; + + for( i = MAX_LIGHTSTYLES; i < MAX_LIGHTSTYLES * 2; i++ ) + { + if ( !cg_lightstyle[ i ].name[ 0 ] ) + { + return i; + } + } + return -1; + } + +/* +================ +CG_ClearLightStyles +================ +*/ +void CG_ClearLightStyles( void ) + { + memset( cg_lightstyle, 0, sizeof( cg_lightstyle ) ); + } + +/* +================ +CG_RegisterLightStyle +================ +*/ +int CG_RegisterLightStyle( const char * name ) + { + int num; + + num = CG_GetLightStyle( name ); + if ( num == -1 ) + { + num = CG_GetFreeLightStyle(); + if ( num != -1 ) + { + CG_SetLightStyle( num, name ); + } + else + { + cgi.DPrintf ("CG_RegisterLightStyle: no free spots for lightstyle %s.\n"); + } + } + + return num; + } + diff --git a/source/source/cgame/cg_listener.cpp b/source/source/cgame/cg_listener.cpp new file mode 100644 index 0000000..ccf3653 --- /dev/null +++ b/source/source/cgame/cg_listener.cpp @@ -0,0 +1,1394 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/cgame/cg_listener.cpp $ +// $Revision:: 2 $ +// $Author:: Aldie $ +// $Date:: 9/10/99 5:24p $ +// +// Copyright (C) 1998 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source is may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/cgame/cg_listener.cpp $ +// +// 2 9/10/99 5:24p Aldie +// Merge code +// +// 2 9/09/99 3:30p Aldie +// Merge +// +// 1 9/08/99 3:35p Aldie +// +// 5 7/29/99 3:32p Aldie +// Updated to new class system +// +// DESCRIPTION: +// + +#include "cg_local.h" +#include "cg_listener.h" + +cvar_t *cg_numevents; +cvar_t *cg_showevents; +cvar_t *cg_eventlimit; +cvar_t *cg_timeevents; +cvar_t *cg_watch; + +Vector vec_zero="0 0 0"; + +Event EV_Remove( "immediateremove" ); +Event EV_ScriptRemove( "remove" ); + +typedef struct eventcache_s + { + Listener *obj; + Event *event; + float time; + + struct eventcache_s *next; + struct eventcache_s *prev; + } eventcache_t; + +#define MAX_EVENTS 2000 + +extern "C" + { + eventcache_t Events[ MAX_EVENTS ]; + int numEvents = 0; + cvar_t *g_numevents; + }; + +eventcache_t FreeEventHead; +eventcache_t *FreeEvents = &FreeEventHead; +eventcache_t EventQueueHead; +eventcache_t *EventQueue = &EventQueueHead; + +Container *Event::commandList = NULL; +Container *Event::flagList = NULL; +Container *Event::sortedList = NULL; +qboolean Event::dirtylist = qfalse; + +qboolean IsNumeric + ( + const char *str + ) + + { + int len; + int i; + qboolean dot; + + if ( *str == '-' ) + { + str++; + } + + dot = qfalse; + len = strlen( str ); + for( i = 0; i < len; i++ ) + { + if ( !isdigit( str[ i ] ) ) + { + if ( ( str[ i ] == '.' ) && !dot ) + { + dot = qtrue; + continue; + } + return qfalse; + } + } + + return qtrue; + } + +Event NullEvent; + +CLASS_DECLARATION( Class, Event, NULL ) + { + { NULL, NULL } + }; + +int Event::NumEventCommands + ( + void + ) + + { + if ( commandList ) + { + // Add 1 since container gives the inclusive number of objects + return commandList->NumObjects() + 1; + } + + return 0; + } + +int Event::compareEvents + ( + const void *arg1, + const void *arg2 + ) + + { + int ev1; + int ev2; + + ev1 = *( int * )arg1; + ev2 = *( int * )arg2; + + return stricmp( commandList->ObjectAt( ev1 )->c_str(), commandList->ObjectAt( ev2 )->c_str() ); + } + +void Event::SortEventList + ( + void + ) + + { + dirtylist = qfalse; + + if ( sortedList && commandList ) + { +#ifndef EXPORT_TEMPLATE + qsort( ( void * )sortedList->AddressOfObjectAt( 1 ), + ( size_t )sortedList->NumObjects(), + sizeof( int ), compareEvents ); +#else + sortedList->Sort( compareEvents ); +#endif + } + } + +inline int Event::FindEvent + ( + const char *name + ) + + { + int eventnum; + int index; + int l; + int r; + int diff; + + assert( name ); + if ( !name ) + { + return 0; + } + + if ( !commandList ) + { + return 0; + } + + if ( dirtylist ) + { + SortEventList(); + } + + l = 1; + r = sortedList->NumObjects(); + while( r >= l ) + { + index = ( l + r ) >> 1; + eventnum = sortedList->ObjectAt( index ); + diff = stricmp( name, commandList->ObjectAt( eventnum )->c_str() ); + if ( diff < 0 ) + { + r = index - 1; + } + else if ( diff > 0 ) + { + l = index + 1; + } + else + { + return eventnum; + } + } + + return 0; + } + +int Event::FindEvent + ( + str &name + ) + + { + return FindEvent( name.c_str() ); + } + +void Event::ListCommands + ( + const char *mask + ) + + { + str name; + int flags; + int eventnum; + int num; + int i; + int n; + int l; + int p; + int hidden; + str text; + + if ( !commandList ) + { + cgi.Printf( "No events.\n" ); + return; + } + + if ( dirtylist ) + { + SortEventList(); + } + + l = 0; + if ( mask ) + { + l = strlen( mask ); + } + + hidden = 0; + num = 0; + n = sortedList->NumObjects(); + for( i = 1; i <= n; i++ ) + { + eventnum = sortedList->ObjectAt( i ); + name = commandList->ObjectAt( eventnum )->c_str(); + flags = flagList->ObjectAt( eventnum ); + + if ( flags & EV_HIDE ) + { + hidden++; + continue; + } + + if ( mask && strnicmp( name.c_str(), mask, l ) ) + { + continue; + } + + num++; + + text = " "; + p = 0; + if ( flags & EV_CONSOLE ) + { + text[ p++ ] = '*'; + } + if ( flags & EV_CHEAT ) + { + text[ p++ ] = 'C'; + } + + cgi.Printf( "%4d : %s%s\n", eventnum, text.c_str(), name.c_str() ); + } + + cgi.Printf( "\n* = console command.\nC = cheat command.\n\n" + "Printed %d of %d total commands.\n", num, n - hidden ); + +/* GAMEFIX + if ( developer->integer && hidden ) + { + cgi.Printf( "Suppressed %d commands.\n", hidden ); + } +*/ + } + +void Event::initCommandList + ( + void + ) + + { + int flags; + str *n; + + flags = 0; + commandList = new Container; + + n = new str( "NULL" ); + NullEvent.eventnum = commandList->AddObject( n ); + + flagList = new Container; + flagList->AddObject( flags ); + + sortedList = new Container; + sortedList->AddObject( NullEvent.eventnum ); + + dirtylist = qfalse; + + NullEvent.data = NULL; + NullEvent.info.inuse = 0; + NullEvent.info.source = EV_FROM_CODE; + NullEvent.info.flags = 0; + NullEvent.info.linenumber = 0; + } + +Event::Event() + { + info.inuse = 0; + info.source = EV_FROM_CODE; + info.flags = 0; + info.linenumber = 0; + threadnum = -1; + eventnum = 0; + data = NULL; + name = NULL; + } + +Event::Event + ( + int num + ) + + { + if ( !commandList ) + { + initCommandList(); + } + + assert( ( num > 0 ) && num <= commandList->NumObjects() ); + + if ( ( num <= 0 ) || ( num > commandList->NumObjects() ) ) + { + num = 0; + name = NULL; + info.flags = 0; + } + else + { + name = commandList->ObjectAt( num )->c_str(); + info.flags = flagList->ObjectAt( num ); + } + + eventnum = num; + data = NULL; + info.inuse = 0; + info.source = EV_FROM_CODE; + info.linenumber = 0; + threadnum = -1; + } + +Event::Event + ( + Event &ev + ) + + { + int num; + int i; + + eventnum = ( int )ev; + assert( ( eventnum > 0 ) && eventnum <= commandList->NumObjects() ); + data = NULL; + + name = commandList->ObjectAt( eventnum )->c_str(); + info.inuse = 0; + info.source = ev.info.source; + info.flags = ev.info.flags; + info.linenumber = ev.info.linenumber; + threadnum = ev.threadnum; + + if ( ev.data ) + { + num = ev.data->NumObjects(); + + data = new Container; + data->Resize( num ); + + for( i = 1; i <= num; i++ ) + { + data->AddObject( ev.data->ObjectAt( i ) ); + } + } + } + +Event::Event + ( + Event *ev + ) + + { + int num; + int i; + + assert( ev ); + if ( !ev ) + { + Class::error( "Event", "NULL Event\n" ); + } + + eventnum = ( int )*ev; + assert( ( eventnum > 0 ) && eventnum <= commandList->NumObjects() ); + data = NULL; + name = commandList->ObjectAt( eventnum )->c_str(); + info.inuse = 0; + info.source = ev->info.source; + info.flags = ev->info.flags; + info.linenumber = ev->info.linenumber; + threadnum = ev->threadnum; + if ( ev->data ) + { + num = ev->data->NumObjects(); + + data = new Container; + data->Resize( num ); + + for( i = 1; i <= num; i++ ) + { + data->AddObject( ev->data->ObjectAt( i ) ); + } + } + } + +Event::Event + ( + const char *command, + int flags + ) + + { + str c; + str *t; + + if ( !commandList ) + { + initCommandList(); + } + + c = command; + eventnum = FindEvent( c ); + if ( !eventnum ) + { + t = new str( c ); + eventnum = commandList->AddObject( t ); + // check for default flags + if ( flags == -1 ) + { + flags = 0; + } + flagList->AddObject( ( int )flags ); + sortedList->AddObject( eventnum ); + dirtylist = qtrue; + } + + // Use the name stored in the command list in case the string passed in + // is not in static memory. + name = commandList->ObjectAt( eventnum )->c_str(); + + data = NULL; + info.inuse = 0; + info.source = EV_FROM_CODE; + info.linenumber = 0; + threadnum = -1; + + // If flags have changed, let the user know. It's probably a development bug. + int &flagobj = flagList->ObjectAt( eventnum ); + + // check for default flags + if ( flags == -1 ) + { + flags = flagobj; + } + + assert( flags == flagobj ); + if ( flags != flagobj ) + { + // Flags not equal. Use combined value. + flagobj |= flags; + } + + info.flags = flagobj; + } + +Event::Event + ( + str &command, + int flags + ) + + { + str *t; + + if ( !commandList ) + { + initCommandList(); + } + + eventnum = FindEvent( command ); + if ( !eventnum ) + { + t = new str( command ); + eventnum = commandList->AddObject( t ); + // check for default flags + if ( flags == -1 ) + { + flags = 0; + } + flagList->AddObject( flags ); + sortedList->AddObject( eventnum ); + dirtylist = qtrue; + } + + // Use the name stored in the command list since the string passed in + // is not in static memory. + name = commandList->ObjectAt( eventnum )->c_str(); + data = NULL; + info.inuse = 0; + info.source = EV_FROM_CODE; + info.linenumber = 0; + threadnum = -1; + + // If flags have changed, let the user know. It's probably a development bug. + int &flagobj = flagList->ObjectAt( eventnum ); + + // check for default flags + if ( flags == -1 ) + { + flags = flagobj; + } + + assert( flags == flagobj ); + if ( flags != flagobj ) + { + // Flags not equal. Use combined value. + flagobj |= flags; + } + + info.flags = flagobj; + } + + Event::~Event() + { + if ( data ) + { + delete data; + data = NULL; + } + } + +void Event::Error + ( + const char *fmt, + ... + ) + + { + va_list argptr; + char text[ 1024 ]; + + va_start( argptr, fmt ); + vsprintf( text, fmt, argptr ); + va_end( argptr ); + + cgi.Printf( "Client: '%s' : %s\n", getName().c_str(), text ); + } + +const char *Event::GetString + ( + int pos + ) + + { + const char *text; + + if ( !data || ( pos < 1 ) || ( data->NumObjects() < pos ) ) + { + Error( "Index %d out of range.", pos ); + return ""; + } + + text = data->ObjectAt( pos ).c_str(); + assert( text ); + + /* GAMEFIX + var = Director.GetExistingVariable( text ); + if ( var ) + { + return var->stringValue(); + } + */ + return text; + } + +void *Event::GetPointer + ( + int pos + ) + + { + const char *text; + + if ( !data || ( pos < 1 ) || ( data->NumObjects() < pos ) ) + { + Error( "Index %d out of range.", pos ); + return 0; + } + + text = data->ObjectAt( pos ).c_str(); + assert( text ); + + if ( !IsNumeric( text ) ) + { + Error( "Expecting a numeric value but found '%s'.", text ); + return 0; + } + + return (void *)atoi( text ); + } + +int Event::GetInteger + ( + int pos + ) + + { + const char *text; + + if ( !data || ( pos < 1 ) || ( data->NumObjects() < pos ) ) + { + Error( "Index %d out of range.", pos ); + return 0; + } + + text = data->ObjectAt( pos ).c_str(); + assert( text ); + + /* GAMEFIX + var = Director.GetExistingVariable( text ); + if ( var ) + { + if ( !IsNumeric( var->stringValue() ) ) + { + Error( "Variable %s contains non-numeric value '%s'", text, var->stringValue() ); + } + return var->intValue(); + } + */ + + if ( !IsNumeric( text ) ) + { + Error( "Expecting a numeric value but found '%s'.", text ); + return 0; + } + + return atoi( text ); + } + +double Event::GetDouble + ( + int pos + ) + + { + const char *text; + + if ( !data || ( pos < 1 ) || ( data->NumObjects() < pos ) ) + { + Error( "Index %d out of range.", pos ); + return 0; + } + + text = data->ObjectAt( pos ).c_str(); + assert( text ); + + /* GAMEFIX + var = Director.GetExistingVariable( text ); + if ( var ) + { + if ( !IsNumeric( var->stringValue() ) ) + { + cgi.Error( "Variable %s contains non-numeric value '%s'", text, var->stringValue() ); + } + return ( double )var->floatValue(); + } + */ + + if ( !IsNumeric( text ) ) + { + Error( "Expecting a numeric value but found '%s'.", text ); + return 0; + } + + return ( double )atof( text ); + } + +float Event::GetFloat + ( + int pos + ) + + { + const char *text; + + if ( !data || ( pos < 1 ) || ( data->NumObjects() < pos ) ) + { + Error( "Index %d out of range.", pos ); + return 0; + } + + text = data->ObjectAt( pos ).c_str(); + assert( text ); + + /* GAMEFIX + var = Director.GetExistingVariable( text ); + if ( var ) + { + if ( !IsNumeric( var->stringValue() ) ) + { + cgi.Error( "Variable %s contains non-numeric value '%s'", text, var->stringValue() ); + } + return var->floatValue(); + } + */ + + if ( !IsNumeric( text ) ) + { + Error( "Expecting a numeric value but found '%s'.", text ); + return 0; + } + + return atof( text ); + } + +Vector Event::GetVector + ( + int pos + ) + + { + const char *text; + + if ( !data || ( pos < 1 ) || ( data->NumObjects() < pos ) ) + { + Error( "Index %d out of range.", pos ); + return vec_zero; + } + + text = data->ObjectAt( pos ).c_str(); + assert( text ); + + /* GAMEFIX + var = Director.GetExistingVariable( text ); + if ( var ) + { + text = var->stringValue(); + } + */ + + // Check if this is a ()-based vector + // we accept both, but using parenthesis we can determine if it is a vector or not + if ( text[ 0 ] == '(' ) + { + return Vector( &text[ 1 ] ); + } + + // give an cgi.Error, but try converting it anyways + Error( "Vector '%s' does not include '(' ')'.", text ); + return Vector( text ); + } + +CLASS_DECLARATION( Class, Listener, NULL ) + { + { &EV_Remove, Listener::Remove }, + { &EV_ScriptRemove, Listener::ScriptRemove }, + { NULL, NULL } + }; + + +void Listener::Remove + ( + Event *e + ) + + { + delete this; + } + +void Listener::ScriptRemove + ( + Event *e + ) + + { + // Forces the remove to be done at a safe time + PostEvent( EV_Remove, 0 ); + } + +#if 0 +void Listener::FloatVar + ( + Event &e, + float *var, + float defaultvalue + ) + + { + } + +void Listener::IntVar + ( + Event &e, + int *var, + float defaultvalue + ) + + { + } + +void Listener::StringVar + ( + Event &e, + str *var, + const char *defaultvalue + ) + + { + } + +void Listener::StringVar + ( + Event &e, + char **var, + const char *defaultvalue + ) + + { + } + +void Listener::VectorVar + ( + Event &e, + Vector *var, + Vector defaultvalue + ) + + { + } +#endif + +qboolean Listener::ValidEvent + ( + Event &e + ) + + { + ClassDef *c; + int ev; + + ev = ( int )e; + + c = this->classinfo(); + assert( ( ev >= 0 ) && ( ev < c->numEvents ) ); + if ( ( ev < 0 ) || ( ev >= c->numEvents ) ) + { + warning( "ValidEvent", "Event '%s' out of response range for class '%s'. " + "Event probably invalid or allocated late.\n", e.getName().c_str(), getClassname() ); + return qfalse; + } + + return ( qboolean )( c->responseLookup[ ev ] != NULL ); + } + +qboolean Listener::ValidEvent + ( + const char *name + ) + + { + ClassDef *c; + int ev; + + ev = Event::FindEvent( name ); + + c = this->classinfo(); + assert( ( ev >= 0 ) && ( ev < c->numEvents ) ); + if ( ( ev < 0 ) || ( ev >= c->numEvents ) ) + { + warning( "ValidEvent", "Event '%s' out of response range for class '%s'. " + "Event probably invalid or allocated late.\n", name, getClassname() ); + return qfalse; + } + + return ( qboolean )( c->responseLookup[ ev ] != NULL ); + } + +qboolean Listener::EventPending + ( + Event &ev + ) + + { + eventcache_t *event; + int eventnum; + + assert( EventQueue ); + assert( EventQueue->next ); + + event = EventQueue->next; + + eventnum = ( int )ev; + while( event != EventQueue ) + { + if ( ( event->obj == this ) && ( (int)*event->event == eventnum ) ) + { + return qtrue; + } + event = event->next; + } + + return qfalse; + } + +inline qboolean Listener::CheckEventFlags + ( + Event *event + ) + + { + /* GAMEFIX + // Special handling of console events + if ( event->GetSource() == EV_FROM_CONSOLE ) + { + if ( !( event->info.flags & (EV_CONSOLE|EV_CHEAT) ) ) + { + if ( isSubclassOf( Entity ) ) + { + Entity *ent; + + ent = ( Entity * )this; + gi.SendServerCommand( ent->edict, "print \"Command not available from console.\n\"" ); + } + + // don't process + return qfalse; + } + + // don't allow console cheats during deathmatch unless the server says it's ok. + if ( ( event->info.flags & EV_CHEAT ) && deathmatch->integer && !sv_cheats->integer ) + { + if ( isSubclassOf( Entity ) ) + { + Entity *ent; + + ent = ( Entity * )this; + gi.SendServerCommand( ent->edict, "print \"You must run the server with '+set cheats 1' to enable this command.\n\"" ); + } + + // don't process + return qfalse; + } + } + */ + // ok to process + return qtrue; + } + +qboolean Listener::ProcessEvent + ( + Event *event + ) + + { + ClassDef *c; + int ev; + int i; + + // Prevent overflow of the inuse count + if ( event->info.inuse >= MAX_EVENT_USE ) + { + cgi.Error( ERR_DROP, "ProcessEvent : Event usage overflow on '%s' event. Possible infinite loop.\n", event->getName().c_str() ); + } + + if ( cg_showevents->integer ) + { + int n; + str text; + + text = va( "%.1f: %s", (float)cgi.Milliseconds()/1000.0f, this->getClassname() ); + text += event->getName().c_str(); + n = event->NumArgs(); + for( i = 1; i <= n; i++ ) + { + text += va( " %s", event->GetToken( i ) ); + } + + text += "\n"; + } + + ev = ( int )*event; + c = this->classinfo(); + if ( ev >= c->numEvents ) + { + event->Error( "Event out of response range for class '%s'. Event probably invalid or allocated late.\n", getClassname() ); + return qfalse; + } + + if ( c->responseLookup[ ev ] ) + { + int start; + int end; + + event->info.inuse++; + + if ( !cg_timeevents->integer ) + { + // only process the event if we allow it + if ( CheckEventFlags( event ) ) + { + ( this->**c->responseLookup[ ev ] )( event ); + } + } + else + { + start = cgi.Milliseconds(); + + // only process the event if we allow it + if ( CheckEventFlags( event ) ) + { + ( this->**c->responseLookup[ ev ] )( event ); + } + + end = cgi.Milliseconds(); + + if ( cg_timeevents->integer == 1 ) + { + cgi.Printf( "'%s' : %d\n", event->getName().c_str(), end - start ); + } + else + { + // GAMEFIX G_DebugPrintf( "'%s' : %d\n", event->getName().c_str(), end - start ); + } + } + + // Prevent an event from being freed twice, in case it's been re-used + event->info.inuse--; + if ( !event->info.inuse ) + { + delete event; + } + + return qtrue; + } + + if ( !event->info.inuse ) + { + delete event; + } + + return qfalse; + } + +void Listener::PostEvent + ( + Event *ev, + float time + ) + + { + eventcache_t *newevent; + eventcache_t *event; + + if ( LL_Empty( FreeEvents, next, prev ) ) + { + cgi.Error( ERR_DROP, "PostEvent : No more free events on '%s' event.\n", ev->getName().c_str() ); + return; + } + + newevent = FreeEvents->next; + LL_Remove( newevent, next, prev ); + + // Probably don't have this many events, but it's a good safety precaution + if ( ev->info.inuse >= MAX_EVENT_USE ) + { + cgi.Error( ERR_DROP, "PostEvent : Event usage overflow on '%s' event. Possible infinite loop.\n", ev->getName().c_str() ); + return; + } + + ev->info.inuse++; + + newevent->obj = this; + newevent->event = ev; + newevent->time = ( ( float )cgi.Milliseconds() / 1000.0f ) + time; + + event = EventQueue->next; + while( ( event != EventQueue ) && ( newevent->time >= event->time ) ) + { + event = event->next; + } + + LL_Add( event, newevent, next, prev ); + numEvents++; + } + +qboolean Listener::PostponeEvent + ( + Event &ev, + float time + ) + + { + eventcache_t *event; + eventcache_t *node; + int eventnum; + + assert( EventQueue ); + assert( EventQueue->next ); + + eventnum = ( int )ev; + + event = EventQueue->next; + while( event != EventQueue ) + { + if ( ( event->obj == this ) && ( ( int )*event->event == eventnum ) ) + { + event->time += time; + + node = event->next; + while( ( node != EventQueue ) && ( event->time >= node->time ) ) + { + node = node->next; + } + + LL_Remove( event, next, prev ); + LL_Add( node, event, next, prev ); + + return qtrue; + } + event = event->next; + } + + return qfalse; + } + +void Listener::CancelEventsOfType + ( + Event *ev + ) + + { + eventcache_t *event; + eventcache_t *next; + int eventnum; + + assert( EventQueue ); + assert( EventQueue->next ); + + event = EventQueue->next; + + eventnum = (int)*ev; + while( event != EventQueue ) + { + next = event->next; + if ( ( event->obj == this ) && ( (int)*event->event == eventnum ) ) + { + delete event->event; + event->event = NULL; + LL_Remove( event, next, prev ); + LL_Add( FreeEvents, event, next, prev ); + numEvents--; + } + event = next; + } + } + +void Listener::CancelPendingEvents + ( + void + ) + + { + eventcache_t *event; + eventcache_t *next; + + assert( EventQueue ); + assert( EventQueue->next ); + + event = EventQueue->next; + + while( event != EventQueue ) + { + next = event->next; + if ( event->obj == this ) + { + delete event->event; + event->event = NULL; + LL_Remove( event, next, prev ); + LL_Add( FreeEvents, event, next, prev ); + numEvents--; + } + event = next; + } + } + +qboolean Listener::ProcessPendingEvents + ( + void + ) + + { + eventcache_t *event; + qboolean processedEvents; + float t; + + assert( EventQueue ); + assert( EventQueue->next ); + assert( EventQueue->prev ); + + processedEvents = qfalse; + + t = ( ( float )cgi.Milliseconds() / 1000.0f ) + 0.001; + + event = EventQueue->next; + while( event != EventQueue ) + { + assert( event ); + assert( event->event ); + assert( event->obj ); + + if ( event->time > t ) + { + break; + } + + if ( event->obj != this ) + { + // traverse normally + event = event->next; + } + else + { + LL_Remove( event, next, prev ); + numEvents--; + + assert( event->obj ); + + // ProcessEvent increments the inuse count, so decrement it since we've already incremented it in PostEvent + event->event->info.inuse--; + + event->obj->ProcessEvent( event->event ); + + event->event = NULL; + LL_Add( FreeEvents, event, next, prev ); + + // start over, since can't guarantee that we didn't process any previous or following events + event = EventQueue->next; + + processedEvents = qtrue; + } + } + + return processedEvents; + } + +Listener::~Listener() + { + CancelPendingEvents(); + } + +void CG_ClearEventList + ( + void + ) + + { + int i; + eventcache_t *e; + + LL_Reset( FreeEvents, next, prev ); + LL_Reset( EventQueue, next, prev ); + memset( Events, 0, sizeof( Events ) ); + + for( e = &Events[ 0 ], i = 0; i < MAX_EVENTS; i++, e++ ) + { + LL_Add( FreeEvents, e, next, prev ); + } + + numEvents = 0; + } + +void CG_ProcessPendingEvents + ( + void + ) + + { + eventcache_t *event; + float t; + int num; + int maxevents; + + assert( EventQueue ); + assert( EventQueue->next ); + assert( EventQueue->prev ); + + maxevents = ( int )cg_eventlimit->integer; + + num = 0; + t = ( ( float )cgi.Milliseconds() / 1000.0f ) + 0.001; + while( !LL_Empty( EventQueue, next, prev ) ) + { + event = EventQueue->next; + + assert( event ); + assert( event->event ); + assert( event->obj ); + + if ( event->time > t ) + { + break; + } + + LL_Remove( event, next, prev ); + numEvents--; + + assert( event->obj ); + + // ProcessEvent increments the inuse count, so decrement it since we've already incremented it in PostEvent + assert( event->event->info.inuse > 0 ); + event->event->info.inuse--; + + event->obj->ProcessEvent( event->event ); + + event->event = NULL; + LL_Add( FreeEvents, event, next, prev ); + + // Don't allow ourselves to stay in here too long. An abnormally high number + // of events being processed is evidence of an infinite loop of events. + num++; + if ( num > maxevents ) + { + cgi.Printf( "Event overflow. Possible infinite loop in script. " + "Enable g_showevents to trace. Aborting frame.\n" ); + break; + } + } + } + +void CG_InitEvents + ( + void + ) + + { + cg_numevents = cgi.Cvar_Get( "cg_numevents", "0", 0 ); + cg_showevents = cgi.Cvar_Get( "cg_showevents", "0", 0 ); + cg_eventlimit = cgi.Cvar_Get( "cg_eventlimit", "1500", 0 ); + cg_timeevents = cgi.Cvar_Get( "cg_timeevents", "0", 0 ); + cg_watch = cgi.Cvar_Get( "cg_watch", "0", 0 ); + + BuildEventResponses(); + CG_ClearEventList(); + CG_InitCommandManager(); + // Sort the list before we go on since we won't be adding any more events + Event::SortEventList(); + } \ No newline at end of file diff --git a/source/source/cgame/cg_listener.h b/source/source/cgame/cg_listener.h new file mode 100644 index 0000000..48ea636 --- /dev/null +++ b/source/source/cgame/cg_listener.h @@ -0,0 +1,541 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/cgame/cg_listener.h $ +// $Revision:: 2 $ +// $Author:: Aldie $ +// $Date:: 9/10/99 5:24p $ +// +// Copyright (C) 1998 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source is may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/cgame/cg_listener.h $ +// +// 2 9/10/99 5:24p Aldie +// Merge code +// +// 1 9/10/99 10:48a Jimdose +// +// 2 9/09/99 3:30p Aldie +// Merge +// +// 1 9/08/99 3:35p Aldie +// +// DESCRIPTION: +// + +#include "cg_local.h" +#include "cg_class.h" +#include "cg_container.h" +#include "cg_vector.h" +#include "../fgame/str.h" + +#ifndef __LISTENER_H__ +#define __LISTENER_H__ + +typedef enum + { + EV_FROM_CODE, + EV_FROM_CONSOLE, + EV_FROM_SCRIPT + } eventsource_t; + +// Event flags +#define EV_CONSOLE 1 // Allow entry from console +#define EV_CHEAT 2 // Only allow entry from console if cheats are enabled +#define EV_HIDE 4 // Hide from eventlist + +#define MAX_EVENT_USE ( ( 1 << 8 ) - 1 ) + +class ScriptThread; + +#ifdef EXPORT_TEMPLATE +template class Container; +#endif + +class Event : public Class + { + private: + typedef struct EventInfo + { + unsigned inuse : 8; // must change MAX_EVENT_USE to reflect maximum number stored here + unsigned source : 2; + unsigned flags : 2; + unsigned linenumber : 20; // linenumber does double duty in the case of the console commands + }; + + int eventnum; + EventInfo info; + const char *name; + Container *data; + int threadnum; + + Event( int num ); + static void initCommandList( void ); + + friend class Listener; + + friend void CG_ProcessPendingEvents( void ); + friend void CG_ClearEventList( void ); + friend void CG_InitEvents( void ); + + static Container *Event::commandList; + static Container *Event::flagList; + static Container *Event::sortedList; + static qboolean Event::dirtylist; + + static int compareEvents( const void *arg1, const void *arg2 ); + static void SortEventList( void ); + static int FindEvent( const char *name ); + static int FindEvent( str &name ); + + public: + + CLASS_PROTOTYPE( Event ); + + static int NumEventCommands( void ); + static void ListCommands( const char *mask = NULL ); + + Event(); + Event( Event &ev ); + Event( Event *ev ); + Event( const char *command, int flags = -1 ); + Event( str &command, int flags = -1 ); + ~Event(); + + str getName( void ); + + void SetSource( eventsource_t source ); + void SetLineNumber( int linenumber ); + //void SetConsoleEdict( gentity_t *consoleedict ); + void SetThread( ScriptThread *thread ); + + eventsource_t GetSource( void ); + ScriptThread *GetThread( void ); + // gentity_t *GetConsoleEdict( void ); + int GetLineNumber( void ); + + void Error( const char *fmt, ... ); + + static Event Find( const char *command ); + static qboolean Exists( const char *command ); + static Event Find( str &command ); + + Event& printInfo(void); + + operator int(); + operator const char *(); + + int NumArgs( void ); + + qboolean IsVectorAt( int pos ); + qboolean IsEntityAt( int pos ); + qboolean IsNumericAt( int pos ); + + const char *GetToken( int pos ); + const char *GetString( int pos ); + int GetInteger( int pos ); + double GetDouble( int pos ); + float GetFloat( int pos ); + Vector GetVector( int pos ); + void *GetPointer( int pos ); + + void AddToken( const char *text ); + void AddTokens( int argc, const char **argv ); + void AddString( const char *text ); + void AddString( str &text ); + void AddInteger( int val ); + void AddDouble( double val ); + void AddFloat( float val ); + void AddVector( Vector &vec ); + void AddPointer( void *ptr ); + }; + +extern Event NullEvent; +extern Event EV_Remove; + +#ifdef EXPORT_TEMPLATE +template class Container; +#endif + +class Listener; + +class Listener : public Class + { + private: + void FloatVarEvent( Event *e ); + void IntVarEvent( Event *e ); + void StringVarEvent( Event *e ); + void CharPtrVarEvent( Event *e ); + void VectorVarEvent( Event *e ); + void ScriptRemove( Event *e ); + + protected: + void FloatVar( Event &e, float *var, float defaultvalue = 0 ); + void IntVar( Event &e, int *var, float defaultvalue = 0 ); + void StringVar( Event &e, str *var, const char *defaultvalue = "" ); + void StringVar( Event &e, char **var, const char *defaultvalue = "" ); + void VectorVar( Event &e, Vector *var, Vector defaultvalue = Vector( 0, 0, 0 ) ); + + qboolean CheckEventFlags( Event *event ); + + public: + CLASS_PROTOTYPE( Listener ); + + ~Listener(); + void Remove( Event *e ); + qboolean ValidEvent( Event &e ); + qboolean ValidEvent( const char *name ); + qboolean EventPending( Event &ev ); + qboolean ProcessEvent( Event *event ); + qboolean ProcessEvent( Event &event ); + void PostEvent( Event *event, float time ); + void PostEvent( Event &event, float time ); + qboolean PostponeEvent( Event &event, float time ); + qboolean PostponeEvent( Event *event, float time ); + void CancelEventsOfType( Event *event ); + void CancelEventsOfType( Event &event ); + void CancelPendingEvents( void ); + qboolean ProcessPendingEvents( void ); + }; + +inline qboolean Event::Exists + ( + const char *command + ) + + { + int num; + str c; + + if ( !commandList ) + { + initCommandList(); + } + + c = command; + num = FindEvent( c ); + if ( num ) + { + return qtrue; + } + + return qfalse; + } + + +inline Event Event::Find + ( + const char *command + ) + + { + int num; + str c; + + if ( !commandList ) + { + initCommandList(); + } + + c = command; + num = FindEvent( c ); + if ( num ) + { + return Event( num ); + } + + return NullEvent; + } + +inline Event Event::Find + ( + str &command + ) + + { + int num; + + if ( !commandList ) + { + initCommandList(); + } + + num = FindEvent( command ); + if ( num ) + { + return Event( num ); + } + + return NullEvent; + } + +inline void Event::SetSource + ( + eventsource_t source + ) + + { + info.source = ( unsigned )source; + } + +inline void Event::SetLineNumber + ( + int linenumber + ) + + { + info.linenumber = linenumber; + } + +inline eventsource_t Event::GetSource + ( + void + ) + + { + return ( eventsource_t )info.source; + } + +inline int Event::GetLineNumber + ( + void + ) + + { + // linenumber does double duty in the case of the console commands + if ( info.source == EV_FROM_SCRIPT ) + { + return info.linenumber; + } + + return 0; + } + +inline str Event::getName + ( + void + ) + + { + assert( name || !eventnum ); + + if ( !name ) + { + return "NULL"; + } + + return name; + } + +inline Event& Event::printInfo + ( + void + ) + + { + cgi.Printf( "event '%s' is number %d\n", getName().c_str(), eventnum ); + return *this; + } + +inline Event::operator int() + { + return eventnum; + } + +inline Event::operator const char *() + { + return getName().c_str(); + } + +inline int Event::NumArgs + ( + void + ) + + { + if ( !data ) + { + return 0; + } + + return ( data->NumObjects() ); + } + +inline void Event::AddToken + ( + const char *text + ) + + { + AddString( text ); + } + +inline void Event::AddTokens + ( + int argc, + const char **argv + ) + + { + int i; + + for( i = 0; i < argc; i++ ) + { + assert( argv[ i ] ); + AddString( argv[ i ] ); + } + } + +inline void Event::AddString + ( + const char *text + ) + + { + if ( !data ) + { + data = new Container; + data->Resize( 1 ); + } + + data->AddObject( str( text ) ); + } + +inline void Event::AddString + ( + str &text + ) + + { + if ( !data ) + { + data = new Container; + data->Resize( 1 ); + } + + data->AddObject( text ); + } + +inline void Event::AddPointer + ( + void *ptr + ) + + { + char text[ 128 ]; + + sprintf( text, "%d", ptr ); + AddString( text ); + } + +inline void Event::AddInteger + ( + int val + ) + + { + char text[ 128 ]; + + sprintf( text, "%d", val ); + AddString( text ); + } + +inline void Event::AddDouble + ( + double val + ) + + { + char text[ 128 ]; + + sprintf( text, "%f", val ); + AddString( text ); + } + +inline void Event::AddFloat + ( + float val + ) + + { + char text[ 128 ]; + + sprintf( text, "%f", val ); + AddString( text ); + } + +inline void Event::AddVector + ( + Vector &vec + ) + + { + char text[ 128 ]; + + sprintf( text, "(%f %f %f)", vec[ 0 ], vec[ 1 ], vec[ 2 ] ); + AddString( text ); + } + +inline const char *Event::GetToken + ( + int pos + ) + + { + if ( !data || ( pos < 1 ) || ( data->NumObjects() < pos ) ) + { + Error( "Index %d out of range.", pos ); + return ""; + } + + return data->ObjectAt( pos ).c_str(); + } + +inline qboolean Listener::ProcessEvent + ( + Event &event + ) + + { + Event *ev; + + ev = new Event( event ); + return ProcessEvent( ev ); + } + +inline void Listener::PostEvent + ( + Event &event, + float time + ) + + { + Event *ev; + + ev = new Event( event ); + PostEvent( ev, time ); + } + +inline qboolean Listener::PostponeEvent + ( + Event *event, + float time + ) + + { + return PostponeEvent( *event, time ); + } + +inline void Listener::CancelEventsOfType + ( + Event &event + ) + + { + CancelEventsOfType( &event ); + } + +#endif \ No newline at end of file diff --git a/source/source/cgame/cg_local.h b/source/source/cgame/cg_local.h new file mode 100644 index 0000000..d485022 --- /dev/null +++ b/source/source/cgame/cg_local.h @@ -0,0 +1,937 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/cgame/cg_local.h $ +// $Revision:: 93 $ +// $Author:: Aldie $ +// $Date:: 8/10/00 9:26p $ +// +// Copyright (C) 1998 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/cgame/cg_local.h $ +// +// 93 8/10/00 9:26p Aldie +// Fixed a lot of memory leaks on exit +// +// 92 7/29/00 9:05p Aldie +// Added targeting to cg_general ents +// +// 91 7/24/00 11:52a Aldie +// Added cg_effectdetail for reducing number of effects +// +// 90 7/22/00 5:50p Markd +// added flushtikis support +// +// 89 7/19/00 9:52p Aldie +// Put ET_EVENTS back in. They will get sent over once, and should get +// processed once on the client. +// +// 88 7/15/00 12:32p Aldie +// Fixed a bug for restarting tempmodels on a save game +// +// 87 7/14/00 9:52p Markd +// added global volume dampener on ambient sound effects for cinematics +// +// 86 7/10/00 11:54p Markd +// added exit level code +// +// 85 7/07/00 2:58p Markd +// fixed alias bug +// +// 84 6/28/00 4:36p Markd +// added debug footsteps code +// +// 83 6/27/00 2:34p Markd +// clear out swipes when restarting +// +// 82 6/17/00 1:54p Markd +// Added server restarted code +// +// 81 6/15/00 8:21p Markd +// Added CleanupCommandManager support +// +// 80 6/14/00 12:14p Markd +// more intel compiler bug fixes +// +// 79 6/14/00 11:18a Markd +// cleaned up code using Intel compiler +// +// 78 6/09/00 10:27a Markd +// got lagometer and CG_2D operations functioning +// +// 77 6/06/00 1:59p Aldie +// Added fadein to marks +// +// 76 6/05/00 3:10p Markd +// Added has_commands check to client side command processing +// +// 75 6/03/00 8:19p Markd +// Added footstep code +// +// 74 6/03/00 10:55a Markd +// Sped up tracing and debug print messages +// +// 73 6/01/00 7:45p Aldie +// Made it so that swipes are removed when client entities are reset. +// +// 72 6/01/00 12:21p Steven +// Improvement to splashes. +// +// 71 5/20/00 5:14p Markd +// Added ITEM special effects +// +// 70 5/17/00 6:55p Markd +// working on 3rd person camera +// +// 69 5/16/00 6:24p Markd +// added cg_traceinfo support +// +// 68 5/09/00 1:33p Markd +// added some lightstyle utilities to SetLightStyle +// +// 67 5/09/00 1:23p Aldie +// Added lightstyle to marks +// +// 66 5/08/00 6:12p Markd +// Added lightstyle support for the client +// +// 65 5/04/00 8:38p Aldie +// Made beam emitters work better +// +// 64 4/26/00 9:05p Markd +// Added client and cgame class commands +// +// 63 4/10/00 11:16a Markd +// added rope code +// +// 62 4/03/00 4:43p Markd +// fixed a teleportation issue +// +// 61 3/31/00 11:49a Markd +// Added sky_portal control +// +// 60 3/14/00 3:22p Aldie +// Changed some client side emitter functionality and added func_emitter +// +// 59 3/06/00 8:07p Markd +// cleaned up unused cvar's +// +// 58 3/04/00 6:03p Aldie +// Made commandManager static +// +// 57 3/04/00 11:45a Markd +// Added light style support and malloc and free to the cgame +// +// 56 3/01/00 1:45p Aldie +// Added some more beam functionality for beau. Added taglist to do beam +// chains. +// +// 55 2/21/00 7:03p Markd +// Added skyalpha support +// +// 54 2/16/00 6:58p Markd +// cleaned up version of new animation system +// +// 53 2/16/00 6:56p Markd +// added new animation system +// +// 52 2/14/00 10:09a Markd +// Tweaked targeting reticles +// +// 51 2/11/00 3:22p Aldie +// Changed swipe code a bit, and added cg_hidetempmodels cvar. +// +// 50 2/08/00 6:24p Markd +// removed unused mediashader +// +// 49 1/27/00 9:06a Markd +// Added watermark +// +// 48 1/19/00 3:18p Aldie +// Moved cg_updateentity +// +// 47 1/15/00 2:39p Aldie +// Changed definition of RemoveClientEntity +// +// 46 1/12/00 8:03p Markd +// Added NextFrameCameraCut and LastCameraFlags +// +// 45 1/12/00 3:17p Aldie +// Fixed beams so that there may be multiple beams on a model +// +// 44 12/11/99 5:51p Markd +// First wave of bug fixes after q3a gold merge +// +// 43 12/11/99 3:37p Markd +// q3a gold checkin, first time +// +// 42 12/09/99 7:42p Jimdose +// got rid of ignore_angles +// +// 41 11/10/99 6:08p Steven +// Fixed the saving of sound origins of child entities. +// +// 40 11/10/99 2:18p Jimdose +// removed some unused variables from centity_t +// added torso animation control variables +// +// 39 11/04/99 3:18p Markd +// fixed fov lerping +// +// 38 11/04/99 10:03a Markd +// complete overhaul of the camera system +// +// 37 10/29/99 7:34p Aldie +// rope stuff +// +// 36 10/29/99 7:29p Steven +// Moved sound stuff into snapshot. +// +// 35 10/28/99 6:05p Steven +// Added a use_angles flag and an offset to the entity attach stuff. +// +// 34 10/27/99 12:18p Markd +// added smooth camera lerping +// +// 33 10/26/99 6:30p Jimdose +// added animation blending to animstate_t +// +// 32 10/25/99 12:19p Jimdose +// made head and torso angles local to each entity +// +// 31 10/22/99 6:29p Aldie +// Fix for beams in the sky +// +// 30 10/21/99 2:51p Aldie +// Added some more beam functions +// +// 29 10/19/99 7:52p Markd +// Removed three part model system +// +// 28 10/19/99 11:57a Aldie +// Added some more beam features +// +// 27 10/18/99 2:01p Aldie +// Fixed compile error +// +// 26 10/13/99 3:26p Aldie +// Various fixes for particles, beams and lensflares +// +// 25 10/08/99 5:47p Aldie +// More beam stuff +// +// 24 10/08/99 5:07p Aldie +// More beam stuff and fix for UI_CenterPrint +// +// 23 10/07/99 3:08p Aldie +// more beam fun +// +// 22 10/07/99 9:56a Markd +// made fov come out of playerstate, not cvar +// +// 21 10/06/99 3:23p Steven +// Added a dumpevents command. +// +// 20 10/05/99 6:01p Aldie +// Added headers +// +// DESCRIPTION: +// The entire cgame module is unloaded and reloaded on each level change, +// so there is NO persistant data between levels on the client side. +// If you absolutely need something stored, it can either be kept +// by the server in the server stored userinfos, or stashed in a cvar. + + +#include "../fgame/q_shared.h" +#include "tr_types.h" +#include "../fgame/bg_public.h" +#include "../qcommon/cm_public.h" +#include "cg_public.h" + +#ifndef __CG_LOCAL_H__ +#define __CG_LOCAL_H__ + +#ifdef __cplusplus +extern "C" + { +#endif + +typedef struct + { + int anim; + int frame; + int oldanim; + int oldframe; + int starttime; + float framelerp; + } lerpstate_t; + +typedef struct + { + lerpstate_t base; + + // crossblend variables + lerpstate_t crossblend; + int crossblend_totaltime; + float crossblend_lerp; + + // global variables + int numframes; + int time_per_frame; + qboolean driven; + + // non-driven variables + int next_evaluate_time; + + // driven variables + int last_driven_time; + vec3_t last_origin; + vec3_t frame_delta; // normalized frame delta + float frame_distance; // float distance till next frame + float current_distance; // current distance traveled + + // command variables + qboolean has_commands; + int last_cmd_frame; + int last_cmd_anim; + int last_cmd_time; + } animstate_t; + +//================================================= + +#define CF_UPDATESWIPE 0x0000001 +#define CF_COMMANDS_PROCESSED 0x0000002 + +// centity_t have a direct corespondence with gentity_t in the game, but +// not all of the gentity_t will be communicated to the client +typedef struct centity_s { + entityState_t currentState; // from cg.frame + entityState_t nextState; // from cg.nextFrame, if available + qboolean teleported; // true if the entity was just teleported + qboolean interpolate; // true if next is valid to interpolate to + qboolean currentValid; // true if cg.frame holds this entity + + int miscTime; + + animstate_t am; // this holds the animation information for this model + animstate_t torso_am; // this holds the torso animation information for this model + + int errorTime; // decay the error from this time + vec3_t errorOrigin; + vec3_t errorAngles; + + qboolean extrapolated; // false if origin / angles is an interpolation + vec3_t rawOrigin; + vec3_t rawAngles; + + vec3_t beamEnd; + + // exact interpolated position of entity on this frame + vec3_t lerpOrigin; + vec3_t lerpAngles; + + sfxHandle_t tikiLoopSound; + float tikiLoopSoundVolume; + float tikiLoopSoundMinDist; + + float color[4]; + float client_color[4]; // the color set by client commands + int clientFlags; + + int splash_last_spawn_time; + int splash_still_count; +} centity_t; + + +//====================================================================== + +// local entities are created as a result of events or predicted actions, +// and live independantly from all server transmitted entities + +#define MAX_VERTS_ON_POLY 10 +#define MAX_MARK_POLYS 64 + +typedef struct markPoly_s + { + struct markPoly_s *prevMark, *nextMark; + int time; + int lightstyle; + qhandle_t markShader; + qboolean alphaFade; // fade alpha instead of rgb + qboolean fadein; + float color[4]; + poly_t poly; + polyVert_t verts[MAX_VERTS_ON_POLY]; + } markPoly_t; + +#define MAX_CUSTOM_SOUNDS 32 +typedef struct { + char name[MAX_QPATH]; + char data[MAX_QPATH]; + + qhandle_t legsModel; + qhandle_t legsSkin; + + qhandle_t torsoModel; + qhandle_t torsoSkin; + + qhandle_t headModel; + qhandle_t headSkin; + + struct sfx_s *sounds[MAX_CUSTOM_SOUNDS]; + + vec3_t color; + vec3_t color2; +} clientInfo_t; + + +//====================================================================== + +// all cg.stepTime, cg.duckTime, cg.landTime, etc are set to cg.time when the action +// occurs, and they will have visible effects for #define STEP_TIME or whatever msec after + +typedef struct { + int clientFrame; // incremented each frame + + qboolean demoPlayback; + qboolean levelShot; // taking a level menu screenshot + + // there are only one or two snapshot_t that are relevent at a time + int latestSnapshotNum; // the number of snapshots the client system has received + int latestSnapshotTime; // the time from latestSnapshotNum, so we don't need to read the snapshot yet + snapshot_t *snap; // cg.snap->serverTime <= cg.time + snapshot_t *nextSnap; // cg.nextSnap->serverTime > cg.time, or NULL + snapshot_t activeSnapshots[2]; + + float frameInterpolation; // (float)( cg.time - cg.frame->serverTime ) / (cg.nextFrame->serverTime - cg.frame->serverTime) + + qboolean thisFrameTeleport; + qboolean nextFrameTeleport; + qboolean nextFrameCameraCut; + + int frametime; // cg.time - cg.oldTime + + int time; // this is the time value that the client + // is rendering at. + int oldTime; // time at last frame, used for missile trails and prediction checking + + int physicsTime; // either cg.snap->time or cg.nextSnap->time + + int timelimitWarnings; // 5 min, 1 min, overtime + + qboolean renderingThirdPerson; // during deaths, chasecams, etc + + // prediction state + qboolean hyperspace; // true if prediction has hit a trigger_teleport + playerState_t predicted_player_state; + qboolean validPPS; // clear until the first call to CG_PredictPlayerState + int predictedErrorTime; + vec3_t predictedError; + + float stepChange; // for stair up smoothing + int stepTime; + + float duckChange; // for duck viewheight smoothing + int duckTime; + + float landChange; // for landing hard + int landTime; + + // input state sent to server + int weaponSelect; + + // auto rotating items + vec3_t autoAngles; + vec3_t autoAxis[3]; + vec3_t autoAnglesSlow; + vec3_t autoAxisSlow[3]; + vec3_t autoAnglesFast; + vec3_t autoAxisFast[3]; + + // view rendering + refdef_t refdef; + vec3_t playerHeadPos; // position of the players head + vec3_t refdefViewAngles; // will be converted to refdef.viewaxis + vec3_t currentViewPos; // current position of the camera + vec3_t currentViewAngles; // current angles of the camera + + float SoundOrg[3]; // position from where sound should be played + vec3_t SoundAxis[3]; // axis from where sound should be played + + int lastCameraTime; // last time the camera moved + float lerpCameraTime; // is the camera currently lerping from camera to view or vice versa + qboolean inCameraView; // are we currently in a camera view + vec3_t camera_origin; // lerped camera_origin + vec3_t camera_angles; // lerped camera_angles + float camera_fov; // lerped camera_fov + int lastCameraFlags; // last Camera flags for interpolation testing + + // zoom key + qboolean zoomed; + int zoomTime; + float zoomSensitivity; + + // information screen text during loading + char infoScreenText[MAX_STRING_CHARS]; + qboolean showInformation; + + // scoreboard + int scoresRequestTime; + int numScores; + int teamScores[2]; + qboolean showScores; + int scoreFadeTime; + char killerName[MAX_NAME_LENGTH]; + + // centerprinting + int centerPrintTime; + int centerPrintCharWidth; + int centerPrintY; + char centerPrint[1024]; + int centerPrintLines; + + // low ammo warning state + qboolean lowAmmoWarning; // 1 = low, 2 = empty + + // kill timers for carnage reward + int lastKillTime; + + // crosshair client ID + int crosshairClientNum; + int crosshairClientTime; + + float crosshair_offset; + + // powerup active flashing + int powerupActive; + int powerupTime; + + // attacking player + int attackerTime; + + // warmup countdown + int warmupCount; + + //========================== + + int itemPickup; + int itemPickupTime; + int itemPickupBlendTime; // the pulse around the crosshair is timed seperately + + int weaponSelectTime; + int weaponAnimation; + int weaponAnimationTime; + + // blend blobs + float damageTime; + float damageX, damageY, damageValue; + + // status bar head + float headYaw; + float headEndPitch; + float headEndYaw; + int headEndTime; + float headStartPitch; + float headStartYaw; + int headStartTime; + + // view movement + float v_dmg_time; + float v_dmg_pitch; + float v_dmg_roll; + + vec3_t kick_angles; // weapon kicks + vec3_t kick_origin; + + // temp working variables for player view + float bobfracsin; + int bobcycle; + float xyspeed; + + // development tool + refEntity_t testModelEntity; + char testModelName[MAX_QPATH]; + qboolean testGun; + + // farplane parameters + float farplane_distance; + vec3_t farplane_color; + qboolean farplane_cull; + + // portal sky parameters + qboolean sky_portal; + float sky_alpha; + vec3_t sky_origin; + vec3_t sky_axis[3]; // rotation vectors +} cg_t; + + +typedef struct { + qhandle_t backTileShader; + qhandle_t lagometerShader; + qhandle_t shadowMarkShader; + qhandle_t wakeMarkShader; + qhandle_t leftTargetShader; + qhandle_t rightTargetShader; + qhandle_t itemRingShader; + qhandle_t leftTargetModel; + qhandle_t rightTargetModel; + qhandle_t pausedShader; + qhandle_t levelExitShader; + } media_t; + +// The client game static (cgs) structure hold everything +// loaded or calculated from the gamestate. It will NOT +// be cleared when a tournement restart is done, allowing +// all clients to begin playing instantly +typedef struct { + gameState_t gameState; // gamestate from server + glconfig_t glconfig; // rendering configuration + float screenXScale; // derived from glconfig + float screenYScale; + float screenXBias; + + int serverCommandSequence; // reliable command stream counter + int processedSnapshotNum;// the number of snapshots cgame has requested + + qboolean localServer; // detected on startup by checking sv_running + int levelStartTime; // time that game was started + + // parsed from serverinfo + gametype_t gametype; + int dmflags; + int teamflags; + int fraglimit; + int timelimit; + int maxclients; + int cinematic; + char mapname[MAX_QPATH]; + + // + // locally derived information from gamestate + // + qhandle_t model_draw[MAX_MODELS]; + sfxHandle_t sound_precache[MAX_SOUNDS]; + int numInlineModels; + qhandle_t inlineDrawModel[MAX_MODELS]; + vec3_t inlineModelMidpoints[MAX_MODELS]; + + // TIKI handles for all models + int model_tiki[ MAX_MODELS ]; + + clientInfo_t clientinfo[MAX_CLIENTS]; + + media_t media; + } cgs_t; + +//============================================================================== + +extern cgs_t cgs; +extern cg_t cg; +extern clientGameImport_t cgi; +extern centity_t cg_entities[MAX_GENTITIES]; +extern markPoly_t cg_markPolys[MAX_MARK_POLYS]; + +extern cvar_t *cg_animSpeed; +extern cvar_t *cg_debugAnim; +extern cvar_t *cg_debugAnimWatch; +extern cvar_t *cg_errorDecay; +extern cvar_t *cg_nopredict; +extern cvar_t *cg_showmiss; +extern cvar_t *cg_addMarks; +extern cvar_t *cg_viewsize; +extern cvar_t *cg_3rd_person; +extern cvar_t *cg_syncronousClients; +extern cvar_t *cg_stereoSeparation; +extern cvar_t *cg_stats; +extern cvar_t *cg_lagometer; +extern cvar_t *paused; +extern cvar_t *r_lerpmodels; +extern cvar_t *cg_cameraheight; +extern cvar_t *cg_cameradist; +extern cvar_t *cg_cameraverticaldisplacement; +extern cvar_t *cg_camerascale; +extern cvar_t *cg_shadows; +extern cvar_t *cg_hidetempmodels; +extern cvar_t *cg_traceinfo; +extern cvar_t *cg_debugFootsteps; + +// +// cg_main.c +// +void CG_ProcessConfigString( int num ); +const char *CG_ConfigString( int index ); +void CG_AddToTeamChat( const char *str ); +void CG_NewClientinfo( int clientNum ); +sfxHandle_t CG_CustomSound( int entityNum, const char *soundName ); +int CG_CrosshairPlayer( void ); +int CG_LastAttacker( void ); +void CG_Init( clientGameImport_t *imported, int serverMessageNum, int serverCommandSequence ); +void CG_Shutdown( void ); +void CG_ServerRestarted( void ); + +// +// cg_modelanim.cpp +// +void CG_ModelAnim( centity_t *cent ); +void CG_EntityTargeted( int tikihandle, centity_t *cent, refEntity_t *model ); +void CG_ClearModelAnimation( int tikihandle, animstate_t * state, int animationNumber, int time, vec3_t origin, int entnum ); +void CG_AttachEntity( refEntity_t *entity, refEntity_t *parent, int tikihandle, int tagnum, qboolean use_angles, vec3_t attach_offset ); + +// +// cg_commands.cpp +// +void CG_Event( centity_t *cent ); +void CG_UpdateEntity( int tikihandle, refEntity_t *ent, centity_t *cent ); +void CG_RemoveClientEntity( int number, int tikihandle, centity_t *cent ); +void CG_UpdateTestEmitter( void ); +void CG_AddTempModels( void ); +void CG_ResetTempModels( void ); +void CG_InitializeCommandManager( void ); +void CG_ProcessInitCommands( int tikihandle ); +qboolean CG_Command_ProcessFile( const char * filename, qboolean quiet ); +void CG_RestartCommandManager( int timedelta ); +void CG_FlushCommandManager( void ); +void CG_ProcessEntityCommands( int tikihandle, + int frame, + int anim, + int entnum, + refEntity_t *ent, + centity_t *cent + ); +void CG_ClientCommands + ( + int tikihandle, + int frame, + int anim, + animstate_t *state, + refEntity_t *ent, + centity_t *cent + ); + +void CG_Splash( centity_t *cent ); + +void CG_EventList_f( void ); +void CG_EventHelp_f( void ); +void CG_DumpEventHelp_f( void ); +void CG_PendingEvents_f( void ); +void CG_ClassList_f( void ); +void CG_ClassTree_f( void ); +void CG_ClassEvents_f( void ); +void CG_DumpClassEvents_f( void ); +void CG_DumpAllClasses_f( void ); + +void L_InitEvents( void ); +void L_ShutdownEvents( void ); + + +// +// cg_view.c +// +void CG_TestModel_f (void); +void CG_TestGun_f (void); +void CG_TestModelNextFrame_f (void); +void CG_TestModelPrevFrame_f (void); +void CG_TestModelNextSkin_f (void); +void CG_TestModelPrevSkin_f (void); + +void CG_ZoomDown_f( void ); +void CG_ZoomUp_f( void ); + +void CG_DrawActiveFrame( int serverTime, stereoFrame_t stereoView, qboolean demoPlayback ); + + +// +// cg_drawtools.c +// +void CG_AdjustFrom640( float *x, float *y, float *w, float *h ); +void CG_TileClear( void ); +void CG_Draw2D( void ); + +// +// cg_draw.c +// +void CG_AddLagometerFrameInfo( void ); +void CG_AddLagometerSnapshotInfo( snapshot_t *snap ); +void CG_CenterPrint( const char *str, int y, int charWidth ); +void CG_DrawHead( float x, float y, float w, float h, int clientNum, vec3_t headAngles ); +void CG_DrawActive( stereoFrame_t stereoView ); +void CG_DrawFlagModel( float x, float y, float w, float h, int team ); + +// +// cg_predict.c +// +void CG_BuildSolidList( void ); +int CG_PointContents( const vec3_t point, int passEntityNum ); +void CG_Trace( trace_t *result, const vec3_t start, const vec3_t mins, + const vec3_t maxs, const vec3_t end, int skipNumber, + int mask, qboolean cylinder, qboolean cliptoentities, const char * description ); +void CG_PredictPlayerState( void ); + + +// +// cg_ents.c +// +void CG_SetEntitySoundPosition( centity_t *cent ); +void CG_AddPacketEntities( void ); +void CG_Beam( centity_t *cent ); +void CG_AdjustPositionForMover( const vec3_t in, int moverNum, int fromTime, int toTime, vec3_t out ); + +void CG_PositionEntityOnTag( refEntity_t *entity, const refEntity_t *parent, + qhandle_t parentModel, char *tagName ); +void CG_PositionRotatedEntityOnTag( refEntity_t *entity, const refEntity_t *parent, + qhandle_t parentModel, char *tagName ); +void CG_GetOrigin( centity_t *cent, vec3_t origin ); +void CG_EntityEffects( centity_t *cent ); + +// +// cg_marks.c +// +void CG_InitMarkPolys( void ); +void CG_AddMarks( void ); +void CG_ImpactMark( qhandle_t markShader, + const vec3_t origin, const vec3_t dir, + float orientation, + float r, float g, float b, float a, + qboolean alphaFade, + float radius, qboolean temporary, + int lightstyle, qboolean fadein ); + +// +// cg_snapshot.c +// +void CG_ProcessSnapshots( void ); + +// +// cg_consolecmds.c +// +qboolean CG_ConsoleCommand( void ); +void CG_InitConsoleCommands( void ); +void CG_AddTestModel( void ); + +// +// cg_servercmds.c +// +void CG_ExecuteNewServerCommands( int latestSequence ); +void CG_ParseServerinfo( void ); + +// +// cg_playerstate.c +// +void CG_TransitionPlayerState( playerState_t *ps, playerState_t *ops ); + +// +// cg_player.cpp +// +void CG_ResetPlayerEntity( centity_t *cent ); +void CG_Player( centity_t *cent ); + +// +// cg_sound.cpp +// +void CG_ProcessSound( server_sound_t *sound ); + +// +// cg_beam.cpp +// +void CG_AddBeams( void ); +void CG_MultiBeamBegin( void ); +void CG_MultiBeamAddPoints + ( + vec3_t start, + vec3_t end, + int numsegments, + int flags, + float minoffset, + float maxoffset, + qboolean addstartpoint + ); +void CG_MultiBeamEnd + ( + float scale, + int renderfx, + const char *beamshadername, + byte modulate[4], + int flags, + int owner, + float life + ); +void CG_CreateBeam + ( + vec3_t start, + vec3_t dir, + int owner, + qhandle_t hModel, + float alpha, + float scale, + int flags, + float length, + int life, + qboolean create, + vec3_t endpointvec, + int min_offset, + int max_offset, + int overlap, + int subdivisions, + int delay, + const char *beamshader, + byte modulate[4], + int numspherebeams, + float sphereradius, + int toggledelay, + float endalpha, + int renderfx, + const char *name + ); + +void CG_KillBeams( int entity_number ); +void CG_Rope( centity_t *cent ); +void CG_RestartBeams( int timedelta ); + + +// +// cg_nature.cpp +// +void CG_Emitter( centity_t *cent ); + +// +// cg_testemitter.cpp +void CG_InitTestEmitter( void ); +void CG_TestEmitter_f( void ); +void CG_DumpEmitter_f( void ); +void CG_InitializeClientEmitters( void ); + +// +// cg_beam.cpp +void RemoveBeamList( int owner ); +void CG_MultiBeam( centity_t *cent ); + +// +// cg_lightstyles.cpp +void CG_SetLightStyle( int num, const char *s ); +#ifdef __cplusplus +qboolean CG_LightStyleColor( int style, int realtime, float color[4], qboolean clamp = qfalse ); +#else +qboolean CG_LightStyleColor( int style, int realtime, float color[4], qboolean clamp ); +#endif +void CG_ClearLightStyles( void ); +int CG_RegisterLightStyle( const char * name ); + +// +// cg_specialfx.cpp +void CG_Footstep( centity_t * ent, float volume ); + +// +// cg_swipe.cpp +void CG_ClearSwipes( void ); + + +#ifdef __cplusplus +} +#endif + +#endif // __CG_LOCAL_H__ + diff --git a/source/source/cgame/cg_main.c b/source/source/cgame/cg_main.c new file mode 100644 index 0000000..3827011 --- /dev/null +++ b/source/source/cgame/cg_main.c @@ -0,0 +1,611 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/cgame/cg_main.c $ +// $Revision:: 51 $ +// $Author:: Aldie $ +// $Date:: 7/24/00 9:58p $ +// +// Copyright (C) 1998 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/cgame/cg_main.c $ +// +// 51 7/24/00 9:58p Aldie +// Fix for backtile +// +// 50 7/24/00 11:52a Aldie +// Added cg_effectdetail for reducing number of effects +// +// 49 7/16/00 11:01p Markd +// Added updateLoadingScreen calls +// +// 48 7/15/00 12:32p Aldie +// Fixed a bug for restarting tempmodels on a save game +// +// 47 7/10/00 11:54p Markd +// added exit level code +// +// 46 7/07/00 2:58p Markd +// fixed alias bug +// +// 45 6/28/00 4:36p Markd +// added debug footsteps code +// +// 44 6/27/00 2:34p Markd +// clear out swipes when restarting +// +// 43 6/26/00 9:36p Markd +// cleared out blood marks at the beginning of the level and also made sure +// that snapshots from previous games are not sent to the cgame +// +// 42 6/17/00 1:54p Markd +// Added server restarted code +// +// 41 6/14/00 12:14p Markd +// more intel compiler bug fixes +// +// 40 6/09/00 10:27a Markd +// got lagometer and CG_2D operations functioning +// +// 39 5/20/00 5:14p Markd +// Added ITEM special effects +// +// 38 5/16/00 6:24p Markd +// added cg_traceinfo support +// +// 37 5/11/00 11:06a Steven +// Changed the water ripple shader. +// +// 36 5/08/00 6:12p Markd +// Added lightstyle support for the client +// +// 35 5/02/00 7:20p Markd +// changed camera defaults +// +// 34 3/31/00 11:48a Markd +// Added sky_portal control +// +// 33 3/06/00 8:07p Markd +// cleaned up unused cvar's +// +// 32 3/06/00 1:16p Markd +// fixed bug where sounds were overflowing their configstring range +// +// 31 3/04/00 12:23p Markd +// Fixed some lightstyle bugs +// +// 30 3/04/00 11:45a Markd +// Added light style support and malloc and free to the cgame +// +// 29 2/21/00 7:03p Markd +// Added skyalpha support +// +// 28 2/14/00 10:09a Markd +// Tweaked targeting reticles +// +// 27 2/11/00 3:22p Aldie +// Changed swipe code a bit, and added cg_hidetempmodels cvar. +// +// 26 2/08/00 6:24p Markd +// removed unused mediashader +// +// 25 1/28/00 6:11p Jimdose +// added CG_GetRendererConfig +// +// 24 1/27/00 9:06a Markd +// Added watermark +// +// 23 1/06/00 11:10p Jimdose +// removed unused commands +// +// 22 12/11/99 5:51p Markd +// First wave of bug fixes after q3a gold merge +// +// 21 12/11/99 3:37p Markd +// q3a gold checkin, first time +// +// 20 10/29/99 7:23p Steven +// Moved sound stuff into snapshot. +// +// 19 10/07/99 9:56a Markd +// made fov come out of playerstate, not cvar +// +// 18 10/05/99 6:01p Aldie +// Added headers +// +// DESCRIPTION: +// Init functions for the cgame + +#include "cg_local.h" + +#ifdef _WIN32 +#include +#endif + +clientGameImport_t cgi; + +cg_t cg; +cgs_t cgs; +centity_t cg_entities[MAX_GENTITIES]; + +cvar_t *cg_animSpeed; +cvar_t *cg_debugFootsteps; +cvar_t *cg_debugAnim; +cvar_t *cg_debugAnimWatch; +cvar_t *cg_errorDecay; +cvar_t *cg_nopredict; +cvar_t *cg_showmiss; +cvar_t *cg_addMarks; +cvar_t *cg_viewsize; +cvar_t *cg_3rd_person; +cvar_t *cg_syncronousClients; +cvar_t *cg_stats; +cvar_t *cg_hidetempmodels; +cvar_t *paused; +cvar_t *r_lerpmodels; +cvar_t *cg_stereoSeparation; +cvar_t *cg_lagometer; +cvar_t *cg_cameraheight; +cvar_t *cg_cameradist; +cvar_t *cg_camerascale; +cvar_t *cg_cameraverticaldisplacement; +cvar_t *cg_traceinfo; +cvar_t *cg_shadows; +cvar_t *developer; + +/* +================= +CG_RegisterCvars +================= +*/ +void CG_RegisterCvars( void ) + { + cvar_t * temp; + + cg_viewsize = cgi.Cvar_Get( "viewsize", "100", CVAR_ARCHIVE ); + cg_addMarks = cgi.Cvar_Get( "cg_marks", "1", CVAR_ARCHIVE ); + cg_animSpeed = cgi.Cvar_Get( "cg_animspeed", "1", CVAR_CHEAT ); + cg_debugAnim = cgi.Cvar_Get( "cg_debuganim", "0", CVAR_CHEAT ); + cg_debugAnimWatch = cgi.Cvar_Get( "cg_debuganimwatch", "0", CVAR_CHEAT ); + cg_errorDecay = cgi.Cvar_Get( "cg_errordecay", "100", 0 ); + cg_nopredict = cgi.Cvar_Get( "cg_nopredict", "0", 0 ); + cg_showmiss = cgi.Cvar_Get( "cg_showmiss", "0", 0 ); + cg_stats = cgi.Cvar_Get( "cg_stats", "0", 0 ); + cg_hidetempmodels = cgi.Cvar_Get( "cg_hidetempmodels", "0", 0 ); + cg_syncronousClients = cgi.Cvar_Get( "g_syncronousClients", "0", 0 ); + cg_stereoSeparation = cgi.Cvar_Get( "cg_stereosep", "0.4", CVAR_ARCHIVE ); + cg_lagometer = cgi.Cvar_Get( "cg_lagometer", "0", 0 ); + paused = cgi.Cvar_Get( "paused", "0", 0 ); + r_lerpmodels = cgi.Cvar_Get( "r_lerpmodels", "1", 0 ); + cg_3rd_person = cgi.Cvar_Get( "cg_3rd_person", "1", 0 ); + cg_cameraheight = cgi.Cvar_Get ("cg_cameraheight", "18", CVAR_ARCHIVE); + cg_cameradist = cgi.Cvar_Get ("cg_cameradist" , "120", CVAR_ARCHIVE); + cg_cameraverticaldisplacement = cgi.Cvar_Get ("cg_cameraverticaldisplacement" , "-2", CVAR_ARCHIVE); + cg_camerascale = cgi.Cvar_Get ("cg_camerascale" , "0.3", CVAR_ARCHIVE); + cg_traceinfo = cgi.Cvar_Get ("cg_traceinfo" , "0", CVAR_ARCHIVE); + cg_debugFootsteps = cgi.Cvar_Get( "cg_debugfootsteps", "0", CVAR_CHEAT ); + + cg_shadows = cgi.Cvar_Get( "cg_shadows", "1", 0 ); + developer = cgi.Cvar_Get( "developer", "0", 0 ); + + // see if we are also running the server on this machine + temp = cgi.Cvar_Get( "sv_running", "0", 0 ); + cgs.localServer = temp->integer; + } + +/* +================= +CG_RegisterSounds + +called during a precache command +================= +*/ +void CG_RegisterSounds( void ) { + int i; + + // process the global defs + for ( i = 0; i < 10; i++ ) + { + char filename[ MAX_QPATH ]; + + Com_sprintf( filename, sizeof( filename ), "global/global%i.scr", i ); + if ( !CG_Command_ProcessFile( filename, qtrue ) ) + { + break; + } + } +} + +/* +================ +CG_ProcessConfigString +================ +*/ +void CG_ProcessConfigString( int num ) + { + const char *str; + + if ( num == CS_SOUNDTRACK ) + { + cgi.UpdateLoadingScreen(); + str = CG_ConfigString( num ); + cgi.MUSIC_NewSoundtrack( str ); + } + if ( num == CS_FOGINFO ) + { + str = CG_ConfigString( num ); + sscanf + ( + str, + "%d %f %f %f %f", + &cg.farplane_cull, + &cg.farplane_distance, + &cg.farplane_color[ 0 ], + &cg.farplane_color[ 1 ], + &cg.farplane_color[ 2 ] + ); + } + else if ( num == CS_SKYINFO ) + { + str = CG_ConfigString( num ); + sscanf + ( + str, + "%f %d", + &cg.sky_alpha, + &cg.sky_portal + ); + } + else if ( num == CS_SERVERINFO ) + { + CG_ParseServerinfo(); + } + else if ( num == CS_LEVEL_START_TIME ) + { + str = CG_ConfigString( num ); + cgs.levelStartTime = atoi( str ); + } + else if ( num >= CS_MODELS && num < CS_MODELS+MAX_MODELS ) + { + str = CG_ConfigString( num ); + if ( str && str[ 0 ] ) + { + cgs.model_draw[ num-CS_MODELS ] = cgi.R_RegisterModel( str ); + if ( strstr( str, ".tik" ) ) + { + cgs.model_tiki[ num-CS_MODELS ] = cgi.TIKI_GetHandle( cgs.model_draw[ num-CS_MODELS ] ); + if ( cgs.model_tiki[ num-CS_MODELS ] >= 0 ) + CG_ProcessInitCommands( cgs.model_tiki[ num-CS_MODELS ] ); + } + cgi.UpdateLoadingScreen(); + } + } + else if ( num >= CS_SOUNDS && num < CS_SOUNDS+MAX_SOUNDS ) + { + str = CG_ConfigString( num ); + if ( str && str[ 0 ] && ( str[0] != '*' ) ) + { + cgs.sound_precache[ num-CS_SOUNDS] = cgi.S_RegisterSound( str ); + cgi.UpdateLoadingScreen(); + } + } + else if ( num >= CS_LIGHTSTYLES && num < CS_LIGHTSTYLES+MAX_LIGHTSTYLES ) + { + str = CG_ConfigString( num ); + CG_SetLightStyle( num - CS_LIGHTSTYLES, str ); + } + } + +//=================================================================================== + +/* +================= +CG_PrepRefresh + +Call before entering a new level, or after changing renderers +This function may execute for a couple of minutes with a slow disk. +================= +*/ +void CG_PrepRefresh( void ) + { + int i; + + memset( &cg.refdef, 0, sizeof( cg.refdef ) ); + + cgi.R_ClearScene(); + + // clear any tiki handles to bad values + memset( &cgs.model_tiki, -1, sizeof( cgs.model_tiki ) ); + + cgi.R_LoadWorldMap( cgs.mapname ); + + // register the inline models + cgs.numInlineModels = cgi.CM_NumInlineModels(); + + for ( i=1; i= MAX_CONFIGSTRINGS ) { + cgi.Error( ERR_DROP, "CG_ConfigString: bad index: %i", index ); + } + return cgs.gameState.stringData + cgs.gameState.stringOffsets[ index ]; +} + +//================================================================== + + +void CG_GetRendererConfig( void ) + { + // get the rendering configuration from the client system + cgi.GetGlconfig( &cgs.glconfig ); + cgs.screenXScale = cgs.glconfig.vidWidth / 640.0; + cgs.screenYScale = cgs.glconfig.vidHeight / 480.0; + } + +/* +====================== +CG_GameStateReceived + +Displays the info screen while loading media +====================== +*/ +void CG_GameStateReceived( void ) + { + const char *s; + + // clear everything + memset( &cg, 0, sizeof( cg ) ); + memset( cg_entities, 0, sizeof(cg_entities) ); + + // clear the light styles + CG_ClearLightStyles(); + + // get the rendering configuration from the client system + CG_GetRendererConfig(); + + // get the gamestate from the client system + cgi.GetGameState( &cgs.gameState ); + + // check version + s = CG_ConfigString( CS_GAME_VERSION ); + if ( strcmp( s, GAME_VERSION ) ) { + cgi.Error( ERR_DROP, "Client/Server game mismatch: %s/%s", GAME_VERSION, s ); + } + + s = CG_ConfigString( CS_LEVEL_START_TIME ); + cgs.levelStartTime = atoi( s ); + + CG_ParseServerinfo(); + + // load the new map + cgi.CM_LoadMap( cgs.mapname ); + + CG_InitMarkPolys(); + + CG_RegisterSounds(); + + CG_PrepRefresh(); + + // remove the last loading update + cg.infoScreenText[0] = 0; + } + + +/* +====================== +CG_ServerRestarted + +The server has beeen restarted, adjust our cgame data accordingly +====================== +*/ +void CG_ServerRestarted( void ) + { + int timedelta; + const char * s; + + s = CG_ConfigString( CS_LEVEL_START_TIME ); + cgs.levelStartTime = atoi( s ); + + CG_ParseServerinfo(); + + cg.thisFrameTeleport = qtrue; + cg.lastCameraTime = -1; + timedelta = cg.oldTime - cg.time; + // free up any temp models currently spawned + CG_RestartCommandManager( timedelta ); + // restart beams + CG_RestartBeams( timedelta ); + // get rid of left over decals from the last game + CG_InitMarkPolys(); + // clear all the swipes + CG_ClearSwipes(); + // Reset tempmodels + CG_ResetTempModels(); + } + +/* +================= +CG_Init + +Called after every level change or subsystem restart +================= +*/ +void CG_Init( clientGameImport_t *imported, int serverMessageNum, int serverCommandSequence ) { + + cgi = *imported; + + memset( &cg, 0, sizeof( cg ) ); + memset( &cgs, 0, sizeof( cgs ) ); + + cgs.processedSnapshotNum = serverMessageNum; + cgs.serverCommandSequence = serverCommandSequence; + + CG_RegisterCvars(); + + L_InitEvents(); + + // init swapping for endian conversion + Swap_Init (); + + CG_InitializeCommandManager(); + + CG_GameStateReceived(); + + CG_InitConsoleCommands(); + } + +/* +================= +CG_Shutdown + +Called before every level change or subsystem restart +================= +*/ +void CG_Shutdown( void ) + { + L_ShutdownEvents(); + // some mods may need to do cleanup work here, + // like closing files or archiving session data + } + + +/* +================ +GetCGameAPI + +The only exported function from this module +================ +*/ +clientGameExport_t *GetCGameAPI( void ) + { + static clientGameExport_t cge; + + cge.CG_Init = CG_Init; + cge.CG_DrawActiveFrame = CG_DrawActiveFrame; + cge.CG_Shutdown = CG_Shutdown; + cge.CG_ConsoleCommand = CG_ConsoleCommand; + cge.CG_GetRendererConfig = CG_GetRendererConfig; + cge.CG_Draw2D = CG_Draw2D; + + return &cge; + } + +/* +===================== +CG_DrawActive + +Perform all drawing needed to completely fill the screen +===================== +*/ +void CG_DrawActive( stereoFrame_t stereoView ) + { + float separation; + vec3_t baseOrg; + + switch ( stereoView ) + { + case STEREO_CENTER: + separation = 0; + break; + case STEREO_LEFT: + separation = -cg_stereoSeparation->value / 2; + break; + case STEREO_RIGHT: + separation = cg_stereoSeparation->value / 2; + break; + default: + separation = 0; + cgi.Error( ERR_DROP, "CG_DrawActive: Undefined stereoView" ); + } + + // clear around the rendered view if sized down + CG_TileClear(); + + // offset vieworg appropriately if we're doing stereo separation + VectorCopy( cg.refdef.vieworg, baseOrg ); + if ( separation != 0 ) + { + VectorMA( cg.refdef.vieworg, -separation, cg.refdef.viewaxis[1], cg.refdef.vieworg ); + } + + // draw 3D view + cgi.R_RenderScene( &cg.refdef ); + + // restore original viewpoint if running stereo + if ( separation != 0 ) + { + VectorCopy( baseOrg, cg.refdef.vieworg ); + } + } + +#ifndef CGAME_HARD_LINKED +// this is only here so the functions in q_shared.c and bg_*.c can link (FIXME) + +void Com_Error( int level, const char *error, ... ) { + va_list argptr; + char text[1024]; + + va_start (argptr, error); + vsprintf (text, error, argptr); + va_end (argptr); + + cgi.Error( level, "%s", text); +} + +void Com_Printf( const char *msg, ... ) { + va_list argptr; + char text[1024]; + + va_start (argptr, msg); + vsprintf (text, msg, argptr); + va_end (argptr); + + cgi.Printf( "%s", text); +} + +#endif + + diff --git a/source/source/cgame/cg_marks.c b/source/source/cgame/cg_marks.c new file mode 100644 index 0000000..295893b --- /dev/null +++ b/source/source/cgame/cg_marks.c @@ -0,0 +1,388 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/cgame/cg_marks.c $ +// $Revision:: 11 $ +// $Author:: Aldie $ +// $Date:: 6/27/00 7:17p $ +// +// Copyright (C) 1998 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/cgame/cg_marks.c $ +// +// 11 6/27/00 7:17p Aldie +// Increase projection of point for impact mark +// +// 10 6/06/00 1:59p Aldie +// Added fadein to marks +// +// 9 5/09/00 1:33p Markd +// added some lightstyle utilities to SetLightStyle +// +// 8 5/09/00 1:29p Aldie +// Added lightstyles to impact marks +// +// 7 2/10/00 8:05p Aldie +// Changed marks again +// +// 6 2/10/00 6:59p Aldie +// Made some changes to bulletholes. +// +// 5 12/11/99 3:37p Markd +// q3a gold checkin, first time +// +// 4 10/22/99 6:29p Aldie +// Fix for beams in the sky +// +// 3 10/05/99 6:01p Aldie +// Added headers +// +// DESCRIPTION: +// wall marks + +#include "cg_local.h" + +/* +=================================================================== + +MARK POLYS + +=================================================================== +*/ + + +markPoly_t cg_activeMarkPolys; // double linked list +markPoly_t *cg_freeMarkPolys; // single linked list +markPoly_t cg_markPolys[MAX_MARK_POLYS]; + +/* +=================== +CG_InitMarkPolys + +This is called at startup and for tournement restarts +=================== +*/ +void CG_InitMarkPolys( void ) { + int i; + + memset( cg_markPolys, 0, sizeof(cg_markPolys) ); + + cg_activeMarkPolys.nextMark = &cg_activeMarkPolys; + cg_activeMarkPolys.prevMark = &cg_activeMarkPolys; + cg_freeMarkPolys = cg_markPolys; + for ( i = 0 ; i < MAX_MARK_POLYS - 1 ; i++ ) { + cg_markPolys[i].nextMark = &cg_markPolys[i+1]; + } +} + + +/* +================== +CG_FreeMarkPoly +================== +*/ +void CG_FreeMarkPoly( markPoly_t *le ) { + if ( !le->prevMark ) { + cgi.Error( ERR_DROP, "CG_FreeLocalEntity: not active" ); + } + + // remove from the doubly linked active list + le->prevMark->nextMark = le->nextMark; + le->nextMark->prevMark = le->prevMark; + + // the free list is only singly linked + le->nextMark = cg_freeMarkPolys; + cg_freeMarkPolys = le; +} + +/* +=================== +CG_AllocMark + +Will allways succeed, even if it requires freeing an old active mark +=================== +*/ +markPoly_t *CG_AllocMark( void ) { + markPoly_t *le; + + if ( !cg_freeMarkPolys ) { + int time; + // no free entities, so free the one at the end of the chain + // remove the oldest active entity + time = cg_activeMarkPolys.prevMark->time; + while (cg_activeMarkPolys.prevMark && time == cg_activeMarkPolys.prevMark->time) { + CG_FreeMarkPoly( cg_activeMarkPolys.prevMark ); + } + } + + le = cg_freeMarkPolys; + cg_freeMarkPolys = cg_freeMarkPolys->nextMark; + + memset( le, 0, sizeof( *le ) ); + + // link into the active list + le->nextMark = cg_activeMarkPolys.nextMark; + le->prevMark = &cg_activeMarkPolys; + cg_activeMarkPolys.nextMark->prevMark = le; + cg_activeMarkPolys.nextMark = le; + return le; +} + + + +/* +================= +CG_ImpactMark + +origin should be a point within a unit of the plane +dir should be the plane normal + +temporary marks will not be stored or randomly oriented, but immediately +passed to the renderer. +================= +*/ +#define MAX_MARK_FRAGMENTS 128 +#define MAX_MARK_POINTS 384 + +void CG_ImpactMark + ( + qhandle_t markShader, + const vec3_t origin, + const vec3_t dir, + float orientation, + float red, + float green, + float blue, + float alpha, + qboolean alphaFade, + float radius, + qboolean temporary, + int lightstyle, + qboolean fadein + ) + + { + vec3_t axis[3]; + float texCoordScale; + vec3_t originalPoints[4]; + byte colors[4]; + int i, j; + int numFragments; + markFragment_t markFragments[MAX_MARK_FRAGMENTS], *mf; + vec3_t markPoints[MAX_MARK_POINTS]; + vec3_t projection; + + if ( !cg_addMarks->integer ) { + return; + } + + if ( radius <= 0 ) { + cgi.Error( ERR_DROP, "CG_ImpactMark called with <= 0 radius" ); + } + + // create the texture axis + + if ( orientation ) + { + VectorNormalize2( dir, axis[0] ); + PerpendicularVector( axis[1], axis[0] ); + RotatePointAroundVector( axis[2], axis[0], axis[1], orientation ); + CrossProduct( axis[0], axis[2], axis[1] ); + } + else + { + vec3_t angles; + vec3_t tmp; + + VectorNormalize2( dir, axis[0] ); + VectorCopy( dir, tmp ); + tmp[0] = -tmp[0]; + tmp[1] = -tmp[1]; + vectoangles( tmp, angles ); + AnglesToMat( angles, axis ); + VectorScale( axis[2], -1, axis[2] ); + } + + texCoordScale = 0.5 * 1.0 / radius; + + // create the full polygon + for ( i = 0 ; i < 3 ; i++ ) { + originalPoints[0][i] = origin[i] - radius * axis[1][i] - radius * axis[2][i]; + originalPoints[1][i] = origin[i] + radius * axis[1][i] - radius * axis[2][i]; + originalPoints[2][i] = origin[i] + radius * axis[1][i] + radius * axis[2][i]; + originalPoints[3][i] = origin[i] - radius * axis[1][i] + radius * axis[2][i]; + } + + // get the fragments + VectorScale( dir, -32, projection ); + + numFragments = cgi.CM_MarkFragments( 4, (void *)originalPoints, + projection, MAX_MARK_POINTS, markPoints[0], + MAX_MARK_FRAGMENTS, markFragments ); + + if ( fadein ) + { + colors[0] = 0; + colors[1] = 0; + colors[2] = 0; + colors[3] = 0; + } + else + { + colors[0] = red * 255; + colors[1] = green * 255; + colors[2] = blue * 255; + colors[3] = alpha * 255; + } + + for ( i = 0, mf = markFragments ; i < numFragments ; i++, mf++ ) { + polyVert_t *v; + polyVert_t verts[MAX_VERTS_ON_POLY]; + markPoly_t *mark; + + // we have an upper limit on the complexity of polygons + // that we store persistantly + if ( mf->numPoints > MAX_VERTS_ON_POLY ) { + mf->numPoints = MAX_VERTS_ON_POLY; + } + for ( j = 0, v = verts ; j < mf->numPoints ; j++, v++ ) { + vec3_t delta; + + VectorCopy( markPoints[mf->firstPoint + j], v->xyz ); + + VectorSubtract( v->xyz, origin, delta ); + v->st[0] = 0.5 + DotProduct( delta, axis[1] ) * texCoordScale; + v->st[1] = 0.5 + DotProduct( delta, axis[2] ) * texCoordScale; + *(int *)v->modulate = *(int *)colors; + } + + // if it is a temporary (shadow) mark, add it immediately and forget about it + if ( temporary ) { + cgi.R_AddPolyToScene( markShader, mf->numPoints, verts, 0 ); + continue; + } + + // otherwise save it persistantly + mark = CG_AllocMark(); + mark->time = cg.time; + mark->alphaFade = alphaFade; + mark->markShader = markShader; + mark->poly.numVerts = mf->numPoints; + mark->color[0] = red; + mark->color[1] = green; + mark->color[2] = blue; + mark->color[3] = alpha; + mark->fadein = fadein; + mark->lightstyle = lightstyle; + memcpy( mark->verts, verts, mf->numPoints * sizeof( verts[0] ) ); + } +} + + +/* +=============== +CG_AddMarks +=============== +*/ +#define MARK_TOTAL_TIME 10000 +#define MARK_FADE_TIME 1000 + +void CG_AddMarks( void ) { + int j; + markPoly_t *mp, *next; + int t; + int fade; + + if ( !cg_addMarks->integer ) { + return; + } + + mp = cg_activeMarkPolys.nextMark; + for ( ; mp != &cg_activeMarkPolys ; mp = next ) { + // grab next now, so if the local entity is freed we + // still have it + next = mp->nextMark; + + // see if it is time to completely remove it + if ( cg.time > mp->time + MARK_TOTAL_TIME ) { + CG_FreeMarkPoly( mp ); + continue; + } + + // fade all marks out with time + t = mp->time + MARK_TOTAL_TIME - cg.time; + + if ( mp->lightstyle > 0 ) + { + CG_LightStyleColor( mp->lightstyle, t, mp->color, qtrue ); + + if ( mp->color[3] <= 0 ) + { + CG_FreeMarkPoly( mp ); + continue; + } + + for ( j = 0 ; j < mp->poly.numVerts ; j++ ) + { + mp->verts[j].modulate[0] = mp->color[0] * 255; + mp->verts[j].modulate[1] = mp->color[1] * 255; + mp->verts[j].modulate[2] = mp->color[2] * 255; + mp->verts[j].modulate[3] = mp->color[3] * 255; + } + } + + // Fade in marks + if ( mp->fadein ) + { + fade = 255 * ( cg.time - mp->time ) / MARK_FADE_TIME; + + if ( fade > 255 ) + fade = 255; + + if ( mp->alphaFade ) + { + for ( j = 0 ; j < mp->poly.numVerts ; j++ ) + { + mp->verts[j].modulate[3] = fade; + } + } + else + { + for ( j = 0 ; j < mp->poly.numVerts ; j++ ) + { + mp->verts[j].modulate[0] = mp->color[0] * fade; + mp->verts[j].modulate[1] = mp->color[1] * fade; + mp->verts[j].modulate[2] = mp->color[2] * fade; + } + } + } + + // Fade out marks + if ( t < MARK_FADE_TIME ) + { + fade = 255 * t / MARK_FADE_TIME; + if ( mp->alphaFade ) + { + for ( j = 0 ; j < mp->poly.numVerts ; j++ ) + { + mp->verts[j].modulate[3] = fade; + } + } + else + { + for ( j = 0 ; j < mp->poly.numVerts ; j++ ) + { + mp->verts[j].modulate[0] = mp->color[0] * fade; + mp->verts[j].modulate[1] = mp->color[1] * fade; + mp->verts[j].modulate[2] = mp->color[2] * fade; + } + } + } + + cgi.R_AddPolyToScene( mp->markShader, mp->poly.numVerts, mp->verts, 0 ); + } +} + diff --git a/source/source/cgame/cg_modelanim.c b/source/source/cgame/cg_modelanim.c new file mode 100644 index 0000000..3a7e46b --- /dev/null +++ b/source/source/cgame/cg_modelanim.c @@ -0,0 +1,1405 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/cgame/cg_modelanim.c $ +// $Revision:: 83 $ +// $Author:: Markd $ +// $Date:: 7/30/00 2:58p $ +// +// Copyright (C) 1998 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/cgame/cg_modelanim.c $ +// +// 83 7/30/00 2:58p Markd +// don't use ground targeting reticle when they are standing in water +// +// 82 7/28/00 2:39a Aldie +// Added notimecheck anim flag, and handle it in cg_modelanim to help with +// jittering on crossblending +// +// 81 7/23/00 1:28p Aldie +// Trying out some fixes for crossblending hitches +// +// 80 7/23/00 10:47a Aldie +// Fixed a syntax error +// +// 79 7/23/00 12:28a Aldie +// Slight fix for frame lerping problems in the player anims +// +// 78 7/03/00 9:11p Markd +// fixed lerping issue when entities are reset +// +// 77 6/26/00 5:50p Markd +// re-did some renderfx commands, fixed anti-sb juice stuff +// +// 76 6/06/00 1:59p Aldie +// Added fadein to marks +// +// 75 6/05/00 3:10p Markd +// Added has_commands check to client side command processing +// +// 74 6/04/00 6:03p Markd +// Added precise shadow support +// +// 73 6/03/00 5:25p Aldie +// Take out shadow on hidden RF_DONTDRAW objects +// +// 72 6/03/00 10:55a Markd +// Sped up tracing and debug print messages +// +// 71 5/25/00 9:57a Steven +// Made it so the player's shadow is not drawn if in first person mode. +// +// 70 5/22/00 8:00p Markd +// fixed crossblend problem +// +// 69 5/22/00 4:49p Markd +// added fix for blend bit not being masked off on crossblend anim +// +// 68 5/09/00 1:29p Aldie +// Added lightstyles to impact marks +// +// 67 5/03/00 5:27p Markd +// when resetting the animation, we set the old anim and old frame to the new +// anim and new frame so that we don't get unwanted crossfading +// +// 66 5/02/00 3:46p Markd +// fixed targeting reticles spinning the right direction +// +// 65 4/29/00 11:45a Markd +// made targeting reticles turn in the same direction +// +// 64 4/21/00 4:36p Steven +// Bulletproofed CG_RunModelAnimation a little more. +// +// 63 4/21/00 3:02p Markd +// removed RF_LIGHTINGORIGIN usage from models +// +// 62 4/05/00 7:09p Markd +// fixed exit command problem +// +// 61 4/03/00 10:55a Markd +// fixed targeting reticles on flying creatures +// +// 60 3/22/00 11:19a Markd +// fixed lighting bug on attached models +// +// 59 3/20/00 9:39a Markd +// fixed driven animations when switching animations and net resetting the +// frame of the animation +// +// 58 3/18/00 10:25a Markd +// fixed some bit masking issues with anims in ValidateSkelFrame and the model +// code +// +// 57 3/03/00 4:36p Markd +// Fixed air targeting on creatures +// +// 56 2/24/00 3:18p Jimdose +// when changing from no legs or no torso anim, crossblend from the opposite +// part's animation +// +// 55 2/23/00 1:46p Jimdose +// removed warning about uselegs and usetorso not being set +// +// 54 2/23/00 12:15p Jimdose +// added checks to prevent an animation without legs or torso +// +// 53 2/22/00 5:55p Markd +// Fixed 2 frame animations with low framerate +// +// 52 2/21/00 2:51p Markd +// Added GlobalRadius support to tikis +// +// 51 2/16/00 6:58p Markd +// cleaned up version of new animation system +// +// 50 2/16/00 6:56p Markd +// added new animation system +// +// 49 2/15/00 8:55p Jimdose +// fixed animation frames and delta sync problem +// +// 48 2/14/00 5:48p Jimdose +// legs animation now only plays when ANIM_BLEND is set on anim or if uselegs +// is set +// +// 47 2/14/00 10:09a Markd +// Tweaked targeting reticles +// +// 46 2/12/00 4:32p Markd +// fixed some bugs with the targeting +// +// 45 2/12/00 3:44p Markd +// Added targeted entity support +// +// 44 2/12/00 3:24p Jimdose +// renamed ANIM_BLEND_TORSO to ANIM_BLEND +// +// 43 1/27/00 1:16p Steven +// Fixed some looping sound origin issues. +// +// 42 1/26/00 10:49p Jimdose +// crossblending was taking the crossblend time from the source anim and not +// the destination anim +// +// 41 1/26/00 5:56p Jimdose +// CG_ClearModelAnimation now sets crossblend_frametime to cg.time. This way, +// the game doesn't try to crossblend just because a model entered the view +// +// 40 1/26/00 3:34p Markd +// Added Renderfx mask for inherited entities +// +// 39 1/25/00 8:08p Jimdose +// added crossblend time to tikis +// +// 38 1/19/00 6:42p Markd +// Added UpdateEntity to CG_General and ModelAnim specifically +// +// 37 1/19/00 12:32p Jimdose +// trying some code to fix pause in looking anims +// +// 36 1/11/00 7:16p Markd +// fixed com_speeds bug where rendering time was not being properly subtracted +// from client time +// +// 35 12/17/99 7:03p Markd +// changed shadow code a little bit +// +// 34 12/14/18 2:42p Jimdose +// fixed problem with FRAME_EXPLICIT models not showing proper animation frame. +// +// 33 12/13/99 3:30p Aldie +// Updated printout +// +// 32 12/09/99 7:42p Jimdose +// got rid of ignore_angles +// +// 31 12/09/99 10:52a Jimdose +// got tags working with torso and crossblended animations +// +// 30 11/17/99 3:07p Markd +// Fixed lerping problem in animation system +// +// 29 11/17/99 12:17p Markd +// Took out RF_NOSHADOW flag +// +// 28 11/17/99 10:08a Markd +// Lightened character shadows slightly +// +// 27 11/17/99 10:07a Markd +// fixed bug with first person models +// +// 26 11/16/99 7:03p Markd +// Put in variable shadows based off of bounding box sizes +// +// 25 11/11/99 3:53p Jimdose +// fixed crossblending into and out of torso animations +// +// 24 11/11/99 11:34a Jimdose +// first pass at torso animation blending in +// +// 23 11/10/99 2:18p Jimdose +// working on torso animation +// +// 22 11/04/99 11:34a Jimdose +// fixed problem where CG_ClearModelAnimation set the animation crossfading +// into a state that wouldn't animate until the animation changed +// +// 21 11/01/99 4:11p Jimdose +// made tags work with bone controllers +// +// 20 11/01/99 10:35a Markd +// if there is no tikihandle, still setup frame and anim as a general entity +// +// 19 10/29/99 6:52p Jimdose +// added bone controllers +// +// 18 10/28/99 6:05p Steven +// Added a use_angles flag and an offset to the entity attach stuff. +// +// 17 10/26/99 6:30p Jimdose +// added animation blending +// +// 16 10/25/99 12:20p Jimdose +// made head and torso angles local to each entity +// +// 15 10/22/99 10:43a Markd +// Rewrote command processor +// +// 14 10/19/99 7:52p Markd +// Removed three part model system +// +// 13 10/08/99 7:36p Markd +// put in -1 frame check in ModelAnim +// +// 12 10/06/99 7:25p Markd +// removed TIMESTAMP, time and fixed make_static bug +// +// 11 10/05/99 6:01p Aldie +// Added headers +// +// DESCRIPTION: +// Functions for doing model animation and attachments + +#include "cg_local.h" + +/* +=============== +CG_EntityTargeted +=============== +*/ +#define TARGET_GROUND_DISTANCE 32 +void CG_EntityTargeted( int tikihandle, centity_t *cent, refEntity_t *model ) { + vec3_t end, sprite_org; + trace_t trace; + qboolean ground; + float radius; + + // send a trace down from the player to the ground + VectorCopy( model->origin, end ); + end[2] -= TARGET_GROUND_DISTANCE; + + cgi.CM_BoxTrace( &trace, model->origin, end, NULL, NULL, 0, MASK_PLAYERSOLID, qfalse ); + + // no shadow if too high + if ( trace.fraction == 1.0 ) + { + ground = qfalse; + } + else + { + if ( trace.contents & MASK_WATER ) + { + ground = qfalse; + } + else + { + ground = qtrue; + } + } + + // + // get the bounds of the current frame + // + if ( ground ) + { + radius = cgi.R_ModelRadius( model->hModel ) * model->scale * 1.25f; + } + else + { + vec3_t mins, maxs; + //vec3_t delta; + + if ( tikihandle >= 0 ) + { + radius = cgi.R_ModelRadius( model->hModel ) * model->scale * 2.0f; + VectorCopy( model->origin, sprite_org ); + sprite_org[ 2 ] += 0.5f * radius; + } + else + { + cgi.R_ModelBounds( model->hModel, mins, maxs ); + radius = ( maxs[ 2 ] - mins[ 2 ] ) * 0.5f; + VectorAdd( mins, maxs, sprite_org ); + VectorMA( model->origin, 0.5f, sprite_org, sprite_org ); + } + } + + + if ( radius < 1 ) + { + return; + } + + if ( ground ) + { + if ( cent->currentState.eFlags & EF_LEFT_TARGETED ) + { + CG_ImpactMark( cgs.media.leftTargetShader, trace.endpos, trace.plane.normal, + ( cg.time * 120 / 1000 ) % 360, 1, 1, 1, 1, qfalse, radius, qtrue, -1, qfalse ); + } + if ( cent->currentState.eFlags & EF_RIGHT_TARGETED ) + { + CG_ImpactMark( cgs.media.rightTargetShader, trace.endpos, trace.plane.normal, + ( cg.time * 120 / 1000 ) % 360, 1, 1, 1, 1, qfalse, radius, qtrue, -1, qfalse ); + } + } + else + { + vec3_t angles; + refEntity_t sprite; + + memset( &sprite, 0, sizeof( sprite ) ); + VectorCopy( sprite_org, sprite.origin); + VectorCopy( sprite_org, sprite.oldorigin); + VectorCopy( vec3_origin, angles ); + sprite.shaderRGBA[ 0 ] = 255; + sprite.shaderRGBA[ 1 ] = 255; + sprite.shaderRGBA[ 2 ] = 255; + sprite.shaderRGBA[ 3 ] = 128; + + if ( cent->currentState.eFlags & EF_LEFT_TARGETED ) + { + angles[ ROLL ] = ( cg.time * 120 / 1000 ) % 360; + // convert angles to axis + AnglesToAxis( angles, sprite.axis ); + + sprite.hModel = cgs.media.leftTargetModel; + sprite.scale = radius / cgi.R_ModelRadius( sprite.hModel ); + // add to refresh list + cgi.R_AddRefSpriteToScene( &sprite ); + } + if ( cent->currentState.eFlags & EF_RIGHT_TARGETED ) + { + angles[ ROLL ] = ( cg.time * 120 / 1000 ) % 360; + // convert angles to axis + AnglesToAxis( angles, sprite.axis ); + + sprite.hModel = cgs.media.rightTargetModel; + sprite.scale = radius / cgi.R_ModelRadius( sprite.hModel ); + // add to refresh list + cgi.R_AddRefSpriteToScene( &sprite ); + } + } + + return; +} + +/* +=============== +CG_EntityShadow + +Returns the Z component of the surface being shadowed + + should it return a full plane instead of a Z? +=============== +*/ +#define SHADOW_DISTANCE 96 +qboolean CG_EntityShadow( centity_t *cent, refEntity_t *model ) { + vec3_t end; + trace_t trace; + float alpha, radius; + + + model->shadowPlane = 0; + + if ( cg_shadows->integer == 0 ) { + return qfalse; + } + + if ( model->renderfx & RF_SKYENTITY ) + { + // no shadows on sky entities + return qfalse; + } + + // no shadows when invisible +// if ( cent->currentState.powerups & ( 1 << PW_INVIS ) ) { +// return qfalse; +// } + + // send a trace down from the player to the ground + VectorCopy( model->origin, end ); + end[2] -= SHADOW_DISTANCE; + + cgi.CM_BoxTrace( &trace, model->origin, end, NULL, NULL, 0, MASK_PLAYERSOLID, qfalse ); + + // no shadow if too high + if ( trace.fraction == 1.0 ) { + return qfalse; + } + + model->shadowPlane = trace.endpos[2] + 1; + + if ( ( cg_shadows->integer == 2 ) && ( model->renderfx & RF_SHADOW_PRECISE ) ) + { + return qtrue; + } + + // + // get the bounds of the current frame + // + radius = model->scale * cgi.R_ModelRadius( model->hModel ); + + if ( radius < 1 ) + { + return qfalse; + } + + // fade the shadow out with height + alpha = ( 1.0 - trace.fraction ) * 0.8f; + + if ( ( cg_shadows->integer == 3 ) && ( model->renderfx & RF_SHADOW_PRECISE ) ) + { + if ( model->shaderRGBA[ 3 ] == 255 ) + { + model->shaderRGBA[ 3 ] = alpha * 255; + } + return qtrue; + } + + // add the mark as a temporary, so it goes directly to the renderer + // without taking a spot in the cg_marks array + CG_ImpactMark( cgs.media.shadowMarkShader, trace.endpos, trace.plane.normal, + cent->lerpAngles[ YAW ], alpha,alpha,alpha,1, qfalse, radius, qtrue, -1, qfalse ); + + return qtrue; +} + +// +// +// NEW ANIMATION AND THREE PART MODEL SYSTEM +// +// + +//================= +//CG_AnimationDebugMessage +//================= +void CG_AnimationDebugMessage + ( + int number, + const char *fmt, + ... + ) + { +#ifndef NDEBUG + if ( cg_debugAnim->integer ) + { + va_list argptr; + char msg[1024]; + + va_start (argptr,fmt); + vsprintf (msg,fmt,argptr); + va_end (argptr); + + if ( ( !cg_debugAnimWatch->integer ) || ( ( cg_debugAnimWatch->integer - 1 ) == number ) ) + { + if ( cg_debugAnim->integer == 2 ) + { + cgi.DebugPrintf( msg ); + } + else + { + cgi.Printf( msg ); + } + } + } +#endif + } + +/* +=============== +CG_SetModelAnimation + +may include ANIM_TOGGLEBIT +=============== +*/ +void CG_SetModelAnimation( int tikihandle, animstate_t * state, animstate_t * altstate, int newAnimation, int time, vec3_t origin, int entnum, qboolean timecheck ) + { + int numframes; + int flags; + qboolean driven; + + numframes = cgi.Anim_NumFrames( tikihandle, newAnimation & ANIM_MASK ); + if ( !numframes ) + { + cgi.DPrintf( "Can't find animation %i\n", newAnimation & ANIM_MASK ); + return; + } + flags = cgi.Anim_Flags( tikihandle, newAnimation & ANIM_MASK ); + if ( flags & MDL_ANIM_DELTA_DRIVEN ) + driven = qtrue; + else + driven = qfalse; + + state->time_per_frame = 1000.0f * cgi.Frame_Time( tikihandle, newAnimation & ANIM_MASK, 0 ); + if ( !state->time_per_frame ) + { + cgi.DPrintf( "Animation %i has no time information\n", newAnimation & ANIM_MASK ); + return; + } + +#if 0 + // set the oldanim + state->base.oldanim = state->base.anim; + // set the oldframe + state->base.oldframe = state->base.frame; +#else + // We are blending from the last state so set the oldanim and frame from it + if ( state->base.anim & ANIM_BLEND ) + { + // set the oldanim + state->base.oldanim = state->base.anim; + // set the oldframe + state->base.oldframe = state->base.frame; + } + else // We are not blending, so get the oldanim and oldframe from the alternate state + { + // set the oldanim + state->base.oldanim = altstate->base.oldanim; + // set the oldframe + state->base.oldframe = altstate->base.oldframe; + } +#endif + + // if the anims are different and we aren't crossblending than crossblend from the previous animation + if ( + ( ( newAnimation & ANIM_MASK ) != ( state->base.anim & ANIM_MASK ) ) && + ( ( ( time - state->crossblend.starttime ) >= state->crossblend_totaltime ) || !timecheck || ( flags & MDL_ANIM_NO_TIMECHECK ) ) + ) + { + // if we didn't have an anim last state then use the alternate state for the crossblend + if ( state->base.anim & ANIM_BLEND ) + { + // copy the previous state over + state->crossblend = state->base; +#if 0 + cgi.DPrintf( "Setting crossblend:%s\n", cgi.Anim_NameForNum( tikihandle, state->base.anim & ANIM_MASK ) ); +#endif + } + else + { + // copy the previous state over from the alternate state + state->crossblend = altstate->base; +#if 0 + cgi.DPrintf( "Setting crossblend (alt):%s\n", cgi.Anim_NameForNum( tikihandle, altstate->base.anim & ANIM_MASK ) ); +#endif + } + // start crossblending from the nearest serverTime so it is synced with the other animations + state->crossblend.starttime = time; + // total time is determined by the animation + state->crossblend_totaltime = cgi.Anim_CrossblendTime( tikihandle, newAnimation & ANIM_MASK ); + } + + // if we went from a non-driven to a driven or vice versa reset certain variables + if ( driven != state->driven ) + { + if ( driven ) + { + // reset our position + VectorCopy( origin, state->last_origin ); + // reset the last time we animated for driven animations + state->last_driven_time = cg.time; + // reset our current distance + state->current_distance = 0; + // reset our frame number so that we start at the beginning of the animation + state->base.frame = 0; + } + else + { + // we don't want to process commands from the previous delta-driven animation any more, so we skip over them + // by making it look like we are at the beginning of this animation + state->last_cmd_frame = 0; + } + } + // if we were driving last animatino, and our anim change, reset the frame number + else if ( driven && ( newAnimation & ANIM_MASK ) != ( state->base.anim & ANIM_MASK ) ) + { + state->base.frame = 0; + } + + // special case for single frame animations + // this makes sure that we replay any events on the first frame + if ( ( state->numframes == numframes ) && ( numframes < 3 ) ) + state->last_cmd_frame = 0; + + state->driven = driven; + + state->base.anim = newAnimation; + + newAnimation &= ANIM_MASK; + + if ( state->driven ) + { + cgi.Anim_Delta( tikihandle, newAnimation, state->frame_delta ); + VectorScale( state->frame_delta, 1.0f / ( float )numframes, state->frame_delta ); + state->frame_distance = VectorLength( state->frame_delta ); + VectorNormalize( state->frame_delta ); + if ( state->frame_distance < 0.1f ) + { + cgi.DPrintf( "Animation has no delta information, canceling delta.\n" ); + state->driven = qfalse; + } + } + else + { + // reset our frame number so that we start at the beginning of the animation + state->base.frame = 0; + } + + state->has_commands = cgi.Anim_HasCommands( tikihandle, newAnimation ); + + state->numframes = numframes; + + state->base.starttime = time; + + assert( cg.time >= time ); + + state->next_evaluate_time = time + state->time_per_frame; + +#ifndef NDEBUG + if ( state->driven ) + { + CG_AnimationDebugMessage( entnum, "cg.time: %d Entity: %3d Anim: %s(#%i) (%i) driven\n", + cg.time, entnum, cgi.Anim_NameForNum( tikihandle, newAnimation ), newAnimation, state->base.starttime ); + } + else + { + CG_AnimationDebugMessage( entnum, "cg.time: %d Entity: %3d Anim: %s(#%i) (%i) not-driven\n", + cg.time, entnum, cgi.Anim_NameForNum( tikihandle, newAnimation ), newAnimation, state->base.starttime ); + } +#endif + } + +/* +=============== +CG_RunModelAnimation +=============== +*/ +void CG_RunModelAnimation + ( + int tikihandle, + animstate_t * state, + animstate_t * altstate, + int newAnimation, + int animtime, + vec3_t origin, + vec3_t or[ 3 ], + centity_t * cent, + qboolean timecheck + ) + { + int f; + int timedelta; + + // must not be a tiki model + if ( tikihandle < 0 ) + return; + + // debugging tool to get no animations + if ( cg_animSpeed->value == 0 ) + { + state->base.oldframe = state->base.frame = state->base.framelerp = 0; + return; + } + + // see if the animation sequence is switching + if ( newAnimation != state->base.anim ) + { + CG_SetModelAnimation( tikihandle, state, altstate, newAnimation, animtime, origin, cent->currentState.number, timecheck ); + } + + // This is here to bullet proof this proc (prevents possible divide by 0 errors farther down) + + if ( !state->time_per_frame ) + return; + + if ( state->driven ) + { + vec3_t tmp; + vec3_t delta; + float dot; + float delta_length; + + // calculate distance since last time and time elapsed + VectorSubtract( origin, state->last_origin, tmp ); + VectorCopy( origin, state->last_origin ); + timedelta = cg.time - state->last_driven_time; + state->last_driven_time = cg.time; + + // transform the delta into our local coordinate system + delta[ 0 ] = DotProduct( tmp, or[ 0 ] ); + delta[ 1 ] = DotProduct( tmp, or[ 1 ] ); + delta[ 2 ] = DotProduct( tmp, or[ 2 ] ); + + delta_length = VectorNormalize( delta ); + dot = DotProduct( state->frame_delta, delta ); + delta_length *= dot; + + // add our distance along the direction of movement to our current distance + state->current_distance += delta_length; + // if we passed the distance for one frame in the forward direction, switch frames + while ( state->current_distance > state->frame_distance ) + { + state->base.oldanim = state->base.anim & ANIM_MASK; + state->base.oldframe = state->base.frame; + state->base.frame++; + state->current_distance -= state->frame_distance; + if ( state->base.frame >= state->numframes ) + state->base.frame -= state->numframes; + } + // if we passed the distance for one frame in the backwards direction, switch frames + while ( state->current_distance < -state->frame_distance ) + { + state->base.oldanim = state->base.anim & ANIM_MASK; + state->base.oldframe = state->base.frame; + state->base.frame--; + state->current_distance += state->frame_distance; + if ( state->base.frame < 0 ) + state->base.frame += state->numframes; + } + // calculate the lerp for this frame + if ( state->current_distance >= 0 ) + { + state->base.framelerp = ( ( state->frame_distance - state->current_distance ) / state->frame_distance ); + } + else + { + state->base.framelerp = ( ( state->current_distance + state->frame_distance ) / state->frame_distance ); + } + } + else + { + if ( cg.time >= state->next_evaluate_time ) + { + state->next_evaluate_time += state->time_per_frame; + + // calculate the current frame based on the starttime of the animation + timedelta = cg.time - state->base.starttime; + f = timedelta / state->time_per_frame; + + // make sure frame is not negative + if ( f < 0 ) + { + f = 0; + } + + // don't let frame wrap around numframes + if ( f >= state->numframes ) + { + f = state->numframes - 1; + } + +#ifndef NDEBUG + CG_AnimationDebugMessage( cent->currentState.number, "cg.time: %d Entity: %3d anim %s frame %d\n", + cg.time, cent->currentState.number, cgi.Anim_NameForNum( tikihandle, state->base.anim & ANIM_MASK ), f ); +#endif + state->base.oldframe = state->base.frame; + state->base.oldanim = state->base.anim & ANIM_MASK; + + state->base.frame = f; + } + + state->base.framelerp = 1.0f - ( float )( cg.time - state->base.starttime - ( state->base.frame * state->time_per_frame ) ) / ( float )state->time_per_frame; + + if ( state->base.framelerp < 0 ) + { + state->base.framelerp = 0; + } + } + + if ( state->crossblend_totaltime ) + { + state->crossblend_lerp = ( float )( cg.time - state->crossblend.starttime ) / ( float )state->crossblend_totaltime; + if ( state->crossblend_lerp < 0 ) + { + state->crossblend_lerp = 0; + } + if ( state->crossblend_lerp > 1.0f ) + { + // < 0 means no crossfade + state->crossblend_lerp = -1.0f; + } + } + else + { + // < 0 means no crossfade + state->crossblend_lerp = -1.0f; + } + } + + +/* +=============== +CG_ClearModelAnimation +=============== +*/ +void CG_ClearModelAnimation( int tikihandle, animstate_t * state, int animationNumber, int time, vec3_t origin, int entnum ) + { + memset( &state->base, 0, sizeof( state->base ) ); + if ( tikihandle >= 0 ) + { + CG_SetModelAnimation( tikihandle, state, state, animationNumber, time, origin, entnum, qtrue ); + // + // we set this hear to prevent unwanted crossfading when we first start + // + // set the oldanim + state->base.oldanim = state->base.anim; + // set the oldframe + state->base.oldframe = state->base.frame; + } + + memset( &state->crossblend, 0, sizeof( state->crossblend ) ); + state->crossblend.starttime = time; + state->crossblend_totaltime = 0; + state->crossblend_lerp = -1.0f; + + state->last_cmd_anim = state->last_cmd_frame = state->last_cmd_time = 0; + } + +/* +====================== +CG_AttachEntity + +Modifies the entities position and axis by the given +tag location +====================== +*/ +void CG_AttachEntity( refEntity_t *entity, refEntity_t *parent, int tikihandle, int tagnum, qboolean use_angles, vec3_t attach_offset ) + { + int i; + orientation_t or; + vec3_t tempAxis[3]; + + // lerp the tag + if ( r_lerpmodels->integer ) + { + or = cgi.Tag_LerpedOrientation( tikihandle, parent, tagnum ); + } + else + { + //FIXME + // doesn't handle torso animations + or = cgi.Tag_Orientation + ( + tikihandle, + parent->anim, + parent->frame, + tagnum, + parent->scale, + parent->bone_tag, + parent->bone_quat + ); + } + //cgi.Printf( "th = %d %.2f %.2f %.2f\n", tikihandle, or.origin[ 0 ], or.origin[ 1 ], or.origin[ 2 ] ); + + VectorCopy( parent->origin, entity->origin ); + + for ( i = 0 ; i < 3 ; i++ ) + { + VectorMA( entity->origin, or.origin[i], parent->axis[i], entity->origin ); + } + + VectorCopy( entity->origin, entity->oldorigin ); + + VectorAdd( entity->origin, attach_offset, entity->origin ); + + if ( use_angles ) + { + MatrixMultiply( entity->axis, parent->axis, tempAxis ); + MatrixMultiply( or.axis, tempAxis, entity->axis ); + } + + entity->scale *= parent->scale; + entity->renderfx |= ( parent->renderfx & ~( RF_FLAGS_NOT_INHERITED | RF_LIGHTING_ORIGIN ) ); + entity->shadowPlane = parent->shadowPlane; + VectorCopy( parent->lightingOrigin, entity->lightingOrigin ); + } + +void CG_ModelAnim + ( + centity_t *cent + ) + + { + entityState_t *s1; + refEntity_t model; + int thandle; + int i; + qboolean dolegs; + qboolean dotorso; + + memset( &model, 0, sizeof(model) ); + + s1 = ¢->currentState; + + // add loop sound only if it is not attached + if ( s1->loopSound && ( s1->parent == ENTITYNUM_NONE ) ) + { + cgi.S_AddLoopingSound( cent->lerpOrigin, vec3_origin, cgs.sound_precache[s1->loopSound], s1->loopSoundVolume, s1->loopSoundMinDist ); + } + if ( cent->tikiLoopSound && ( s1->parent == ENTITYNUM_NONE ) ) + cgi.S_AddLoopingSound( cent->lerpOrigin, vec3_origin, cent->tikiLoopSound, cent->tikiLoopSoundVolume, cent->tikiLoopSoundMinDist ); + + // if set to invisible, skip + if ( !s1->modelindex ) + { + return; + } + + // take the results of CL_InterpolateEntities + VectorCopy( cent->lerpOrigin, model.origin); + VectorCopy( cent->lerpOrigin, model.oldorigin); + + // convert angles to axis + AnglesToAxis( cent->lerpAngles, model.axis ); + + // set the entity number + model.entityNumber = s1->number; + + // copy shader specific data + model.shader_data[ 0 ] = s1->tag_num; + model.shader_data[ 1 ] = s1->skinNum; + + // set and lerp the bone controllers + model.useAngles = qfalse; + for( i = 0; i < NUM_BONE_CONTROLLERS; i++ ) + { + model.bone_tag[ i ] = s1->bone_tag[ i ]; + if ( model.bone_tag[ i ] >= 0 ) + { + model.useAngles = qtrue; + if ( ( cent->interpolate ) && ( cent->nextState.bone_tag[ i ] == cent->currentState.bone_tag[ i ] ) ) + { + SlerpQuaternion( cent->currentState.bone_quat[ i ], cent->nextState.bone_quat[ i ], + cg.frameInterpolation, model.bone_quat[ i ] ); + } + else + { + model.bone_quat[ i ][ 0 ] = s1->bone_quat[ i ][ 0 ]; + model.bone_quat[ i ][ 1 ] = s1->bone_quat[ i ][ 1 ]; + model.bone_quat[ i ][ 2 ] = s1->bone_quat[ i ][ 2 ]; + model.bone_quat[ i ][ 3 ] = s1->bone_quat[ i ][ 3 ]; + } + } + } + + // Interpolated state variables + if ( cent->interpolate ) + { + model.scale = s1->scale + cg.frameInterpolation * ( cent->nextState.scale - s1->scale ); + } + else + { + model.scale = s1->scale; + } + +#if 0 + if ( s1->parent != ENTITYNUM_NONE ) + { + refEntity_t *parent; + int tikihandle; + + parent = cgi.R_GetRenderEntity( s1->parent ); + + if ( !parent ) + { + cgi.DPrintf( "CG_ModelAnim: Could not find parent entity\n" ); + return; + } + + tikihandle = cgi.TIKI_GetHandle( parent->hModel ); + CG_AttachEntity( &model, parent, tikihandle, s1->tag_num & TAG_MASK, s1->attach_use_angles, s1->attach_offset ); + + if ( s1->loopSound ) + { + cgi.S_AddLoopingSound( model.origin, vec3_origin, cgs.sound_precache[s1->loopSound], s1->loopSoundVolume, s1->loopSoundMinDist ); + } + if ( cent->tikiLoopSound ) + cgi.S_AddLoopingSound( cent->lerpOrigin, vec3_origin, cent->tikiLoopSound, cent->tikiLoopSoundVolume, cent->tikiLoopSoundMinDist ); + } +#endif + + // + // add the model + // + thandle = cgs.model_tiki[ s1->modelindex ]; + + dolegs = ( s1->anim & ANIM_BLEND ); + dotorso = ( s1->torso_anim & ANIM_BLEND ); + + if ( !dolegs && !dotorso ) + { + // always do a leg anim if we don't have a torso + dolegs = qtrue; + } + + if ( dolegs ) + { + model.uselegs = qtrue; + + if ( ( thandle == -1 ) || ( s1->frame & FRAME_EXPLICIT ) ) + { + // explicit frame + model.anim = model.oldanim = s1->anim & ANIM_MASK; + model.frame = model.oldframe = s1->frame & FRAME_MASK; + model.backlerp = 0; + + // < 0 means no crossfade + model.crossblend_lerp = -1.0f; + + } + else + { + // run the animation + CG_RunModelAnimation + ( + thandle, + ¢->am, + ¢->torso_am, + s1->anim, + cg.snap->serverTime, + cent->lerpOrigin, + model.axis, + cent, + qtrue + ); + + model.anim = cent->am.base.anim & ANIM_MASK; + model.frame = cent->am.base.frame; + + model.oldanim = cent->am.base.oldanim & ANIM_MASK; + model.oldframe = cent->am.base.oldframe; + model.backlerp = cent->am.base.framelerp; + + model.crossblend_anim = cent->am.crossblend.anim & ANIM_MASK; + model.crossblend_frame = cent->am.crossblend.frame; + model.crossblend_oldframe = cent->am.crossblend.oldframe; + model.crossblend_backlerp = cent->am.crossblend.framelerp; + model.crossblend_lerp = cent->am.crossblend_lerp; + +#if 0 + cgi.DPrintf( "Crossblending to Legs Anim: %s from %s\n", cgi.Anim_NameForNum( thandle, model.anim ), + cgi.Anim_NameForNum( thandle, model.crossblend_anim ) + ); +#endif + + } + } + + // + // add the torso animation + // + if ( dotorso ) + { + int flags = cgi.Anim_Flags( thandle, cent->torso_am.base.anim & ANIM_MASK ); + + model.usetorso = qtrue; + + // if we're just switching to a torso animation and we don't have a crossblend going, + // set the crossblend to be from the base animation + if ( + !( cent->torso_am.base.anim & ANIM_BLEND ) && + ( ( ( cg.time - cent->torso_am.crossblend.starttime ) >= cent->torso_am.crossblend_totaltime ) || ( flags & MDL_ANIM_NO_TIMECHECK ) ) + ) + { + cent->torso_am.crossblend = cent->am.crossblend; + } + + // if we have a torso anim, we explicitly set the current anim and let CG_RunModelAnimation handle crossblending + if ( ( thandle == -1 ) || s1->torso_frame & FRAME_EXPLICIT ) + { + // explicit frame + model.torso_anim = model.torso_oldanim = s1->torso_anim & ANIM_MASK; + model.torso_frame = model.torso_oldframe = s1->torso_frame & FRAME_MASK; + model.torso_backlerp = 0; + + // < 0 means no crossfade + model.torso_crossblend_lerp = -1.0f; + } + else + { + // run the animation + CG_RunModelAnimation + ( + thandle, + ¢->torso_am, + ¢->am, + s1->torso_anim, + cg.snap->serverTime, + cent->lerpOrigin, + model.axis, + cent, + qfalse + ); + + model.torso_anim = cent->torso_am.base.anim & ANIM_MASK; + model.torso_frame = cent->torso_am.base.frame; + model.torso_oldanim = cent->torso_am.base.oldanim & ANIM_MASK; + model.torso_oldframe = cent->torso_am.base.oldframe; + model.torso_backlerp = cent->torso_am.base.framelerp; + + model.torso_crossblend_anim = cent->torso_am.crossblend.anim & ANIM_MASK; + model.torso_crossblend_frame = cent->torso_am.crossblend.frame; + model.torso_crossblend_oldframe = cent->torso_am.crossblend.oldframe; + model.torso_crossblend_backlerp = cent->torso_am.crossblend.framelerp; + model.torso_crossblend_lerp = cent->torso_am.crossblend_lerp; + } + +#if 0 + cgi.DPrintf( "Animating Torso: %s from %s\n", cgi.Anim_NameForNum( thandle, model.torso_anim ), + cgi.Anim_NameForNum( thandle, model.torso_crossblend_anim ) + ); +#endif + + } + else + { + // we don't have a torso anim, so crossblend from whatever the torso is currently doing +#if 1 + if ( + ( cent->torso_am.base.anim & ANIM_BLEND ) // This is a hack for the torso, don't do any crossblend time checking + ) +#else + if ( + ( cent->torso_am.base.anim & ANIM_BLEND ) && + ( ( cg.time - cent->torso_am.crossblend.starttime ) >= cent->torso_am.crossblend_totaltime ) + ) +#endif + { + CG_AnimationDebugMessage( cent->currentState.number, "TORSO_AM_BASE: %s\n", cgi.Anim_NameForNum( thandle, cent->torso_am.base.anim & ANIM_MASK ) ); + +#if 0 + cgi.DPrintf( "TORSO_AM_BASE: %s\n", cgi.Anim_NameForNum( thandle, cent->torso_am.base.anim & ANIM_MASK ) ); +#endif + + // only crossblend when the previous torso anim has it's flag set. + // set the crossblend information directly from the current animation + cent->torso_am.crossblend = cent->torso_am.base; + cent->torso_am.crossblend.starttime = cg.snap->serverTime; + cent->torso_am.crossblend_totaltime = cgi.Anim_CrossblendTime( thandle, cent->torso_am.crossblend.anim & ANIM_MASK ); + + // clear out the torso flag so that we only copy this when the torso animation goes away and there's no crossblending + cent->torso_am.base.anim &= ~ANIM_BLEND; + } + + // only set the torso information if we're crossblending from an anim + if ( ( cg.time - cent->torso_am.crossblend.starttime ) <= cent->torso_am.crossblend_totaltime ) + { + if ( cent->torso_am.crossblend_totaltime ) + { + cent->torso_am.crossblend_lerp = ( float )( cg.time - cent->torso_am.crossblend.starttime ) / + ( float )cent->torso_am.crossblend_totaltime; + if ( cent->torso_am.crossblend_lerp < 0 ) + { + cent->torso_am.crossblend_lerp = 0; + } + if ( cent->torso_am.crossblend_lerp > 1.0f ) + { + // < 0 means no crossfade + cent->torso_am.crossblend_lerp = -1.0f; + } + } + else + { + // < 0 means no crossfade + cent->torso_am.crossblend_lerp = -1.0f; + } + + model.usetorso = qtrue; + + model.torso_crossblend_anim = cent->torso_am.crossblend.anim & ANIM_MASK; + model.torso_crossblend_frame = cent->torso_am.crossblend.frame; + model.torso_crossblend_oldframe = cent->torso_am.crossblend.oldframe; + model.torso_crossblend_backlerp = cent->torso_am.crossblend.framelerp; + model.torso_crossblend_lerp = cent->torso_am.crossblend_lerp; + + // this isn't set if we don't have a leg anim + if ( s1->anim & ANIM_BLEND ) + { + model.torso_anim = model.anim; + model.torso_frame = model.frame; + model.torso_oldanim = model.oldanim; + model.torso_oldframe = model.oldframe; + model.torso_backlerp = model.backlerp; + } + else + { + // put in some valid frame info + model.torso_anim = model.torso_crossblend_anim; + model.torso_frame = model.torso_crossblend_frame; + model.torso_oldanim = model.torso_crossblend_anim; + model.torso_oldframe = model.torso_crossblend_oldframe; + model.torso_backlerp = model.torso_crossblend_backlerp; + } +#if 0 + cgi.DPrintf( "Crossblending to Torso Anim: %s from %s\n", cgi.Anim_NameForNum( thandle, model.torso_anim ), + cgi.Anim_NameForNum( thandle, model.torso_crossblend_anim ) + ); +#endif + } + } + + // if we don't have a leg anim + if ( !dolegs ) + { + // we don't have a leg anim, so crossblend from whatever the leg is currently doing + if ( + ( cent->am.base.anim & ANIM_BLEND ) && + ( ( cg.time - cent->am.crossblend.starttime ) >= cent->am.crossblend_totaltime ) + ) + { + // only crossblend when the previous leg anim has it's flag set. + // set the crossblend information directly from the current animation + cent->am.crossblend = cent->am.base; + cent->am.crossblend.starttime = cg.snap->serverTime; + cent->am.crossblend_totaltime = cgi.Anim_CrossblendTime( thandle, cent->am.crossblend.anim & ANIM_MASK ); + + // clear out the leg flag so that we only copy this when the leg animation goes away and there's no crossblending + cent->am.base.anim &= ~ANIM_BLEND; + } + + // only set the leg information if we're crossblending from an anim + if ( ( cg.time - cent->am.crossblend.starttime ) <= cent->am.crossblend_totaltime ) + { + if ( cent->am.crossblend_totaltime ) + { + cent->am.crossblend_lerp = ( float )( cg.time - cent->am.crossblend.starttime ) / + ( float )cent->am.crossblend_totaltime; + if ( cent->am.crossblend_lerp < 0 ) + { + cent->am.crossblend_lerp = 0; + } + if ( cent->am.crossblend_lerp > 1.0f ) + { + // < 0 means no crossfade + cent->am.crossblend_lerp = -1.0f; + } + } + else + { + // < 0 means no crossfade + cent->am.crossblend_lerp = -1.0f; + } + + model.uselegs = qtrue; + + model.crossblend_anim = cent->am.crossblend.anim & ANIM_MASK; + model.crossblend_frame = cent->am.crossblend.frame; + model.crossblend_oldframe = cent->am.crossblend.oldframe; + model.crossblend_backlerp = cent->am.crossblend.framelerp; + model.crossblend_lerp = cent->am.crossblend_lerp; + + model.anim = model.torso_anim; + model.frame = model.torso_frame; + model.oldanim = model.torso_oldanim; + model.oldframe = model.torso_oldframe; + model.backlerp = model.torso_backlerp; + } + } + + if ( s1->parent != ENTITYNUM_NONE ) + { + refEntity_t *parent; + int tikihandle; + + parent = cgi.R_GetRenderEntity( s1->parent ); + + if ( !parent ) + { + cgi.DPrintf( "CG_ModelAnim: Could not find parent entity\n" ); + return; + } + + tikihandle = cgi.TIKI_GetHandle( parent->hModel ); + CG_AttachEntity( &model, parent, tikihandle, s1->tag_num & TAG_MASK, s1->attach_use_angles, s1->attach_offset ); + + if ( s1->loopSound ) + { + cgi.S_AddLoopingSound( model.origin, vec3_origin, cgs.sound_precache[s1->loopSound], s1->loopSoundVolume, s1->loopSoundMinDist ); + } + if ( cent->tikiLoopSound ) + cgi.S_AddLoopingSound( model.origin, vec3_origin, cent->tikiLoopSound, cent->tikiLoopSoundVolume, cent->tikiLoopSoundMinDist ); + } + + // set skin + model.skinNum = s1->skinNum; + model.renderfx |= s1->renderfx; + model.customSkin = 0; + model.hModel = cgs.model_draw[s1->modelindex]; + + for( i=0; i<3; i++ ) + { + model.shaderRGBA[i] = cent->color[i] * 255; + } + model.shaderRGBA[3] = s1->alpha * 255; + + // set surfaces + memcpy( model.surfaces, s1->surfaces, MAX_MODEL_SURFACES ); + + // get the player model information + if ( + !( s1->renderfx & RF_DONTDRAW ) && + ( model.renderfx & RF_SHADOW ) && + !( model.renderfx & RF_DEPTHHACK ) && + !( ( s1->number == cg.snap->ps.clientNum ) && ( !cg_3rd_person->integer ) ) + ) + { + qboolean shadow; + + // add the shadow + shadow = CG_EntityShadow( cent, &model ); + if ( + shadow && + ( cg_shadows->integer == 3 ) && + ( model.renderfx & RF_SHADOW_PRECISE ) + ) + { + model.renderfx |= RF_SHADOW_PLANE; + } + } + + if ( s1->eFlags & ( EF_LEFT_TARGETED | EF_RIGHT_TARGETED ) ) + { + CG_EntityTargeted( thandle, cent, &model ); + } + + if ( s1->number == cg.snap->ps.clientNum ) + { + if (!cg_3rd_person->integer) + model.renderfx |= RF_THIRD_PERSON; // In 1st person, only draw self in mirrors + } + + if ( model.renderfx & RF_SKYORIGIN ) + { + memcpy( cg.sky_axis, model.axis, sizeof( cg.sky_axis ) ); + VectorCopy( model.origin, cg.sky_origin ); + } + + if ( s1->eFlags & EF_ANTISBJUICE ) + { + model.customShader = cgi.R_RegisterShader( "antisuckshader" ); + model.renderfx |= RF_CUSTOMSHADERPASS; + } + + if ( !( s1->renderfx & RF_DONTDRAW ) ) + { + // add to refresh list + cgi.R_AddRefEntityToScene( &model ); + } + + // Run any client frame commands + if ( thandle != -1 ) + { + // update any emitter's... + CG_UpdateEntity( thandle, &model, cent ); + + CG_ClientCommands + ( + thandle, + model.frame, + model.anim, + ¢->am, + &model, + cent + ); + + if ( s1->torso_anim & ANIM_BLEND ) + { + // Run any client frame commands + CG_ClientCommands + ( + thandle, + model.torso_frame, + model.torso_anim, + ¢->torso_am, + &model, + cent + ); + } + } + } diff --git a/source/source/cgame/cg_player.cpp b/source/source/cgame/cg_player.cpp new file mode 100644 index 0000000..e89dec3 --- /dev/null +++ b/source/source/cgame/cg_player.cpp @@ -0,0 +1,102 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/cgame/cg_player.cpp $ +// $Revision:: 13 $ +// $Author:: Steven $ +// $Date:: 6/01/00 12:21p $ +// +// Copyright (C) 1998 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/cgame/cg_player.cpp $ +// +// 13 6/01/00 12:21p Steven +// Improvement to splashes. +// +// 12 5/11/00 11:08a Steven +// Added water ripple stuff. +// +// 11 1/27/00 9:06a Markd +// Added watermark +// +// 10 10/29/99 6:52p Jimdose +// moved torso and head angles to player.cpp +// +// 9 10/27/99 12:18p Markd +// added smooth camera lerping +// +// 8 10/25/99 12:20p Jimdose +// made head and torso angles local to each entity +// +// 7 10/19/99 7:52p Markd +// Removed three part model system +// +// 6 10/14/99 4:52p Jimdose +// added head_angles and torso_angles to refdef_t +// +// 5 10/05/99 6:01p Aldie +// Added headers +// +// DESCRIPTION: +// Player functions for the cgame + +#include "cg_local.h" +#include "cg_commands.h" + +/* + +player entities generate a great deal of information from implicit ques +taken from the entityState_t + +*/ + +//===================================================================== + +/* +=============== +CG_ResetPlayerEntity + +A player just came into view or teleported, so reset all animation info +=============== +*/ +void CG_ResetPlayerEntity( centity_t *cent ) + { + cent->errorTime = -99999; // guarantee no error decay added + cent->extrapolated = qfalse; + + VectorCopy( cent->currentState.origin, cent->lerpOrigin ); + VectorCopy( cent->lerpOrigin, cent->rawOrigin ); + + VectorCopy( cent->currentState.angles, cent->lerpAngles ); + VectorCopy( cent->lerpAngles, cent->rawAngles ); + + if ( cent->currentState.number == cg.snap->ps.clientNum ) + { + // initialize the camera position + VectorCopy( cent->lerpOrigin, cg.currentViewPos ); + // initialize the camera angles + VectorCopy( cent->lerpAngles, cg.currentViewAngles ); + // setup the lastCameraTime + cg.lastCameraTime = -1; + // setup the lerpCameraTime + cg.lerpCameraTime = 0; + // clear the cameraView flag + cg.inCameraView = qfalse; + } + + // Reset splash info + cent->splash_still_count = 0; + } + +/* +=============== +CG_Player +=============== +*/ +void CG_Player( centity_t *cent ) + { + //CG_PlayerSplash( cent ); + } diff --git a/source/source/cgame/cg_playerstate.c b/source/source/cgame/cg_playerstate.c new file mode 100644 index 0000000..ae7a52d --- /dev/null +++ b/source/source/cgame/cg_playerstate.c @@ -0,0 +1,38 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/cgame/cg_playerstate.c $ +// $Revision:: 2 $ +// $Author:: Aldie $ +// $Date:: 10/05/99 6:01p $ +// +// Copyright (C) 1998 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/cgame/cg_playerstate.c $ +// +// 2 10/05/99 6:01p Aldie +// Added headers +// +// DESCRIPTION: +// +// this file acts on changes in a new playerState_t. +// With normal play, this will be done after local prediction, but when +// following another player or playing back a demo, it will be checked +// when the snapshot transitions like all the other entities + +#include "cg_local.h" + +/* +=============== +CG_TransitionPlayerState + +=============== +*/ +void CG_TransitionPlayerState( playerState_t *ps, playerState_t *ops ) + { + + } + diff --git a/source/source/cgame/cg_predict.c b/source/source/cgame/cg_predict.c new file mode 100644 index 0000000..dd87ec0 --- /dev/null +++ b/source/source/cgame/cg_predict.c @@ -0,0 +1,702 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/cgame/cg_predict.c $ +// $Revision:: 33 $ +// $Author:: Markd $ +// $Date:: 7/10/00 11:54p $ +// +// Copyright (C) 1998 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/cgame/cg_predict.c $ +// +// 33 7/10/00 11:54p Markd +// added exit level code +// +// 32 6/25/00 11:21a Markd +// fixed slime code for player +// +// 31 6/14/00 12:14p Markd +// more intel compiler bug fixes +// +// 30 6/08/00 9:14p Markd +// improved player prediction model +// +// 29 6/03/00 10:55a Markd +// Sped up tracing and debug print messages +// +// 28 5/16/00 6:24p Markd +// added cg_traceinfo support +// +// 27 5/16/00 4:25p Steven +// Made entities use CONTENTS_BODY instead of CONTENTS_BODY and CONTENTS_SOLID. +// +// 26 5/11/00 11:08a Steven +// Made sure trypush is NULL on client side. +// +// 25 4/28/00 3:30p Steven +// If a trace started in a solid made sure the world is set as the entitynum +// +// 24 4/21/00 9:30a Markd +// fixed camera fov problems +// +// 23 4/20/00 5:38p Markd +// fixed fov lerping bug, I introduced yesterday +// +// 22 4/19/00 2:38p Markd +// fixed lerping bug +// +// 21 3/31/00 11:49a Markd +// Added contents support to TempBbox models +// +// 20 2/15/00 8:47p Jimdose +// fixed animation frames and delta sync problem +// +// 19 2/01/00 11:25a Markd +// Fixed up camera cutting so that there are no more false origin issues +// +// 18 1/27/00 11:35a Markd +// Fixed solid/notsolid client side entities +// +// 17 1/12/00 8:01p Markd +// Added nextFrameCameraCut variable for cameras +// +// 16 12/11/99 3:37p Markd +// q3a gold checkin, first time +// +// 15 11/29/99 6:32p Aldie +// Lots of changes for ammo system +// +// 14 11/05/99 11:18a Aldie +// Fixed fov bug with Mark +// +// 13 11/04/99 3:18p Markd +// fixed fov lerping +// +// 12 11/04/99 10:03a Markd +// complete overhaul of the camera system +// +// 11 10/27/99 4:31p Markd +// Fixed all camera prediction and smmoth lerping issues +// +// 10 10/12/99 6:56p Markd +// Fixed some player interpolation bugs and also interpolated camera +// +// 9 10/12/99 2:23p Markd +// Rewrote camera and player movetype system +// +// 8 10/08/99 2:10p Markd +// Added PM_LOCKVIEW for when playerstate should just be predicted +// +// 7 10/05/99 6:01p Aldie +// Added headers +// +// DESCRIPTION: +// this file generates cg.predicted_player_state by either +// interpolating between snapshots from the server or locally predicting +// ahead the client's movement. It also handles local physics interaction, +// like fragments bouncing off walls + +#include "cg_local.h" + +static pmove_t cg_pmove; + +static int cg_numSolidEntities; +static centity_t *cg_solidEntities[MAX_ENTITIES_IN_SNAPSHOT]; +static int cg_numTriggerEntities; +//static centity_t *cg_triggerEntities[MAX_ENTITIES_IN_SNAPSHOT]; + +/* +==================== +CG_BuildSolidList + +When a new cg.snap has been set, this function builds a sublist +of the entities that are actually solid, to make for more +efficient collision detection +==================== +*/ +void CG_BuildSolidList( void ) + { + int i; + centity_t *cent; + snapshot_t *snap; + entityState_t *ent; + + cg_numSolidEntities = 0; + cg_numTriggerEntities = 0; + + if ( cg.nextSnap && !cg.nextFrameTeleport && !cg.thisFrameTeleport ) + { + snap = cg.nextSnap; + } + else + { + snap = cg.snap; + } + + for ( i = 0 ; i < snap->numEntities ; i++ ) + { + cent = &cg_entities[ snap->entities[ i ].number ]; + ent = ¢->currentState; + + if ( ent->eType == ET_ITEM || ent->eType == ET_PUSH_TRIGGER || ent->eType == ET_TELEPORT_TRIGGER ) + { + /* + cg_triggerEntities[cg_numTriggerEntities] = cent; + cg_numTriggerEntities++; + */ + continue; + } + + if ( cent->nextState.solid ) + { + cg_solidEntities[cg_numSolidEntities] = cent; + cg_numSolidEntities++; + continue; + } + } + } + +/* +==================== +CG_ClipMoveToEntities + +==================== +*/ +static void CG_ClipMoveToEntities + ( + const vec3_t start, + const vec3_t mins, + const vec3_t maxs, + const vec3_t end, + int skipNumber, + int mask, + trace_t *tr, + qboolean cylinder + ) + + { + int i; + trace_t trace; + entityState_t *ent; + clipHandle_t cmodel; + vec3_t bmins, bmaxs; + vec3_t origin, angles; + centity_t *cent; + + for ( i = 0 ; i < cg_numSolidEntities ; i++) + { + cent = cg_solidEntities[ i ]; + ent = ¢->currentState; + + if ( ent->number == skipNumber ) + continue; + + if ( ent->solid == SOLID_BMODEL ) + { + // special value for bmodel + cmodel = cgi.CM_InlineModel( ent->modelindex ); + if ( !cmodel ) + continue; + VectorCopy( cent->lerpAngles, angles ); + VectorCopy( cent->lerpOrigin, origin ); + } + else + { + IntegerToBoundingBox( ent->solid, bmins, bmaxs ); + cmodel = cgi.CM_TempBoxModel( bmins, bmaxs, CONTENTS_BODY ); //CONTENTS_SOLID | CONTENTS_BODY ); + VectorCopy( vec3_origin, angles ); + VectorCopy( cent->lerpOrigin, origin ); + } + + cgi.CM_TransformedBoxTrace( &trace, start, end, mins, maxs, cmodel, mask, origin, angles, cylinder ); + + if (trace.allsolid || trace.fraction < tr->fraction) + { + trace.entityNum = ent->number; + *tr = trace; + } + else if (trace.startsolid) + { + tr->startsolid = qtrue; + } + } + } + +void CG_ShowTrace + ( + trace_t *trace, + int passent, + const char *reason + ) + + { + char text[ 1024 ]; + + assert( reason ); + assert( trace ); + + sprintf( text, "%0.2f : Pass (%d) Frac %f Hit (%d): '%s'\n", + ( float )cg.time / 1000.0f, passent, trace->fraction, trace->entityNum, reason ? reason : "" ); + + if ( cg_traceinfo->integer == 3 ) + { + cgi.DebugPrintf( text ); + } + else + { + cgi.DPrintf( text ); + } + } + +/* +================ +CG_Trace +================ +*/ +void CG_Trace + ( + trace_t *result, + const vec3_t start, + const vec3_t mins, + const vec3_t maxs, + const vec3_t end, + int skipNumber, + int mask, + qboolean cylinder, + qboolean cliptoentities, + const char * description + ) + + { + trace_t t; + + cgi.CM_BoxTrace ( &t, start, end, mins, maxs, 0, mask, cylinder ); + t.entityNum = t.fraction != 1.0 ? ENTITYNUM_WORLD : ENTITYNUM_NONE; + + // If starting in a solid make sure the world is set as the entitynum + + if ( t.startsolid ) + t.entityNum = ENTITYNUM_WORLD; + + if ( cliptoentities ) + { + // check all other solid models + CG_ClipMoveToEntities(start, mins, maxs, end, skipNumber, mask, &t, cylinder ); + } + + *result = t; + + if ( cg_traceinfo->integer ) + { + CG_ShowTrace( result, skipNumber, description ); + } + } + +/* +================ +CG_PlayerTrace +================ +*/ +void CG_PlayerTrace + ( + trace_t *result, + const vec3_t start, + const vec3_t mins, + const vec3_t maxs, + const vec3_t end, + int skipNumber, + int mask, + qboolean cylinder + ) + + { + CG_Trace( result, start, mins, maxs, end, skipNumber, mask, cylinder, qtrue, "PlayerTrace" ); + } + +/* +================ +CG_PointContents +================ +*/ +int CG_PointContents( const vec3_t point, int passEntityNum ) { + int i; + entityState_t *ent; + centity_t *cent; + clipHandle_t cmodel; + int contents; + + contents = cgi.CM_PointContents (point, 0); + + for ( i = 0 ; i < cg_numSolidEntities ; i++ ) { + cent = cg_solidEntities[ i ]; + + ent = ¢->currentState; + + if ( ent->number == passEntityNum ) { + continue; + } + + if (ent->solid != SOLID_BMODEL) { // special value for bmodel + continue; + } + + cmodel = cgi.CM_InlineModel( ent->modelindex ); + if ( !cmodel ) { + continue; + } + + contents |= cgi.CM_TransformedPointContents( point, cmodel, ent->origin, ent->angles ); + } + + return contents; +} + + +/* +======================== +CG_InterpolatePlayerStateCamera + +Generates cg.predicted_player_state by interpolating between +cg.snap->player_state and cg.nextFrame->player_state +======================== +*/ +static void CG_InterpolatePlayerStateCamera( void ) + { + float f; + int i; + snapshot_t *prev, *next; + + prev = cg.snap; + next = cg.nextSnap; + + // + // copy in the current ones if nothing else + // + VectorCopy( cg.predicted_player_state.camera_angles, cg.camera_angles ); + VectorCopy( cg.predicted_player_state.camera_origin, cg.camera_origin ); + cg.camera_fov = cg.predicted_player_state.fov; + + // if the next frame is a teleport, we can't lerp to it + if ( cg.nextFrameCameraCut ) + { + return; + } + + if ( + !next || + next->serverTime <= prev->serverTime + ) + { + return; + } + + f = (float)( cg.time - prev->serverTime ) / ( next->serverTime - prev->serverTime ); + + // interpolate fov + cg.camera_fov = prev->ps.fov + f * ( next->ps.fov - prev->ps.fov ); + + if ( !( cg.snap->ps.pm_flags & PMF_CAMERA_VIEW ) ) + { + return; + } + + for ( i = 0 ; i < 3 ; i++ ) + { + cg.camera_origin[i] = prev->ps.camera_origin[i] + f * (next->ps.camera_origin[i] - prev->ps.camera_origin[i] ); + cg.camera_angles[i] = LerpAngle( prev->ps.camera_angles[i], next->ps.camera_angles[i], f ); + } + } + +/* +======================== +CG_InterpolatePlayerState + +Generates cg.predicted_player_state by interpolating between +cg.snap->player_state and cg.nextFrame->player_state +======================== +*/ +static void CG_InterpolatePlayerState( qboolean grabAngles ) { + float f; + int i; + playerState_t *out; + snapshot_t *prev, *next; + + out = &cg.predicted_player_state; + prev = cg.snap; + next = cg.nextSnap; + + *out = cg.snap->ps; + + // interpolate the camera if necessary + CG_InterpolatePlayerStateCamera(); + + // if we are still allowing local input, short circuit the view angles + if ( grabAngles ) { + usercmd_t cmd; + int cmdNum; + + cmdNum = cgi.GetCurrentCmdNumber(); + cgi.GetUserCmd( cmdNum, &cmd ); + + PM_UpdateViewAngles( out, &cmd ); + } + + // if the next frame is a teleport, we can't lerp to it + if ( cg.nextFrameTeleport ) { + return; + } + + if ( !next || next->serverTime <= prev->serverTime ) { + return; + } + + f = cg.frameInterpolation; + + i = next->ps.bobCycle; + if ( i < prev->ps.bobCycle ) { + i += 256; // handle wraparound + } + out->bobCycle = prev->ps.bobCycle + f * ( i - prev->ps.bobCycle ); + + for ( i = 0 ; i < 3 ; i++ ) { + out->origin[i] = prev->ps.origin[i] + f * (next->ps.origin[i] - prev->ps.origin[i] ); + if ( !grabAngles ) { + out->viewangles[i] = LerpAngle( + prev->ps.viewangles[i], next->ps.viewangles[i], f ); + } + out->velocity[i] = prev->ps.velocity[i] + + f * (next->ps.velocity[i] - prev->ps.velocity[i] ); + } + +} + +/* +================= +CG_PredictPlayerState + +Generates cg.predicted_player_state for the current cg.time +cg.predicted_player_state is guaranteed to be valid after exiting. + +For demo playback, this will be an interpolation between two valid +playerState_t. + +For normal gameplay, it will be the result of predicted usercmd_t on +top of the most recent playerState_t received from the server. + +Each new snapshot will usually have one or more new usercmd over the last, +but we simulate all unacknowledged commands each time, not just the new ones. +This means that on an internet connection, quite a few pmoves may be issued +each frame. + +OPTIMIZE: don't re-simulate unless the newly arrived snapshot playerState_t +differs from the predicted one. Would require saving all intermediate +playerState_t during prediction. + +We detect prediction errors and allow them to be decayed off over several frames +to ease the jerk. +================= +*/ +void CG_PredictPlayerState( void ) { + int cmdNum, current; + playerState_t oldPlayerState; + qboolean moved; + usercmd_t oldestCmd; + usercmd_t latestCmd; + + cg.hyperspace = qfalse; // will be set if touching a trigger_teleport + + // if this is the first frame we must guarantee + // predicted_player_state is valid even if there is some + // other error condition + if ( !cg.validPPS ) { + cg.validPPS = qtrue; + cg.predicted_player_state = cg.snap->ps; + } + + // demo playback just copies the moves + if ( + cg.demoPlayback || + ( cg.snap->ps.pm_flags & PMF_NO_PREDICTION ) || + ( cg.snap->ps.pm_flags & PMF_FROZEN ) + ) + { + CG_InterpolatePlayerState( qfalse ); + return; + } + + // non-predicting local movement will grab the latest angles + //FIXME + // Noclip is jittery for some reason, so I'm disabling prediction while noclipping + if ( cg_nopredict->integer || cg_syncronousClients->integer || (cg.snap->ps.pm_type == PM_NOCLIP) ) { + CG_InterpolatePlayerState( qtrue ); + return; + } + + // prepare for pmove + cg_pmove.ps = &cg.predicted_player_state; + cg_pmove.trace = CG_PlayerTrace; + cg_pmove.pointcontents = CG_PointContents; + cg_pmove.trypush = NULL; + + if ( cg_pmove.ps->pm_type == PM_DEAD ) + { + cg_pmove.tracemask = MASK_PLAYERSOLID & ~CONTENTS_BODY; + } + else + { + cg_pmove.tracemask = MASK_PLAYERSOLID; + } + + /* FIXME + if ( cg.snap->ps.persistant[PERS_TEAM] == TEAM_SPECTATOR ) + { + cg_pmove.tracemask &= ~CONTENTS_BODY; // spectators can fly through bodies + } + */ + + cg_pmove.noFootsteps = ( cgs.dmflags & DF_NO_FOOTSTEPS ) > 0; + + // save the state before the pmove so we can detect transitions + oldPlayerState = cg.predicted_player_state; + + current = cgi.GetCurrentCmdNumber(); + + // if we don't have the commands right after the snapshot, we + // can't accurately predict a current position, so just freeze at + // the last good position we had + cmdNum = current - CMD_BACKUP + 1; + cgi.GetUserCmd( cmdNum, &oldestCmd ); + if ( oldestCmd.serverTime > cg.snap->ps.commandTime + && oldestCmd.serverTime < cg.time ) { // special check for map_restart + if ( cg_showmiss->integer ) { + cgi.Printf ("exceeded PACKET_BACKUP on commands\n"); + } + + return; + } + + // get the latest command so we can know which commands are from previous map_restarts + cgi.GetUserCmd( current, &latestCmd ); + + // get the most recent information we have, even if + // the server time is beyond our current cg.time, + // because predicted player positions are going to + // be ahead of everything else anyway + if ( cg.nextSnap && !cg.nextFrameTeleport && !cg.thisFrameTeleport ) { + cg.predicted_player_state = cg.nextSnap->ps; + cg.physicsTime = cg.nextSnap->serverTime; + } else { + cg.predicted_player_state = cg.snap->ps; + cg.physicsTime = cg.snap->serverTime; + } + + // run cmds + moved = qfalse; + for ( cmdNum = current - CMD_BACKUP + 1 ; cmdNum <= current ; cmdNum++ ) { + // get the command + cgi.GetUserCmd( cmdNum, &cg_pmove.cmd ); + + // don't do anything if the time is before the snapshot player time + if ( cg_pmove.cmd.serverTime <= cg.predicted_player_state.commandTime ) { + continue; + } + + // don't do anything if the command was from a previous map_restart + if ( cg_pmove.cmd.serverTime > latestCmd.serverTime ) { + continue; + } + + // check for a prediction error from last frame + // on a lan, this will often be the exact value + // from the snapshot, but on a wan we will have + // to predict several commands to get to the point + // we want to compare + if ( cg.predicted_player_state.commandTime == oldPlayerState.commandTime ) { + vec3_t delta; + float len; + + if ( cg.thisFrameTeleport ) { + // a teleport will not cause an error decay + VectorClear( cg.predictedError ); + cg.thisFrameTeleport = qfalse; + if ( cg_showmiss->integer ) { + cgi.Printf( "PredictionTeleport\n" ); + } + } else { + vec3_t adjusted; + + CG_AdjustPositionForMover( cg.predicted_player_state.origin, + cg.predicted_player_state.groundEntityNum, cg.physicsTime, cg.oldTime, adjusted ); + VectorSubtract( oldPlayerState.origin, adjusted, delta ); + len = VectorLength( delta ); + if ( len > 0.1 ) { + if ( cg_showmiss->integer ) { + cgi.Printf("Prediction miss: %f\n", len); + } + if ( cg_errorDecay->integer ) { + int t; + float f; + + t = cg.time - cg.predictedErrorTime; + f = ( cg_errorDecay->value - t ) / cg_errorDecay->value; + if ( f < 0 ) { + f = 0; + } + if ( f > 0 && cg_showmiss->integer ) { + cgi.Printf("Double prediction decay: %f\n", f); + } + VectorScale( cg.predictedError, f, cg.predictedError ); + } else { + VectorClear( cg.predictedError ); + } + VectorAdd( delta, cg.predictedError, cg.predictedError ); + cg.predictedErrorTime = cg.oldTime; + } + } + } + + // if our feet are falling, don't try to move + if ( cg_pmove.ps->feetfalling && ( cg_pmove.waterlevel < 2 ) ) + { + cg_pmove.cmd.forwardmove = 0; + cg_pmove.cmd.rightmove = 0; + } + + Pmove (&cg_pmove); + + moved = qtrue; + + // add push trigger movement effects + //CG_TouchTriggerPrediction(); + } + + if ( cg_showmiss->integer > 1 ) { + cgi.Printf( "[%i : %i] ", cg_pmove.cmd.serverTime, cg.time ); + } + + // interpolate the camera if necessary + CG_InterpolatePlayerStateCamera(); + + // adjust for the movement of the groundentity + CG_AdjustPositionForMover( cg.predicted_player_state.origin, + cg.predicted_player_state.groundEntityNum, + cg.snap->serverTime, cg.time, cg.predicted_player_state.origin ); + + if ( !moved ) { + if ( cg_showmiss->integer ) { + cgi.Printf( "not moved\n" ); + } + return; + } + + // fire events and other transition triggered things + CG_TransitionPlayerState( &cg.predicted_player_state, &oldPlayerState ); + + +} + + diff --git a/source/source/cgame/cg_public.h b/source/source/cgame/cg_public.h new file mode 100644 index 0000000..e54bf38 --- /dev/null +++ b/source/source/cgame/cg_public.h @@ -0,0 +1,422 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/cgame/cg_public.h $ +// $Revision:: 47 $ +// $Author:: Markd $ +// $Date:: 7/16/00 11:01p $ +// +// Copyright (C) 1998 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/cgame/cg_public.h $ +// +// 47 7/16/00 11:01p Markd +// Added UpdateLoadingScreen call +// +// 46 7/14/00 9:52p Markd +// added global volume dampener on ambient sound effects for cinematics +// +// 45 7/10/00 11:54p Markd +// added exit level code +// +// 44 6/14/00 11:18a Markd +// cleaned up code using Intel compiler +// +// 43 6/09/00 10:27a Markd +// got lagometer and CG_2D operations functioning +// +// 42 6/05/00 3:10p Markd +// Added has_commands check to client side command processing +// +// 41 6/02/00 6:51p Markd +// added better camera look features +// +// 40 5/18/00 12:52p Steven +// Added use_listener to S_UpdateEntity. +// +// 39 3/31/00 11:45a Markd +// Added skyportal toggling support +// +// 38 3/04/00 11:45a Markd +// Added light style support and malloc and free to the cgame +// +// 37 3/02/00 10:35a Steven +// Changed reverb interface. +// +// 36 2/21/00 4:59p Steven +// Changed S_StartLocalSound to be able to use aliases. +// +// 35 2/21/00 2:51p Markd +// Added GlobalRadius support to tikis +// +// 34 2/14/00 7:34p Aldie +// Fixed some beam rendering issues +// +// 33 2/14/00 5:48p Jimdose +// legs animation now only plays when ANIM_BLEND is set on anim or if uselegs +// is set +// +// 32 2/12/00 3:45p Markd +// Added new exports for cgame access +// +// 31 2/07/00 7:38p Aldie +// Fixed swiping, also various weapons fixes for sword and for sling +// +// 30 2/03/00 1:05p Markd +// added real cameralook +// +// 29 1/29/00 6:17p Aldie +// Added TIKI_NameForNum +// +// 28 1/28/00 6:11p Jimdose +// added CG_GetRendererConfig to clientGameExport_t +// +// 27 1/25/00 8:07p Jimdose +// added Anim_CrossblendTime +// +// 26 1/24/00 6:43p Steven +// Added reverb stuff. +// +// 25 1/20/00 5:20p Markd +// Added skin support into the game +// +// 24 1/11/00 7:30p Jimdose +// added Tag_OrientationEx +// +// 23 12/11/99 5:51p Markd +// First wave of bug fixes after q3a gold merge +// +// 22 12/11/99 3:37p Markd +// q3a gold checkin, first time +// +// 21 12/09/99 10:52a Jimdose +// got tags working with torso and crossblended animations +// +// 20 12/02/99 4:33p Jimdose +// exported TIKI_Tag_NamedLerpOrientation +// +// 19 11/03/99 6:20p Steven +// Cleaned up some sound entity position stuff. +// +// 18 11/01/99 4:11p Jimdose +// made tags work with bone controllers +// +// 17 10/29/99 7:29p Steven +// Moved sound stuff into snapshot. +// +// 16 10/22/99 6:29p Aldie +// Fix for beams in the sky +// +// 15 10/22/99 4:29p Aldie +// Added debuglines +// +// 14 10/19/99 7:52p Markd +// Removed three part model system +// +// 13 10/05/99 6:01p Aldie +// Added headers +// +// DESCRIPTION: +// client game public interfaces + +#ifndef __CG_PUBLIC_H__ +#define __CG_PUBLIC_H__ + +#ifdef __cplusplus +extern "C" + { +#endif + +#define MAGIC_UNUSED_NUMBER 7777 +#define CMD_BACKUP 64 +#define CMD_MASK (CMD_BACKUP - 1) +// allow a lot of command backups for very fast systems +// multiple commands may be combined into a single packet, so this +// needs to be larger than PACKET_BACKUP + + +#define MAX_ENTITIES_IN_SNAPSHOT 256 + +// snapshots are a view of the server at a given time + +// Snapshots are generated at regular time intervals by the server, +// but they may not be sent if a client's rate level is exceeded, or +// they may be dropped by the network. +typedef struct { + int snapFlags; // SNAPFLAG_RATE_DELAYED, etc + int ping; + + int serverTime; // server time the message is valid for (in msec) + + byte areamask[MAX_MAP_AREA_BYTES]; // portalarea visibility bits + + playerState_t ps; // complete information about the current player at this time + + int numEntities; // all of the entities that need to be presented + entityState_t entities[MAX_ENTITIES_IN_SNAPSHOT]; // at the time of this snapshot + + int numServerCommands; // text based server commands to execute when this + int serverCommandSequence; // snapshot becomes current + + int number_of_sounds; + server_sound_t sounds[ MAX_SERVER_SOUNDS ]; +} snapshot_t; + + +/* +================================================================== + +functions imported from the main executable + +================================================================== +*/ + +#define CGAME_IMPORT_API_VERSION 3 + +/* +================================================================== + +functions exported to the main executable + +================================================================== +*/ + +// This was put back in for FAKK2 + +typedef struct + { + int apiversion; + + //============== general services ================== + + // print message on the local console + void (*Printf)( const char *fmt, ...); + void (*DPrintf)( const char *fmt, ...); + void (*DebugPrintf)( const char *fmt, ...); + + // managed memory allocation + void *(*Malloc)( int size ); + void (*Free)( void *block ); + + // abort the game + void (*Error)( int errorLevel, const char *fmt, ...); + + // milliseconds should only be used for profiling, never + // for anything game related. Get time from CG_ReadyToBuildScene. + int (*Milliseconds)( void ); + + // console variable interaction + cvar_t * (*Cvar_Get)( const char *var_name, const char *value, int flags ); + void (*Cvar_Set)( const char *var_name, const char *value ); + + // ClientCommand and ConsoleCommand parameter access + int (*Argc)( void ); + char * (*Argv)( int n ); + char * (*Args)( void ); // concatenation of all argv >= 1 + void (*AddCommand)( const char *cmd ); + + // a -1 return means the file does not exist + // NULL can be passed for buf to just determine existance + int (*FS_ReadFile)( const char *name, void **buf, qboolean quiet ); + void (*FS_FreeFile)( void *buf ); + void (*FS_WriteFile)( const char *qpath, const void *buffer, int size ); + void (*FS_WriteTextFile)( const char *qpath, const void *buffer, int size ); + // add commands to the local console as if they were typed in + // for map changing, etc. The command is not executed immediately, + // but will be executed in order the next time console commands + // are processed + void (*SendConsoleCommand)( const char *text ); + + void (*UpdateLoadingScreen)( void ); + // =========== client specific functions =============== + + // send a string to the server over the network + void (*SendClientCommand)( const char *s ); + + // CM functions + void (*CM_LoadMap)( const char *name ); + clipHandle_t (*CM_InlineModel)( int index ); // 0 = world, 1+ = bmodels + int (*CM_NumInlineModels)( void ); + int (*CM_PointContents)( const vec3_t p, int headnode ); + int (*CM_TransformedPointContents)( const vec3_t p, int headnode, vec3_t origin, vec3_t angles ); + void (*CM_BoxTrace)( trace_t *results, const vec3_t start, const vec3_t end, + const vec3_t mins, const vec3_t maxs, + int headnode, int brushmask, qboolean cylinder ); + void (*CM_TransformedBoxTrace)( trace_t *results, const vec3_t start, const vec3_t end, + const vec3_t mins, const vec3_t maxs, + int headnode, int brushmask, + const vec3_t origin, const vec3_t angles, + qboolean cylinder + ); + clipHandle_t (*CM_TempBoxModel)( const vec3_t mins, const vec3_t maxs, int contents ); + int (*CM_MarkFragments)( int numPoints, const vec3_t *points, const vec3_t projection, + int maxPoints, vec3_t pointBuffer, + int maxFragments, markFragment_t *fragmentBuffer ); + + // =========== sound function calls =============== + + void (*S_StartSound)( vec3_t origin, int entnum, int entchannel, sfxHandle_t sfx, float volume, float min_dist ); + void (*S_StartLocalSound)( const char *sound_name ); + void (*S_StopSound)( int entnum, int channel ); + void (*S_ClearLoopingSounds)( void ); + void (*S_AddLoopingSound)( const vec3_t origin, const vec3_t velocity, sfxHandle_t sfx, float volume, float min_dist ); + void (*S_Respatialize)( int entityNum, vec3_t origin, vec3_t axis[3] ); + void (*S_BeginRegistration)( void ); + sfxHandle_t (*S_RegisterSound)( const char *sample ); + void (*S_EndRegistration)( void ); + void (*S_UpdateEntity)( int entityNum, const vec3_t origin, const vec3_t velocity, qboolean use_listener ); + void (*S_SetReverb)( int reverb_type, float reverb_level ); + void (*S_SetGlobalAmbientVolumeLevel)( float volume ); + + // =========== music function calls =============== + + void (*MUSIC_NewSoundtrack)( const char *name ); + void (*MUSIC_UpdateMood)( int current_mood, int fallback_mood ); + void (*MUSIC_UpdateVolume)( float volume, float fade_time ); + + + // =========== lip function calls =============== + + float (*get_lip_length)(const char * name); + byte * (*get_lip_amplitudes)(const char * name, int *number_of_amplitudes); + + // =========== camera function calls =============== + + float * (*get_camera_offset)( qboolean *lookactive, qboolean *resetview ); + + // =========== renderer function calls ================ + void (*BeginRegistration)( void ); + void (*EndRegistration)( void ); + + void (*R_ClearScene)( void ); + void (*R_RenderScene)( const refdef_t *fd ); + void (*R_LoadWorldMap)( const char *mapname ); + qhandle_t (*R_RegisterModel)( const char *name ); + qhandle_t (*R_RegisterSkin)( const char *name ); + qhandle_t (*R_RegisterShader)( const char *name ); + qhandle_t (*R_RegisterShaderNoMip)( const char *name ); + void (*R_AddRefEntityToScene)( refEntity_t *ent ); + void (*R_AddRefSpriteToScene)( refEntity_t *ent ); + void (*R_AddLightToScene)( vec3_t origin, float intensity, float r, float g, float b, int type ); + void (*R_AddPolyToScene)( qhandle_t hShader, int numVerts, const polyVert_t *verts, int renderfx ); + void (*R_SetColor)( const vec4_t rgba ); // NULL = 1,1,1,1 + void (*R_DrawStretchPic) ( float x, float y, float w, float h, + float s1, float t1, float s2, float t2, + qhandle_t hShader ); // 0 = white + refEntity_t * (*R_GetRenderEntity)( int entityNumber ); + void (*R_ModelBounds)( clipHandle_t model, vec3_t mins, vec3_t maxs ); + float (*R_ModelRadius)( clipHandle_t model ); + float (*R_Noise)( float x, float y, float z, float t ); + void (*R_DebugLine)( vec3_t start, vec3_t end, float r, float g, float b, float alpha ); + // =========== Swipes ============= + void (*R_SwipeBegin) ( float thistime, float life, qhandle_t shader ); + void (*R_SwipePoint) ( vec3_t p1, vec3_t p2, float time ); + void (*R_SwipeEnd) ( void ); + int (*R_GetShaderWidth)( qhandle_t shader ); + int (*R_GetShaderHeight)( qhandle_t shader ); + void (*R_DrawBox)( float x, float y, float w, float h ); + + // =========== data shared with the client ============= + void (*GetGameState)( gameState_t *gamestate ); + int (*GetSnapshot)( int snapshotNumber, snapshot_t *snapshot ); + void (*GetCurrentSnapshotNumber)( int *snapshotNumber, int *serverTime ); + void (*GetGlconfig)( glconfig_t *glconfig ); + + // will return false if the number is so old that it doesn't exist in the buffer anymore + qboolean (*GetParseEntityState)( int parseEntityNumber, entityState_t *state ); + int (*GetCurrentCmdNumber)( void ); // returns the most recent command number + // which is the local predicted command for + // the following frame + qboolean (*GetUserCmd)( int cmdNumber, usercmd_t *ucmd ); + qboolean (*GetServerCommand)( int serverCommandNumber ); + + // ALIAS STUFF + qboolean (*Alias_Add)( const char * alias, const char * name, const char *parameters ); + const char * (*Alias_FindRandom)( const char * alias ); + void (*Alias_Dump)( void ); + void (*Alias_Clear)( void ); + + // ==================== TIKI STUFF ========================== + // TIKI SPECIFIC STUFF + int (*TIKI_GetHandle)( qhandle_t handle ); + int (*NumAnims) ( int tikihandle ); + int (*NumSkins) ( int tikihandle ); + int (*NumSurfaces) ( int tikihandle ); + int (*NumTags) ( int tikihandle ); + qboolean (*InitCommands) ( int tikihandle, tiki_cmd_t * tiki_cmd ); + void (*CalculateBounds) ( int tikihandle, float scale, vec3_t mins, vec3_t maxs ); + void (*FlushAll) ( void ); + const char * (*TIKI_NameForNum)( int tikihandle ); + + // ANIM SPECIFIC STUFF + const char * (*Anim_NameForNum) ( int tikihandle, int animnum ); + int (*Anim_NumForName) ( int tikihandle, const char * name ); + int (*Anim_Random) ( int tikihandle, const char * name ); + int (*Anim_NumFrames) ( int tikihandle, int animnum ); + float (*Anim_Time) ( int tikihandle, int animnum ); + void (*Anim_Delta) ( int tikihandle, int animnum, vec3_t delta ); + int (*Anim_Flags) ( int tikihandle, int animnum ); + int (*Anim_CrossblendTime) ( int tikihandle, int animnum ); + qboolean (*Anim_HasCommands) ( int tikihandle, int animnum ); + + // FRAME SPECIFIC STUFF + qboolean (*Frame_Commands) ( int tikihandle, int animnum, int framenum, tiki_cmd_t * tiki_cmd ); + void (*Frame_Delta) ( int tikihandle, int animnum, int framenum, vec3_t delta ); + float (*Frame_Time) ( int tikihandle, int animnum, int framenum ); + void (*Frame_Bounds)( int tikihandle, int animnum, int framenum, float scale, vec3_t mins, vec3_t maxs ); + float (*Frame_Radius)( int tikihandle, int animnum, int framenum ); + + // SURFACE SPECIFIC STUFF + int (*Surface_NameToNum) ( int tikihandle, const char * name ); + const char * (*Surface_NumToName) ( int tikihandle, int num ); + int (*Surface_Flags) ( int tikihandle, int num ); + int (*Surface_NumSkins) ( int tikihandle, int num ); + + // TAG SPECIFIC STUFF + int (*Tag_NumForName) ( int tikihandle, const char * name ); + const char * (*Tag_NameForNum) ( int tikihandle, int num ); + orientation_t (*Tag_Orientation) ( int tikihandle, int anim, int frame, int tagnum, float scale, int *bone_tag, vec4_t *bone_quat ); + orientation_t (*Tag_OrientationEx) ( int tikihandle, int anim, int frame, int tagnum, float scale, int *bone_tag, vec4_t *bone_quat, + int crossblend_anim, int crossblend_frame, float crossblend_lerp, qboolean uselegs, qboolean usetorso, int torso_anim, int torso_frame, + int torso_crossblend_anim, int torso_crossblend_frame, float torso_crossblend_lerp ); + + orientation_t (*Tag_NamedOrientation) ( int tikihandle, int anim, int frame, float scale, const char *tagName, int *bone_tag, vec4_t *bone_quat ); + orientation_t (*Tag_LerpedOrientation) ( int tikihandle, refEntity_t *model, int tagnum ); + + // ALIAS SPECIFIC STUF + qboolean (*TIKI_Alias_Add)( int tikihandle, const char * alias, const char * name, const char *parameters ); + const char * (*TIKI_Alias_FindRandom)( int tikihandle, const char * alias ); + void (*TIKI_Alias_Dump)( int tikihandle ); + void (*TIKI_Alias_Clear)( int tikihandle ); + const char * (*TIKI_Alias_FindDialog)( int tikihandle, const char * alias, int random, int entity_number ); + +} clientGameImport_t; + + +/* +================================================================== + +functions exported to the main executable + +================================================================== +*/ + +typedef struct { + void (*CG_Init)( clientGameImport_t *imported, int serverMessageNum, int serverCommandSequence ); + void (*CG_Shutdown)( void ); + void (*CG_DrawActiveFrame)( int serverTime, stereoFrame_t stereoView, qboolean demoPlayback ); + qboolean (*CG_ConsoleCommand)( void ); + void (*CG_GetRendererConfig)( void ); + void (*CG_Draw2D)( void ); + + } clientGameExport_t; + + +#ifdef __cplusplus +} +#endif + +#endif // __CG_PUBLIC_H__ diff --git a/source/source/cgame/cg_servercmds.c b/source/source/cgame/cg_servercmds.c new file mode 100644 index 0000000..5520649 --- /dev/null +++ b/source/source/cgame/cg_servercmds.c @@ -0,0 +1,166 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/cgame/cg_servercmds.c $ +// $Revision:: 8 $ +// $Author:: Steven $ +// $Date:: 7/24/00 6:46p $ +// +// Copyright (C) 1998 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/cgame/cg_servercmds.c $ +// +// 8 7/24/00 6:46p Steven +// Changed sv_cinematic from a cvar to a player stat. +// +// 7 7/14/00 9:52p Markd +// added global volume dampener on ambient sound effects for cinematics +// +// 6 2/29/00 5:51p Jimdose +// added alternate spawnpoint support +// +// 5 12/11/99 5:51p Markd +// First wave of bug fixes after q3a gold merge +// +// 4 12/11/99 3:37p Markd +// q3a gold checkin, first time +// +// 3 10/05/99 6:01p Aldie +// Added headers +// +// DESCRIPTION: +// cg_servercmds.c -- text commands sent by the server + +#include "cg_local.h" + + +/* +================ +CG_ParseServerinfo + +This is called explicitly when the gamestate is first received, +and whenever the server updates any serverinfo flagged cvars +================ +*/ +void CG_ParseServerinfo( void ) { + const char *info; + const char *mapname; + char map[ MAX_QPATH ]; + char *spawnpos; + + info = CG_ConfigString( CS_SERVERINFO ); + cgs.gametype = atoi( Info_ValueForKey( info, "g_gametype" ) ); + cgs.dmflags = atoi( Info_ValueForKey( info, "dmflags" ) ); + cgs.teamflags = atoi( Info_ValueForKey( info, "teamflags" ) ); + cgs.fraglimit = atoi( Info_ValueForKey( info, "fraglimit" ) ); + cgs.timelimit = atoi( Info_ValueForKey( info, "timelimit" ) ); + cgs.maxclients = atoi( Info_ValueForKey( info, "sv_maxclients" ) ); + + mapname = Info_ValueForKey( info, "mapname" ); + + spawnpos = strchr( mapname, '$' ); + if ( spawnpos ) + { + Q_strncpyz( map, mapname, spawnpos - mapname + 1 ); + } + else + { + strcpy( map, mapname ); + } + + Com_sprintf( cgs.mapname, sizeof( cgs.mapname ), "maps/%s.bsp", map ); +} + + +/* +================ +CG_ConfigStringModified + +================ +*/ +static void CG_ConfigStringModified( void ) + { + int num; + + num = atoi( cgi.Argv( 1 ) ); + + // get the gamestate from the client system, which will have the + // new configstring already integrated + cgi.GetGameState( &cgs.gameState ); + + CG_ProcessConfigString( num ); + } + +/* +=============== +CG_MapRestart +=============== +*/ +static void CG_MapRestart( void ) { + if ( cg_showmiss->integer ) { + cgi.Printf( "CG_MapRestart\n" ); + } + CG_Shutdown(); + CG_Init( &cgi, cgs.processedSnapshotNum, cgs.serverCommandSequence ); +} + +/* +================= +CG_ServerCommand + +The string has been tokenized and can be retrieved with +Cmd_Argc() / Cmd_Argv() +================= +*/ +static void CG_ServerCommand( void ) + { + const char *cmd; + + cmd = cgi.Argv(0); + + if ( !cmd[0] ) + { + // server claimed the command + return; + } + + if ( !strcmp( cmd, "cs" ) ) + { + CG_ConfigStringModified(); + return; + } + + if ( !strcmp( cmd, "print" ) ) + { + cgi.Printf( "%s", cgi.Argv(1) ); + return; + } + + if ( !strcmp( cmd, "map_restart" ) ) + { + CG_MapRestart(); + return; + } + + cgi.Printf( "Unknown client game command: %s\n", cmd ); + } + + +/* +==================== +CG_ExecuteNewServerCommands + +Execute all of the server commands that were received along +with this this snapshot. +==================== +*/ +void CG_ExecuteNewServerCommands( int latestSequence ) { + while ( cgs.serverCommandSequence < latestSequence ) { + if ( cgi.GetServerCommand( ++cgs.serverCommandSequence ) ) { + CG_ServerCommand(); + } + } +} diff --git a/source/source/cgame/cg_snapshot.c b/source/source/cgame/cg_snapshot.c new file mode 100644 index 0000000..456f545 --- /dev/null +++ b/source/source/cgame/cg_snapshot.c @@ -0,0 +1,573 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/cgame/cg_snapshot.c $ +// $Revision:: 37 $ +// $Author:: Aldie $ +// $Date:: 7/19/00 9:52p $ +// +// Copyright (C) 1998 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/cgame/cg_snapshot.c $ +// +// 37 7/19/00 9:52p Aldie +// Put ET_EVENTS back in. They will get sent over once, and should get +// processed once on the client. +// +// 36 6/17/00 1:54p Markd +// Added server restarted code +// +// 35 6/15/00 8:21p Markd +// Added CleanupCommandManager support +// +// 34 6/15/00 7:58p Markd +// added same map restarting support +// +// 33 6/01/00 7:45p Aldie +// Made it so that swipes are removed when client entities are reset. +// +// 32 6/01/00 12:21p Steven +// Improvement to splashes. +// +// 31 5/20/00 5:14p Markd +// Added ITEM special effects +// +// 30 5/04/00 9:45a Markd +// added check for different modelindex's +// +// 29 4/20/00 3:35p Steven +// Reset the teleport flag back to false in CG_ResetEntity. +// +// 28 4/03/00 4:43p Markd +// fixed a teleportation issue +// +// 27 3/24/00 1:05p Aldie +// Added flag clearing to CG_ResetEntity +// +// 26 3/02/00 10:35a Steven +// Changed reverb interface. +// +// 25 2/07/00 10:10a Markd +// fixed bug with interpolating attached and non-attached entites +// +// 24 1/24/00 6:43p Steven +// Added reverb stuff. +// +// 23 1/15/00 2:39p Aldie +// Changed definition of RemoveClientEntity +// +// 22 1/12/00 8:02p Markd +// nextFrameCameraCut gets set based on whether or not there is a camera cut in +// the following frame +// +// 21 12/13/99 3:31p Aldie +// Commented out some Carmack code to make fakk work +// +// 20 12/13/99 10:46a Markd +// incremental merge fix +// +// 19 12/11/99 5:51p Markd +// First wave of bug fixes after q3a gold merge +// +// 18 12/11/99 3:37p Markd +// q3a gold checkin, first time +// +// 17 11/11/99 11:35a Jimdose +// first pass at torso animation blending in +// +// 16 11/10/99 2:18p Jimdose +// removed some unused variables from centity_t +// working on torso animation +// +// 15 11/03/99 4:59p Steven +// Included music stuff in initial snapshot. +// +// 14 10/29/99 7:24p Steven +// Moved sound stuff into snapshot. +// +// 13 10/21/99 6:19p Markd +// removed torso and head members from entity_state +// +// 12 10/19/99 7:52p Markd +// Removed three part model system +// +// 11 10/12/99 2:23p Markd +// Rewrote camera and player movetype system +// +// 10 10/08/99 7:36p Markd +// Added ET_PLAYER check for ET_MODELANIM +// +// 9 10/06/99 7:25p Markd +// removed TIMESTAMP, time and fixed make_static bug +// +// 8 10/05/99 6:01p Aldie +// Added headers +// +// DESCRIPTION: +// things that happen on snapshot transition, not necessarily every +// single frame + +#include "cg_local.h" + +/* +================== +CG_ResetEntity +================== +*/ +static void CG_ResetEntity( centity_t *cent ) { + + VectorCopy (cent->currentState.origin, cent->lerpOrigin); + + VectorCopy (cent->currentState.angles, cent->lerpAngles); + + // if we just teleported, all we care about is the position and orientation information + if ( cent->teleported ) + { + cent->teleported = qfalse; + return; + } + + // reset local color + cent->client_color[ 0 ] = 1; + cent->client_color[ 1 ] = 1; + cent->client_color[ 2 ] = 1; + cent->client_color[ 3 ] = 1; + + // Make sure entity starts with no loop sound + cent->tikiLoopSound = 0; + + // Reset client flags + cent->clientFlags = 0; + + // Reset splash info + cent->splash_last_spawn_time = 0; + cent->splash_still_count = -1; + + // reset client command + CG_RemoveClientEntity( cent->currentState.number, cgs.model_tiki[ cent->currentState.modelindex ], cent ); + + // reset the animation for the entities + if ( cent->currentState.eType < ET_GENERAL ) + { + CG_ClearModelAnimation( cgs.model_tiki[ cent->currentState.modelindex ], + ¢->am, cent->currentState.anim, + cg.snap->serverTime, + cent->lerpOrigin, + cent->currentState.number + ); + CG_ClearModelAnimation( cgs.model_tiki[ cent->currentState.modelindex ], + ¢->torso_am, cent->currentState.torso_anim, + cg.snap->serverTime, + cent->lerpOrigin, + cent->currentState.number + ); + } + + if ( cent->currentState.eType == ET_PLAYER ) { + CG_ResetPlayerEntity( cent ); + } +} + +/* +=============== +CG_TransitionEntity + +cent->nextState is moved to cent->currentState and events are fired +=============== +*/ +static void CG_TransitionEntity( centity_t *cent ) + { + cent->currentState = cent->nextState; + cent->currentValid = qtrue; + + // reset if the entity wasn't in the last frame or was teleported + if ( !cent->interpolate ) { + CG_ResetEntity( cent ); + } + + // clear the next state. if will be set by the next CG_SetNextSnap + cent->interpolate = qfalse; + // reset the teleported state + cent->teleported = qfalse; + + if ( cent->currentState.eType == ET_EVENTS ) + { + CG_Event( cent ); + } + } + + +/* +================== +CG_SetInitialSnapshot + +This will only happen on the very first snapshot, or +on tourney restarts. All other times will use +CG_TransitionSnapshot instead. +================== +*/ +void CG_SetInitialSnapshot( snapshot_t *snap ) { + int i; + centity_t *cent; + entityState_t *state; + + cg.snap = snap; + + // sort out solid entities + CG_BuildSolidList(); + + CG_ExecuteNewServerCommands( snap->serverCommandSequence ); + + for ( i = 0 ; i < cg.snap->numEntities ; i++ ) { + state = &cg.snap->entities[ i ]; + cent = &cg_entities[ state->number ]; + + cent->currentState = *state; + cent->interpolate = qfalse; + cent->currentValid = qtrue; + + CG_ResetEntity( cent ); + } + + cgi.MUSIC_UpdateMood( snap->ps.current_music_mood, snap->ps.fallback_music_mood ); + cgi.MUSIC_UpdateVolume( snap->ps.music_volume, snap->ps.music_volume_fade_time ); + cgi.S_SetReverb( snap->ps.reverb_type, snap->ps.reverb_level ); +} + + +/* +=================== +CG_TransitionSnapshot + +The transition point from snap to nextSnap has passed +=================== +*/ +static void CG_TransitionSnapshot( void ) { + centity_t *cent; + snapshot_t *oldFrame; + qboolean differentServer; + int i; + + + if ( !cg.snap ) { + cgi.Error( ERR_DROP, "CG_TransitionSnapshot: NULL cg.snap" ); + } + if ( !cg.nextSnap ) { + cgi.Error( ERR_DROP, "CG_TransitionSnapshot: NULL cg.nextSnap" ); + } + + // execute any server string commands before transitioning entities + CG_ExecuteNewServerCommands( cg.nextSnap->serverCommandSequence ); + + // clear the currentValid flag for all entities in the existing snapshot + for ( i = 0 ; i < cg.snap->numEntities ; i++ ) { + cent = &cg_entities[ cg.snap->entities[ i ].number ]; + cent->currentValid = qfalse; + } + + // move nextSnap to snap and do the transitions + oldFrame = cg.snap; + cg.snap = cg.nextSnap; + + // if restarted, teleport and no camera lerp + if ( ( oldFrame->snapFlags ^ cg.snap->snapFlags ) & SNAPFLAG_SERVERCOUNT ) + { + CG_ServerRestarted(); + differentServer = qtrue; + } + else + { + differentServer = qfalse; + } + + //FAKK: Commented out to make our stuff work + //cg_entities[ cg.snap->ps.clientNum ].interpolate = qfalse; + + for ( i = 0 ; i < cg.snap->numEntities ; i++ ) { + cent = &cg_entities[ cg.snap->entities[ i ].number ]; + if ( differentServer ) + { + cent->interpolate = qfalse; + cent->teleported = qfalse; + } + CG_TransitionEntity( cent ); + } + + for ( i = 0 ; i < cg.snap->number_of_sounds ; i++ ) + { + CG_ProcessSound( &cg.snap->sounds[ i ] ); + } + + cg.nextSnap = NULL; + + // check for playerstate transition events + + if ( oldFrame ) + { + playerState_t *ops, *ps; + + ops = &oldFrame->ps; + ps = &cg.snap->ps; + + // teleporting checks are irrespective of prediction + if ( ps->pm_flags & PMF_TIME_TELEPORT ) { + cg.thisFrameTeleport = qtrue; + } + + if ( ( ops->current_music_mood != ps->current_music_mood ) || ( ops->fallback_music_mood != ps->fallback_music_mood ) ) + cgi.MUSIC_UpdateMood( ps->current_music_mood, ps->fallback_music_mood ); + + if ( ( ops->music_volume != ps->music_volume ) || ( ops->music_volume_fade_time != ps->music_volume_fade_time ) ) + cgi.MUSIC_UpdateVolume( ps->music_volume, ps->music_volume_fade_time ); + + if ( ( ops->reverb_type != ps->reverb_type ) || ( ops->reverb_level != ps->reverb_level ) ) + cgi.S_SetReverb( ps->reverb_type, ps->reverb_level ); + + // if we are not doing client side movement prediction for any + // reason, then the client events and view changes will be issued now + if + ( + cg.demoPlayback || + ( cg.snap->ps.pm_flags & PMF_NO_PREDICTION ) || + cg_nopredict->integer || + cg_syncronousClients->integer + ) + { + CG_TransitionPlayerState( ps, ops ); + } + } +} + + +/* +=================== +CG_SetNextSnap + +A new snapshot has just been read in from the client system. +=================== +*/ +static void CG_SetNextSnap( snapshot_t *snap ) { + int num; + entityState_t *es; + centity_t *cent; + + cg.nextSnap = snap; + + cg_entities[ cg.snap->ps.clientNum ].interpolate = qtrue; + + // check for extrapolation errors + for ( num = 0 ; num < snap->numEntities ; num++ ) { + es = &snap->entities[num]; + cent = &cg_entities[ es->number ]; + + cent->nextState = *es; + + // if this frame is a teleport, or the entity wasn't in the + // previous frame, don't interpolate + if ( + !cent->currentValid || + ( ( cent->currentState.eFlags ^ es->eFlags ) & EF_TELEPORT_BIT ) || + ( cent->currentState.parent != es->parent ) || + ( cent->currentState.modelindex != es->modelindex ) + ) { + cent->interpolate = qfalse; + // if this isn't the first frame and we have valid data, set the teleport flag + if ( cent->currentValid ) + { + cent->teleported = qtrue; + } + } else { + cent->interpolate = qtrue; + } + } + + // if the next frame is a teleport for the playerstate, we + // can't interpolate during demos + if ( cg.snap && ( snap->ps.pm_flags & PMF_TIME_TELEPORT ) ) { + cg.nextFrameTeleport = qtrue; + } else { + cg.nextFrameTeleport = qfalse; + } + + // if changing follow mode, don't interpolate + if ( cg.nextSnap->ps.clientNum != cg.snap->ps.clientNum ) { + cg.nextFrameTeleport = qtrue; + } + + // if the camera cut bit changed, than the next frame is a camera cut + if ( + ( cg.nextSnap->ps.camera_flags & CF_CAMERA_CUT_BIT ) != + ( cg.snap->ps.camera_flags & CF_CAMERA_CUT_BIT ) + ) { + cg.nextFrameCameraCut = qtrue; + } else { + cg.nextFrameCameraCut = qfalse; + } + + // if changing server restarts, don't interpolate + if ( ( cg.nextSnap->snapFlags ^ cg.snap->snapFlags ) & SNAPFLAG_SERVERCOUNT ) { + // reset the camera + cg.lastCameraTime = -1; + cg.nextFrameTeleport = qtrue; + } + + + + // sort out solid entities + CG_BuildSolidList(); +} + + +/* +======================== +CG_ReadNextSnapshot + +This is the only place new snapshots are requested +This may increment cgs.processedSnapshotNum multiple +times if the client system fails to return a +valid snapshot. +======================== +*/ +static snapshot_t *CG_ReadNextSnapshot( void ) { + qboolean r; + snapshot_t *dest; + + if ( cg.latestSnapshotNum > cgs.processedSnapshotNum + 1000 ) { + cgi.Error( ERR_DROP, "CG_ReadNextSnapshot: way out of range, %i > %i", + cg.latestSnapshotNum, cgs.processedSnapshotNum ); + } + + while ( cgs.processedSnapshotNum < cg.latestSnapshotNum ) { + // decide which of the two slots to load it into + if ( cg.snap == &cg.activeSnapshots[0] ) { + dest = &cg.activeSnapshots[1]; + } else { + dest = &cg.activeSnapshots[0]; + } + + // try to read the snapshot from the client system + cgs.processedSnapshotNum++; + r = cgi.GetSnapshot( cgs.processedSnapshotNum, dest ); + + // if it succeeded, return + if ( r ) { + CG_AddLagometerSnapshotInfo( dest ); + return dest; + } + + // a GetSnapshot will return failure if the snapshot + // never arrived, or is so old that its entities + // have been shoved off the end of the circular + // buffer in the client system. + + // record as a dropped packet + CG_AddLagometerSnapshotInfo( NULL ); + + // If there are additional snapshots, continue trying to + // read them. + } + + // nothing left to read + return NULL; +} + +/* +============ +CG_ProcessSnapshots + +We are trying to set up a renderable view, so determine +what the simulated time is, and try to get snapshots +both before and after that time if available. + +If we don't have a valid cg.snap after exiting this function, +then a 3D game view cannot be rendered. This should only happen +right after the initial connection. After cg.snap has been valid +once, it will never turn invalid. + +Even if cg.snap is valid, cg.nextSnap may not be, if the snapshot +hasn't arrived yet (it becomes an extrapolating situation instead +of an interpolating one) + +============ +*/ +void CG_ProcessSnapshots( void ) { + snapshot_t *snap; + int n; + + // see what the latest snapshot the client system has is + cgi.GetCurrentSnapshotNumber( &n, &cg.latestSnapshotTime ); + if ( n != cg.latestSnapshotNum ) { + if ( n < cg.latestSnapshotNum ) { + // this should never happen + cgi.Error( ERR_DROP, "CG_ProcessSnapshots: n < cg.latestSnapshotNum" ); + } + cg.latestSnapshotNum = n; + } + + // If we have yet to receive a snapshot, check for it. + // Once we have gotten the first snapshot, cg.snap will + // always have valid data for the rest of the game + while ( !cg.snap ) { + snap = CG_ReadNextSnapshot(); + if ( !snap ) { + // we can't continue until we get a snapshot + return; + } + + // set our weapon selection to what + // the playerstate is currently using + if ( !( snap->snapFlags & SNAPFLAG_NOT_ACTIVE ) ) { + CG_SetInitialSnapshot( snap ); + } + } + + // loop until we either have a valid nextSnap with a serverTime + // greater than cg.time to interpolate towards, or we run + // out of available snapshots + do { + // if we don't have a nextframe, try and read a new one in + if ( !cg.nextSnap ) { + snap = CG_ReadNextSnapshot(); + + // if we still don't have a nextframe, we will just have to + // extrapolate + if ( !snap ) { + break; + } + + CG_SetNextSnap( snap ); + + // if time went backwards, we have a level restart + if ( cg.nextSnap->serverTime < cg.snap->serverTime ) { + // only drop if this is not a restart or loadgame + if ( !( ( cg.nextSnap->snapFlags ^ cg.snap->snapFlags ) & SNAPFLAG_SERVERCOUNT ) ) { + cgi.Error( ERR_DROP, "CG_ProcessSnapshots: Server time went backwards" ); + } + } + } + + // if our time is < nextFrame's, we have a nice interpolating state + if ( cg.time >= cg.snap->serverTime && cg.time < cg.nextSnap->serverTime ) { + break; + } + + // we have passed the transition from nextFrame to frame + CG_TransitionSnapshot(); + } while ( 1 ); + + // assert our valid conditions upon exiting + if ( cg.snap == NULL ) { + cgi.Error( ERR_DROP, "CG_ProcessSnapshots: cg.snap == NULL" ); + } + if ( cg.time < cg.snap->serverTime ) { + // this can happen right after a vid_restart + cg.time = cg.snap->serverTime; + } + if ( cg.nextSnap != NULL && cg.nextSnap->serverTime <= cg.time ) { + cgi.Error( ERR_DROP, "CG_ProcessSnapshots: cg.nextSnap->serverTime <= cg.time" ); + } +} + diff --git a/source/source/cgame/cg_sound.cpp b/source/source/cgame/cg_sound.cpp new file mode 100644 index 0000000..3370bae --- /dev/null +++ b/source/source/cgame/cg_sound.cpp @@ -0,0 +1,38 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/cgame/cg_sound.cpp $ +// $Revision:: 4 $ +// $Author:: Steven $ +// $Date:: 10/29/99 7:24p $ +// +// Copyright (C) 1998 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/cgame/cg_sound.cpp $ +// +// 4 10/29/99 7:24p Steven +// Moved sound stuff into snapshot. +// +// 3 10/05/99 6:01p Aldie +// Added headers +// +// DESCRIPTION: +// Sound function + +#include "cg_local.h" + +void CG_ProcessSound( server_sound_t *sound ) + { + if ( sound->stop_flag ) + { + cgi.S_StopSound( sound->entity_number, sound->channel ); + } + else + { + cgi.S_StartSound( sound->origin, sound->entity_number, sound->channel, cgs.sound_precache[sound->sound_index], + sound->volume, sound->min_dist ); + } + } diff --git a/source/source/cgame/cg_specialfx.cpp b/source/source/cgame/cg_specialfx.cpp new file mode 100644 index 0000000..eceeff2 --- /dev/null +++ b/source/source/cgame/cg_specialfx.cpp @@ -0,0 +1,370 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/cgame/cg_specialfx.cpp $ +// $Revision:: 12 $ +// $Author:: Markd $ +// $Date:: 7/29/00 12:05p $ +// +// Copyright (C) 1998 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/cgame/cg_specialfx.cpp $ +// +// 12 7/29/00 12:05p Markd +// fixed footstep sounds +// +// 11 6/28/00 4:36p Markd +// added debug footsteps code +// +// 10 6/25/00 11:21a Markd +// fixed slime code for player +// +// 9 6/16/00 5:52p Steven +// Raised footstep special effect a little bit off of the ground. +// +// 8 6/16/00 5:45p Aldie +// Fix some stuff for footsteps +// +// 7 6/16/00 5:27p Steven +// More work on dirtcloud stuff. +// +// 6 6/16/00 3:31p Steven +// Commented out dirt cloud stuff temporarily until we get the correct effect. +// +// 5 6/15/00 10:11a Steven +// Added some temporary stuff so we could see the feet surface effects. +// +// 4 6/13/00 10:59a Steven +// Moved splash stuff to here, added the flagT_ANGLES to splashes, and added +// some of the stuff for footstep special effects. +// +// 3 6/09/00 7:53p Aldie +// Added origin to playsound and fixed bouncesound and a couple other sound +// things +// +// 2 6/03/00 8:19p Markd +// Added footstep code +// +// 1 6/03/00 7:26p Markd +// +// DESCRIPTION: +// Special Effects code + +#include "cg_local.h" +#include "cg_commands.h" + +extern refEntity_t *current_entity; +extern int current_tiki; + +/* +============================================================== + +FOOTSTEP CODE + +============================================================== +*/ + +#define GROUND_DISTANCE 32 +#define WATER_NO_SPLASH_HEIGHT 16 + +void CG_Footstep + ( + centity_t * ent, + float volume + ) + + { + vec3_t end, midlegs; + trace_t trace; + int contents, surftype; + spawnthing_t effect; + refEntity_t *old_entity; + int old_tiki; + refEntity_t new_entity; + int new_tiki; + qhandle_t hModel; + + // send a trace down from the player to the ground + VectorCopy( ent->lerpOrigin, end ); + end[2] -= GROUND_DISTANCE; + + if ( ent->currentState.eType == ET_PLAYER ) + { + CG_Trace( &trace, ent->lerpOrigin, NULL, NULL, end, ent->currentState.number, MASK_PLAYERSOLID, qtrue, qtrue, "Player Footsteps" ); + } + else + { + CG_Trace( &trace, ent->lerpOrigin, NULL, NULL, end, ent->currentState.number, MASK_MONSTERSOLID, qfalse, qfalse, "Monster Footsteps" ); + } + + if ( trace.fraction == 1.0f ) + { + return; + } + + contents = CG_PointContents( trace.endpos, -1 ); + if ( contents & MASK_WATER ) + { + // take our ground position and trace upwards + VectorCopy( trace.endpos, midlegs ); + midlegs[ 2 ] += WATER_NO_SPLASH_HEIGHT; + contents = CG_PointContents( midlegs, -1 ); + if ( contents & MASK_WATER ) + { + commandManager.PlaySound( "footstep_wade", NULL, CHAN_AUTO, volume ); + if ( cg_debugFootsteps->integer ) + { + cgi.DPrintf( "Footstep: wade volume: %.2f\n", volume ); + } + } + else + { + commandManager.PlaySound( "footstep_splash", NULL, CHAN_AUTO, volume ); + if ( cg_debugFootsteps->integer ) + { + cgi.DPrintf( "Footstep: splash volume: %.2f\n", volume ); + } + } + } + else + { + surftype = trace.surfaceFlags & MASK_SURF_TYPE; + switch ( surftype ) + { + case SURF_TYPE_WOOD: + commandManager.PlaySound( "footstep_wood", NULL, CHAN_AUTO, volume ); + if ( cg_debugFootsteps->integer ) + { + cgi.DPrintf( "Footstep: wood volume: %.2f\n", volume ); + } + break; + case SURF_TYPE_METAL: + commandManager.PlaySound( "footstep_metal", NULL, CHAN_AUTO, volume ); + if ( cg_debugFootsteps->integer ) + { + cgi.DPrintf( "Footstep: metal volume: %.2f\n", volume ); + } + break; + case SURF_TYPE_ROCK: + commandManager.PlaySound( "footstep_rock", NULL, CHAN_AUTO, volume ); + if ( cg_debugFootsteps->integer ) + { + cgi.DPrintf( "Footstep: rock volume: %.2f\n", volume ); + } + break; + case SURF_TYPE_DIRT: + memset( &new_entity, 0, sizeof( refEntity_t ) ); + + commandManager.PlaySound( "footstep_dirt", NULL, CHAN_AUTO, volume ); + + if ( cg_debugFootsteps->integer ) + { + cgi.DPrintf( "Footstep: dirt volume: %.2f\n", volume ); + } + + // Save the old stuff + + old_entity = current_entity; + old_tiki = current_tiki; + + // Setup the new entity + memset( &new_entity.shaderRGBA, 0xff, sizeof( new_entity.shaderRGBA ) ); + new_entity.origin[0] = trace.endpos[0]; + new_entity.origin[1] = trace.endpos[1]; + new_entity.origin[2] = trace.endpos[2] + 5; + new_entity.scale = 1; + + current_entity = &new_entity; + + // Setup the new tiki + + hModel = cgi.R_RegisterModel( "models/fx_dirtstep.tik" ); + new_tiki = cgi.TIKI_GetHandle( hModel ); + current_tiki = new_tiki; + + // Process new entity + + CG_ProcessInitCommands( current_tiki ); + + // Put the old stuff back + + current_entity = old_entity; + current_tiki = old_tiki; + + /* commandManager.InitializeSpawnthing( &effect ); + + effect.SetModel( "models/fx_dirtstep.tik" ); + + effect.cgd.origin[0] = trace.endpos[0]; + effect.cgd.origin[1] = trace.endpos[1]; + effect.cgd.origin[2] = trace.endpos[2] + 5; + + effect.cgd.scale = 1; + + //effect.cgd.scaleRate = 1; + + effect.cgd.life = 2000; + + effect.cgd.flags |= T_FADE; + + effect.cgd.flags |= T_ANGLES; + + effect.randangles[ 0 ] = NOT_RANDOM; + effect.cgd.angles[ 0 ] = 0; + effect.randangles[ 1 ] = NOT_RANDOM; + effect.cgd.angles[ 1 ] = 0; + effect.randangles[ 2 ] = NOT_RANDOM; + effect.cgd.angles[ 2 ] = 0; + + commandManager.SpawnTempModel( 1, &effect ); */ + + break; + case SURF_TYPE_GRILL: + commandManager.PlaySound( "footstep_grill", NULL, CHAN_AUTO, volume ); + if ( cg_debugFootsteps->integer ) + { + cgi.DPrintf( "Footstep: grill volume: %.2f\n", volume ); + } + break; + case SURF_TYPE_ORGANIC: + commandManager.PlaySound( "footstep_organic", NULL, CHAN_AUTO, volume ); + if ( cg_debugFootsteps->integer ) + { + cgi.DPrintf( "Footstep: organic volume: %.2f\n", volume ); + } + break; + case SURF_TYPE_SQUISHY: + commandManager.PlaySound( "footstep_squishy", NULL, CHAN_AUTO, volume ); + if ( cg_debugFootsteps->integer ) + { + cgi.DPrintf( "Footstep: squishy volume: %.2f\n", volume ); + } + break; + } + } + } + +/* +=============== +CG_Splash + +Draw a mark at the water surface +=============== +*/ +void CG_Splash( centity_t *cent ) { + vec3_t start, end, diff; + trace_t trace; + int contents; + float dist; + float time_required; + + spawnthing_t m_ripple; + + if ( !cg_shadows->integer ) { + return; + } + + VectorSubtract( cent->currentState.origin, cent->nextState.origin, diff ); + diff[ 2 ] = 0; + dist = VectorLength( diff ); + + // See if enough time has passed to add another ripple + + if ( dist >= 1 ) + time_required = 100 - dist; + else + time_required = 200; + + if ( time_required < 10 ) + time_required = 10; + + if ( cent->splash_last_spawn_time + time_required > cg.time ) + return; + + // Save the current time + + cent->splash_last_spawn_time = cg.time; + + // Make sure the entity is moving + if ( dist < 1 ) + { + if ( cent->splash_still_count >= 0 ) + { + cent->splash_still_count++; + + if ( cent->splash_still_count > 2 ) + cent->splash_still_count = 0; + else + return; + } + else + return; + } + + + VectorCopy( cent->lerpOrigin, end ); + + // if the feet aren't in liquid, don't make a mark + // this won't handle moving water brushes, but they wouldn't draw right anyway... + contents = cgi.CM_PointContents( end, 0 ); + if ( !( contents & ( CONTENTS_WATER | CONTENTS_SLIME | CONTENTS_LAVA ) ) ) { + return; + } + + VectorCopy( cent->lerpOrigin, start ); + start[2] += 88; + + // if the head isn't out of liquid, don't make a mark + contents = cgi.CM_PointContents( start, 0 ); + if ( contents & ( CONTENTS_SOLID | CONTENTS_WATER | CONTENTS_SLIME | CONTENTS_LAVA ) ) { + return; + } + + // trace down to find the surface + cgi.CM_BoxTrace( &trace, start, end, NULL, NULL, 0, ( CONTENTS_WATER | CONTENTS_SLIME | CONTENTS_LAVA ), qfalse ); + + if ( trace.fraction == 1.0 ) { + return; + } + + // Add a ripple to the scene + + commandManager.InitializeSpawnthing( &m_ripple ); + + m_ripple.SetModel( "ripple.spr" ); + + m_ripple.cgd.origin[0] = trace.endpos[0]; + m_ripple.cgd.origin[1] = trace.endpos[1]; + m_ripple.cgd.origin[2] = trace.endpos[2]; + + m_ripple.cgd.scale = 0.33 + dist / 100; + + if ( m_ripple.cgd.scale > 1 ) + m_ripple.cgd.scale = 1; + + m_ripple.cgd.scaleRate = 1 + dist / 250; + + if ( m_ripple.cgd.scaleRate > 1.4 ) + m_ripple.cgd.scaleRate = 1.4; + + m_ripple.cgd.life = 2000 - dist * 10; + + if ( m_ripple.cgd.life < 1000 ) + m_ripple.cgd.life = 1000; + + m_ripple.cgd.flags |= T_FADE; + + m_ripple.cgd.flags |= T_ANGLES; + + m_ripple.randangles[ 0 ] = NOT_RANDOM; + m_ripple.cgd.angles[ 0 ] = 90; + m_ripple.randangles[ 1 ] = NOT_RANDOM; + m_ripple.cgd.angles[ 1 ] = 0; + m_ripple.randangles[ 2 ] = NOT_RANDOM; + m_ripple.cgd.angles[ 2 ] = 0; + + commandManager.SpawnTempModel( 1, &m_ripple ); +} diff --git a/source/source/cgame/cg_swipe.cpp b/source/source/cgame/cg_swipe.cpp new file mode 100644 index 0000000..f00c160 --- /dev/null +++ b/source/source/cgame/cg_swipe.cpp @@ -0,0 +1,315 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/cgame/cg_swipe.cpp $ +// $Revision:: 12 $ +// $Author:: Markd $ +// $Date:: 6/27/00 2:34p $ +// +// Copyright (C) 1998 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/cgame/cg_swipe.cpp $ +// +// 12 6/27/00 2:34p Markd +// clear out swipes when restarting +// +// 11 6/14/00 12:14p Markd +// more intel compiler bug fixes +// +// 10 5/15/00 2:19p Aldie +// Added new tempmodel system and added player accumulated pain +// +// 9 5/03/00 4:20p Markd +// Only turn off swipes when swipes were active +// +// 8 3/27/00 1:50p Aldie +// Made swipes work for multiple models +// +// 7 3/04/00 6:03p Aldie +// Made commandManager static +// +// 6 2/07/00 7:38p Aldie +// Fixed swiping, also various weapons fixes for sword and for sling +// +// 5 1/26/00 6:36p Aldie +// Fix the swipe +// +// 4 12/09/99 10:52a Jimdose +// got tags working with torso and crossblended animations +// +// 3 11/01/99 4:11p Jimdose +// made tags work with bone controllers +// +// 2 10/05/99 6:01p Aldie +// Added headers +// +// DESCRIPTION: +// General swiping functions + +#include "cg_commands.h" + +swipething_t m_swipes[MAX_SWIPES]; +extern int current_entity_number; +extern refEntity_t *current_entity; +extern int current_tiki; +extern centity_t *current_centity; + +void ClientGameCommandManager::SwipeOn + ( + Event *ev + ) + + { + // Make a swipe for this if available + int i; + int freeswipe = -1; + str tagname_start,tagname_end; + qhandle_t shader; + + if ( ev->NumArgs () != 4 ) + return; + + shader = cgi.R_RegisterShader( ev->GetString( 1 ) ); + tagname_start = ev->GetString( 2 ); + tagname_end = ev->GetString( 3 ); + + for ( i=0; i < MAX_SWIPES; i++ ) + { + swipething_t &swipe = m_swipes[i]; + + if ( !swipe.enabled || + ( + ( swipe.entitynum == current_entity_number ) && + ( tagname_start == swipe.tagname_start ) && + ( tagname_end == swipe.tagname_end ) && + ( shader == swipe.shader ) + ) + ) + { + freeswipe = i; + break; + } + } + + if ( freeswipe == -1 ) + return; + + swipething_t &swipe = m_swipes[freeswipe]; + + if ( !swipe.enabled ) + { + swipe.Init (); + swipe.enabled = qtrue; + swipe.entitynum = current_entity_number; + } + + swipe.shader = cgi.R_RegisterShader( ev->GetString( 1 ) ); + swipe.tagname_start = ev->GetString ( 2 ); + swipe.tagname_end = ev->GetString ( 3 ); + swipe.life = ev->GetFloat ( 4 ) * 1000.f; + + if ( current_centity ) + current_centity->clientFlags |= CF_UPDATESWIPE; + } + +void ClientGameCommandManager::SwipeOff + ( + Event *ev + ) + + { + qboolean was_enabled; + int i; + + was_enabled = qfalse; + for ( i=0; i < MAX_SWIPES; i++ ) + { + swipething_t &swipe = m_swipes[i]; + + if ( swipe.enabled && swipe.entitynum == current_entity_number ) + { + swipe.enabled = qfalse; + was_enabled = qtrue; + } + } + + if ( was_enabled ) + { + //cgi.R_SwipeBegin ( 0.f, 0.f, -1 ); + //cgi.R_SwipeEnd (); + + if ( current_centity ) + current_centity->clientFlags &= ~CF_UPDATESWIPE; + } + } + +void ClientGameCommandManager::Swipe + ( + Event *ev + ) + + { + // This does a swipe effect on the entity + int i,swipenum; + orientation_t or; + int tagnum_start,tagnum_end; + qboolean add_cnt_point = qfalse; + vec3_t tmp; + + assert( current_entity ); + assert( current_tiki != -1 ); + + if ( !current_entity || ( current_tiki == -1 ) ) + { + return; + } + + // Let's find us a new (or current) swipe + for ( swipenum=0; swipenum < MAX_SWIPES; swipenum++ ) + { + swipething_t &swipe = m_swipes[swipenum]; + + if ( swipe.enabled && swipe.entitynum == current_entity_number ) + { + while ( swipe.num_live_swipes > 1 ) + { + i = ( swipe.first_swipe + 1 ) % MAX_SWIPE_POINTS; + swipepoint_t &swipepoint = swipe.swipepoints[i]; + + if ( swipepoint.time < cg.time - swipe.life ) + { + // then let's delete the previous + swipe.first_swipe = ( swipe.first_swipe + 1 ) % MAX_SWIPE_POINTS; + swipe.num_live_swipes--; + } + else + { + break; + } + } + + if ( swipe.num_live_swipes == 1 ) + { + swipepoint_t &swipepoint = swipe.swipepoints[swipe.first_swipe]; + if ( swipepoint.time < cg.time - swipe.life ) + { + swipe.num_live_swipes = 0; + } + } + + swipe.cntPoint.time = cg.time; + VectorCopy ( current_entity->origin, swipe.cntPoint.points[0] ); + + tagnum_start = cgi.Tag_NumForName( current_tiki, swipe.tagname_start.c_str() ); + or = cgi.Tag_LerpedOrientation( current_tiki, current_entity, tagnum_start ); + + // Clear out the points + VectorClear ( tmp ); + VectorClear ( swipe.cntPoint.points[0] ); + VectorClear ( swipe.cntPoint.points[1] ); + + if ( ev->NumArgs() > 0 ) + VectorCopy( ev->GetVector( 1 ), tmp ); + else + VectorCopy ( current_entity->origin, tmp ); + + // Transform the origin of the tag by the axis of the entity and add it to the origin of the entity + for ( i = 0; i < 3; i++ ) + { + VectorMA ( tmp, or.origin[i], current_entity->axis[i], tmp ); + } + + // Copy tmp into the startpoint + VectorCopy ( tmp, swipe.cntPoint.points[0] ); + + tagnum_end = cgi.Tag_NumForName( current_tiki, swipe.tagname_end.c_str() ); + or = cgi.Tag_LerpedOrientation( current_tiki, current_entity, tagnum_end ); + + if ( ev->NumArgs() > 0 ) + VectorCopy( ev->GetVector( 1 ), tmp ); + else + VectorCopy ( current_entity->origin, tmp ); + + // Transform the origin of the tag by the axis of the entity and add it to the origin of the entity + for ( i = 0; i < 3; i++ ) + { + VectorMA ( tmp, or.origin[i], current_entity->axis[i], tmp ); + } + + // Copy tmp into the startpoint + VectorCopy ( tmp, swipe.cntPoint.points[1] ); + + if ( swipe.num_live_swipes == 0 ) + add_cnt_point = qtrue; + else + { + float deltime = swipe.life / float ( MAX_SWIPES ); + swipepoint_t &lastpoint = swipe.swipepoints[ ( swipe.first_swipe + swipe.num_live_swipes - 1 ) % MAX_SWIPE_POINTS]; + + if ( swipe.cntPoint.time - lastpoint.time >= deltime ) + add_cnt_point = qtrue; + } + + cgi.R_SwipeBegin ( cg.time, swipe.life, swipe.shader ); + + if ( add_cnt_point ) + { + swipepoint_t &swipepoint = swipe.swipepoints[ ( swipe.first_swipe + swipe.num_live_swipes ) % MAX_SWIPE_POINTS]; + + swipepoint = swipe.cntPoint; + + if ( swipe.num_live_swipes == MAX_SWIPE_POINTS ) + swipe.first_swipe = ( swipe.first_swipe + 1 ) % MAX_SWIPE_POINTS; + else + swipe.num_live_swipes++; + } + + for ( i = 0; i != swipe.num_live_swipes; i++ ) + { + swipepoint_t &swipepoint = swipe.swipepoints[ ( swipe.first_swipe + i ) % MAX_SWIPE_POINTS]; + + cgi.R_SwipePoint ( swipepoint.points[0], swipepoint.points[1], swipepoint.time ); + } + + if ( !add_cnt_point ) + cgi.R_SwipePoint ( swipe.cntPoint.points[0], swipe.cntPoint.points[1], swipe.cntPoint.time ); + + cgi.R_SwipeEnd (); + } + } + } + +void ClientGameCommandManager::ClearSwipes + ( + void + ) + + { + int i; + + for ( i=0; i < MAX_SWIPES; i++ ) + { + swipething_t &swipe = m_swipes[i]; + + swipe.enabled = qfalse; + } + + cgi.R_SwipeBegin ( 0.f, 0.f, -1 ); + cgi.R_SwipeEnd (); + } + + +/* +=================== +CG_ClearSwipes + +This is called at startup and for tournement restarts +=================== +*/ +void CG_ClearSwipes( void ) + { + commandManager.ClearSwipes(); + } diff --git a/source/source/cgame/cg_syscalls.c b/source/source/cgame/cg_syscalls.c new file mode 100644 index 0000000..8550343 --- /dev/null +++ b/source/source/cgame/cg_syscalls.c @@ -0,0 +1,264 @@ +#include "cg_local.h" + +// this file is only included when building a dll +// syscalls.asm is included instead when building a qvm + +static int (*syscall)( int arg, ... ) = (int (*)( int, ...))-1; + + +void dllEntry( int (*syscallptr)( int arg,... ) ) { + syscall = syscallptr; +} + + +int PASSFLOAT( float x ) { + float floatTemp; + floatTemp = x; + return *(int *)&floatTemp; +} + +void trap_Print( const char *fmt ) { + syscall( CG_PRINT, fmt ); +} + +void trap_Error( const char *fmt ) { + syscall( CG_ERROR, fmt ); +} + +int trap_Milliseconds( void ) { + return syscall( CG_MILLISECONDS ); +} + +void trap_Cvar_Register( vmCvar_t *vmCvar, const char *varName, const char *defaultValue, int flags ) { + syscall( CG_CVAR_REGISTER, vmCvar, varName, defaultValue, flags ); +} + +void trap_Cvar_Update( vmCvar_t *vmCvar ) { + syscall( CG_CVAR_UPDATE, vmCvar ); +} + +void trap_Cvar_Set( const char *var_name, const char *value ) { + syscall( CG_CVAR_SET, var_name, value ); +} + +int trap_Argc( void ) { + return syscall( CG_ARGC ); +} + +void trap_Argv( int n, char *buffer, int bufferLength ) { + syscall( CG_ARGV, n, buffer, bufferLength ); +} + +void trap_Args( char *buffer, int bufferLength ) { + syscall( CG_ARGS, buffer, bufferLength ); +} + +int trap_FS_FOpenFile( const char *qpath, fileHandle_t *f, fsMode_t mode ) { + return syscall( CG_FS_FOPENFILE, qpath, f, mode ); +} + +void trap_FS_Read( void *buffer, int len, fileHandle_t f ) { + syscall( CG_FS_READ, buffer, len, f ); +} + +void trap_FS_Write( const void *buffer, int len, fileHandle_t f ) { + syscall( CG_FS_WRITE, buffer, len, f ); +} + +void trap_FS_FCloseFile( fileHandle_t f ) { + syscall( CG_FS_FCLOSEFILE, f ); +} + +void trap_SendConsoleCommand( const char *text ) { + syscall( CG_SENDCONSOLECOMMAND, text ); +} + +void trap_AddCommand( const char *cmdName ) { + syscall( CG_ADDCOMMAND, cmdName ); +} + +void trap_SendClientCommand( const char *s ) { + syscall( CG_SENDCLIENTCOMMAND, s ); +} + +void trap_UpdateScreen( void ) { + syscall( CG_UPDATESCREEN ); +} + +void trap_CM_LoadMap( const char *mapname ) { + syscall( CG_CM_LOADMAP, mapname ); +} + +int trap_CM_NumInlineModels( void ) { + return syscall( CG_CM_NUMINLINEMODELS ); +} + +clipHandle_t trap_CM_InlineModel( int index ) { + return syscall( CG_CM_INLINEMODEL, index ); +} + +clipHandle_t trap_CM_TempBoxModel( const vec3_t mins, const vec3_t maxs ) { + return syscall( CG_CM_TEMPBOXMODEL, mins, maxs ); +} + +int trap_CM_PointContents( const vec3_t p, clipHandle_t model ) { + return syscall( CG_CM_POINTCONTENTS, p, model ); +} + +int trap_CM_TransformedPointContents( const vec3_t p, clipHandle_t model, const vec3_t origin, const vec3_t angles ) { + return syscall( CG_CM_TRANSFORMEDPOINTCONTENTS, p, model, origin, angles ); +} + +void trap_CM_BoxTrace( trace_t *results, const vec3_t start, const vec3_t end, + const vec3_t mins, const vec3_t maxs, + clipHandle_t model, int brushmask ) { + syscall( CG_CM_BOXTRACE, results, start, end, mins, maxs, model, brushmask ); +} + +void trap_CM_TransformedBoxTrace( trace_t *results, const vec3_t start, const vec3_t end, + const vec3_t mins, const vec3_t maxs, + clipHandle_t model, int brushmask, + const vec3_t origin, const vec3_t angles ) { + syscall( CG_CM_TRANSFORMEDBOXTRACE, results, start, end, mins, maxs, model, brushmask, origin, angles ); +} + +int trap_CM_MarkFragments( int numPoints, const vec3_t *points, + const vec3_t projection, + int maxPoints, vec3_t pointBuffer, + int maxFragments, markFragment_t *fragmentBuffer ) { + return syscall( CG_CM_MARKFRAGMENTS, numPoints, points, projection, maxPoints, pointBuffer, maxFragments, fragmentBuffer ); +} + +void trap_S_StartSound( vec3_t origin, int entityNum, int entchannel, sfxHandle_t sfx, float volume, float min_dist ) { + syscall( CG_S_STARTSOUND, origin, entityNum, entchannel, sfx, volume, min_dist ); +} + +void trap_S_StartLocalSound( sfxHandle_t sfx ) { + syscall( CG_S_STARTLOCALSOUND, sfx ); +} + +void trap_S_ClearLoopingSounds( void ) { + syscall( CG_S_CLEARLOOPINGSOUNDS ); +} + +void trap_S_AddLoopingSound( const vec3_t origin, const vec3_t velocity, sfxHandle_t sfx, float volume, float min_dist ) { + syscall( CG_S_ADDLOOPINGSOUND, origin, velocity, sfx, volume, min_dist ); +} + +void trap_S_UpdateEntityPosition( int entityNum, const vec3_t origin ) { + syscall( CG_S_UPDATEENTITYPOSITION, entityNum, origin ); +} + +void trap_S_UpdateEntityVelocity( int entityNum, const vec3_t vel ) { + syscall( CG_S_UPDATEENTITYVELOCITY, entityNum, vel ); +} + +void trap_S_Respatialize( int entityNum, const vec3_t origin, vec3_t axis[3] ) { + syscall( CG_S_RESPATIALIZE, entityNum, origin, axis ); +} + +sfxHandle_t trap_S_RegisterSound( const char *sample ) { + return syscall( CG_S_REGISTERSOUND, sample ); +} + +/* void trap_S_StartBackgroundTrack( const char *name ) { + syscall( CG_S_STARTBACKGROUNDTRACK, name ); +} */ + +/*qboolean trap_S_ChannelInUse( soundChannel_t entchannel ) { + return syscall( CG_S_CHANNELINUSE, entchannel ); +} */ + +void trap_R_LoadWorldMap( const char *mapname ) { + syscall( CG_R_LOADWORLDMAP, mapname ); +} + +qhandle_t trap_R_RegisterModel( const char *name ) { + return syscall( CG_R_REGISTERMODEL, name ); +} + +qhandle_t trap_R_RegisterSkin( const char *name ) { + return syscall( CG_R_REGISTERSKIN, name ); +} + +qhandle_t trap_R_RegisterShader( const char *name ) { + return syscall( CG_R_REGISTERSHADER, name ); +} + +void trap_R_ClearScene( void ) { + syscall( CG_R_CLEARSCENE ); +} + +void trap_R_AddRefEntityToScene( const refEntity_t *re ) { + syscall( CG_R_ADDREFENTITYTOSCENE, re ); +} + +void trap_R_AddPolyToScene( qhandle_t hShader , int numVerts, const polyVert_t *verts ) { + syscall( CG_R_ADDPOLYTOSCENE, hShader, numVerts, verts ); +} + +void trap_R_AddLightToScene( const vec3_t org, float intensity, float r, float g, float b ) { + syscall( CG_R_ADDLIGHTTOSCENE, org, PASSFLOAT(intensity), PASSFLOAT(r), PASSFLOAT(g), PASSFLOAT(b) ); +} + +void trap_R_RenderScene( const refdef_t *fd ) { + syscall( CG_R_RENDERSCENE, fd ); +} + +void trap_R_SetColor( const float *rgba ) { + syscall( CG_R_SETCOLOR, rgba ); +} + +void trap_R_DrawStretchPic( float x, float y, float w, float h, + float s1, float t1, float s2, float t2, qhandle_t hShader ) { + syscall( CG_R_DRAWSTRETCHPIC, PASSFLOAT(x), PASSFLOAT(y), PASSFLOAT(w), PASSFLOAT(h), PASSFLOAT(s1), PASSFLOAT(t1), PASSFLOAT(s2), PASSFLOAT(t2), hShader ); +} + +void trap_R_ModelBounds( clipHandle_t model, vec3_t mins, vec3_t maxs ) { + syscall( CG_R_MODELBOUNDS, model, mins, maxs ); +} + +void trap_R_LerpTag( orientation_t *tag, clipHandle_t mod, int startFrame, int endFrame, + float frac, const char *tagName ) { + syscall( CG_R_LERPTAG, tag, mod, startFrame, endFrame, PASSFLOAT(frac), tagName ); +} + +void trap_GetGlconfig( glconfig_t *glconfig ) { + syscall( CG_GETGLCONFIG, glconfig ); +} + +void trap_GetGameState( gameState_t *gamestate ) { + syscall( CG_GETGAMESTATE, gamestate ); +} + +void trap_GetCurrentSnapshotNumber( int *snapshotNumber, int *serverTime ) { + syscall( CG_GETCURRENTSNAPSHOTNUMBER, snapshotNumber, serverTime ); +} + +qboolean trap_GetSnapshot( int snapshotNumber, snapshot_t *snapshot ) { + return syscall( CG_GETSNAPSHOT, snapshotNumber, snapshot ); +} + +qboolean trap_GetServerCommand( int serverCommandNumber ) { + return syscall( CG_GETSERVERCOMMAND, serverCommandNumber ); +} + +int trap_GetCurrentCmdNumber( void ) { + return syscall( CG_GETCURRENTCMDNUMBER ); +} + +qboolean trap_GetUserCmd( int cmdNumber, usercmd_t *ucmd ) { + return syscall( CG_GETUSERCMD, cmdNumber, ucmd ); +} + +void trap_SetUserCmdValue( int stateValue, float sensitivityScale ) { + syscall( CG_SETUSERCMDVALUE, stateValue, PASSFLOAT(sensitivityScale) ); +} + +void testPrintInt( char *string, int i ) { + syscall( CG_TESTPRINTINT, string, i ); +} + +void testPrintFloat( char *string, float f ) { + syscall( CG_TESTPRINTFLOAT, string, PASSFLOAT(f) ); +} diff --git a/source/source/cgame/cg_testemitter.cpp b/source/source/cgame/cg_testemitter.cpp new file mode 100644 index 0000000..1097201 --- /dev/null +++ b/source/source/cgame/cg_testemitter.cpp @@ -0,0 +1,637 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/cgame/cg_testemitter.cpp $ +// $Revision:: 18 $ +// $Author:: Markd $ +// $Date:: 7/22/00 5:50p $ +// +// Copyright (C) 1998 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/cgame/cg_testemitter.cpp $ +// +// 18 7/22/00 5:50p Markd +// added flushtikis support +// +// 17 7/10/00 11:54p Markd +// added exit level code +// +// 16 6/14/00 12:14p Markd +// more intel compiler bug fixes +// +// 15 5/15/00 2:19p Aldie +// Added new tempmodel system and added player accumulated pain +// +// 13 3/16/00 7:35p Aldie +// Added t2 flags to testemitter +// +// 12 3/16/00 5:09p Aldie +// Added some optimizations for tempmodels +// +// 11 3/15/00 11:01a Aldie +// Changed m_emitters to container instead of array. +// +// 10 3/11/00 4:47p Aldie +// Fix for scaleupdown +// +// 9 3/04/00 6:03p Aldie +// Made commandManager static +// +// 8 2/09/00 4:27p Aldie +// Fixed pause on the client emitters +// +// 7 1/26/00 11:35a Aldie +// New data structures for emitters +// +// 6 1/22/00 12:41p Jimdose +// got rid of calls to vec3() +// +// 5 10/22/99 4:29p Aldie +// Added debuglines +// +// 4 10/13/99 3:26p Aldie +// Various fixes for particles, beams and lensflares +// +// 3 10/05/99 6:01p Aldie +// Added headers +// +// DESCRIPTION: +// testemitter functions. Used for designing emitters in game + +#include "cg_commands.h" + +cvar_t *cg_te_xangles; +cvar_t *cg_te_yangles; +cvar_t *cg_te_zangles; +cvar_t *cg_te_alpha; +cvar_t *cg_te_dietouch; +cvar_t *cg_te_bouncefactor; +cvar_t *cg_te_scale; +cvar_t *cg_te_scalemin; +cvar_t *cg_te_scalemax; +cvar_t *cg_te_model; +cvar_t *cg_te_life; +cvar_t *cg_te_color_r; +cvar_t *cg_te_color_g; +cvar_t *cg_te_color_b; +cvar_t *cg_te_startcolor_r; +cvar_t *cg_te_startcolor_g; +cvar_t *cg_te_startcolor_b; +cvar_t *cg_te_endcolor_r; +cvar_t *cg_te_endcolor_g; +cvar_t *cg_te_endcolor_b; +cvar_t *cg_te_accel_x; +cvar_t *cg_te_accel_y; +cvar_t *cg_te_accel_z; +cvar_t *cg_te_count; +cvar_t *cg_te_fade; +cvar_t *cg_te_fadein; +cvar_t *cg_te_spawnrate; +cvar_t *cg_te_orgoffset_x; +cvar_t *cg_te_orgoffset_y; +cvar_t *cg_te_orgoffset_z; +cvar_t *cg_te_rorgx; +cvar_t *cg_te_rorgy; +cvar_t *cg_te_rorgz; +cvar_t *cg_te_scalerate; +cvar_t *cg_te_circle; +cvar_t *cg_te_sphere; +cvar_t *cg_te_insphere; +cvar_t *cg_te_radius; +cvar_t *cg_te_swarm; +cvar_t *cg_te_wavy; +cvar_t *cg_te_align; +cvar_t *cg_te_flickeralpha; +cvar_t *cg_te_collision; +cvar_t *cg_te_globalfade; +cvar_t *cg_te_randomroll; +cvar_t *cg_te_angles_pitch; +cvar_t *cg_te_angles_yaw; +cvar_t *cg_te_angles_roll; +cvar_t *cg_te_randpitch; +cvar_t *cg_te_randyaw; +cvar_t *cg_te_randroll; +cvar_t *cg_te_forwardvelocity; +cvar_t *cg_te_randvelx; +cvar_t *cg_te_randvely; +cvar_t *cg_te_randvelz; +cvar_t *cg_te_rvxtype; +cvar_t *cg_te_rvytype; +cvar_t *cg_te_rvztype; + +spawnthing_t *testspawnthing=NULL; + +//=============== +//UpdateTestEmitter +//=============== +void ClientGameCommandManager::UpdateTestEmitter + ( + void + ) + + { + int count; + Vector delta; + Vector end,end2,perp; + + emittertime_t *et=NULL; + + if ( !testspawnthing ) + return; + + SetTestEmitterValues(); + + et = testspawnthing->GetEmitTime( 1 ); + + if ( !et->active ) + return; + + testspawnthing->cgd.createTime = cg.time; + + end = testspawnthing->cgd.origin + testspawnthing->forward * 50; + + cgi.R_DebugLine( testspawnthing->cgd.origin, end, 1,0,0,1 ); + + PerpendicularVector( perp, testspawnthing->forward ); + perp.normalize(); + + end2 = end + ( perp * 16 ) + ( m_spawnthing->forward * -16 ); + cgi.R_DebugLine( end, end2, 1,0,0,1 ); + + end2 = end + ( perp * -16 ) + ( m_spawnthing->forward * -16 ); + cgi.R_DebugLine( end, end2, 1,0,0,1 ); + + if ( ( et->last_emit_time > 0 ) && ( testspawnthing->spawnRate ) ) + { + float dtime = cg.time - et->last_emit_time; + float lerp, lerpfrac; + + count = dtime / testspawnthing->spawnRate; + + // This is kind of a nasty bit of code. If the count is 1, just spawn + // a single tempmodel, if it's greater than 1, then spawn the number + // of tempmodels over a period of time, and adjust their create times + // accordingly. Also lerp the origins so they appear where they are + // supposed to. This helps smoothing out low frame rate situations + // where this is only get called a few times a second, but the spawn + // rate is high, and it will look a lot smoother. + if ( !count ) + { + return; + } + else if ( count == 1 ) + { + SpawnTempModel( 1 ); + et->last_emit_time = cg.time; + } + else + { + lerpfrac = 1.0f / (float)count; + + lerp = 0; + while ( dtime > testspawnthing->spawnRate ) + { + float last_time = et->last_emit_time; + et->last_emit_time = cg.time; + dtime -= testspawnthing->spawnRate; + if ( et->lerp_emitter ) + testspawnthing->cgd.origin = et->oldorigin + ( delta * lerp ); + SpawnTempModel( 1, last_time + dtime ); + lerp += lerpfrac; + } + } + } + else + { + et->last_emit_time = cg.time; + } + } + +void ClientGameCommandManager::DumpEmitter + ( + void + ) + + { + cvar_t *filename; + str buff; + int i; + + if ( !testspawnthing ) + return; + + filename = cgi.Cvar_Get( "cg_te_filename", "dump/emitter.txt", 0 ); + + buff += va( "model %s\n", testspawnthing->m_modellist.ObjectAt( 1 ).c_str() ); + + if ( testspawnthing->cgd.alpha != 1.0 ) + buff += va( "alpha %0.2f\n", testspawnthing->cgd.alpha ); + + if ( testspawnthing->cgd.bouncefactor != 1 ) + buff += va( "bouncefactor %0.2f\n", testspawnthing->cgd.bouncefactor ); + + if ( testspawnthing->cgd.scale != 1 ) + buff += va( "scale %0.2f\n", testspawnthing->cgd.scale ); + + buff += va( "life %0.2f\n", cg_te_life->value ); + + if ( testspawnthing->cgd.accel[0] || testspawnthing->cgd.accel[1] || testspawnthing->cgd.accel[2] ) + buff += va( "accel %0.2f %0.2f %0.2f\n", testspawnthing->cgd.accel[0], testspawnthing->cgd.accel[1], testspawnthing->cgd.accel[2] ); + + buff += va( "spawnrate %0.2f\n", cg_te_spawnrate->value ); + + if ( testspawnthing->cgd.scaleRate ) + buff += va( "scalerate %0.2f\n", testspawnthing->cgd.scaleRate ); + + if ( testspawnthing->sphereRadius ) + buff += va( "radius %0.2f\n", testspawnthing->sphereRadius ); + + if ( testspawnthing->forwardVelocity ) + buff += va( "velocity %0.2f\n", testspawnthing->forwardVelocity ); + + if ( testspawnthing->origin_offset[0] || testspawnthing->origin_offset[1] || testspawnthing->origin_offset[2] ) + { + buff += "offset "; + + for ( i=0; i<3; i++ ) + { + if ( testspawnthing->randorg[i] == NOT_RANDOM ) + buff += va( "%0.2f ", testspawnthing->origin_offset[i] ); + if ( testspawnthing->randorg[i] == RANDOM ) + buff += va( "random %0.2f ", testspawnthing->origin_offset[i] ); + if ( testspawnthing->randorg[i] == CRANDOM ) + buff += va( "crandom %0.2f ", testspawnthing->origin_offset[i] ); + } + buff += "\n"; + } + + if ( testspawnthing->cgd.angles[0] || testspawnthing->cgd.angles[1] || testspawnthing->cgd.angles[2] ) + { + buff += "angles "; + + for ( i=0; i<3; i++ ) + { + if ( testspawnthing->randangles[i] == NOT_RANDOM ) + buff += va( "%0.2f ", testspawnthing->cgd.angles[i] ); + if ( testspawnthing->randangles[i] == RANDOM ) + buff += va( "random %0.2f ", testspawnthing->cgd.angles[i] ); + if ( testspawnthing->randangles[i] == CRANDOM ) + buff += va( "crandom %0.2f ", testspawnthing->cgd.angles[i] ); + } + buff += "\n"; + } + + if ( testspawnthing->velocityVariation[0] || testspawnthing->velocityVariation[1] || testspawnthing->velocityVariation[2] ) + { + buff += "randvel "; + + for ( i=0; i<3; i++ ) + { + if ( testspawnthing->randvel[i] == NOT_RANDOM ) + buff += va( "%0.2f ", testspawnthing->velocityVariation[i] ); + if ( testspawnthing->randvel[i] == RANDOM ) + buff += va( "random %0.2f ", testspawnthing->velocityVariation[i] ); + if ( testspawnthing->randvel[i] == CRANDOM ) + buff += va( "crandom %0.2f ", testspawnthing->velocityVariation[i] ); + } + buff += "\n"; + } + + if ( testspawnthing->cgd.scalemin ) + buff += va( "scalemin %0.2f\n", testspawnthing->cgd.scalemin ); + + if ( testspawnthing->cgd.scalemax ) + buff += va( "scalemax %0.2f\n", testspawnthing->cgd.scalemax ); + + if ( testspawnthing->cgd.flags & T_DIETOUCH ) + buff +="dietouch\n"; + if ( testspawnthing->cgd.flags & T_FADE ) + buff +="fade\n"; + if ( testspawnthing->cgd.flags & T_CIRCLE ) + buff +="circle\n"; + if ( testspawnthing->cgd.flags & T_SPHERE ) + buff +="sphere\n"; + if ( testspawnthing->cgd.flags & T_INWARDSPHERE ) + buff +="inwardsphere\n"; + if ( testspawnthing->cgd.flags & T_ALIGN ) + buff +="align\n"; + if ( testspawnthing->cgd.flags & T_FLICKERALPHA ) + buff +="flickeralpha\n"; + if ( testspawnthing->cgd.flags & T_RANDOMROLL ) + buff +="randomroll\n"; + + cgi.FS_WriteTextFile( filename->string, buff.c_str(), buff.length() + 1 ); + } + +void ClientGameCommandManager::SetTestEmitterValues + ( + void + ) + + { + vec3_t angles; + vec3_t axis[3]; + + testspawnthing->cgd.flags2 |= (T2_MOVE|T2_AMOVE|T2_ACCEL); + + angles[0] = cg_te_xangles->value; + angles[1] = cg_te_yangles->value; + angles[2] = cg_te_zangles->value; + + AnglesToAxis( angles, axis ); + testspawnthing->SetModel( cg_te_model->string ); + + testspawnthing->forward = axis[0]; + testspawnthing->right = axis[1]; + testspawnthing->up = axis[2]; + testspawnthing->cgd.alpha = cg_te_alpha->value; + testspawnthing->cgd.color[3] = cg_te_alpha->value * 255; + testspawnthing->cgd.bouncefactor = cg_te_bouncefactor->value; + testspawnthing->cgd.scale = cg_te_scale->value; + testspawnthing->cgd.life = cg_te_life->value * 1000; + testspawnthing->cgd.color[0] = cg_te_color_r->value * 255; + testspawnthing->cgd.color[1] = cg_te_color_g->value * 255; + testspawnthing->cgd.color[2] = cg_te_color_b->value * 255; + testspawnthing->cgd.accel[0] = cg_te_accel_x->value; + testspawnthing->cgd.accel[1] = cg_te_accel_y->value; + testspawnthing->cgd.accel[2] = cg_te_accel_z->value; + testspawnthing->count = cg_te_count->value; + testspawnthing->spawnRate = ( 1.0f / cg_te_spawnrate->value ) * 1000.0f; + testspawnthing->cgd.scaleRate = cg_te_scalerate->value; + testspawnthing->sphereRadius = cg_te_radius->value; + testspawnthing->forwardVelocity = cg_te_forwardvelocity->value; + + // Orgin Offset + testspawnthing->origin_offset[0] = cg_te_orgoffset_x->value; + testspawnthing->origin_offset[1] = cg_te_orgoffset_y->value; + testspawnthing->origin_offset[2] = cg_te_orgoffset_z->value; + + if ( !strcmp( cg_te_rorgx->string, "No" ) ) + testspawnthing->randorg[0] = NOT_RANDOM; + else if ( !strcmp( cg_te_rorgx->string, "Cr" ) ) + testspawnthing->randorg[0] = CRANDOM; + else if ( !strcmp( cg_te_rorgx->string, "Ra" ) ) + testspawnthing->randorg[0] = RANDOM; + + if ( !strcmp( cg_te_rorgy->string, "No" ) ) + testspawnthing->randorg[1] = NOT_RANDOM; + else if ( !strcmp( cg_te_rorgy->string, "Cr" ) ) + testspawnthing->randorg[1] = CRANDOM; + else if ( !strcmp( cg_te_rorgy->string, "Ra" ) ) + testspawnthing->randorg[1] = RANDOM; + + if ( !strcmp( cg_te_rorgz->string, "No" ) ) + testspawnthing->randorg[2] = NOT_RANDOM; + else if ( !strcmp( cg_te_rorgz->string, "Cr" ) ) + testspawnthing->randorg[2] = CRANDOM; + else if ( !strcmp( cg_te_rorgz->string, "Ra" ) ) + testspawnthing->randorg[2] = RANDOM; + + // Random angles + testspawnthing->cgd.angles[PITCH] = cg_te_angles_pitch->value; + testspawnthing->cgd.angles[YAW] = cg_te_angles_yaw->value; + testspawnthing->cgd.angles[ROLL] = cg_te_angles_roll->value; + + if ( !strcmp( cg_te_randpitch->string, "No" ) ) + testspawnthing->randangles[0] = NOT_RANDOM; + else if ( !strcmp( cg_te_randpitch->string, "Cr" ) ) + testspawnthing->randangles[0] = CRANDOM; + else if ( !strcmp( cg_te_randpitch->string, "Ra" ) ) + testspawnthing->randangles[0] = RANDOM; + + if ( !strcmp( cg_te_randyaw->string, "No" ) ) + testspawnthing->randangles[0] = NOT_RANDOM; + else if ( !strcmp( cg_te_randyaw->string, "Cr" ) ) + testspawnthing->randangles[0] = CRANDOM; + else if ( !strcmp( cg_te_randyaw->string, "Ra" ) ) + testspawnthing->randangles[0] = RANDOM; + + if ( !strcmp( cg_te_randroll->string, "No" ) ) + testspawnthing->randangles[0] = NOT_RANDOM; + else if ( !strcmp( cg_te_randroll->string, "Cr" ) ) + testspawnthing->randangles[0] = CRANDOM; + else if ( !strcmp( cg_te_randroll->string, "Ra" ) ) + testspawnthing->randangles[0] = RANDOM; + + // Random Velocity + testspawnthing->velocityVariation[0] = cg_te_randvelx->value; + testspawnthing->velocityVariation[1] = cg_te_randvely->value; + testspawnthing->velocityVariation[2] = cg_te_randvelz->value; + + if ( !strcmp( cg_te_rvxtype->string, "No" ) ) + testspawnthing->randvel[0] = NOT_RANDOM; + else if ( !strcmp( cg_te_rvxtype->string, "Cr" ) ) + testspawnthing->randvel[0] = CRANDOM; + else if ( !strcmp( cg_te_rvxtype->string, "Ra" ) ) + testspawnthing->randvel[0] = RANDOM; + + if ( !strcmp( cg_te_rvytype->string, "No" ) ) + testspawnthing->randvel[1] = NOT_RANDOM; + else if ( !strcmp( cg_te_rvytype->string, "Cr" ) ) + testspawnthing->randvel[1] = CRANDOM; + else if ( !strcmp( cg_te_rvytype->string, "Ra" ) ) + testspawnthing->randvel[1] = RANDOM; + + if ( !strcmp( cg_te_rvztype->string, "No" ) ) + testspawnthing->randvel[2] = NOT_RANDOM; + else if ( !strcmp( cg_te_rvztype->string, "Cr" ) ) + testspawnthing->randvel[2] = CRANDOM; + else if ( !strcmp( cg_te_rvztype->string, "Ra" ) ) + testspawnthing->randvel[2] = RANDOM; + + testspawnthing->cgd.scalemin = cg_te_scalemin->value; + testspawnthing->cgd.scalemax = cg_te_scalemax->value; + + if ( testspawnthing->cgd.scalemin || testspawnthing->cgd.scalemax ) + testspawnthing->cgd.flags |= T_RANDSCALE; + else + testspawnthing->cgd.flags &= ~T_RANDSCALE; + + if ( cg_te_dietouch->integer ) + testspawnthing->cgd.flags |= T_DIETOUCH; + else + testspawnthing->cgd.flags &= ~T_DIETOUCH; + + if ( cg_te_fade->integer ) + testspawnthing->cgd.flags |= T_FADE; + else + testspawnthing->cgd.flags &= ~T_FADE; + + if ( cg_te_circle->integer ) + testspawnthing->cgd.flags |= T_CIRCLE; + else + testspawnthing->cgd.flags &= ~T_CIRCLE; + + if ( cg_te_sphere->integer ) + testspawnthing->cgd.flags |= T_SPHERE; + else + testspawnthing->cgd.flags &= ~T_SPHERE; + + if ( cg_te_insphere->integer ) + testspawnthing->cgd.flags |= T_INWARDSPHERE; + else + testspawnthing->cgd.flags &= ~T_INWARDSPHERE; + + if ( cg_te_align->integer ) + testspawnthing->cgd.flags |= T_ALIGN; + else + testspawnthing->cgd.flags &= ~T_ALIGN; + + if ( cg_te_flickeralpha->integer ) + testspawnthing->cgd.flags |= T_FLICKERALPHA; + else + testspawnthing->cgd.flags &= ~T_FLICKERALPHA; + + if ( cg_te_randomroll->integer ) + testspawnthing->cgd.flags |= T_RANDOMROLL; + else + testspawnthing->cgd.flags &= ~T_RANDOMROLL; + +#if 0 + testspawnthing->cgd.cg_te_globalfade; + testspawnthing->cgd.cg_te_collision; + testspawnthing->cgd.cg_te_swarm; + testspawnthing->cgd.cg_te_wavy; +#endif + } + +void ClientGameCommandManager::TestEmitter + ( + void + ) + + { + // Create a test emitter that can be modified by the user + + // Init the emitter + testspawnthing = CreateNewEmitter(); + if( !testspawnthing ) + { + return; + } + + // Get the emitter's name + testspawnthing->emittername = "TestEmitter"; + + // Set the origin of the emitter + VectorMA( cg.refdef.vieworg, 100, cg.refdef.viewaxis[0], testspawnthing->cgd.origin ); + + float angles[3]; + vec3_t axis[3]; + + angles[PITCH] = 0; + angles[YAW] = cg.refdefViewAngles[1]; + angles[ROLL] = 0; + + AnglesToAxis( angles, axis ); + + testspawnthing->forward = axis[0]; + testspawnthing->right = axis[1]; + testspawnthing->up = axis[2]; + testspawnthing->cgd.tikihandle = 9999999; + SetTestEmitterValues(); + } + +void CG_TestEmitter_f + ( + void + ) + + { + commandManager.TestEmitter(); + } + +void CG_DumpEmitter_f + ( + void + ) + + { + commandManager.DumpEmitter(); + } + +void CG_UpdateTestEmitter + ( + void + ) + + { + commandManager.UpdateTestEmitter(); + } + + +void CG_InitTestEmitter + ( + void + ) + + { + cg_te_xangles = cgi.Cvar_Get( "cg_te_xangles", "0", 0 ); + cg_te_yangles = cgi.Cvar_Get( "cg_te_yangles", "0", 0 ); + cg_te_zangles = cgi.Cvar_Get( "cg_te_zangles", "0", 0 ); + cg_te_life = cgi.Cvar_Get( "cg_te_life", "1", 0 ); + cg_te_alpha = cgi.Cvar_Get( "cg_te_alpha", "1", 0 ); + cg_te_dietouch = cgi.Cvar_Get( "cg_te_dietouch", "0", 0 ); + cg_te_bouncefactor = cgi.Cvar_Get( "cg_te_bouncefactor", "1", 0 ); + cg_te_scale = cgi.Cvar_Get( "cg_te_scale", "1", 0 ); + cg_te_scalemin = cgi.Cvar_Get( "cg_te_scalemin", "0", 0 ); + cg_te_scalemax = cgi.Cvar_Get( "cg_te_scalemax", "0", 0 ); + cg_te_model = cgi.Cvar_Get( "cg_te_model", "none", 0 ); + cg_te_life = cgi.Cvar_Get( "cg_te_life", "1", 0 ); + cg_te_color_r = cgi.Cvar_Get( "cg_te_color_r", "1", 0 ); + cg_te_color_g = cgi.Cvar_Get( "cg_te_color_g", "1", 0 ); + cg_te_color_b = cgi.Cvar_Get( "cg_te_color_b", "1", 0 ); + cg_te_startcolor_r = cgi.Cvar_Get( "cg_te_startcolor_r", "1", 0 ); + cg_te_startcolor_g = cgi.Cvar_Get( "cg_te_startcolor_g", "1", 0 ); + cg_te_startcolor_b = cgi.Cvar_Get( "cg_te_startcolor_b", "1", 0 ); + cg_te_endcolor_r = cgi.Cvar_Get( "cg_te_endcolor_r", "1", 0 ); + cg_te_endcolor_g = cgi.Cvar_Get( "cg_te_endcolor_g", "1", 0 ); + cg_te_endcolor_b = cgi.Cvar_Get( "cg_te_endcolor_b", "1", 0 ); + cg_te_accel_x = cgi.Cvar_Get( "cg_te_accel_x", "0", 0 ); + cg_te_accel_y = cgi.Cvar_Get( "cg_te_accel_y", "0", 0 ); + cg_te_accel_z = cgi.Cvar_Get( "cg_te_accel_z", "0", 0 ); + cg_te_count = cgi.Cvar_Get( "cg_te_count", "1", 0 ); + cg_te_fade = cgi.Cvar_Get( "cg_te_fade", "0", 0 ); + cg_te_fadein = cgi.Cvar_Get( "cg_te_fadein", "0", 0 ); + cg_te_spawnrate = cgi.Cvar_Get( "cg_te_spawnrate", "1", 0 ); + cg_te_scalerate = cgi.Cvar_Get( "cg_te_scalerate", "0", 0 ); + cg_te_circle = cgi.Cvar_Get( "cg_te_circle", "0", 0 ); + cg_te_sphere = cgi.Cvar_Get( "cg_te_sphere", "0", 0 ); + cg_te_insphere = cgi.Cvar_Get( "cg_te_insphere", "0", 0 ); + cg_te_radius = cgi.Cvar_Get( "cg_te_radius", "0", 0 ); + cg_te_swarm = cgi.Cvar_Get( "cg_te_swarm", "0", 0 ); + cg_te_wavy = cgi.Cvar_Get( "cg_te_wavy", "0", 0 ); + cg_te_align = cgi.Cvar_Get( "cg_te_align", "0", 0 ); + cg_te_flickeralpha = cgi.Cvar_Get( "cg_te_flickeralpha", "0", 0 ); + cg_te_collision = cgi.Cvar_Get( "cg_te_collision", "0", 0 ); + cg_te_globalfade = cgi.Cvar_Get( "cg_te_globalfade", "0", 0 ); + cg_te_randomroll = cgi.Cvar_Get( "cg_te_randomroll", "0", 0 ); + + cg_te_orgoffset_x = cgi.Cvar_Get( "cg_te_orgoffset_x", "0", 0 ); + cg_te_orgoffset_y = cgi.Cvar_Get( "cg_te_orgoffset_y", "0", 0 ); + cg_te_orgoffset_z = cgi.Cvar_Get( "cg_te_orgoffset_z", "0", 0 ); + cg_te_rorgx = cgi.Cvar_Get( "cg_te_rorgx", "No", 0 ); + cg_te_rorgy = cgi.Cvar_Get( "cg_te_rorgy", "No", 0 ); + cg_te_rorgz = cgi.Cvar_Get( "cg_te_rorgz", "No", 0 ); + + cg_te_angles_pitch = cgi.Cvar_Get( "cg_te_angles_pitch", "0", 0 ); + cg_te_angles_yaw = cgi.Cvar_Get( "cg_te_angles_yaw", "0", 0 ); + cg_te_angles_roll = cgi.Cvar_Get( "cg_te_angles_roll", "0", 0 ); + cg_te_randpitch = cgi.Cvar_Get( "cg_te_randpitch", "No", 0 ); + cg_te_randyaw = cgi.Cvar_Get( "cg_te_randyaw", "No", 0 ); + cg_te_randroll = cgi.Cvar_Get( "cg_te_randroll", "No", 0 ); + + cg_te_randvelx = cgi.Cvar_Get( "cg_te_randvelx", "0", 0 ); + cg_te_randvely = cgi.Cvar_Get( "cg_te_randvely", "0", 0 ); + cg_te_randvelz = cgi.Cvar_Get( "cg_te_randvelz", "0", 0 ); + cg_te_rvxtype = cgi.Cvar_Get( "cg_te_rvxtype", "No", 0 ); + cg_te_rvytype = cgi.Cvar_Get( "cg_te_rvytype", "No", 0 ); + cg_te_rvztype = cgi.Cvar_Get( "cg_te_rvztype", "No", 0 ); + + cg_te_forwardvelocity = cgi.Cvar_Get( "cg_te_forwardvel", "0", 0 ); + } + + diff --git a/source/source/cgame/cg_vector.h b/source/source/cgame/cg_vector.h new file mode 100644 index 0000000..37e40ff --- /dev/null +++ b/source/source/cgame/cg_vector.h @@ -0,0 +1,862 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/cgame/cg_vector.h $ +// $Revision:: 1 $ +// $Author:: Aldie $ +// $Date:: 9/10/99 2:46p $ +// +// Copyright (C) 1997 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source is may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/cgame/cg_vector.h $ +// +// 1 9/10/99 2:46p Aldie +// +// 1 9/09/99 5:06p Aldie +// +// DESCRIPTION: +// C++ implemention of a Vector object. Handles standard vector operations +// such as addition, subtraction, normalization, scaling, dot product, +// cross product, length, and decomposition into Euler angles. +// + +#ifndef __VECTOR_H__ +#define __VECTOR_H__ + +#include +#include + +class Vector + { + public: + float x; + float y; + float z; + + Vector(); + Vector( vec3_t src ); + Vector( double x, double y, double z ); + Vector( const char *text ); + + float *vec3( void ); + float pitch( void ); + float yaw( void ); + float roll( void ); + float operator[]( int index ) const; + float& operator[]( int index ); + void copyTo( vec3_t vec ); + void setPitch( double x ); + void setYaw( double y ); + void setRoll( double z ); + void setXYZ( double x, double y, double z ); + void operator=( Vector a ); + void operator=( vec3_t a ); + friend Vector operator+( Vector a, Vector b ); + Vector& operator+=( Vector a ); + friend Vector operator-( Vector a, Vector b ); + Vector& operator-=( Vector a ); + friend Vector operator*( Vector a, double b ); + friend Vector operator*( double a, Vector b ); + friend float operator*( Vector a, Vector b ); + Vector& operator*=( double a ); + friend int operator==( Vector a, Vector b ); + friend int operator!=( Vector a, Vector b ); + Vector& CrossProduct( Vector a, Vector b ); + float length( void ); + Vector& normalize( void ); +#if 0 +//FIXME +// Some kind of compiler bug in VC++ prevents this from working. +// Returns result of ( -x, -y, -x ) for some reason + Vector& operator-(); +#endif + friend Vector fabs( Vector a ); + float toYaw( void ); + float toPitch( void ); + Vector toAngles( void ); + void AngleVectors( Vector *forward, Vector *right, Vector *up ); + friend Vector LerpVector( Vector w1, Vector w2, float t ); + friend float MaxValue( Vector a ); + }; + +inline float Vector::pitch( void ) { return x; } +inline float Vector::yaw( void ) { return y; } +inline float Vector::roll( void ) { return z; } +inline void Vector::setPitch( double pitch ) { x = ( float )pitch; } +inline void Vector::setYaw( double yaw ) { y = ( float )yaw; } +inline void Vector::setRoll( double roll ) { z = ( float )roll; } + +inline void Vector::copyTo + ( + vec3_t vec + ) + + { + vec[ 0 ] = x; + vec[ 1 ] = y; + vec[ 2 ] = z; + } + +inline float Vector::operator[] + ( + int index + ) const + + { + assert( ( index >= 0 ) && ( index < 3 ) ); + return ( &x )[ index ]; + } + +inline float& Vector::operator[] + ( + int index + ) + + { + assert( ( index >= 0 ) && ( index < 3 ) ); + return ( &x )[ index ]; + } + +inline void Vector::setXYZ + ( + double x, + double y, + double z + ) + + { + this->x = x; + this->y = y; + this->z = z; + } + +inline Vector::Vector() + { + x = 0; + y = 0; + z = 0; + } + +inline Vector::Vector + ( + vec3_t src + ) + + { + x = src[ 0 ]; + y = src[ 1 ]; + z = src[ 2 ]; + } + +inline Vector::Vector + ( + double x, + double y, + double z + ) + + { + this->x = x; + this->y = y; + this->z = z; + } + +inline Vector::Vector + ( + const char *text + ) + + { + if ( text ) + { + sscanf( text, "%f %f %f", &x, &y, &z ); + } + else + { + x = 0; + y = 0; + z = 0; + } + } + +inline float *Vector::vec3 + ( + void + ) + + { + return &x; + } + +inline void Vector::operator= + ( + Vector a + ) + + { + x = a.x; + y = a.y; + z = a.z; + } + +inline void Vector::operator= + ( + vec3_t a + ) + + { + x = a[ 0 ]; + y = a[ 1 ]; + z = a[ 2 ]; + } + +inline Vector operator+ + ( + Vector a, + Vector b + ) + + { + return Vector( a.x + b.x, a.y + b.y, a.z + b.z ); + } + +inline Vector& Vector::operator+= + ( + Vector a + ) + + { + x += a.x; + y += a.y; + z += a.z; + + return *this; + } + +inline Vector operator- + ( + Vector a, + Vector b + ) + + { + return Vector( a.x - b.x, a.y - b.y, a.z - b.z ); + } + +inline Vector& Vector::operator-= + ( + Vector a + ) + + { + x -= a.x; + y -= a.y; + z -= a.z; + + return *this; + } + +inline Vector operator* + ( + Vector a, + double b + ) + + { + return Vector( a.x * b, a.y * b, a.z * b ); + } + +inline Vector operator* + ( + double a, + Vector b + ) + + { + return b * a; + } + +inline float operator* + ( + Vector a, + Vector b + ) + + { + return a.x * b.x + a.y * b.y + a.z * b.z; + } + +inline Vector& Vector::operator*= + ( + double a + ) + + { + x *= a; + y *= a; + z *= a; + + return *this; + } + +inline int operator== + ( + Vector a, + Vector b + ) + + { + return ( ( a.x == b.x ) && ( a.y == b.y ) && ( a.z == b.z ) ); + } + +inline int operator!= + ( + Vector a, + Vector b + ) + + { + return ( ( a.x != b.x ) || ( a.y != b.y ) || ( a.z != b.z ) ); + } + +inline Vector& Vector::CrossProduct + ( + Vector a, + Vector b + ) + + { + x = a.y * b.z - a.z * b.y; + y = a.z * b.x - a.x * b.z; + z = a.x * b.y - a.y * b.x; + + return *this; + } + +inline float Vector::length + ( + void + ) + + { + float length; + + length = x * x + y * y + z * z; + return ( float )sqrt( length ); + } + +inline Vector& Vector::normalize + ( + void + ) + + { + float length, ilength; + + length = this->length(); + if ( length ) + { + ilength = 1 / length; + x *= ilength; + y *= ilength; + z *= ilength; + } + + return *this; + } + +#if 0 +//FIXME +// Some kind of compiler bug in VC++ prevents this from working. +// Returns result of ( -x, -y, -x ) for some reason +inline Vector& Vector::operator-() + { + return Vector( -x, -y, -z ); + } +#endif + +inline Vector fabs + ( + Vector a + ) + + { + return Vector( fabs( a.x ), fabs( a.y ), fabs( a.z ) ); + } + +inline float MaxValue + ( + Vector a + ) + + { + float maxy; + float maxz; + float max; + + max = fabs( a.x ); + maxy = fabs( a.y ); + maxz = fabs( a.z ); + if ( maxy > max ) + max = maxy; + if ( maxz > max ) + max = maxz; + return max; + } + +inline float Vector::toYaw + ( + void + ) + + { + float yaw; + + if ( ( y == 0 ) && ( x == 0 ) ) + { + yaw = 0; + } + else + { + yaw = ( float )( ( int )( atan2( y, x ) * 180 / M_PI ) ); + if ( yaw < 0 ) + { + yaw += 360; + } + } + + return yaw; + } + +inline float Vector::toPitch + ( + void + ) + + { + float forward; + float pitch; + + if ( ( x == 0 ) && ( y == 0 ) ) + { + if ( z > 0 ) + { + pitch = 90; + } + else + { + pitch = 270; + } + } + else + { + forward = ( float )sqrt( x * x + y * y ); + pitch = ( float )( ( int )( atan2( z, forward ) * 180 / M_PI ) ); + if ( pitch < 0 ) + { + pitch += 360; + } + } + + return pitch; + } + +inline Vector Vector::toAngles + ( + void + ) + + { + float forward; + float yaw, pitch; + + if ( ( x == 0 ) && ( y == 0 ) ) + { + yaw = 0; + if ( z > 0 ) + { + pitch = 90; + } + else + { + pitch = 270; + } + } + else + { + yaw = atan2( y, x ) * 180 / M_PI; + if ( yaw < 0 ) + { + yaw += 360; + } + + forward = ( float )sqrt( x * x + y * y ); + pitch = atan2( z, forward ) * 180 / M_PI; + if ( pitch < 0 ) + { + pitch += 360; + } + } + + return Vector( pitch, yaw, 0 ); + } + +inline void Vector::AngleVectors + ( + Vector *forward, + Vector *right, + Vector *up + ) + + { + float angle; + static float sr, sp, sy, cr, cp, cy; // static to help MS compiler fp bugs + + angle = yaw() * ( M_PI * 2 / 360 ); + sy = sin( angle ); + cy = cos( angle ); + + angle = pitch() * ( M_PI * 2 / 360 ); + sp = sin( angle ); + cp = cos( angle ); + + angle = roll() * ( M_PI * 2 / 360 ); + sr = sin( angle ); + cr = cos( angle ); + + if ( forward ) + { + forward->setXYZ( cp * cy, cp * sy, -sp ); + } + + if ( right ) + { + right->setXYZ( -1 * sr * sp * cy + -1 * cr * -sy, -1 * sr * sp * sy + -1 * cr * cy, -1 * sr * cp ); + } + + if ( up ) + { + up->setXYZ( cr * sp * cy + -sr * -sy, cr * sp * sy + -sr * cy, cr * cp ); + } + } + + +#define LERP_DELTA 1e-6 +inline Vector LerpVector + ( + Vector w1, + Vector w2, + float t + ) + { + double omega, cosom, sinom, scale0, scale1; + + w1.normalize(); + w2.normalize(); + + cosom = w1 * w2; + if ( ( 1.0 - cosom ) > LERP_DELTA ) + { + omega = acos( cosom ); + sinom = sin( omega ); + scale0 = sin( ( 1.0 - t ) * omega ) / sinom; + scale1 = sin( t * omega ) / sinom; + } + else + { + scale0 = 1.0 - t; + scale1 = t; + } + + return ( w1 * scale0 + w2 * scale1 ); + } + +class Quat + { + public: + float x; + float y; + float z; + float w; + + Quat(); + Quat( Vector angles ); + Quat( float scrMatrix[ 3 ][ 3 ] ); + Quat( double x, double y, double z, double w ); + + float *vec4( void ); + float operator[]( int index ) const; + float& operator[]( int index ); + void set( double x, double y, double z, double w ); + void operator=( Quat a ); + friend Quat operator+( Quat a, Quat b ); + Quat& operator+=( Quat a ); + friend Quat operator-( Quat a, Quat b ); + Quat& operator-=( Quat a ); + friend Quat operator*( Quat a, double b ); + friend Quat operator*( double a, Quat b ); + Quat& operator*=( double a ); + friend int operator==( Quat a, Quat b ); + friend int operator!=( Quat a, Quat b ); + float length( void ); + Quat& normalize( void ); + Quat operator-(); + Vector toAngles( void ); + }; + +inline float Quat::operator[] + ( + int index + ) const + + { + assert( ( index >= 0 ) && ( index < 4 ) ); + return ( &x )[ index ]; + } + +inline float& Quat::operator[] + ( + int index + ) + + { + assert( ( index >= 0 ) && ( index < 4 ) ); + return ( &x )[ index ]; + } + +inline float *Quat::vec4 + ( + void + ) + + { + return &x; + } + +inline void Quat::set + ( + double x, + double y, + double z, + double w + ) + + { + this->x = x; + this->y = y; + this->z = z; + this->w = w; + } + +inline Quat::Quat() + { + x = 0; + y = 0; + z = 0; + w = 0; + } + +inline Quat::Quat + ( + Vector Angles + ) + + { + EulerToQuat( Angles.vec3(), this->vec4() ); + } + +inline Quat::Quat + ( + float srcMatrix[ 3 ][ 3 ] + ) + + { + MatToQuat( srcMatrix, this->vec4() ); + } + +inline Quat::Quat + ( + double x, + double y, + double z, + double w + ) + + { + this->x = x; + this->y = y; + this->z = z; + this->w = w; + } + +inline void Quat::operator= + ( + Quat a + ) + + { + x = a.x; + y = a.y; + z = a.z; + w = a.w; + } + +inline Quat operator+ + ( + Quat a, + Quat b + ) + + { + return Quat( a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w ); + } + +inline Quat& Quat::operator+= + ( + Quat a + ) + + { + x += a.x; + y += a.y; + z += a.z; + w += a.w; + + return *this; + } + +inline Quat operator- + ( + Quat a, + Quat b + ) + + { + return Quat( a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w ); + } + +inline Quat& Quat::operator-= + ( + Quat a + ) + + { + x -= a.x; + y -= a.y; + z -= a.z; + w -= a.w; + + return *this; + } + +inline Quat operator* + ( + Quat a, + double b + ) + + { + return Quat( a.x * b, a.y * b, a.z * b, a.w * b ); + } + +inline Quat operator* + ( + double a, + Quat b + ) + + { + return b * a; + } + +inline Quat& Quat::operator*= + ( + double a + ) + + { + x *= a; + y *= a; + z *= a; + w *= a; + + return *this; + } + +inline int operator== + ( + Quat a, + Quat b + ) + + { + return ( ( a.x == b.x ) && ( a.y == b.y ) && ( a.z == b.z ) && ( a.w == b.w ) ); + } + +inline int operator!= + ( + Quat a, + Quat b + ) + + { + return ( ( a.x != b.x ) || ( a.y != b.y ) || ( a.z != b.z ) && ( a.w != b.w ) ); + } + +inline float Quat::length + ( + void + ) + + { + float length; + + length = x * x + y * y + z * z + w * w; + return ( float )sqrt( length ); + } + +inline Quat& Quat::normalize + ( + void + ) + + { + float length, ilength; + + length = this->length(); + if ( length ) + { + ilength = 1 / length; + x *= ilength; + y *= ilength; + z *= ilength; + w *= ilength; + } + + return *this; + } + +inline Quat Quat::operator-() + { + return Quat( -x, -y, -z, -w ); + } + +inline Vector Quat::toAngles + ( + void + ) + + { + float m[ 3 ][ 3 ]; + vec3_t angles; + + QuatToMat( this->vec4(), m ); + MatrixToEulerAngles( m, angles ); + return Vector( angles ); + } + +extern Vector vec_zero; +#endif /* Vector.h */ diff --git a/source/source/cgame/cg_view.c b/source/source/cgame/cg_view.c new file mode 100644 index 0000000..5627828 --- /dev/null +++ b/source/source/cgame/cg_view.c @@ -0,0 +1,663 @@ + +#include "cg_local.h" + +//============================================================================ + +/* +================= +CG_CalcVrect + +Sets the coordinates of the rendered window +================= +*/ +static void CG_CalcVrect (void) { + int size; + + // the intermission should allways be full screen + if ( cg.snap->ps.pm_flags & PMF_INTERMISSION ) { + size = 100; + } else { + // bound normal viewsize + if (cg_viewsize->integer < 30) { + cgi.Cvar_Set ("viewsize","30"); + size = 30; + } else if (cg_viewsize->integer > 100) { + cgi.Cvar_Set ("viewsize","100"); + size = 100; + } else { + size = cg_viewsize->integer; + } + + } + cg.refdef.width = cgs.glconfig.vidWidth*size/100; + cg.refdef.width &= ~1; + + cg.refdef.height = cgs.glconfig.vidHeight*size/100; + cg.refdef.height &= ~1; + + cg.refdef.x = (cgs.glconfig.vidWidth - cg.refdef.width)/2; + cg.refdef.y = (cgs.glconfig.vidHeight - cg.refdef.height)/2; +} + +//============================================================================== + + +/* +=============== +CG_OffsetThirdPersonView + +=============== +*/ +#define CAMERA_MINIMUM_DISTANCE 40 +static void CG_OffsetThirdPersonView( void ) +{ + vec3_t forward; + vec3_t original_camera_position; + vec3_t new_vieworg; + trace_t trace; + vec3_t min, max; + float *look_offset; + float *target_angles; + float *target_position; + vec3_t delta; + vec3_t original_angles; + qboolean lookactive, resetview; + static vec3_t saved_look_offset; + vec3_t camera_offset; + + target_angles = cg.refdefViewAngles; + target_position = cg.refdef.vieworg; + + // see if angles are absolute + if ( cg.predicted_player_state.camera_flags & CF_CAMERA_ANGLES_ABSOLUTE ) + { + VectorClear( target_angles ); + } + + // see if we need to ignore yaw + if ( cg.predicted_player_state.camera_flags & CF_CAMERA_ANGLES_IGNORE_YAW ) + { + target_angles[ YAW ] = 0; + } + + // see if we need to ignore pitch + if ( cg.predicted_player_state.camera_flags & CF_CAMERA_ANGLES_IGNORE_PITCH ) + { + target_angles[ PITCH ] = 0; + } + + // offset the current angles by the camera offset + VectorSubtract( target_angles, cg.predicted_player_state.camera_offset, target_angles ); + + // Get the position of the camera after any needed rotation + look_offset = cgi.get_camera_offset( &lookactive, &resetview ); + + if ( + ( !resetview ) && + ( + ( cg.predicted_player_state.camera_flags & CF_CAMERA_ANGLES_ALLOWOFFSET ) || + ( lookactive ) + ) + ) + { + VectorSubtract( look_offset, saved_look_offset, camera_offset ); + VectorAdd( target_angles, camera_offset, target_angles ); + if ( target_angles[ PITCH ] > 90 ) + target_angles[ PITCH ] = 90; + else if ( target_angles[ PITCH ] < -90 ) + target_angles[ PITCH ] = -90; + } + else + { + VectorCopy( look_offset, saved_look_offset ); + } + + target_angles[ YAW ] = AngleNormalize360( target_angles[ YAW ] ); + target_angles[ PITCH ] = AngleNormalize180( target_angles[ PITCH ] ); + + // Move reference point up + + target_position[2] += cg_cameraheight->value; + + VectorCopy(target_position, original_camera_position); + + // Move camera back from reference point + + AngleVectors(target_angles, forward, NULL, NULL); + + VectorMA(target_position, -cg_cameradist->value, forward, new_vieworg); + + new_vieworg[ 2 ] += cg_cameraverticaldisplacement->value; + + // Create a bounding box for our camera + + min[0] = -5; + min[1] = -5; + min[2] = -5; + + max[0] = 5; + max[1] = 5; + max[2] = 5; + + // Make sure camera does not collide with anything + CG_Trace(&trace, cg.playerHeadPos, min, max, new_vieworg, 0, MASK_CAMERASOLID, qfalse, qtrue, "ThirdPersonTrace 1" ); + + VectorCopy(trace.endpos, target_position); + + // calculate distance from end position to head position + VectorSubtract( target_position, cg.playerHeadPos, delta ); + // kill any negative z difference in delta + if ( delta[ 2 ] < CAMERA_MINIMUM_DISTANCE ) + delta[ 2 ] = 0; + if ( VectorLength( delta ) < CAMERA_MINIMUM_DISTANCE ) + { + VectorNormalize( delta); +/* + // see if we are going straight up + if ( ( delta[ 2 ] > 0.75 ) && ( height > 0.85f * cg.predicted_player_state.viewheight ) ) + { + // we just need to lower our start position slightly, since we are on top of the player + new_vieworg[ 2 ] -= 16; + CG_Trace(&trace, cg.playerHeadPos, min, max, new_vieworg, 0, MASK_CAMERASOLID, qfalse, true, "ThirdPersonTrace 2" ); + VectorCopy(trace.endpos, target_position); + } + else +*/ + { + // we are probably up against the wall so we want the camera to pitch up on top of the player + // save off the original angles + VectorCopy( target_angles, original_angles ); + // start cranking up the target angles, pitch until we are the correct distance away from the player + while ( target_angles[ PITCH ] < 90 ) + { + target_angles[ PITCH ] += 2; + + AngleVectors(target_angles, forward, NULL, NULL); + + VectorMA( original_camera_position, -cg_cameradist->value, forward, new_vieworg); + + new_vieworg[ 2 ] += cg_cameraverticaldisplacement->value; + + CG_Trace(&trace, cg.playerHeadPos, min, max, new_vieworg, 0, MASK_CAMERASOLID, qfalse, qtrue, "ThirdPersonTrace 3" ); + + VectorCopy(trace.endpos, target_position); + + // calculate distance from end position to head position + VectorSubtract( target_position, cg.playerHeadPos, delta ); + // kill any negative z difference in delta + if ( delta[ 2 ] < 0 ) + delta[ 2 ] = 0; + if ( VectorLength( delta ) >= CAMERA_MINIMUM_DISTANCE ) + { + target_angles[ PITCH ] = ( 0.25f * target_angles[ PITCH ] ) + ( 0.75f * original_angles[ PITCH ] ); + // set the pitch to be that of the angle we are currently looking + //target_angles[ PITCH ] = original_angles[ PITCH ]; + break; + } + } + if ( target_angles[ PITCH ] > 90 ) + { + // if we failed, go with the original angles + target_angles[ PITCH ] = original_angles[ PITCH ]; + } + } + } + } + +/* +=============== +CG_OffsetFirstPersonView + +=============== +*/ +static void CG_OffsetFirstPersonView( void ) + { + float *origin; + float *angles; +#if 0 + float delta; + float f; +#endif + + // FIXME, rewrite this to just use what we need + + origin = cg.refdef.vieworg; + angles = cg.refdefViewAngles; + + // if dead, fix the angle and don't add any kick + if ( cg.snap->ps.stats[STAT_HEALTH] <= 0 ) { + angles[ROLL] = 40; + angles[PITCH] = -15; + angles[YAW] = cg.snap->ps.stats[STAT_DEAD_YAW]; + origin[2] += cg.predicted_player_state.viewheight; + return; + } + + //=================================== + + +#if 0 + // smooth out duck height changes + delta = cg.time - cg.duckTime; + if (delta < DUCK_TIME) { + cg.refdef.vieworg[2] -= cg.duckChange + * (DUCK_TIME - delta) / DUCK_TIME; + } + + // add fall height + delta = cg.time - cg.landTime; + if ( delta < LAND_DEFLECT_TIME ) { + f = delta / LAND_DEFLECT_TIME; + cg.refdef.vieworg[2] += cg.landChange * f; + } else if ( delta < LAND_DEFLECT_TIME + LAND_RETURN_TIME ) { + delta -= LAND_DEFLECT_TIME; + f = 1.0 - ( delta / LAND_RETURN_TIME ); + cg.refdef.vieworg[2] += cg.landChange * f; + } +#endif + + // add kick offset + VectorAdd (origin, cg.kick_origin, origin); + } + +/* +=============== +CG_InterpolateView + +=============== +*/ +static void CG_InterpolateView( void ) + { + float timedelta; + float scale; + vec3_t target_angles; + vec3_t target_position; + vec3_t delta_angles; + vec3_t delta_position; + + // if we just started out, or there is a camera cut, cut! + if ( + ( cg.lastCameraTime == -1 ) || + ( + ( cg.predicted_player_state.camera_flags & CF_CAMERA_CUT_BIT ) != + ( cg.lastCameraFlags & CF_CAMERA_CUT_BIT ) + ) + ) + { + // if we reset just set scale to 1 + timedelta = 0; + scale = 1; + } + else + { + timedelta = ( cg.time - cg.lastCameraTime ) / 1000.0f; + if ( paused->integer ) + { + scale = cg_camerascale->value; + } + else + { + scale = timedelta * cg_camerascale->value * 30.0f; + if ( scale > 1.0f ) + scale = 1.0f; + if ( scale < 0 ) + scale = 0; + } + } + + // save off cameraFlags + cg.lastCameraFlags = cg.predicted_player_state.camera_flags; + + // save off cameraTime + cg.lastCameraTime = cg.time; + + if ( cg.predicted_player_state.pm_flags & PMF_CAMERA_VIEW ) + { + if ( !cg.inCameraView ) + { + // we just entered camera view + cg.inCameraView = qtrue; + cg.lerpCameraTime = cg.predicted_player_state.camera_time; + } + // copy off target_angles and target_origin + VectorCopy( cg.camera_origin, target_position ); + VectorCopy( cg.camera_angles, target_angles ); + } + else + { + if ( cg.inCameraView ) + { + // we just left camera view + cg.inCameraView = qfalse; + cg.lerpCameraTime = cg.predicted_player_state.camera_time; + } + // copy off target_angles and target_origin + VectorCopy( cg.refdefViewAngles, target_angles ); + VectorCopy( cg.refdef.vieworg, target_position ); + } + + if ( cg.lerpCameraTime ) + { + scale = cg.lerpCameraTime / cg.snap->ps.camera_time; + cg.lerpCameraTime -= timedelta; + if ( cg.lerpCameraTime < 0 ) + cg.lerpCameraTime = 0; + if ( scale > 1.0f ) + scale = 1.0f; + scale = 1.0f - scale; + } + + if ( cg.lerpCameraTime || ( !( cg.predicted_player_state.pm_flags & PMF_CAMERA_VIEW ) ) ) + { + // interpolate the camera + AnglesSubtract( target_angles, cg.currentViewAngles, delta_angles ); + VectorSubtract( target_position, cg.currentViewPos, delta_position ); + + VectorMA( cg.currentViewAngles, scale, delta_angles, cg.refdefViewAngles ); + VectorMA( cg.currentViewPos, scale, delta_position, cg.refdef.vieworg ); + +#if 0 + // if we are in the normal 3rd person camera make sure we are looking at the player + if ( !cg.lerpCameraTime ) + { + VectorSubtract( cg.playerHeadPos, cg.refdef.vieworg, delta_position ); + vectoangles( delta_position, cg.refdefViewAngles ); + } +#endif + + cg.refdefViewAngles[ 0 ] = AngleMod( cg.refdefViewAngles[ 0 ] ); + cg.refdefViewAngles[ 1 ] = AngleMod( cg.refdefViewAngles[ 1 ] ); + cg.refdefViewAngles[ 2 ] = AngleMod( cg.refdefViewAngles[ 2 ] ); + } + else + { + // just a normal camera view + VectorCopy( cg.camera_origin, cg.refdef.vieworg ); + VectorCopy( cg.camera_angles, cg.refdefViewAngles ); + } + + if ( !cg.lerpCameraTime ) + { + // save off the current position and view + VectorCopy( cg.refdef.vieworg, cg.currentViewPos ); + VectorCopy( cg.refdefViewAngles, cg.currentViewAngles ); + } + } + + +/* +==================== +CG_CalcFov + +Fixed fov at intermissions, otherwise account for fov variable and zooms. +==================== +*/ +#define WAVE_AMPLITUDE 1 +#define WAVE_FREQUENCY 0.4 + +static int CG_CalcFov( void ) + { + float x; + float phase; + float v; + int contents; + float fov_x, fov_y; + int inwater; + + fov_x = cg.camera_fov; + x = cg.refdef.width / tan( fov_x / 360 * M_PI ); + fov_y = atan2( cg.refdef.height, x ); + fov_y = fov_y * 360 / M_PI; + + // warp if underwater + contents = CG_PointContents( cg.refdef.vieworg, -1 ); + if ( contents & ( CONTENTS_WATER | CONTENTS_SLIME | CONTENTS_LAVA ) ){ + phase = cg.time / 1000.0 * WAVE_FREQUENCY * M_PI * 2; + v = WAVE_AMPLITUDE * sin( phase ); + fov_x += v; + fov_y -= v; + inwater = qtrue; + } + else { + inwater = qfalse; + } + + + // set it + cg.refdef.fov_x = fov_x; + cg.refdef.fov_y = fov_y; + + if ( !cg.zoomed ) { + cg.zoomSensitivity = 1; + } else { + cg.zoomSensitivity = cg.refdef.fov_y / 75.0; + } + return inwater; + } + + +/* +=============== +CG_CalcViewValues + +Sets cg.refdef view values +=============== +*/ +static int CG_CalcViewValues( void ) { + playerState_t *ps; + float SoundAngles[3]; + + memset( &cg.refdef, 0, sizeof( cg.refdef ) ); + + // calculate size of 3D view + CG_CalcVrect(); + + // setup fog and far clipping plane + cg.refdef.farplane_distance = cg.farplane_distance; + VectorCopy( cg.farplane_color, cg.refdef.farplane_color ); + cg.refdef.farplane_cull = cg.farplane_cull; + + // setup portal sky + cg.refdef.sky_alpha = cg.sky_alpha; + cg.refdef.sky_portal = cg.sky_portal; + memcpy( cg.refdef.sky_axis, cg.sky_axis, sizeof( cg.sky_axis ) ); + VectorCopy( cg.sky_origin, cg.refdef.sky_origin ); + + ps = &cg.predicted_player_state; + + cg.bobcycle = ( ps->bobCycle & 128 ) >> 7; + cg.bobfracsin = fabs( sin( ( ps->bobCycle & 127 ) / 127.0 * M_PI ) ); + cg.xyspeed = sqrt( ps->velocity[0] * ps->velocity[0] + + ps->velocity[1] * ps->velocity[1] ); + + VectorCopy( ps->origin, cg.refdef.vieworg ); + VectorCopy( ps->viewangles, cg.refdefViewAngles ); + + // add error decay + if ( cg_errorDecay->value > 0 ) + { + int t; + float f; + + t = cg.time - cg.predictedErrorTime; + f = ( cg_errorDecay->value - t ) / cg_errorDecay->value; + if ( f > 0 && f < 1 ) + { + VectorMA( cg.refdef.vieworg, f, cg.predictedError, cg.refdef.vieworg ); + } + else + { + cg.predictedErrorTime = 0; + } + } + + // calculate position of player's head + cg.refdef.vieworg[ 2 ] += cg.predicted_player_state.viewheight; + // save off the position of the player's head + VectorCopy( cg.refdef.vieworg, cg.playerHeadPos ); + + // Set the aural position of the player + VectorCopy( cg.playerHeadPos, cg.SoundOrg ); + + // Set the aural axis of the player + VectorCopy( cg.refdefViewAngles, SoundAngles ); + // yaw is purposely inverted because of the miles sound system + SoundAngles[YAW] = -SoundAngles[YAW]; + AnglesToAxis( SoundAngles, cg.SoundAxis ); + + // decide on third person view + cg.renderingThirdPerson = cg_3rd_person->integer || (cg.snap->ps.stats[STAT_HEALTH] <= 0); + + if ( cg.renderingThirdPerson ) + { + // back away from character + CG_OffsetThirdPersonView(); + } + else + { + CG_OffsetFirstPersonView(); + // offset for local bobbing and kicks + cg.crosshair_offset = 0.0f; + } + + // interpolate the view as necessary + CG_InterpolateView(); + + // if we are in a camera view, we take our audio cues directly from the camera + if ( cg.inCameraView ) + { + // Set the aural position to that of the camera + VectorCopy( cg.refdef.vieworg, cg.SoundOrg ); + + // Set the aural axis to the camera's angles + VectorCopy( cg.refdefViewAngles, SoundAngles ); + // yaw is purposely inverted because of the miles sound system + SoundAngles[YAW] = -SoundAngles[YAW]; + AnglesToAxis( SoundAngles, cg.SoundAxis ); + } + + // offset the current angles by the damage angles + VectorSubtract( cg.refdefViewAngles, cg.predicted_player_state.damage_angles, cg.refdefViewAngles ); + + // position eye reletive to origin + AnglesToAxis( cg.refdefViewAngles, cg.refdef.viewaxis ); + + if ( cg.hyperspace ) { + cg.refdef.rdflags |= RDF_NOWORLDMODEL | RDF_HYPERSPACE; + } + + // field of view + return CG_CalcFov(); +} + +//========================================================================= + +/* +================= +CG_DrawActiveFrame + +Generates and draws a game scene and status information at the given time. +================= +*/ +void CG_DrawActiveFrame( int serverTime, stereoFrame_t stereoView, qboolean demoPlayback ) + { + cg.time = serverTime; + cg.demoPlayback = demoPlayback; + + // if we are only updating the screen as a loading + // pacifier, don't even try to read snapshots + if ( cg.infoScreenText[0] != 0 ) + { + return; + } + + // any looped sounds will be respecified as entities + // are added to the render list + cgi.S_ClearLoopingSounds(); + + // clear all the render lists + cgi.R_ClearScene(); + + // set up cg.snap and possibly cg.nextSnap + CG_ProcessSnapshots(); + + // if we haven't received any snapshots yet, all + // we can draw is the information screen + if ( !cg.snap || ( cg.snap->snapFlags & SNAPFLAG_NOT_ACTIVE ) ) + { + return; + } + + // this counter will be bumped for every valid scene we generate + cg.clientFrame++; + + // set cg.frameInterpolation + if ( cg.nextSnap && r_lerpmodels->integer ) { + int delta; + + delta = (cg.nextSnap->serverTime - cg.snap->serverTime); + if ( delta == 0 ) { + cg.frameInterpolation = 0; + } else { + cg.frameInterpolation = (float)( cg.time - cg.snap->serverTime ) / delta; + } + } else { + cg.frameInterpolation = 0; // actually, it should never be used, because + // no entities should be marked as interpolating + } + + // update cg.predicted_player_state + CG_PredictPlayerState(); + + // build cg.refdef + CG_CalcViewValues(); + + // build the render lists + if ( !cg.hyperspace ) + { + CG_AddPacketEntities(); // after calcViewValues, so predicted player state is correct + CG_AddMarks(); + } + + // finish up the rest of the refdef +#if 0 + if ( cg.testModelEntity.hModel ) + { + CG_AddTestModel(); + } +#endif + + cg.refdef.time = cg.time; + memcpy( cg.refdef.areamask, cg.snap->areamask, sizeof( cg.refdef.areamask ) ); + + // update audio positions + cgi.S_Respatialize( cg.snap->ps.clientNum, cg.SoundOrg, cg.SoundAxis ); + + // make sure the lagometerSample and frame timing isn't done twice when in stereo + if ( stereoView != STEREO_RIGHT ) + { + cg.frametime = cg.time - cg.oldTime; + if ( cg.frametime < 0 ) + { + cg.frametime = 0; + } + cg.oldTime = cg.time; + CG_AddLagometerFrameInfo(); + } + + CG_UpdateTestEmitter(); + + if ( !cg_hidetempmodels->integer ) + CG_AddTempModels(); + + CG_AddBeams(); + + // actually issue the rendering calls + CG_DrawActive( stereoView ); + + if ( cg_stats->integer ) + { + cgi.Printf( "cg.clientFrame:%i\n", cg.clientFrame ); + } + } + diff --git a/source/source/cgame/cgame.def b/source/source/cgame/cgame.def new file mode 100644 index 0000000..e224286 --- /dev/null +++ b/source/source/cgame/cgame.def @@ -0,0 +1,2 @@ +EXPORTS + GetCGameAPI diff --git a/source/source/cgame/cgame.dsp b/source/source/cgame/cgame.dsp new file mode 100644 index 0000000..a421c35 --- /dev/null +++ b/source/source/cgame/cgame.dsp @@ -0,0 +1,273 @@ +# Microsoft Developer Studio Project File - Name="cgame" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=cgame - 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 "cgame.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 "cgame.mak" CFG="cgame - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "cgame - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "cgame - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName ""$/fakk2_code/fakk2_new/cgame", DYHAAAAA" +# PROP Scc_LocalPath "." +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "cgame - 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 /G5 /MT /W3 /GX /Zi /O2 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "CGAME_DLL" /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 /nologo /base:"0x30000000" /subsystem:windows /dll /map /machine:I386 /out:"../Release/cgamex86.dll" +# SUBTRACT LINK32 /debug + +!ELSEIF "$(CFG)" == "cgame - 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 /G5 /MTd /W4 /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "CGAME_DLL" /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 /nologo /base:"0x30000000" /subsystem:windows /dll /map /debug /machine:I386 /out:"..\Debug/cgamex86.dll" +# SUBTRACT LINK32 /profile /nodefaultlib + +!ENDIF + +# Begin Target + +# Name "cgame - Win32 Release" +# Name "cgame - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "c" +# Begin Source File + +SOURCE=..\fgame\bg_misc.c +# End Source File +# Begin Source File + +SOURCE=..\fgame\bg_pmove.c +# End Source File +# Begin Source File + +SOURCE=.\cg_beam.cpp +# End Source File +# Begin Source File + +SOURCE=.\cg_commands.cpp +# End Source File +# Begin Source File + +SOURCE=.\cg_consolecmds.c +# End Source File +# Begin Source File + +SOURCE=.\cg_drawtools.cpp +# End Source File +# Begin Source File + +SOURCE=.\cg_ents.c +# End Source File +# Begin Source File + +SOURCE=.\cg_lightstyles.cpp +# End Source File +# Begin Source File + +SOURCE=.\cg_main.c +# End Source File +# Begin Source File + +SOURCE=.\cg_marks.c +# End Source File +# Begin Source File + +SOURCE=.\cg_modelanim.c +# End Source File +# Begin Source File + +SOURCE=.\cg_player.cpp +# End Source File +# Begin Source File + +SOURCE=.\cg_playerstate.c +# End Source File +# Begin Source File + +SOURCE=.\cg_predict.c +# End Source File +# Begin Source File + +SOURCE=.\cg_servercmds.c +# End Source File +# Begin Source File + +SOURCE=.\cg_snapshot.c +# End Source File +# Begin Source File + +SOURCE=.\cg_sound.cpp +# End Source File +# Begin Source File + +SOURCE=.\cg_specialfx.cpp +# End Source File +# Begin Source File + +SOURCE=.\cg_swipe.cpp +# End Source File +# Begin Source File + +SOURCE=.\cg_testemitter.cpp +# End Source File +# Begin Source File + +SOURCE=.\cg_view.c +# End Source File +# Begin Source File + +SOURCE=.\class.cpp +# End Source File +# Begin Source File + +SOURCE=.\listener.cpp +# End Source File +# Begin Source File + +SOURCE=..\fgame\q_math.c +# End Source File +# Begin Source File + +SOURCE=..\fgame\q_mathsys.c +# End Source File +# Begin Source File + +SOURCE=..\fgame\q_shared.c +# End Source File +# Begin Source File + +SOURCE=.\script.cpp +# End Source File +# Begin Source File + +SOURCE=.\str.cpp +# End Source File +# Begin Source File + +SOURCE=..\win32\win_bounds.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h" +# Begin Source File + +SOURCE=..\fgame\bg_local.h +# End Source File +# Begin Source File + +SOURCE=..\fgame\bg_public.h +# End Source File +# Begin Source File + +SOURCE=.\cg_commands.h +# End Source File +# Begin Source File + +SOURCE=.\cg_local.h +# End Source File +# Begin Source File + +SOURCE=.\cg_public.h +# End Source File +# Begin Source File + +SOURCE=.\class.h +# End Source File +# Begin Source File + +SOURCE=.\container.h +# End Source File +# Begin Source File + +SOURCE=.\Linklist.h +# End Source File +# Begin Source File + +SOURCE=.\listener.h +# End Source File +# Begin Source File + +SOURCE=.\script.h +# End Source File +# Begin Source File + +SOURCE=.\str.h +# End Source File +# Begin Source File + +SOURCE=.\tr_types.h +# End Source File +# Begin Source File + +SOURCE=.\vector.h +# End Source File +# End Group +# Begin Source File + +SOURCE=.\cgame.def +# End Source File +# End Target +# End Project diff --git a/source/source/cgame/cgame.dsw b/source/source/cgame/cgame.dsw new file mode 100644 index 0000000..4364e03 --- /dev/null +++ b/source/source/cgame/cgame.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "cgame"=.\cgame.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/source/source/cgame/class.cpp b/source/source/cgame/class.cpp new file mode 100644 index 0000000..c5c278d --- /dev/null +++ b/source/source/cgame/class.cpp @@ -0,0 +1,1035 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/cgame/class.cpp $ +// $Revision:: 17 $ +// $Author:: Aldie $ +// $Date:: 8/10/00 6:34p $ +// +// Copyright (C) 1997 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source is may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/cgame/class.cpp $ +// +// 17 8/10/00 6:34p Aldie +// Added a shutdown method +// +// 16 7/26/00 1:07p Steven +// Made it so in classes new function NULL is returned if we try to allocate 0 +// bytes. +// +// 15 7/07/00 6:57p Markd +// changed default debug printf when starting up event system +// +// 14 5/24/00 3:14p Markd +// first phase of save/load games +// +// 13 4/29/00 3:50p Markd +// added some convenience classes and printed out classID when appropriate +// +// 12 4/29/00 3:26p Markd +// fleshed out the rest of the event/class documentation +// +// 11 4/29/00 11:38a Markd +// changed formatting for dump all classes +// +// 10 4/26/00 7:55p Markd +// Added more documentation code into various systems +// +// 9 4/12/00 6:19p Aldie +// Fixed formatting +// +// 8 3/04/00 11:45a Markd +// Added malloc and free for cgame and client +// +// 7 2/26/00 3:27p Markd +// pre-initialized all memory with known bad value +// +// 6 2/04/00 11:20a Markd +// Added memory leak test code to new and delete operators +// +// 5 1/10/00 5:34p Markd +// Changed Allocation routines for fgame to use the gi.Malloc and gi.Free +// instead of the in game heap +// +// 4 12/15/99 11:45a Markd +// made Event's Classes and also freed up safe pointers at the appropriate +// times +// +// 3 10/05/99 2:03p Markd +// Added warning about files being in multiple projects +// +// 2 9/28/99 4:26p Markd +// merged listener, class and vector between 3 projects +// +// 1 9/10/99 10:53a Jimdose +// +// 1 9/08/99 3:15p Aldie +// +// DESCRIPTION: +// Base class that all classes that are used in conjunction with Sin should +// be based off of. Class gives run-time type information about any class +// derived from it. This is really handy when you have a pointer to an object +// that you need to know if it supports certain behaviour. +// +// WARNING: This file is shared between fgame, cgame and possibly the user interface. +// It is instanced in each one of these directories because of the way that SourceSafe works. +// + +#include +#include +#include + +#if defined( GAME_DLL ) + +#include "g_local.h" + +#elif defined ( CGAME_DLL ) + +#include "cg_local.h" +#include "listener.h" +#include "../qcommon/qcommon.h" + +#else + +#include "listener.h" +#include "../qcommon/qcommon.h" + +#endif + +#include "class.h" +#include "linklist.h" + +int totalmemallocated = 0; +int numclassesallocated = 0; + +static ClassDef *classlist = NULL; + + +ClassDef::ClassDef() + { + this->classname = NULL; + this->classID = NULL; + this->superclass = NULL; + this->responses = NULL, + this->numEvents = 0; + this->responseLookup = NULL; + this->newInstance = NULL; + this->classSize = 0; + this->super = NULL; + this->prev = this; + this->next = this; + } + +ClassDef::ClassDef + ( + const char *classname, + const char *classID, + const char *superclass, + ResponseDef *responses, + void *( *newInstance )( void ), + int classSize + ) + + { + ClassDef *node; + + if ( classlist == NULL ) + { + classlist = new ClassDef; + } + + this->classname = classname; + this->classID = classID; + this->superclass = superclass; + this->responses = responses; + this->numEvents = 0; + this->responseLookup = NULL; + this->newInstance = newInstance; + this->classSize = classSize; + this->super = getClass( superclass ); + + // It's not uncommon for classes to not have a class id, so just set it + // to an empty string so that we're not checking for it all the time. + if ( !classID ) + { + this->classID = ""; + } + + // Check if any subclasses were initialized before their superclass + for( node = classlist->next; node != classlist; node = node->next ) + { + if ( ( node->super == NULL ) && ( !Q_stricmp( node->superclass, this->classname ) ) && + ( Q_stricmp( node->classname, "Class" ) ) ) + { + node->super = this; + } + } + + // Add to front of list + LL_Add( classlist, this, prev, next ); + } + +void ClassDef::Shutdown + ( + void + ) + + { + if ( responseLookup ) + { + delete[] responseLookup; + responseLookup = NULL; + } + } + +ClassDef::~ClassDef() + { + ClassDef *node; + + if ( classlist != this ) + { + LL_Remove( this, prev, next ); + + // Check if any subclasses were initialized before their superclass + for( node = classlist->next; node != classlist; node = node->next ) + { + if ( node->super == this ) + { + node->super = NULL; + } + } + } + else + { + // If the head of the list is deleted before the list is cleared, then we may have problems + assert( this->next == this->prev ); + } + + if ( responseLookup ) + { + delete[] responseLookup; + responseLookup = NULL; + } + } + +void ClassDef::BuildResponseList + ( + void + ) + + { + ClassDef *c; + ResponseDef *r; + int ev; + int i; + qboolean *set; + int num; + + if ( responseLookup ) + { + delete[] responseLookup; + responseLookup = NULL; + } + + num = Event::NumEventCommands(); + responseLookup = ( Response ** )new char[ sizeof( Response * ) * num ]; + memset( responseLookup, 0, sizeof( Response * ) * num ); + + set = new qboolean[ num ]; + memset( set, 0, sizeof( qboolean ) * num ); + + this->numEvents = num; + + for( c = this; c != NULL; c = c->super ) + { + r = c->responses; + if ( r ) + { + for( i = 0; r[ i ].event != NULL; i++ ) + { + ev = ( int )*r[ i ].event; + if ( !set[ ev ] ) + { + set[ ev ] = true; + if ( r[ i ].response ) + { + responseLookup[ ev ] = &r[ i ].response; + } + else + { + responseLookup[ ev ] = NULL; + } + } + } + } + } + + delete[] set; + } + +void BuildEventResponses + ( + void + ) + + { + ClassDef *c; + int amount; + int numclasses; + + amount = 0; + numclasses = 0; + for( c = classlist->next; c != classlist; c = c->next ) + { + c->BuildResponseList(); + + amount += c->numEvents * sizeof( Response * ); + numclasses++; + } + + CLASS_DPrintf( "\n------------------\nEvent system initialized: " + "%d classes %d events %d total memory in response list\n\n", + numclasses, Event::NumEventCommands(), amount ); + } + +ClassDef *getClassForID + ( + const char *name + ) + + { + ClassDef *c; + + for( c = classlist->next; c != classlist; c = c->next ) + { + if ( c->classID && !Q_stricmp( c->classID, name ) ) + { + return c; + } + } + + return NULL; + } + +ClassDef *getClass + ( + const char *name + ) + + { + ClassDef *c; + + for( c = classlist->next; c != classlist; c = c->next ) + { + if ( !Q_stricmp( c->classname, name ) ) + { + return c; + } + } + + return NULL; + } + +ClassDef *getClassList + ( + void + ) + + { + return classlist; + } + +void listAllClasses + ( + void + ) + + { + ClassDef *c; + + for( c = classlist->next; c != classlist; c = c->next ) + { + CLASS_DPrintf( "%s\n", c->classname ); + } + } + +void listInheritanceOrder + ( + const char *classname + ) + + { + ClassDef *cls; + ClassDef *c; + + cls = getClass( classname ); + if ( !cls ) + { + CLASS_DPrintf( "Unknown class: %s\n", classname ); + return; + } + for( c = cls; c != NULL; c = c->super ) + { + CLASS_DPrintf( "%s\n", c->classname ); + } + } + +qboolean checkInheritance + ( + ClassDef *superclass, + ClassDef *subclass + ) + + { + ClassDef *c; + + for( c = subclass; c != NULL; c = c->super ) + { + if ( c == superclass ) + { + return true; + } + } + return false; + } + +qboolean checkInheritance + ( + ClassDef *superclass, + const char *subclass + ) + + { + ClassDef *c; + + c = getClass( subclass ); + if ( c == NULL ) + { + CLASS_DPrintf( "Unknown class: %s\n", subclass ); + return false; + } + return checkInheritance( superclass, c ); + } + +qboolean checkInheritance + ( + const char *superclass, + const char *subclass + ) + + { + ClassDef *c1; + ClassDef *c2; + + c1 = getClass( superclass ); + c2 = getClass( subclass ); + if ( c1 == NULL ) + { + CLASS_DPrintf( "Unknown class: %s\n", superclass ); + return false; + } + if ( c2 == NULL ) + { + CLASS_DPrintf( "Unknown class: %s\n", subclass ); + return false; + } + return checkInheritance( c1, c2 ); + } + +void CLASS_Print( FILE *class_file, const char *fmt, ... ) + { + va_list argptr; + char text[ 1024 ]; + + va_start( argptr, fmt ); + vsprintf( text, fmt, argptr ); + va_end( argptr ); + + if ( class_file ) + fprintf( class_file, text ); + else + CLASS_DPrintf( text ); + } + + +CLASS_DECLARATION( NULL, Class, NULL ) + { + { NULL, NULL } + }; + +#ifdef NDEBUG + +void * Class::operator new( size_t s ) + { + int *p; + + if ( s == 0 ) + return NULL; + + s += sizeof( int ); +#if defined( GAME_DLL ) + p = ( int * )gi.Malloc( s ); +#elif defined( CGAME_DLL ) + p = ( int * )cgi.Malloc( s ); +#else + p = ( int * )Z_TagMalloc( s, TAG_CLIENT ); +#endif + *p = s; + totalmemallocated += s; + numclassesallocated++; + return p + 1; + } + +void Class::operator delete( void *ptr ) + { + int *p; + + p = ( ( int * )ptr ) - 1; + totalmemallocated -= *p; + numclassesallocated--; +#if defined( GAME_DLL ) + gi.Free( p ); +#elif defined( CGAME_DLL ) + cgi.Free( p ); +#else + Z_Free( p ); +#endif + } + +#else + +#ifdef MEMORY_LEAK_TEST +int classindex = 0; +#endif + +void * Class::operator new( size_t s ) + { + int *p; + + s += sizeof( int ) * 3; +#if defined( GAME_DLL ) + p = ( int * )gi.Malloc( s ); +#elif defined( CGAME_DLL ) + p = ( int * )cgi.Malloc( s ); +#else + p = ( int * )Z_TagMalloc( s, TAG_CLIENT ); +#endif + // set memory to a known wrong number + memset( p, 0xaa, s ); +#ifdef MEMORY_LEAK_TEST + p[ 0 ] = classindex++; +#else + p[ 0 ] = 0x12348765; +#endif + *( int * )( ((byte *)p) + s - sizeof( int ) ) = 0x56784321; + p[ 1 ] = s; + totalmemallocated += s; + numclassesallocated++; + return p + 2; + } + +void Class::operator delete( void *ptr ) + { + int *p; + + p = ( ( int * )ptr ) - 2; +#ifndef MEMORY_LEAK_TEST + assert( p[ 0 ] == 0x12348765 ); +#endif + assert( *( int * )( ((byte *)p) + p[ 1 ] - sizeof( int ) ) == 0x56784321 ); + + totalmemallocated -= p[ 1 ]; + numclassesallocated--; +#if defined( GAME_DLL ) + gi.Free( p ); +#elif defined( CGAME_DLL ) + cgi.Free( p ); +#else + Z_Free( p ); +#endif + } + +#endif + +void DisplayMemoryUsage + ( + void + ) + + { + CLASS_Printf( "Classes %-5d Class memory used: %d\n", numclassesallocated, totalmemallocated ); + } + +Class::Class() + { + SafePtrList = NULL; + } + +Class::~Class() + { + ClearSafePointers(); + } + +#ifdef GAME_DLL + +void Class::Archive + ( + Archiver &arc + ) + + { + } + +#endif + +void Class::ClearSafePointers( void ) + { + while( SafePtrList != NULL ) + { + SafePtrList->Clear(); + } + } + + +void Class::warning + ( + const char *function, + const char *fmt, + ... + ) + + { + va_list argptr; + char text[ 1024 ]; + + va_start( argptr, fmt ); + vsprintf( text, fmt, argptr ); + va_end( argptr ); + + if ( getClassID() ) + { + CLASS_DPrintf( "%s::%s : %s\n", getClassID(), function, text ); + } + else + { + CLASS_DPrintf( "%s::%s : %s\n", getClassname(), function, text ); + } + } + +void Class::error + ( + const char *function, + const char *fmt, + ... + ) + + { + va_list argptr; + char text[ 1024 ]; + + va_start( argptr, fmt ); + vsprintf( text, fmt, argptr ); + va_end( argptr ); + + if ( getClassID() ) + { + CLASS_Error( ERR_DROP, "%s::%s : %s\n", getClassID(), function, text ); + } + else + { + CLASS_Error( ERR_DROP, "%s::%s : %s\n", getClassname(), function, text ); + } + } + +qboolean Class::inheritsFrom + ( + const char *name + ) + + { + ClassDef *c; + + c = getClass( name ); + if ( c == NULL ) + { + CLASS_DPrintf( "Unknown class: %s\n", name ); + return false; + } + return checkInheritance( c, classinfo() ); + } + +qboolean Class::isInheritedBy + ( + const char *name + ) + + { + ClassDef *c; + + c = getClass( name ); + if ( c == NULL ) + { + CLASS_DPrintf( "Unknown class: %s\n", name ); + return false; + } + return checkInheritance( classinfo(), c ); + } + +const char *Class::getClassname + ( + void + ) + + { + ClassDef *cls; + + cls = classinfo(); + return cls->classname; + } + +const char *Class::getClassID + ( + void + ) + + { + ClassDef *cls; + + cls = classinfo(); + return cls->classID; + } + +const char *Class::getSuperclass + ( + void + ) + + { + ClassDef *cls; + + cls = classinfo(); + return cls->superclass; + } + +void *Class::newInstance + ( + void + ) + + { + ClassDef *cls; + + cls = classinfo(); + return cls->newInstance(); + } + +#define MAX_INHERITANCE 64 +void ClassEvents + ( + const char *classname, + qboolean print_to_disk + ) + + { + ClassDef *c; + ResponseDef *r; + int ev; + int i, j; + qboolean *set; + int num, orderNum; + Event **events; + byte *order; + FILE *class_file; + str classNames[ MAX_INHERITANCE ]; + str class_filename; + + c = getClass( classname ); + if ( !c ) + { + CLASS_DPrintf( "Unknown class: %s\n", classname ); + return; + } + + class_file = NULL; + + if ( print_to_disk ) + { + class_filename = str ( classname ) + ".txt"; + class_file = fopen( class_filename.c_str(), "w" ); + if ( class_file == NULL ) + return; + } + + num = Event::NumEventCommands(); + + set = new qboolean[ num ]; + memset( set, 0, sizeof( qboolean ) * num ); + + events = new Event *[ num ]; + memset( events, 0, sizeof( Event * ) * num ); + + order = new byte[ num ]; + memset( order, 0, sizeof( byte ) * num ); + + orderNum = 0; + for( ; c != NULL; c = c->super ) + { + if ( orderNum < MAX_INHERITANCE ) + { + classNames[ orderNum ] = c->classname; + } + r = c->responses; + if ( r ) + { + for( i = 0; r[ i ].event != NULL; i++ ) + { + ev = ( int )*r[ i ].event; + if ( !set[ ev ] ) + { + set[ ev ] = true; + + if ( r[ i ].response ) + { + events[ ev ] = r[ i ].event; + order[ ev ] = orderNum; + } + } + } + } + orderNum++; + } + + CLASS_Print( class_file, "********************************************************\n" ); + CLASS_Print( class_file, "********************************************************\n" ); + CLASS_Print( class_file, "* All Events For Class: %s\n", classname ); + CLASS_Print( class_file, "********************************************************\n" ); + CLASS_Print( class_file, "********************************************************\n\n" ); + + for( j = orderNum - 1; j >= 0; j-- ) + { + CLASS_Print( class_file, "\n********************************************************\n" ); + CLASS_Print( class_file, "* Class: %s\n", classNames[ j ].c_str() ); + CLASS_Print( class_file, "********************************************************\n\n" ); + for( i = 1; i < num; i++ ) + { + int index; + + index = Event::MapSortedEventIndex( i ); + if ( events[ index ] && ( order[ index ] == j ) ) + { + Event::PrintEventDocumentation( events[ index ], class_file ); + } + } + } + + if ( class_file != NULL ) + { + CLASS_DPrintf( "Printed class info to file %s\n", class_filename.c_str() ); + fclose( class_file ); + } + + delete[] events; + delete[] order; + delete[] set; + } + +static int dump_numclasses; +static int dump_numevents; +void DumpClass + ( + FILE * class_file, + const char * className + ) + + { + ClassDef *c; + ResponseDef *r; + int ev; + int i; + int num; + Event **events; + + c = getClass( className ); + if ( !c ) + { + return; + } + + num = Event::NumEventCommands(); + + events = new Event *[ num ]; + memset( events, 0, sizeof( Event * ) * num ); + + // gather event responses for this class + r = c->responses; + if ( r ) + { + for( i = 0; r[ i ].event != NULL; i++ ) + { + ev = ( int )*r[ i ].event; + if ( r[ i ].response ) + { + events[ ev ] = r[ i ].event; + } + } + } + + CLASS_Print( class_file, "\n"); + if ( c->classID[ 0 ] ) + { + CLASS_Print( class_file, "

%s (%s)", c->classname, c->classname, c->classID ); + } + else + { + CLASS_Print( class_file, "

%s", c->classname, c->classname ); + } + + // print out lineage + for( c = c->super; c != NULL; c = c->super ) + { + CLASS_Print( class_file, " -> %s", c->classname, c->classname ); + } + CLASS_Print( class_file, "

\n"); + + dump_numclasses++; + + CLASS_Print( class_file, "
\n"); + for( i = 1; i < num; i++ ) + { + int index; + + index = Event::MapSortedEventIndex( i ); + if ( events[ index ] ) + { + Event::PrintEventDocumentation( events[ index ], class_file, qtrue ); + dump_numevents++; + } + } + CLASS_Print( class_file, "
\n"); + delete[] events; + } + + +#define MAX_CLASSES 1024 +void DumpAllClasses + ( + void + ) + + { + int i, j, num, smallest; + ClassDef *c; + FILE * class_file; + str class_filename; + str class_title; + str classes[ MAX_CLASSES ]; + +#if defined( GAME_DLL ) + class_filename = "g_allclasses.html"; + class_title = "Game Module"; +#elif defined( CGAME_DLL ) + class_filename = "cg_allclasses.html"; + class_title = "Client Game Module"; +#else + class_filename = "cl_allclasses.html"; + class_title = "Client Module"; +#endif + + class_file = fopen( class_filename.c_str(), "w" ); + if ( class_file == NULL ) + return; + + // construct the HTML header for the document + CLASS_Print( class_file, "\n"); + CLASS_Print( class_file, "\n"); + CLASS_Print( class_file, "%s Classes\n", class_title.c_str() ); + CLASS_Print( class_file, "\n"); + CLASS_Print( class_file, "\n"); + CLASS_Print( class_file, "

\n"); + CLASS_Print( class_file, "
%s Classes
\n", class_title.c_str() ); + CLASS_Print( class_file, "

\n"); +#if defined( GAME_DLL ) + // + // print out some commonly used classnames + // + CLASS_Print( class_file, "

" ); + CLASS_Print( class_file, "Actor, " ); + CLASS_Print( class_file, "Animate, " ); + CLASS_Print( class_file, "Entity, " ); + CLASS_Print( class_file, "ScriptSlave, " ); + CLASS_Print( class_file, "ScriptThread, " ); + CLASS_Print( class_file, "Sentient, " ); + CLASS_Print( class_file, "Trigger, " ); + CLASS_Print( class_file, "World" ); + CLASS_Print( class_file, "

" ); +#endif + + dump_numclasses = 0; + dump_numevents = 0; + + // get all the classes + num = 0; + for( c = classlist->next; c != classlist; c = c->next ) + { + if ( num < MAX_CLASSES ) + { + classes[ num++ ] = c->classname; + } + } + + // go through and process each class from smallest to greatest + for( i = 0; i < num; i++ ) + { + smallest = -1; + for( j = 0; j < num; j++ ) + { + if ( classes[ j ].length() > 1 ) + { + if ( smallest >= 0 ) + { + if ( classes[ j ].icmp( classes[ smallest ] ) < 0 ) + { + smallest = j; + } + } + else + { + smallest = j; + } + } + } + DumpClass( class_file, classes[ smallest ] ); + // delete the name from the list + classes[ smallest ] = ""; + } + + if ( class_file != NULL ) + { + CLASS_Print( class_file, "

\n"); + CLASS_Print( class_file, "%d %s Classes.
%d %s Events.\n", dump_numclasses, class_title.c_str(), dump_numevents, class_title.c_str() ); + CLASS_Print( class_file, "

\n"); + CLASS_Print( class_file, "\n"); + CLASS_Print( class_file, "\n"); + CLASS_DPrintf( "Dumped all classes to file %s\n", class_filename.c_str() ); + fclose( class_file ); + } + + } + + +void ShutdownClasses + ( + void + ) + + { + ClassDef *c; + + for( c = classlist->next; c != classlist; c = c->next ) + { + c->Shutdown(); + } + } diff --git a/source/source/cgame/class.h b/source/source/cgame/class.h new file mode 100644 index 0000000..71f3171 --- /dev/null +++ b/source/source/cgame/class.h @@ -0,0 +1,511 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/client/class.h $ +// $Revision:: 13 $ +// $Author:: Aldie $ +// $Date:: 8/10/00 9:27p $ +// +// Copyright (C) 1997 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source is may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/client/class.h $ +// +// 13 8/10/00 9:27p Aldie +// Fixing memory leaks +// +// 12 8/10/00 6:34p Aldie +// Added a shutdown method +// +// 11 6/14/00 12:14p Markd +// more intel compiler bug fixes +// +// 10 6/14/00 11:18a Markd +// cleaned up code using Intel compiler +// +// 9 5/26/00 7:44p Markd +// 2nd phase save games +// +// 8 5/25/00 4:28p Markd +// fixed up archive functions +// +// 7 5/24/00 3:14p Markd +// first phase of save/load games +// +// 6 4/26/00 7:55p Markd +// Added more documentation code into various systems +// +// 5 3/16/00 10:50a Markd +// Fixed some bad syntax in headers that exhibited itself in non-visualc +// compilers +// +// 4 12/15/99 11:45a Markd +// made Event's Classes and also freed up safe pointers at the appropriate +// times +// +// 3 10/05/99 2:03p Markd +// Added warning about files being in multiple projects +// +// 2 9/28/99 4:26p Markd +// merged listener, class and vector between 3 projects +// +// 1 9/10/99 10:53a Jimdose +// +// 1 9/08/99 3:15p Aldie +// +// 6 8/27/99 3:31p Markd +// externed totalmemallocated +// +// DESCRIPTION: +// Base class that all classes that are used in conjunction with Sin should +// be based off of. Class gives run-time type information about any class +// derived from it. This is really handy when you have a pointer to an object +// that you need to know if it supports certain behaviour. +// +// WARNING: This file is shared between fgame, cgame and possibly the user interface. +// It is instanced in each one of these directories because of the way that SourceSafe works. +// + +#ifndef __CLASS_H__ +#define __CLASS_H__ + +#if defined( GAME_DLL ) +// +// game dll specific defines +// +#include "g_local.h" +#include "linklist.h" + +#define CLASS_DPrintf gi.DPrintf +#define CLASS_Printf gi.Printf +#define CLASS_Error gi.Error + +class Archiver; + +#elif defined ( CGAME_DLL ) +// +// cgame dll specific defines +// +#include "../fgame/q_shared.h" +#include "linklist.h" + +#define CLASS_DPrintf cgi.DPrintf +#define CLASS_Printf cgi.Printf +#define CLASS_Error cgi.Error + +#else + +// +// client specific defines +// +#include "../fgame/q_shared.h" +#include "linklist.h" + +#define CLASS_DPrintf Com_DPrintf +#define CLASS_Printf Com_Printf +#define CLASS_Error Com_Error +#endif + +class Class; +class Event; + +typedef void ( Class::*Response )( Event *event ); + +template< class Type > +struct ResponseDef + { + Event *event; + void ( Type::*response )( Event *event ); + }; + +/*********************************************************************** + + ClassDef + +***********************************************************************/ + +class ClassDef + { + public: + const char *classname; + const char *classID; + const char *superclass; + void *( *newInstance )( void ); + int classSize; + ResponseDef *responses; + int numEvents; + Response **responseLookup; + ClassDef *super; + ClassDef *next; + ClassDef *prev; + + ClassDef(); + ~ClassDef(); + ClassDef( const char *classname, const char *classID, const char *superclass, + ResponseDef *responses, void *( *newInstance )( void ), int classSize ); + void BuildResponseList( void ); + void Shutdown( void ); + }; + +/*********************************************************************** + + SafePtr + +***********************************************************************/ + +class SafePtrBase; + +class Class; + +class SafePtrBase + { + private: + void AddReference( Class *ptr ); + void RemoveReference( Class *ptr ); + + protected: + SafePtrBase *prevSafePtr; + SafePtrBase *nextSafePtr; + Class *ptr; + + public: + SafePtrBase(); + virtual ~SafePtrBase(); + void InitSafePtr( Class *newptr ); + Class *Pointer( void ); + void Clear( void ); + }; + +/*********************************************************************** + + Class + +***********************************************************************/ + +#define CLASS_DECLARATION( nameofsuperclass, nameofclass, classid ) \ + ClassDef nameofclass::ClassInfo \ + ( \ + #nameofclass, classid, #nameofsuperclass, \ + ( ResponseDef * )nameofclass::Responses, \ + nameofclass::_newInstance, sizeof( nameofclass ) \ + ); \ + void *nameofclass::_newInstance( void ) \ + { \ + return new nameofclass; \ + } \ + ClassDef *nameofclass::classinfo( void ) \ + { \ + return &( nameofclass::ClassInfo ); \ + } \ + ResponseDef nameofclass::Responses[] = + +#define CLASS_PROTOTYPE( nameofclass ) \ + public: \ + static ClassDef ClassInfo; \ + static void *_newInstance( void ); \ + virtual ClassDef *classinfo( void ); \ + static ResponseDef Responses[] + +class Class + { + private: + SafePtrBase *SafePtrList; + friend class SafePtrBase; + + protected: + void ClearSafePointers( void ); + + public: + CLASS_PROTOTYPE( Class ); + void * operator new( size_t ); + void operator delete( void * ); + + Class(); + virtual ~Class(); + void warning( const char *function, const char *fmt, ... ); + void error( const char *function, const char *fmt, ... ); + qboolean inheritsFrom( ClassDef *c ); + qboolean inheritsFrom( const char *name ); + qboolean isInheritedBy( const char *name ); + qboolean isInheritedBy( ClassDef *c ); + const char *getClassname( void ); + const char *getClassID( void ); + const char *getSuperclass( void ); + void *newInstance( void ); + +#ifdef GAME_DLL + virtual void Archive( Archiver &arc ); +#endif + }; + +void BuildEventResponses( void ); +ClassDef *getClassForID( const char *name ); +ClassDef *getClass( const char *name ); +ClassDef *getClassList( void ); +void listAllClasses( void ); +void listInheritanceOrder( const char *classname ); +qboolean checkInheritance( ClassDef *superclass, ClassDef *subclass ); +qboolean checkInheritance( ClassDef *superclass, const char *subclass ); +qboolean checkInheritance( const char *superclass, const char *subclass ); +void DisplayMemoryUsage( void ); +void ClassEvents( const char *classname, qboolean dump = qfalse ); +void DumpAllClasses( void ); + +inline qboolean Class::inheritsFrom + ( + ClassDef *c + ) + + { + return checkInheritance( c, classinfo() ); + } + +inline qboolean Class::isInheritedBy + ( + ClassDef *c + ) + + { + return checkInheritance( classinfo(), c ); + } + +// The lack of a space between the ")" and "inheritsFrom" is intentional. +// It allows the macro to compile like a function call. However, this +// may cause problems in some compilers (like gcc), so we may have to +// change this to work like a normal macro with the object passed in +// as a parameter to the macro. +#define isSubclassOf( classname )inheritsFrom( &classname::ClassInfo ) +#define isSuperclassOf( classname )isInheritedBy( &classname::ClassInfo ) + +/*********************************************************************** + + SafePtr + +***********************************************************************/ + +inline void SafePtrBase::AddReference + ( + Class *ptr + ) + + { + if ( !ptr->SafePtrList ) + { + ptr->SafePtrList = this; + LL_Reset( this, nextSafePtr, prevSafePtr ); + } + else + { + LL_Add( ptr->SafePtrList, this, nextSafePtr, prevSafePtr ); + } + } + +inline void SafePtrBase::RemoveReference + ( + Class *ptr + ) + + { + if ( ptr->SafePtrList == this ) + { + if ( ptr->SafePtrList->nextSafePtr == this ) + { + ptr->SafePtrList = NULL; + } + else + { + ptr->SafePtrList = nextSafePtr; + LL_Remove( this, nextSafePtr, prevSafePtr ); + } + } + else + { + LL_Remove( this, nextSafePtr, prevSafePtr ); + } + } + +inline void SafePtrBase::Clear + ( + void + ) + + { + if ( ptr ) + { + RemoveReference( ptr ); + ptr = NULL; + } + } + +inline SafePtrBase::SafePtrBase() + { + prevSafePtr = NULL; + nextSafePtr = NULL; + ptr = NULL; + } + +inline SafePtrBase::~SafePtrBase() + { + Clear(); + } + +inline Class * SafePtrBase::Pointer + ( + void + ) + + { + return ptr; + } + +inline void SafePtrBase::InitSafePtr + ( + Class *newptr + ) + + { + if ( ptr != newptr ) + { + if ( ptr ) + { + RemoveReference( ptr ); + } + + ptr = newptr; + if ( ptr == NULL ) + { + return; + } + + AddReference( ptr ); + } + } + +template +class SafePtr : public SafePtrBase + { + public: + SafePtr( T* objptr = 0 ); + SafePtr( const SafePtr& obj ); + + SafePtr& operator=( const SafePtr& obj ); + SafePtr& operator=( T * const obj ); + + friend int operator==( SafePtr a, T *b ); + friend int operator!=( SafePtr a, T *b ); + friend int operator==( T *a, SafePtr b ); + friend int operator!=( T *a, SafePtr b ); + + operator T*() const; + T* operator->() const; + T& operator*() const; + }; + +template +inline SafePtr::SafePtr( T* objptr ) + { + InitSafePtr( objptr ); + } + +template +inline SafePtr::SafePtr( const SafePtr& obj ) + { + InitSafePtr( obj.ptr ); + } + +template +inline SafePtr& SafePtr::operator=( const SafePtr& obj ) + { + InitSafePtr( obj.ptr ); + return *this; + } + +template +inline SafePtr& SafePtr::operator=( T * const obj ) + { + InitSafePtr( obj ); + return *this; + } + +template +inline int operator== + ( + SafePtr a, + T* b + ) + + { + return a.ptr == b; + } + +template +inline int operator!= + ( + SafePtr a, + T* b + ) + + { + return a.ptr != b; + } + +template +inline int operator== + ( + T* a, + SafePtr b + ) + + { + return a == b.ptr; + } + +template +inline int operator!= + ( + T* a, + SafePtr b + ) + + { + return a != b.ptr; + } + +template +inline SafePtr::operator T*() const + { + return ( T * )ptr; + } + +template +inline T* SafePtr::operator->() const + { + return ( T * )ptr; + } + +template +inline T& SafePtr::operator*() const + { + return *( T * )ptr; + } + +typedef SafePtr ClassPtr; + +#ifdef GAME_DLL +#include "archive.h" +#endif + +// used by listener for event allocation +extern int totalmemallocated; + +#ifndef GAME_DLL +extern "C" + { + // interface functions + void ShutdownClasses( void ); + } +#endif + +#endif /* class.h */ diff --git a/source/source/cgame/container.cpp b/source/source/cgame/container.cpp new file mode 100644 index 0000000..1cd829d --- /dev/null +++ b/source/source/cgame/container.cpp @@ -0,0 +1,243 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/cgame/container.cpp $ +// $Revision:: 2 $ +// $Author:: Markd $ +// $Date:: 10/05/99 2:03p $ +// +// Copyright (C) 1997 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source is may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/cgame/container.cpp $ +// +// 2 10/05/99 2:03p Markd +// Added warning about files being in multiple projects +// +// 1 9/10/99 10:53a Jimdose +// +// 1 9/08/99 3:15p Aldie +// +// DESCRIPTION: +// Base class for a dynamic array. Allows adding, removing, index of, +// and finding of entries with specified value. Originally created for +// cataloging entities, but pointers to objects that may be removed at +// any time are bad to keep around, so only entity numbers should be +// used in the future. +// +// WARNING: This file is shared between fgame, cgame and possibly the user interface. +// It is instanced in each one of these directories because of the way that SourceSafe works. +// + +#if 0 + +#include "g_local.h" +#include "class.h" +#include "container.h" + +template< class Type > +Container::Container() + { + objlist = NULL; + FreeObjectList(); + } + +template< class Type > +Container::~Container() + { + FreeObjectList(); + } + +template< class Type > +void Container::FreeObjectList + ( + void + ) + + { + if ( objlist ) + { + delete objlist; + } + objlist = NULL; + numobjects = 0; + maxobjects = 0; + } + +template< class Type > +void Container::ClearObjectList + ( + void + ) + + { + if ( objlist ) + { + memset( objlist, 0, maxobjects * sizeof( Type ) ); + } + numobjects = 0; + } + +template< class Type > +int Container::NumObjects + ( + void + ) + + { + return numobjects; + } + +template< class Type > +void Container::Resize + ( + int maxelements + ) + + { + Type *temp; + + if ( !objlist ) + { + maxobjects = maxelements; + objlist = new Type[ maxobjects ]; + memset( objlist, 0, maxobjects * sizeof( Type ) ); + } + else + { + temp = objlist; + maxobjects = maxelements; + if ( maxobjects < numobjects ) + { + maxobjects = numobjects; + } + + objlist = new Type[ maxobjects ]; + memset( objlist, 0, maxobjects * sizeof( Type ) ); + memcpy( objlist, temp, numobjects * sizeof( Type ) ); + delete temp; + } + } + +template< class Type > +void Container::AddObject + ( + Type obj + ) + + { + Type *temp; + + if ( !objlist ) + { + Resize( 10 ); + } + + if ( numobjects == maxobjects ) + { + Resize( maxobjects * 2 ); + } + + objlist[ numobjects++ ] = obj; + } + +template< class Type > +int Container::IndexOfObject + ( + Type obj + ) + + { + int i; + + for( i = 0; i < numobjects; i++ ) + { + if ( objlist[ i ] == obj ) + { + return i + 1; + } + } + + return 0; + } + +template< class Type > +qboolean Container::ObjectInList + ( + Type obj + ) + + { + if ( !IndexOfObject( obj ) ) + { + return false; + } + + return true; + } + +template< class Type > +Type Container::ObjectAt + ( + int index + ) + + { + if ( ( index <= 0 ) || ( index > numobjects ) ) + { + gi.DPrintf( "Container::ObjectAt : index out of range" ); + return 0; + } + + return objlist[ index - 1 ]; + } + +template< class Type > +void Container::RemoveObjectAt + ( + int index + ) + + { + int i; + + if ( !objlist ) + { + gi.DPrintf( "Container::RemoveObjectAt : Empty list" ); + return; + } + + if ( ( index <= 0 ) || ( index > numobjects ) ) + { + gi.DPrintf( "Container::RemoveObjectAt : index out of range" ); + return; + } + + i = index - 1; + memcpy( &objlist[ i ], &objlist[ i + 1 ], ( numobjects - 1 - i ) * sizeof( Type ) ); + memset( &objlist[ numobjects - 1 ], 0, sizeof( Type ) ); + numobjects--; + } + +template< class Type > +void Container::RemoveObject + ( + Type obj + ) + + { + int index; + + index = IndexOfObject( obj ); + if ( !index ) + { + gi.DPrintf( "Container::RemoveObject : Object not in list" ); + return; + } + + RemoveObjectAt( index ); + } + +#endif \ No newline at end of file diff --git a/source/source/cgame/container.h b/source/source/cgame/container.h new file mode 100644 index 0000000..8cc7518 --- /dev/null +++ b/source/source/cgame/container.h @@ -0,0 +1,538 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/container.h $ +// $Revision:: 9 $ +// $Author:: Steven $ +// $Date:: 7/26/00 1:08p $ +// +// Copyright (C) 1997 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source is may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/container.h $ +// +// 9 7/26/00 1:08p Steven +// In ClearObjectList make sure we don't have 0 maxelements when creating a new +// array. +// +// 8 7/25/00 2:32p Aldie +// Undo checkout for new operator +// +// 7 7/25/00 2:18p Aldie +// changed the new operator for containers +// +// 6 5/26/00 7:44p Markd +// 2nd phase save games +// +// 5 1/06/00 11:18p Jimdose +// put sort back in +// +// 4 1/06/00 11:08p Jimdose +// cleaning up unused code +// +// 3 10/05/99 2:03p Markd +// Added warning about files being in multiple projects +// +// 2 9/28/99 4:26p Markd +// merged listener, class and vector between 3 projects +// +// 1 9/10/99 10:53a Jimdose +// +// 1 9/08/99 3:15p Aldie +// +// DESCRIPTION: +// Base class for a dynamic array. Allows adding, removing, index of, +// and finding of entries with specified value. NOTE: indices in container +// are 1 based, not 0. This means that loops must check from 1 up to and including +// NumObjects() (ei. for( i = 1; i <= list.NumObjects(); i++ ) ). +// +// FIXME: Someday make this 0 based and update all code to match. +// +// WARNING: This file is shared between fgame, cgame and possibly the user interface. +// It is instanced in each one of these directories because of the way that SourceSafe works. +// + +#ifndef __CONTAINER_H__ +#define __CONTAINER_H__ + +#if defined( GAME_DLL ) +// +// game dll specific defines +// +#include "g_local.h" + +#define CONTAINER_Error gi.Error +#define CONTAINER_DPrintf gi.DPrintf + +#elif defined ( CGAME_DLL ) +// +// cgame dll specific defines +// +#define CONTAINER_Error cgi.Error +#define CONTAINER_DPrintf cgi.DPrintf + +#else + +// +// client specific defines +// +#define CONTAINER_Error Com_Error +#define CONTAINER_DPrintf Com_DPrintf +#endif + +#include + +class Archiver; +template< class Type > +class Container + { + private: + Type *objlist; + int numobjects; + int maxobjects; + + public: + Container(); + ~Container(); + + void FreeObjectList( void ); + void ClearObjectList( void ); + int NumObjects( void ); + void Resize( int maxelements ); + void SetObjectAt( int index, Type& obj ); + int AddObject( Type& obj ); + int AddUniqueObject( Type& obj ); + void AddObjectAt( int index, Type& obj ); + int IndexOfObject( Type& obj ); + qboolean ObjectInList( Type& obj ); + Type& ObjectAt( int index ); + Type *AddressOfObjectAt( int index ); + void RemoveObjectAt( int index ); + void RemoveObject( Type& obj ); + void Sort( int ( __cdecl *compare )( const void *elem1, const void *elem2 ) ); +#if defined( GAME_DLL ) + void Archive( Archiver &arc ); +#endif + }; + +template< class Type > +Container::Container() + { + objlist = NULL; + FreeObjectList(); + } + +template< class Type > +Container::~Container() + { + FreeObjectList(); + } + +template< class Type > +void Container::FreeObjectList + ( + void + ) + + { + if ( objlist ) + { + delete[] objlist; + } + objlist = NULL; + numobjects = 0; + maxobjects = 0; + } + +template< class Type > +void Container::ClearObjectList + ( + void + ) + + { + // only delete the list if we have objects in it + if ( objlist && numobjects ) + { + delete[] objlist; + + if ( maxobjects == 0 ) + { + objlist = NULL; + return; + } + + objlist = new Type[ maxobjects ]; + numobjects = 0; + } + } + +template< class Type > +int Container::NumObjects + ( + void + ) + + { + return numobjects; + } + +template< class Type > +void Container::Resize + ( + int maxelements + ) + + { + Type *temp; + int i; + + assert( maxelements >= 0 ); + + if ( maxelements <= 0 ) + { + FreeObjectList(); + return; + } + + if ( !objlist ) + { + maxobjects = maxelements; + objlist = new Type[ maxobjects ]; + } + else + { + temp = objlist; + maxobjects = maxelements; + if ( maxobjects < numobjects ) + { + maxobjects = numobjects; + } + + objlist = new Type[ maxobjects ]; + for( i = 0; i < numobjects; i++ ) + { + objlist[ i ] = temp[ i ]; + } + delete[] temp; + } + } + +template< class Type > +void Container::SetObjectAt + ( + int index, + Type& obj + ) + + { + if ( ( index <= 0 ) || ( index > numobjects ) ) + { + CONTAINER_Error( ERR_DROP, "Container::SetObjectAt : index out of range" ); + } + + objlist[ index - 1 ] = obj; + } + +template< class Type > +int Container::AddObject + ( + Type& obj + ) + + { + if ( !objlist ) + { + Resize( 10 ); + } + + if ( numobjects == maxobjects ) + { + Resize( maxobjects * 2 ); + } + + objlist[ numobjects ] = obj; + numobjects++; + + return numobjects; + } + +template< class Type > +int Container::AddUniqueObject + ( + Type& obj + ) + + { + int index; + + index = IndexOfObject( obj ); + if ( !index ) + index = AddObject( obj ); + return index; + } + +template< class Type > +void Container::AddObjectAt + ( + int index, + Type& obj + ) + + { + // + // this should only be used when reconstructing a list that has to be identical to the original + // + if ( index > maxobjects ) + { + Resize( index ); + } + if ( index > numobjects ) + { + numobjects = index; + } + SetObjectAt( index, obj ); + } + +template< class Type > +int Container::IndexOfObject + ( + Type& obj + ) + + { + int i; + + for( i = 0; i < numobjects; i++ ) + { + if ( objlist[ i ] == obj ) + { + return i + 1; + } + } + + return 0; + } + +template< class Type > +qboolean Container::ObjectInList + ( + Type& obj + ) + + { + if ( !IndexOfObject( obj ) ) + { + return false; + } + + return true; + } + +template< class Type > +Type& Container::ObjectAt + ( + int index + ) + + { + if ( ( index <= 0 ) || ( index > numobjects ) ) + { + CONTAINER_Error( ERR_DROP, "Container::ObjectAt : index out of range" ); + } + + return objlist[ index - 1 ]; + } + +template< class Type > +Type * Container::AddressOfObjectAt + ( + int index + ) + + { + // + // this should only be used when reconstructing a list that has to be identical to the original + // + if ( index > maxobjects ) + { + CONTAINER_Error( ERR_DROP, "Container::AddressOfObjectAt : index is greater than maxobjects" ); + } + if ( index > numobjects ) + { + numobjects = index; + } + return &objlist[ index - 1 ]; + } + +template< class Type > +void Container::RemoveObjectAt + ( + int index + ) + + { + int i; + + if ( !objlist ) + { + CONTAINER_DPrintf( "Container::RemoveObjectAt : Empty list\n" ); + return; + } + + if ( ( index <= 0 ) || ( index > numobjects ) ) + { + CONTAINER_Error( ERR_DROP, "Container::RemoveObjectAt : index out of range" ); + return; + } + + i = index - 1; + numobjects--; + for( i = index - 1; i < numobjects; i++ ) + { + objlist[ i ] = objlist[ i + 1 ]; + } + } + +template< class Type > +void Container::RemoveObject + ( + Type& obj + ) + + { + int index; + + index = IndexOfObject( obj ); + if ( !index ) + { + CONTAINER_DPrintf( "Container::RemoveObject : Object not in list\n" ); + return; + } + + RemoveObjectAt( index ); + } + +template< class Type > +void Container::Sort + ( + int ( __cdecl *compare )( const void *elem1, const void *elem2 ) + ) + + { + if ( !objlist ) + { + CONTAINER_DPrintf( "Container::Sort : Empty list\n" ); + return; + } + + qsort( ( void * )objlist, ( size_t )numobjects, sizeof( Type ), compare ); + } + +#if 0 +#if defined( GAME_DLL ) + +#include "str.h" +void Container::Archive + ( + Archiver &arc + ) + { + int i, num; + + if ( arc.Loading() ) + { + ClearObjectList(); + arc.ArchiveInteger( &num ); + Resize( num ); + } + else + { + num = numobjects; + arc.ArchiveInteger( &num ); + } + for( i = 1; i <= num; i++ ) + { + arc.ArchiveString( AddressOfObjectAt( i ) ); + } + } + +#include "vector.h" +void Container::Archive + ( + Archiver &arc + ) + { + int i, num; + + if ( arc.Loading() ) + { + ClearObjectList(); + arc.ArchiveInteger( &num ); + Resize( num ); + } + else + { + num = numobjects; + arc.ArchiveInteger( &num ); + } + for( i = 1; i <= num; i++ ) + { + arc.ArchiveVector( AddressOfObjectAt( i ) ); + } + } + +void Container::Archive + ( + Archiver &arc + ) + { + int i, num; + + if ( arc.Loading() ) + { + ClearObjectList(); + arc.ArchiveInteger( &num ); + Resize( num ); + } + else + { + num = numobjects; + arc.ArchiveInteger( &num ); + } + for( i = 1; i <= num; i++ ) + { + arc.ArchiveInteger( AddressOfObjectAt( i ) ); + } + } + +void Container::Archive + ( + Archiver &arc + ) + { + int i, num; + + if ( arc.Loading() ) + { + ClearObjectList(); + arc.ArchiveInteger( &num ); + Resize( num ); + } + else + { + num = numobjects; + arc.ArchiveInteger( &num ); + } + for( i = 1; i <= num; i++ ) + { + arc.ArchiveFloat( AddressOfObjectAt( i ) ); + } + } + +#endif +#endif + +#endif /* container.h */ diff --git a/source/source/cgame/listener.cpp b/source/source/cgame/listener.cpp new file mode 100644 index 0000000..e485689 --- /dev/null +++ b/source/source/cgame/listener.cpp @@ -0,0 +1,3435 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/listener.cpp $ +// $Revision:: 61 $ +// $Author:: Aldie $ +// $Date:: 8/10/00 7:38p $ +// +// Copyright (C) 1998 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source is may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/listener.cpp $ +// +// 61 8/10/00 7:38p Aldie +// Working on cleaning stuff +// +// 60 8/10/00 7:34p Aldie +// +// 59 8/10/00 7:21p Aldie +// Added some cleanup to events +// +// 58 8/10/00 7:04p Aldie +// Changed a string allocation +// +// 57 7/14/00 11:30a Markd +// changed initial number of allocated events +// +// 56 7/13/00 12:31p Steven +// Check to see if event is equal to EV_Remove before trying to use it to print +// out info on it. +// +// 55 7/03/00 2:12p Steven +// fixed a crash bug in EventVar::GetVector +// +// 54 6/27/00 2:35p Markd +// allowed vectors to be set to entities to get their origins +// +// 53 6/23/00 9:12p Markd +// fixed some loading of events at spawn time +// +// 52 6/22/00 3:45p Markd +// fixed a bunch of saved game issues +// +// 51 6/14/00 12:14p Markd +// more intel compiler bug fixes +// +// 50 6/06/00 10:57a Steven +// Fixed a compiler issue with g_timeevents change. +// +// 49 6/06/00 10:38a Steven +// Improved g_timeevents. +// +// 48 5/27/00 8:07p Markd +// Saved games 3rd pass +// +// 47 5/26/00 7:44p Markd +// 2nd phase save games +// +// 46 5/25/00 4:28p Markd +// fixed up archive functions +// +// 45 5/24/00 3:14p Markd +// first phase of save/load games +// +// 44 4/29/00 3:26p Markd +// fleshed out the rest of the event/class documentation +// +// 43 4/26/00 7:55p Markd +// Added more documentation code into various systems +// +// 42 4/08/00 3:57p Steven +// Made it so in EventVar( Entity *ent ) if ent was NULL it would save the +// entnum as ENTITYNUM_NONE instead of 0. +// +// 41 3/16/00 7:04p Markd +// Increased number of events allocated at startup +// +// 40 3/06/00 8:07p Markd +// cleaned up unused cvar's +// +// 39 2/24/00 3:16p Jimdose +// changed asserts when Event is unknown into dprintfs +// +// 38 2/23/00 10:07a Markd +// fixed center print and event system crash +// +// 37 2/15/00 5:17p Aldie +// Increased eventlimit and also added a count to print out the number of +// entities spawned +// +// 36 1/06/00 11:10p Jimdose +// cleaning up unused code +// +// 35 12/15/99 3:26p Markd +// fixed listener up a bit, but deleting events instead of realDeallocating +// them right away. +// +// 34 12/15/99 2:08p Markd +// undid test from before +// +// 33 12/15/99 12:11p Markd +// testing undoing my fix +// +// 32 12/15/99 11:45a Markd +// made Event's Classes and also freed up safe pointers at the appropriate +// times +// +// 31 12/13/99 11:14a Markd +// Incremental checkin +// +// 30 12/11/99 5:51p Markd +// First wave of bug fixes after q3a gold merge +// +// 29 12/11/99 3:37p Markd +// q3a gold checkin, first time +// +// 28 10/21/99 2:19p Markd +// Changed range to use ..., fixed fadein and fadeout some more +// +// 27 10/21/99 10:57a Markd +// fixed suppression of _events +// +// 26 10/20/99 7:04p Markd +// suppress commands starting with '_' +// +// 25 10/18/99 2:54p Aldie +// Upped the number of client events +// +// 24 10/11/99 12:01p Steven +// Added some more tabing support when printing out event documentation. +// +// 23 10/11/99 10:05a Markd +// Added some tabbing support to event documentation +// +// 22 10/09/99 6:04p Markd +// changed up documentation a bit +// +// 21 10/07/99 7:14p Aldie +// More beam stuff +// +// 20 10/07/99 3:03p Steven +// Added a new event constructor that only takes a const char * as a parm. +// +// 19 10/06/99 3:09p Steven +// Added dumpevents command. +// +// 18 10/05/99 2:03p Markd +// Added warning about files being in multiple projects +// +// 17 10/03/99 4:50p Markd +// removed str& constructor from listener +// +// 16 10/02/99 6:51p Markd +// Put in backend work for event documentation and fixed a lot of event +// documentation bugs +// +// 15 10/01/99 3:50p Markd +// fixed some level 4 warnings +// +// 14 9/30/99 10:50a Markd +// put in different warning printing depending on which module is used +// +// 13 9/29/99 7:43p Markd +// Made items behave better when dropping to floor +// +// 12 9/29/99 3:36p Steven +// Event formatting. +// +// 11 9/28/99 7:15p Morbid +// +// 10 9/28/99 5:31p Markd +// Successfully merged class.h, listener.h and vector.h into all three modules, +// cgame, fgame and client +// +// 9 9/28/99 5:15p Markd +// Fixed more merge bugs with sharing class, vector and listener between three +// modules +// +// 8 9/28/99 4:26p Markd +// merged listener, class and vector between 3 projects +// +// 7 9/28/99 10:12a Markd +// fixed some event issues +// +// 6 9/27/99 5:44p Markd +// began documentation and cleanup phase after merge +// +// 5 9/22/99 4:48p Markd +// fixed more G_GetEntity, G_FindClass and G_GetNextEntity bugs +// +// 4 9/21/99 7:51p Markd +// Fixed a lot of entitynum_none issues +// +// 3 9/15/99 6:57p Aldie +// Update to get game working +// +// 2 9/10/99 5:45p Jimdose +// merge +// +// 1 9/10/99 10:54a Jimdose +// +// 1 9/08/99 3:16p Aldie +// +// 17 9/02/99 2:33p Markd +// Added cache ability to entities +// +// 16 8/28/99 3:33p Jimdose +// Added EventVar +// All event args now have type information and use lazy evaluation +// +// 15 8/27/99 8:25p Markd +// added pengingevents and fixed some event holes +// +// 14 8/27/99 3:30p Markd +// put in event caching system so that events are reused +// +// 13 8/19/99 12:16p Jimdose +// added event stats +// added lru check to FindEvent +// +// DESCRIPTION: +// +// WARNING: This file is shared between fgame, cgame and possibly the user interface. +// It is instanced in each one of these directories because of the way that SourceSafe works. +// + +#include "listener.h" + +#if defined( GAME_DLL ) + +#include "scriptvariable.h" +#include "worldspawn.h" +#include "scriptmaster.h" + +#elif defined( CGAME_DLL ) + +#elif defined( UI_LIB ) + +#else + +#include "client.h" + +#endif + +Event EV_Remove + ( + "immediateremove", + EV_DEFAULT, + NULL, + NULL, + "Removes this listener immediately." + ); +Event EV_ScriptRemove + ( + "remove", + EV_DEFAULT, + NULL, + NULL, + "Removes this listener the next time events are processed." + ); + +extern "C" + { + int numEvents = 0; + int numFreeEvents = 0; + } + +cvar_t *g_showevents; +cvar_t *g_eventlimit; +cvar_t *g_timeevents; +cvar_t *g_watch; +cvar_t *g_eventstats; + +Event FreeEventHead; +Event *FreeEvents = &FreeEventHead; +Event EventQueueHead; +Event *EventQueue = &EventQueueHead; +Event ActiveEventHead; +Event *ActiveEvents = &ActiveEventHead; + +Container *Event::commandList = NULL; +Container *Event::flagList = NULL; +Container *Event::sortedList = NULL; +Container *Event::eventDefList = NULL; +qboolean Event::dirtylist = false; + +int Event::numfinds; +int Event::numfirstsearch; +int Event::numcompares; +int Event::lastevent; +bool Event::EventSystemStarted; + +int Event_totalmemallocated; + +Event NullEvent; + +void EV_Print( FILE *event_file, const char *fmt, ... ) + { + va_list argptr; + char text[ 1024 ]; + + va_start( argptr, fmt ); + vsprintf( text, fmt, argptr ); + va_end( argptr ); + + if ( event_file ) + fprintf( event_file, text ); + else + EVENT_Printf( text ); + } + +EventVar::EventVar + ( + const char *text + ) + + { + assert( text ); + if ( !text ) + { + text = ""; + } + + dirtyFlags = DIRTY_ALL & ~DIRTY_STRING; + stringValue = text; +#ifdef GAME_DLL + type = Director.isVarGroup( text ) ? IS_SCRIPTVARIABLE : IS_STRING; +#else + type = IS_STRING; +#endif + } + +EventVar::EventVar + ( + str &text + ) + + { + dirtyFlags = DIRTY_ALL & ~DIRTY_STRING; + stringValue = text; +#ifdef GAME_DLL + type = Director.isVarGroup( text.c_str() ) ? IS_SCRIPTVARIABLE : IS_STRING; +#else + type = IS_STRING; +#endif + } + +#ifdef GAME_DLL + +EventVar::EventVar + ( + Entity *ent + ) + + { + type = IS_ENTITY; + dirtyFlags = DIRTY_ALL & ~DIRTY_INTEGER; + if ( ent ) + { + intValue = ent->entnum; + } + else + { + intValue = ENTITYNUM_NONE; + } + } + +void EventVar::Archive + ( + Archiver &arc + ) + + { + arc.ArchiveShort( &type ); + arc.ArchiveShort( &dirtyFlags ); + arc.ArchiveString( &stringValue ); + arc.ArchiveVector( &vectorValue ); + arc.ArchiveInteger( &intValue ); + arc.ArchiveFloat( &floatValue ); + } + +#endif + +const char *EventVar::GetToken + ( + Event &ev + ) + + { + if ( dirtyFlags & DIRTY_STRING ) + { + switch( type ) + { + case IS_VECTOR : + stringValue = va( "(%f %f %f)", vectorValue.x, vectorValue.y, vectorValue.z ); + break; + + case IS_INTEGER : + stringValue = va( "%d", intValue ); + break; + + case IS_FLOAT : + stringValue = va( "%f", floatValue ); + break; + + case IS_ENTITY : + stringValue = va( "*%d", intValue ); + break; + } + + dirtyFlags &= ~DIRTY_STRING; + } + + return stringValue.c_str(); + } + +const char *EventVar::GetString + ( + Event &ev + ) + + { + if ( dirtyFlags & DIRTY_STRING ) + { + switch( type ) + { + case IS_VECTOR : + stringValue = va( "(%f %f %f)", vectorValue.x, vectorValue.y, vectorValue.z ); + break; + + case IS_INTEGER : + stringValue = va( "%d", intValue ); + break; + + case IS_FLOAT : + stringValue = va( "%f", floatValue ); + break; + + case IS_ENTITY : + stringValue = va( "*%d", intValue ); + break; + } + + dirtyFlags &= ~DIRTY_STRING; + } + +#ifdef GAME_DLL + if ( type == IS_SCRIPTVARIABLE ) + { + ScriptVariable *var; + + var = Director.GetExistingVariable( stringValue.c_str() ); + if ( var ) + { + return var->stringValue(); + } + else + { + ev.Error( "Variable %s does not exist.", stringValue.c_str() ); + return ""; + } + } +#endif + + return stringValue.c_str(); + } + +int EventVar::GetInteger + ( + Event &ev + ) + + { + if ( dirtyFlags & DIRTY_INTEGER ) + { + switch( type ) + { + case IS_STRING : + intValue = atoi( stringValue.c_str() ); + break; + + case IS_VECTOR : + intValue = 0; + break; + + case IS_FLOAT : + intValue = int( floatValue ); + break; + + case IS_SCRIPTVARIABLE : +#ifdef GAME_DLL + ScriptVariable *var; + + var = Director.GetExistingVariable( stringValue.c_str() ); + if ( var ) + { + if ( !::IsNumeric( var->stringValue() ) ) + { + ev.Error( "Variable %s contains non-numeric value '%s'", stringValue.c_str(), + var->stringValue() ); + } + + // don't change the dirty flag since the variable may change in the future + return var->intValue(); + } + else + { + ev.Error( "Variable %s does not exist.", stringValue.c_str() ); + // don't change the dirty flag since the variable may exist in the future + //FIXME + // someday, missing variable names should be an error... + return 0; + } +#endif + break; + } + + dirtyFlags &= ~DIRTY_INTEGER; + } + + return intValue; + } + +float EventVar::GetFloat + ( + Event &ev + ) + + { + if ( dirtyFlags & DIRTY_FLOAT ) + { + switch( type ) + { + case IS_STRING : + floatValue = atof( stringValue.c_str() ); + break; + + case IS_VECTOR : + floatValue = 0; + break; + + case IS_ENTITY : + case IS_INTEGER : + floatValue = float( intValue ); + break; + + case IS_SCRIPTVARIABLE : +#ifdef GAME_DLL + ScriptVariable *var; + + var = Director.GetExistingVariable( stringValue.c_str() ); + if ( var ) + { + if ( !::IsNumeric( var->stringValue() ) ) + { + ev.Error( "Variable %s contains non-numeric value '%s'", stringValue.c_str(), + var->stringValue() ); + } + + // don't change the dirty flag since the variable may change in the future + return var->floatValue(); + } + else + { + ev.Error( "Variable %s does not exist.", stringValue.c_str() ); + // don't change the dirty flag since the variable may exist in the future + //FIXME + // someday, missing variable names should be an error... + return 0.0f; + } +#endif + break; + } + + dirtyFlags &= ~DIRTY_FLOAT; + } + + return floatValue; + } + +Vector EventVar::GetVector + ( + Event &ev + ) + + { + if ( dirtyFlags & DIRTY_VECTOR ) + { + switch( type ) + { + case IS_STRING : + const char *text; + + text = stringValue.c_str(); + if ( text[ 0 ] == '(' ) + { + vectorValue = &text[ 1 ]; + } +#ifdef GAME_DLL + // is it an entity + else if ( text[ 0 ] == '$' ) + { + Entity * ent; + + // allow console users to not use '$' + ent = G_FindTarget( NULL, &text[ 1 ] ); + + if ( ent ) + { + vectorValue = ent->origin; + } + else + { + vectorValue = vec_zero; + } + } +#endif + else + { + vectorValue = text; + } + break; + + case IS_FLOAT : + case IS_INTEGER : + vectorValue = vec_zero; + break; + case IS_ENTITY : +#ifdef GAME_DLL + { + Entity * ent; + + ent = G_GetEntity( intValue ); + if ( ent ) + { + vectorValue = ent->origin; + } + else + { + vectorValue = vec_zero; + } + } +#else + vectorValue = vec_zero; +#endif + break; + + case IS_SCRIPTVARIABLE : +#ifdef GAME_DLL + ScriptVariable *var; + + var = Director.GetExistingVariable( stringValue.c_str() ); + if ( !var ) + { + ev.Error( "Variable %s does not exist.", stringValue.c_str() ); + return vec_zero; + } + + // don't change the dirty flag since the variable may change in the future + return var->vectorValue(); +#endif + break; + } + + dirtyFlags &= ~DIRTY_VECTOR; + } + + return vectorValue; + } + +#ifdef GAME_DLL +Entity *EventVar::GetEntity + ( + Event &ev + ) + + { + if ( dirtyFlags & DIRTY_INTEGER ) + { + switch( type ) + { + case IS_VECTOR : + intValue = 0; + break; + + case IS_FLOAT : + intValue = int( floatValue ); + break; + + case IS_SCRIPTVARIABLE : + case IS_STRING : + const char *name; + int t; + + t = 0; + if ( type == IS_STRING ) + { + name = stringValue.c_str(); + if ( ev.GetSource() == EV_FROM_CONSOLE ) + { + Entity * ent; + + // allow console users to not use '$' + ent = G_FindTarget( NULL, name ); + intValue = ent->entnum; + break; + } + } + else + { + ScriptVariable *var; + + var = Director.GetExistingVariable( stringValue.c_str() ); + if ( !var ) + { + ev.Error( "Variable %s does not exist.", stringValue.c_str() ); + return NULL; + } + + name = var->stringValue(); + } + + if ( name[ 0 ] == '$' ) + { + Entity * ent; + + ent = G_FindTarget( NULL, &name[ 1 ] ); + if ( !ent ) + { + ev.Error( "Entity with targetname of '%s' not found", &name[ 1 ] ); + + return NULL; + } + else + { + t = ent->entnum; + } + } + else + { + if ( name[ 0 ] != '*' ) + { + if ( ev.GetSource() == EV_FROM_CONSOLE ) + { + ev.Error( "Entity with targetname of '%s' not found", name ); + } + else + { + ev.Error( "Expecting a '*'-prefixed entity number but found '%s'.", name ); + } + + return NULL; + } + + if ( !::IsNumeric( &name[ 1 ] ) ) + { + ev.Error( "Expecting a numeric value but found '%s'.", &name[ 1 ] ); + + return NULL; + } + else + { + t = atoi( &name[ 1 ] ); + } + } + + if ( type == IS_STRING ) + { + intValue = t; + } + else + { + if ( ( t < 0 ) || ( t > game.maxentities ) ) + { + ev.Error( "%d out of valid range for entity.", t ); + return NULL; + } + + // don't change the dirty flag since the variable may change in the future + return G_GetEntity( t ); + } + break; + } + + dirtyFlags &= ~DIRTY_INTEGER; + } + + if ( ( intValue < 0 ) || ( intValue > game.maxentities ) ) + { + ev.Error( "%d out of valid range for entity.", intValue ); + return NULL; + } + + return G_GetEntity( intValue ); + } + +ScriptVariable *EventVar::GetVariable + ( + Event &ev + ) + + { + if ( type != IS_SCRIPTVARIABLE ) + { + return NULL; + } + + return Director.GetExistingVariable( stringValue.c_str() ); + } +#else + +qboolean IsNumeric + ( + const char *str + ) + + { + int len; + int i; + qboolean dot; + + if ( *str == '-' ) + { + str++; + } + + dot = qfalse; + len = strlen( str ); + for( i = 0; i < len; i++ ) + { + if ( !isdigit( str[ i ] ) ) + { + if ( ( str[ i ] == '.' ) && !dot ) + { + dot = qtrue; + continue; + } + return qfalse; + } + } + + return qtrue; + } + +#endif + +qboolean EventVar::IsVector + ( + Event &ev + ) + + { + switch( type ) + { + case IS_VECTOR : + return true; + break; + + case IS_STRING : + if ( stringValue.c_str()[ 0 ] == '(' ) + { + return true; + } + break; + + case IS_SCRIPTVARIABLE : +#ifdef GAME_DLL + ScriptVariable *var; + + var = Director.GetExistingVariable( stringValue.c_str() ); + if ( var && ( var->stringValue()[ 0 ] == '(' ) ) + { + return true; + } +#endif + break; + } + + return false; + } + +qboolean EventVar::IsNumeric + ( + Event &ev + ) + + { + switch( type ) + { + case IS_STRING : + return ::IsNumeric( stringValue.c_str() ); + break; + +#ifdef GAME_DLL + case IS_SCRIPTVARIABLE : + ScriptVariable *var; + + var = Director.GetExistingVariable( stringValue.c_str() ); + if ( var ) + { + return ::IsNumeric( var->stringValue() ); + } + break; +#endif + + case IS_FLOAT : + case IS_INTEGER : + return true; + break; + } + + return false; + } + +//=========================================================================== +// EventArgDef +//=========================================================================== + +void EventArgDef::Setup + ( + const char *eventName, + const char *argName, + const char *argType, + const char *argRange + ) + { + char scratch[ 256 ]; + const char *ptr; + char *tokptr; + const char *endptr; + int index; + + // set name + name = argName; + + // set optionality + if ( isupper( argType[ 0 ] ) ) + { + optional = qtrue; + } + else + { + optional = qfalse; + } + + // grab the ranges + index = 0; + memset( minRangeDefault, qtrue, sizeof( minRangeDefault ) ); + memset( minRange, 0, sizeof( minRange ) ); + memset( maxRangeDefault, qtrue, sizeof( maxRangeDefault ) ); + memset( maxRange, 0, sizeof( maxRange ) ); + + if ( argRange && argRange[ 0 ] ) + { + ptr = argRange; + while( 1 ) + { + // find opening '[' + tokptr = strchr( ptr, '[' ); + if ( !tokptr ) + { + break; + } + // find closing ']' + endptr = strchr( tokptr, ']' ); + if ( !endptr ) + { + assert( 0 ); + EVENT_DPrintf( "Argument defintion %s, no matching ']' found for range spec in event %s.\n", name, eventName ); + break; + } + // point to the next range + ptr = endptr; + // skip the '[' + tokptr++; + // copy off the range spec + // skip the ']' + strncpy( scratch, tokptr, endptr - tokptr ); + // terminate the range + scratch[ endptr - tokptr ] = 0; + // see if there is one or two parameters here + tokptr = strchr( scratch, ',' ); + if ( !tokptr ) + { + // just one parameter + minRange[ index >> 1 ] = atof( scratch ); + minRangeDefault[ index >> 1 ] = qfalse; + index++; + // skip the second parameter + index++; + } + else if ( tokptr == scratch ) + { + // just second parameter + // skip the first paremeter + index++; + tokptr++; + maxRange[ index >> 1 ] = atof( scratch ); + maxRangeDefault[ index >> 1 ] = qfalse; + index++; + } + else + { + qboolean second; + // one or two parameters + // see if there is anything behind the ',' + if ( strlen( scratch ) > ( tokptr - scratch + 1) ) + second = qtrue; + else + second = qfalse; + // zero out the ',' + *tokptr = 0; + minRange[ index >> 1 ] = atof( scratch ); + minRangeDefault[ index >> 1 ] = qfalse; + index++; + // skip over the nul character + tokptr++; + if ( second ) + { + maxRange[ index >> 1 ] = atof( tokptr ); + maxRangeDefault[ index >> 1 ] = qfalse; + } + index++; + } + } + } + + // figure out the type of variable it is + switch( tolower( argType[ 0 ] ) ) + { + case 'e': + type = IS_ENTITY; + break; + case 'v': + type = IS_VECTOR; + break; + case 'i': + type = IS_INTEGER; + break; + case 'f': + type = IS_FLOAT; + break; + case 's': + type = IS_STRING; + break; + case 'b': + type = IS_BOOLEAN; + break; + } + } + +void EventArgDef::PrintRange + ( + FILE *event_file + ) + { + qboolean integer; + qboolean single; + int numRanges; + int i; + + single = qfalse; + integer = qtrue; + numRanges = 1; + switch( type ) + { + case IS_VECTOR: + integer = qfalse; + numRanges = 3; + break; + case IS_FLOAT: + integer = qfalse; + break; + case IS_STRING: + single = qtrue; + break; + } + for( i = 0; i < numRanges; i++ ) + { + if ( single ) + { + if ( !minRangeDefault[ i ] ) + { + if ( integer ) + { + EV_Print( event_file, "<%d>", ( int )minRange[ i ] ); + } + else + { + EV_Print( event_file, "<%.2f>", minRange[ i ] ); + } + } + } + else + { + // both non-default + if ( !minRangeDefault[ i ] && !maxRangeDefault[ i ] ) + { + if ( integer ) + { + EV_Print( event_file, "<%d...%d>", ( int )minRange[ i ], ( int )maxRange[ i ] ); + } + else + { + EV_Print( event_file, "<%.2f...%.2f>", minRange[ i ], maxRange[ i ] ); + } + } + // max default + else if ( !minRangeDefault[ i ] && maxRangeDefault[ i ] ) + { + if ( integer ) + { + EV_Print( event_file, "<%d...max_integer>", ( int )minRange[ i ] ); + } + else + { + EV_Print( event_file, "<%.2f...max_float>", minRange[ i ] ); + } + } + // min default + else if ( minRangeDefault[ i ] && !maxRangeDefault[ i ] ) + { + if ( integer ) + { + EV_Print( event_file, "", ( int )maxRange[ i ] ); + } + else + { + EV_Print( event_file, "", maxRange[ i ] ); + } + } + } + } + } + +void EventArgDef::PrintArgument + ( + FILE *event_file + ) + { + if ( optional ) + { + EV_Print( event_file, "[ " ); + } + switch( type ) + { + case IS_ENTITY: + EV_Print( event_file, "Entity " ); + break; + case IS_VECTOR: + EV_Print( event_file, "Vector " ); + break; + case IS_INTEGER: + EV_Print( event_file, "Integer " ); + break; + case IS_FLOAT: + EV_Print( event_file, "Float " ); + break; + case IS_STRING: + EV_Print( event_file, "String " ); + break; + case IS_BOOLEAN: + EV_Print( event_file, "Boolean " ); + break; + } + EV_Print( event_file, "%s", name.c_str() ); + + // print the range of the argument + PrintRange( event_file ); + + if ( optional ) + { + EV_Print( event_file, " ]" ); + } + } + + +//=========================================================================== +// EventCode +//=========================================================================== + +CLASS_DECLARATION( Class, Event, NULL ) + { + { NULL, NULL } + }; + +// Free Event Management routines +static Event *RealAllocateEvent + ( + void + ) + { + Event *event; + + event = ( Event * )::new char[ sizeof( Event ) ]; + Event_totalmemallocated += sizeof( Event ); + + return event; + } + +static void RealDeallocateEvent + ( + Event * event + ) + { + ::delete[]( ( void * )event ); + Event_totalmemallocated -= sizeof( Event ); + } + +void * Event::operator new( size_t s ) + { + Event * newevent; + + assert( sizeof( Event ) == s ); + + // if the list is empty create a new one + if ( LL_Empty( FreeEvents, next, prev ) ) + { + // this is here to let us know that it is happening + assert( 0 ); + newevent = RealAllocateEvent(); + } + else + { + newevent = FreeEvents->next; + LL_Remove( newevent, next, prev ); + numFreeEvents--; + } + + // add it to the active list of events + LL_Add( ActiveEvents, newevent, next, prev ); + + newevent->time = EVENT_time; + newevent->flags = 0; + + return newevent; + } + +void Event::operator delete( void *ptr ) + { + Event * event; + + event = ( Event * )ptr; + + // clear out any safe pointers we have setup + event->ClearSafePointers(); + + LL_Remove( event, next, prev ); + LL_Add( FreeEvents, event, next, prev ); + numFreeEvents++; + } + +#if defined( GAME_DLL ) +#define INITIALLY_ALLOCATED_EVENTS 4500 +#elif defined ( CGAME_DLL ) +#define INITIALLY_ALLOCATED_EVENTS 512 +#elif defined ( UI_LIB ) +#define INITIALLY_ALLOCATED_EVENTS 192 +#else +#define INITIALLY_ALLOCATED_EVENTS 192 +#endif + +void Event::InitializeEventLists + ( + void + ) + { + Event * newevent; + int i; + + numEvents = 0; + numFreeEvents = 0; + // + // initialize lists + // + LL_Reset( FreeEvents, next, prev ); + LL_Reset( EventQueue, next, prev ); + LL_Reset( ActiveEvents, next, prev ); + + // + // allocate the initial allottment of events + // + for( i = 0; i < INITIALLY_ALLOCATED_EVENTS; i++ ) + { + newevent = RealAllocateEvent(); + LL_Add( FreeEvents, newevent, next, prev ); + numFreeEvents++; + } + } + +void Event::ShutdownEventLists + ( + void + ) + { + Event *event, *next; + + // free queued events + for( event = EventQueue->next; event != EventQueue; event = next ) + { + next = event->next; + delete event; + } + // free active events + for( event = ActiveEvents->next; event != ActiveEvents; event = next ) + { + next = event->next; + delete event; + } + // free free events + for( event = FreeEvents->next; event != FreeEvents; event = next ) + { + next = event->next; + RealDeallocateEvent( event ); + } + + assert( Event_totalmemallocated == 0 ); + + numEvents = 0; + numFreeEvents = 0; + + // + // initialize lists + // + LL_Reset( FreeEvents, next, prev ); + LL_Reset( EventQueue, next, prev ); + LL_Reset( ActiveEvents, next, prev ); + } + +int Event::NumEventCommands + ( + void + ) + + { + if ( commandList ) + { + // Add 1 since container gives the inclusive number of objects + return commandList->NumObjects() + 1; + } + + return 0; + } + +int Event::compareEvents + ( + const void *arg1, + const void *arg2 + ) + + { + int ev1; + int ev2; + + ev1 = *( int * )arg1; + ev2 = *( int * )arg2; + + return stricmp( commandList->ObjectAt( ev1 )->c_str(), commandList->ObjectAt( ev2 )->c_str() ); + } + +void Event::SortEventList + ( + void + ) + + { + dirtylist = false; + + if ( sortedList && commandList ) + { + qsort( ( void * )sortedList->AddressOfObjectAt( 1 ), + ( size_t )sortedList->NumObjects(), + sizeof( int ), compareEvents ); + } + } + +inline int Event::FindEvent + ( + const char *name + ) + + { + int eventnum; + int index; + int l; + int r; + int diff; + + assert( name ); + if ( !name ) + { + return 0; + } + + if ( !commandList ) + { + return 0; + } + + if ( dirtylist ) + { + SortEventList(); + } + + numfinds++; + numcompares++; + if ( lastevent && !stricmp( name, commandList->ObjectAt( lastevent )->c_str() ) ) + { + numfirstsearch++; + return lastevent; + } + + l = 1; + r = sortedList->NumObjects(); + while( r >= l ) + { + index = ( l + r ) >> 1; + eventnum = sortedList->ObjectAt( index ); + diff = stricmp( name, commandList->ObjectAt( eventnum )->c_str() ); + numcompares++; + if ( diff < 0 ) + { + r = index - 1; + } + else if ( diff > 0 ) + { + l = index + 1; + } + else + { + lastevent = eventnum; + return eventnum; + } + } + + return 0; + } + +int Event::MapSortedEventIndex + ( + int index + ) + { + return sortedList->ObjectAt( index ); + } + + +int Event::FindEvent + ( + str &name + ) + + { + return FindEvent( name.c_str() ); + } + +void Event::ListCommands + ( + const char *mask + ) + + { + str name; + int flags; + int eventnum; + int num; + int i; + int n; + int l; + int p; + int hidden; + str text; + + if ( !commandList ) + { + EVENT_DPrintf( "No events.\n" ); + return; + } + + if ( dirtylist ) + { + SortEventList(); + } + + l = 0; + if ( mask ) + { + l = strlen( mask ); + } + + hidden = 0; + num = 0; + n = sortedList->NumObjects(); + for( i = 1; i <= n; i++ ) + { + eventnum = sortedList->ObjectAt( i ); + name = commandList->ObjectAt( eventnum )->c_str(); + flags = flagList->ObjectAt( eventnum ); + + if ( flags & EV_HIDE ) + { + hidden++; + continue; + } + + if ( mask && Q_stricmpn( name.c_str(), mask, l ) ) + { + continue; + } + + num++; + + text = " "; + p = 0; + if ( flags & EV_CONSOLE ) + { + text[ p++ ] = '*'; + } + if ( flags & EV_CHEAT ) + { + text[ p++ ] = 'C'; + } + if ( flags & EV_CACHE ) + { + text[ p++ ] = '%'; + } + + EVENT_Printf( "%4d : %s%s\n", eventnum, text.c_str(), name.c_str() ); + } + + EVENT_Printf( "\n* = console command.\nC = cheat command.\n% = cache command.\n\n" + "Printed %d of %d total commands.\n", num, n - hidden ); + + if ( developer->integer && hidden ) + { + EVENT_Printf( "Suppressed %d commands.\n", hidden ); + } + } + +#ifdef GAME_DLL + +void Event::PrintEvent + ( + Event * event + ) + { + int i; + int n; + Listener * obj; + str text; + + obj = event->GetSourceObject(); + + text = va( "%6.1f:%1d: %s", event->time, event->flags, obj->getClassname() ); + if ( obj->isSubclassOf( Entity ) ) + { + text += va( " (*%d) ", ( ( Entity * )obj )->entnum ); + if ( ( ( Entity * )obj )->Targeted() ) + { + text += va( "'%s'", ( ( Entity * )obj )->TargetName() ); + } + } + else if ( obj->isSubclassOf( ScriptThread ) ) + { + text += va( " #%d:'%s'", ( ( ScriptThread * )obj )->ThreadNum(), ( ( ScriptThread * )obj )->ThreadName() ); + } + else if ( obj->isSubclassOf( ScriptVariable ) ) + { + text += va( " '%s'", ( ( ScriptVariable * )obj )->getName() ); + } + + switch( event->GetSource() ) + { + default : + case EV_FROM_CODE : + text += " : Code :"; + break; + + case EV_FROM_SCRIPT : + assert( event->GetThread() ); + if ( event->GetThread() ) + { + text += va( " : %s(%d) :", event->GetThread()->Filename(), event->info.linenumber ); + } + else + { + text += " : NULL :"; + } + break; + + case EV_FROM_CONSOLE : + text += " : Console :"; + break; + } + + text += event->getName().c_str(); + n = event->NumArgs(); + for( i = 1; i <= n; i++ ) + { + text += va( " %s", event->GetToken( i ) ); + } + + text += "\n"; + + if ( !g_watch->integer || ( obj->isSubclassOf( Entity ) && ( g_watch->integer == ( ( Entity * )obj )->entnum ) ) ) + { + if ( g_showevents->integer == 2 ) + { + EVENT_DebugPrintf( text.c_str() ); + } + else + { + EVENT_DPrintf( "%s", text.c_str() ); + } + } + } + +#else + +void Event::PrintEvent + ( + Event * event + ) + { + int i; + int n; + str text; + + + text = va( "%6.1f:%1d ", event->time, event->flags ); + + switch( event->GetSource() ) + { + default : + case EV_FROM_CODE : + text += " : Code :"; + break; + + case EV_FROM_CONSOLE : + text += " : Console :"; + break; + } + + text += event->getName().c_str(); + n = event->NumArgs(); + for( i = 1; i <= n; i++ ) + { + text += va( " %s", event->GetToken( i ) ); + } + + text += "\n"; + + if ( g_showevents->integer == 2 ) + { + EVENT_DebugPrintf( text.c_str() ); + } + else + { + EVENT_DPrintf( text.c_str() ); + } + } + +#endif + +void Event::PendingEvents + ( + const char *mask + ) + + { + Event *event; + int l, num; + + l = 0; + if ( mask ) + { + l = strlen( mask ); + } + + assert( EventQueue ); + assert( EventQueue->next ); + assert( EventQueue->prev ); + + num = 0; + event = EventQueue->next; + while( event != EventQueue ) + { + assert( event ); + assert( event->m_sourceobject ); + + if ( !mask || !Q_stricmpn( event->getName().c_str(), mask, l ) ) + { + num++; + Event::PrintEvent( event ); + } + + event = event->next; + } + EVENT_Printf( "%d pending events as of %.2f\n", num, EVENT_time ); + } + +void Event::PrintDocumentation + ( + FILE *event_file, + qboolean html + ) + + { + int i; + int p; + str text; + + if ( !html ) + { + text = " "; + p = 0; + + if ( flags & EV_CONSOLE ) + { + text[ p++ ] = '*'; + } + if ( flags & EV_CHEAT ) + { + text[ p++ ] = 'C'; + } + if ( flags & EV_CACHE ) + { + text[ p++ ] = '%'; + } + } + + if ( html ) + { + EV_Print( event_file, "\n

%s", name ); + } + else + { + if ( text[ 0 ] != ' ' ) + { + EV_Print( event_file, "\n%s:%s", text.c_str(), name ); + } + else + { + EV_Print( event_file, "\n%s %s", text.c_str(), name ); + } + } + + if ( definition ) + { + if ( html ) + { + EV_Print( event_file, "( " ); + } + else + { + EV_Print( event_file, "( " ); + } + for( i = 1; i <= definition->NumObjects(); i++ ) + { + definition->ObjectAt( i ).PrintArgument( event_file ); + if ( i < definition->NumObjects() ) + { + EV_Print( event_file, ", " ); + } + } + if ( html ) + { + EV_Print( event_file, " )
\n" ); + } + else + { + EV_Print( event_file, " )\n" ); + } + } + else + { + if ( html ) + { + EV_Print( event_file, "
\n" ); + } + else + { + EV_Print( event_file, "\n" ); + } + } + if ( documentation ) + { + char new_doc[1024]; + int old_index; + int new_index = 0; + + for ( old_index = 0 ; old_index < strlen ( documentation ) ; old_index++ ) + { + if ( documentation[old_index] == '\n' ) + { + if ( html ) + { + new_doc[new_index ] = '<'; + new_doc[new_index + 1] = 'B'; + new_doc[new_index + 2] = 'R'; + new_doc[new_index + 3] = '>'; + new_doc[new_index + 4] = '\n'; + new_index += 5; + } + else + { + new_doc[new_index ] = '\n'; + new_doc[new_index + 1] = '\t'; + new_doc[new_index + 2] = '\t'; + new_index += 3; + } + } + else + { + new_doc[new_index] = documentation[old_index]; + new_index++; + } + + } + + new_doc[new_index] = 0; + + if ( html ) + { +// EV_Print( event_file, "

%s
\n", new_doc ); + EV_Print( event_file, "
    %s
\n", new_doc ); + } + else + { + EV_Print( event_file, "\t\t- %s\n", new_doc ); + } + } + } + +void Event::PrintEventDocumentation + ( + Event * ePtr, + FILE *event_file, + qboolean html + ) + + { + int flags; + + flags = ePtr->GetFlags(); + + if ( flags & EV_HIDE ) + { + return; + } + + // purposely suppressed + if ( ePtr->name[ 0 ] == '_' ) + { + return; + } + + ePtr->PrintDocumentation( event_file, html ); + } + + +void Event::ListDocumentation + ( + const char *mask, + qboolean print_to_disk + ) + + { + Event * ePtr; + int num; + int i; + int n; + int l; + int flags; + int hidden; + str name; + str text; + FILE *event_file = NULL; + str event_filename; + + if ( !eventDefList ) + { + EVENT_DPrintf( "No events.\n" ); + return; + } + + if ( print_to_disk ) + { + if ( !mask || !mask[0] ) + event_filename = EVENT_FILENAME; + else + event_filename = str ( mask ) + ".txt"; + + event_file = fopen( event_filename.c_str(), "w" ); + + if ( event_file == NULL ) + return; + } + + l = 0; + if ( mask ) + { + l = strlen( mask ); + } + + + EV_Print( event_file, "\nCommand Documentation\n" ); + EV_Print( event_file, "=====================\n" ); + + hidden = 0; + num = 0; + n = eventDefList->NumObjects(); + for( i = 1; i <= n; i++ ) + { + ePtr = eventDefList->ObjectAt( i ); + flags = ePtr->GetFlags(); + name = ePtr->getName(); + + if ( flags & EV_HIDE ) + { + hidden++; + continue; + } + + if ( mask && Q_stricmpn( name, mask, l ) ) + { + continue; + } + + num++; + + ePtr->PrintDocumentation( event_file ); + } + + + EV_Print( event_file, "\n* = console command.\nC = cheat command.\n% = cache command.\n\n" + "Printed %d of %d total commands.\n", num, n - hidden ); + + if ( developer->integer && hidden ) + { + EV_Print( event_file, "Suppressed %d commands.\n", hidden ); + } + + if ( event_file != NULL ) + { + EVENT_Printf( "Printed event info to file %s\n", event_filename.c_str() ); + fclose( event_file ); + } + } + + +void Event::initCommandList + ( + void + ) + + { + int flags; + str *n; + + flags = 0; + commandList = new Container; + + n = new str( "NULL" ); + NullEvent.eventnum = commandList->AddObject( n ); + + flagList = new Container; + flagList->AddObject( flags ); + + sortedList = new Container; + sortedList->AddObject( NullEvent.eventnum ); + + eventDefList = new Container; + + dirtylist = false; + + NullEvent.data = NULL; + NullEvent.info.inuse = 0; + NullEvent.info.source = EV_FROM_CODE; + NullEvent.info.flags = 0; + NullEvent.info.linenumber = 0; + } + +Event::Event() + { + info.inuse = 0; + info.source = EV_FROM_CODE; + info.flags = 0; + info.linenumber = 0; + threadnum = -1; + eventnum = 0; + data = NULL; + definition = NULL; + name = NULL; + documentation = NULL; + } + +Event::Event + ( + int num + ) + + { + if ( !commandList ) + { + initCommandList(); + } + + assert( ( num > 0 ) && num <= commandList->NumObjects() ); + + if ( ( num <= 0 ) || ( num > commandList->NumObjects() ) ) + { + EVENT_DPrintf( "Event %d out of range.\n", num ); + num = 0; + name = NULL; + info.flags = 0; + } + else + { + name = commandList->ObjectAt( num )->c_str(); + info.flags = flagList->ObjectAt( num ); + } + + eventnum = num; + data = NULL; + definition = NULL; + documentation = NULL; + info.inuse = 0; + info.source = EV_FROM_CODE; + info.linenumber = 0; + threadnum = -1; + } + +Event::Event + ( + Event &ev + ) + + { + int num; + int i; + + eventnum = ( int )ev; + assert( ( eventnum > 0 ) && eventnum <= commandList->NumObjects() ); + data = NULL; + definition = NULL; + documentation = NULL; + + name = commandList->ObjectAt( eventnum )->c_str(); + info.inuse = 0; + info.source = ev.info.source; + info.flags = ev.info.flags; + info.linenumber = ev.info.linenumber; + threadnum = ev.threadnum; + + if ( ev.data ) + { + num = ev.data->NumObjects(); + + data = new Container; + data->Resize( num ); + + for( i = 1; i <= num; i++ ) + { + data->AddObject( ev.data->ObjectAt( i ) ); + } + } + } + +Event::Event + ( + Event *ev + ) + + { + int num; + int i; + + assert( ev ); + if ( !ev ) + { + EVENT_Error( ERR_DROP, "NULL Event\n" ); + } + + eventnum = ( int )*ev; + assert( ( eventnum > 0 ) && eventnum <= commandList->NumObjects() ); + data = NULL; + definition = NULL; + documentation = NULL; + name = commandList->ObjectAt( eventnum )->c_str(); + info.inuse = 0; + info.source = ev->info.source; + info.flags = ev->info.flags; + info.linenumber = ev->info.linenumber; + threadnum = ev->threadnum; + if ( ev->data ) + { + num = ev->data->NumObjects(); + + data = new Container; + data->Resize( num ); + + for( i = 1; i <= num; i++ ) + { + data->AddObject( ev->data->ObjectAt( i ) ); + } + } + } + +Event::Event + ( + const char *command, + int flags, + const char *theFormatspec, + const char *theArgument_names, + const char *theDocumentation + ) + + { + str *t; + + if ( !commandList ) + { + initCommandList(); + } + + eventnum = FindEvent( command ); + if ( !eventnum ) + { + t = new str( command ); + eventnum = commandList->AddObject( t ); + // check for default flags + if ( flags == EV_DEFAULT ) + { + flags = 0; + } + flagList->AddObject( ( int )flags ); + sortedList->AddObject( eventnum ); + dirtylist = true; + } + + // Use the name stored in the command list in case the string passed in + // is not in static memory. + name = commandList->ObjectAt( eventnum )->c_str(); + + data = NULL; + info.inuse = 0; + info.source = EV_FROM_CODE; + info.linenumber = 0; + threadnum = -1; + formatspec = theFormatspec; + argument_names = theArgument_names; + documentation = theDocumentation; + definition = NULL; + + // If flags have changed, let the user know. It's probably a development bug. + int &flagobj = flagList->ObjectAt( eventnum ); + + // check for default flags + if ( flags == EV_DEFAULT ) + { + flags = flagobj; + } + + assert( flags == flagobj ); + if ( flags != flagobj ) + { + // Flags not equal. Use combined value. + flagobj |= flags; + } + + info.flags = flagobj; + + // add it to the list for Documentation + // suppress it if it starts with '_' + if ( documentation && ( command[ 0 ] != '_' ) ) + { + eventDefList->AddObject( ( Event * )this ); + } + else + { + // purposely suppressed + if ( command[ 0 ] != '_' ) + { + // empty documentation! + assert( 0 ); + } + } + } + +Event::Event + ( + const char *command + ) + + { + if ( !commandList ) + { + initCommandList(); + } + + eventnum = FindEvent( command ); + if ( !eventnum ) + { + EVENT_DPrintf( "Event '%s' does not exist.\n", command ); + name = NULL; + info.flags = 0; + } + else + { + name = commandList->ObjectAt( eventnum )->c_str(); + info.flags = flagList->ObjectAt( eventnum ); + } + + data = NULL; + definition = NULL; + documentation = NULL; + info.inuse = 0; + info.source = EV_FROM_CODE; + info.linenumber = 0; + threadnum = -1; + } + +Event::Event + ( + str &command + ) + + { + if ( !commandList ) + { + initCommandList(); + } + + eventnum = FindEvent( command ); + if ( !eventnum ) + { + EVENT_DPrintf( "Event '%s' does not exist.\n", command.c_str() ); + name = NULL; + info.flags = 0; + } + else + { + name = commandList->ObjectAt( eventnum )->c_str(); + info.flags = flagList->ObjectAt( eventnum ); + } + + data = NULL; + definition = NULL; + documentation = NULL; + info.inuse = 0; + info.source = EV_FROM_CODE; + info.linenumber = 0; + threadnum = -1; + } + +Event::~Event() + { + if ( data ) + { + delete data; + data = NULL; + } + if ( definition ) + { + delete definition; + definition = NULL; + } + } + +void Event::SetupDocumentation + ( + void + ) + + { + // setup documentation + if ( formatspec ) + { + if ( argument_names ) + { + char argumentNames[ 256 ]; + str argSpec; + str rangeSpec; + str argName; + EventArgDef argDef; + const char *namePtr; + const char *specPtr; + int specLength, index; + Container argNames; + + specLength = strlen( formatspec ); + specPtr = formatspec; + // + // store off all the names + // + strcpy( argumentNames, argument_names ); + namePtr = strtok( argumentNames, " " ); + while ( namePtr != NULL ) + { + argNames.AddObject( str( namePtr ) ); + namePtr = strtok( NULL, " " ); + } + // + // create the definition container + // + definition = new Container; + definition->Resize( argNames.NumObjects() ); + index = 0; + // go throught he formatspec + while( specLength ) + { + // clear the rangeSpec + rangeSpec = ""; + // get the argSpec + argSpec = ""; + argSpec += *specPtr; + specPtr++; + specLength--; + // see if there is a range specified + while ( *specPtr == '[' ) + { + // add in all the characters until NULL or ']' + while( specLength && ( *specPtr != ']' ) ) + { + rangeSpec += *specPtr; + specPtr++; + specLength--; + } + if ( specLength && *specPtr == ']' ) + { + rangeSpec += *specPtr; + specPtr++; + specLength--; + } + } + if ( index < argNames.NumObjects() ) + { + argName = argNames.ObjectAt( index + 1 ); + argDef.Setup( name, argName, argSpec, rangeSpec ); + definition->AddObject( argDef ); + } + else + { + assert( 0 ); + Error( "More format specifiers than argument names for event %s\n", name ); + } + index++; + } + if ( index < argNames.NumObjects() ) + { + assert( 0 ); + Error( "More argument names than format specifiers for event %s\n", name ); + } + } + } + } + +void Event::DeleteDocumentation + ( + void + ) + + { + // setup documentation + if ( formatspec ) + { + if ( argument_names ) + { + definition->FreeObjectList(); + delete definition; + definition = NULL; + } + } + } + +#ifdef GAME_DLL + +void Event::SetThread + ( + ScriptThread *thread + ) + + { + if ( thread ) + { + threadnum = thread->ThreadNum(); + } + else + { + threadnum = -1; + } + } + +ScriptThread *Event::GetThread + ( + void + ) + + { + if ( threadnum != -1 ) + { + return Director.GetThread( threadnum ); + } + + return NULL; + } +#endif + +void Event::Error + ( + const char *fmt, + ... + ) + + { + va_list argptr; + char text[ 1024 ]; + + va_start( argptr, fmt ); + vsprintf( text, fmt, argptr ); + va_end( argptr ); + + switch( GetSource() ) + { + default : + case EV_FROM_CODE : +#if defined( GAME_DLL ) + EVENT_DPrintf( "Game: '%s' : %s\n", getName().c_str(), text ); +#elif defined( CGAME_DLL ) + EVENT_DPrintf( "CGame: '%s' : %s\n", getName().c_str(), text ); +#elif defined( UI_LIB ) + EVENT_DPrintf( "UI_Lib: '%s' : %s\n", getName().c_str(), text ); +#else + EVENT_DPrintf( "Client: '%s' : %s\n", getName().c_str(), text ); +#endif + break; +#ifdef GAME_DLL + case EV_FROM_SCRIPT : + { + ScriptThread *thread = GetThread(); + const char *filename = "Dead script"; + if ( thread ) + { + filename = thread->Filename(); + } + EVENT_DPrintf( "%s(%d): '%s' :\n%s\n", filename, info.linenumber, getName().c_str(), text ); + } + break; + + case EV_FROM_CONSOLE : + gi.SendServerCommand( GetConsoleEdict()-g_entities, "print \"Console: '%s' : %s\n\"", getName().c_str(), text ); + break; +#endif + } + } + +qboolean Event::IsVectorAt + ( + int pos + ) + + { + if ( !data || ( pos < 1 ) || ( data->NumObjects() < pos ) ) + { + Error( "Index %d out of range.", pos ); + return false; + } + + return data->ObjectAt( pos ).IsVector( *this ); + } + +#ifdef GAME_DLL +qboolean Event::IsEntityAt + ( + int pos + ) + + { + if ( !data || ( pos < 1 ) || ( data->NumObjects() < pos ) ) + { + Error( "Index %d out of range.", pos ); + return false; + } + + return data->ObjectAt( pos ).GetEntity( *this ) != NULL; + } +#endif + +qboolean Event::IsNumericAt + ( + int pos + ) + + { + if ( !data || ( pos < 1 ) || ( data->NumObjects() < pos ) ) + { + Error( "Index %d out of range.", pos ); + return false; + } + + return data->ObjectAt( pos ).IsNumeric( *this ); + } + +#ifdef GAME_DLL +void Event::Archive + ( + Archiver &arc + ) + + { + str name; + int num; + int i; + EventVar var; + + if ( arc.Saving() ) + { + name = getName(); + } + arc.ArchiveString( &name ); + if ( arc.Loading() ) + { + if ( data ) + { + delete data; + data = NULL; + } + *this = Event( name ); + } + + arc.ArchiveRaw( &info, sizeof( info ) ); + arc.ArchiveInteger( &threadnum ); + arc.ArchiveShort( &anim_number ); + arc.ArchiveShort( &anim_frame ); + arc.ArchiveSafePointer( &m_sourceobject ); + arc.ArchiveFloat( &time ); + arc.ArchiveInteger( &flags ); + + if ( arc.Saving() ) + { + if ( !data ) + { + num = 0; + } + else + { + num = data->NumObjects(); + } + } + arc.ArchiveInteger( &num ); + if ( arc.Loading() && num ) + { + data = new Container; + data->Resize( num ); + } + + for( i = 1; i <= num; i++ ) + { + if ( arc.Saving() ) + { + var = data->ObjectAt( i ); + } + var.Archive( arc ); + if ( arc.Loading() ) + { + data->AddObject( var ); + } + } + } +#endif + +CLASS_DECLARATION( Class, Listener, NULL ) + { + { &EV_Remove, Listener::Remove }, + { &EV_ScriptRemove, Listener::ScriptRemove }, + { NULL, NULL } + }; + +void Listener::Remove + ( + Event *e + ) + + { + delete this; + } + +void Listener::ScriptRemove + ( + Event *e + ) + + { + // Forces the remove to be done at a safe time + PostEvent( EV_Remove, 0 ); + } + +qboolean Listener::ValidEvent + ( + Event &e + ) + + { + ClassDef *c; + int ev; + + ev = ( int )e; + + c = this->classinfo(); + assert( ( ev >= 0 ) && ( ev < c->numEvents ) ); + if ( ( ev < 0 ) || ( ev >= c->numEvents ) ) + { + warning( "ValidEvent", "Event '%s' out of response range for class '%s'. " + "Event probably invalid or allocated late.\n", e.getName().c_str(), getClassname() ); + return false; + } + + return ( c->responseLookup[ ev ] != NULL ); + } + +qboolean Listener::ValidEvent + ( + const char *name + ) + + { + ClassDef *c; + int ev; + + ev = Event::FindEvent( name ); + + c = this->classinfo(); + assert( ( ev >= 0 ) && ( ev < c->numEvents ) ); + if ( ( ev < 0 ) || ( ev >= c->numEvents ) ) + { + warning( "ValidEvent", "Event '%s' out of response range for class '%s'. " + "Event probably invalid or allocated late.\n", name, getClassname() ); + return false; + } + + return ( c->responseLookup[ ev ] != NULL ); + } + +qboolean Listener::EventPending + ( + Event &ev + ) + + { + Event *event; + int eventnum; + + assert( EventQueue ); + assert( EventQueue->next ); + + event = EventQueue->next; + + eventnum = ( int )ev; + while( event != EventQueue ) + { + if ( ( event->m_sourceobject == this ) && ( (int)*event == eventnum ) ) + { + return true; + } + event = event->next; + } + + return false; + } + +inline qboolean Listener::CheckEventFlags + ( + Event *event + ) + + { +#ifdef GAME_DLL + // Special handling of console events + if ( event->GetSource() == EV_FROM_CONSOLE ) + { + if ( !( event->info.flags & (EV_CONSOLE|EV_CHEAT) ) ) + { + if ( isSubclassOf( Entity ) ) + { + Entity *ent; + + ent = ( Entity * )this; + gi.SendServerCommand( ent->edict-g_entities, "print \"Command not available from console.\n\"" ); + } + + // don't process + return false; + } + + // don't allow console cheats during deathmatch unless the server says it's ok. + if ( ( event->info.flags & EV_CHEAT ) && deathmatch->integer && !sv_cheats->integer ) + { + if ( isSubclassOf( Entity ) ) + { + Entity *ent; + + ent = ( Entity * )this; + gi.SendServerCommand( ent->edict-g_entities, "print \"You must run the server with '+set cheats 1' to enable this command.\n\"" ); + } + + // don't process + return false; + } + } +#endif + + // ok to process + return true; + } + +qboolean Listener::ProcessEvent + ( + Event *event + ) + + { + ClassDef *c; + int ev; + + if ( !Event::EventSystemStarted ) + { + assert( 0 ); + return false; + } + + // make sure the event has only been used once + if ( event->info.inuse ) + { + EVENT_Error( ERR_DROP, "ProcessEvent : Event '%s' has already been posted.\n", event->getName().c_str() ); + } + + if ( g_showevents->integer ) + { + Listener *obj; + + obj = event->GetSourceObject(); + if ( !obj ) + { + event->SetSourceObject( this ); + } + Event::PrintEvent( event ); + } + + ev = ( int )*event; + c = this->classinfo(); + if ( ev >= c->numEvents ) + { + event->Error( "Event out of response range for class '%s'. Event probably invalid or allocated late.\n", getClassname() ); + return false; + } + + if ( c->responseLookup[ ev ] ) + { + int start; + int end; + + event->info.inuse++; + + if ( !g_timeevents->integer ) + { + // only process the event if we allow it + if ( CheckEventFlags( event ) ) + { + ( this->**c->responseLookup[ ev ] )( event ); + } + } + else + { + start = EVENT_realtime; + + // only process the event if we allow it + if ( CheckEventFlags( event ) ) + { + ( this->**c->responseLookup[ ev ] )( event ); + } + + end = EVENT_realtime; + + if ( end - start >= g_timeevents->integer ) + { +#ifdef GAME_DLL + if ( event != EV_Remove && this->isSubclassOf( Entity ) ) + { + Entity *ent = (Entity *)this; + + EVENT_DebugPrintf( "(%d) ", ent->entnum ); + } +#endif + + EVENT_DebugPrintf( "'%s' : %d\n", event->getName().c_str(), end - start ); + } + } + + // Prevent an event from being freed twice, in case it's been re-used + event->info.inuse--; + if ( !event->info.inuse ) + { + delete event; + } + else + { + EVENT_Error( ERR_DROP, "ProcessEvent : Event '%s' is still in use after being processed.\n", event->getName().c_str() ); + } + + return true; + } + + if ( !event->info.inuse ) + { + delete event; + } + else + { + EVENT_Error( ERR_DROP, "ProcessEvent : Event '%s' is still in use after being processed.\n", event->getName().c_str() ); + } + + return false; + } + +void Listener::PostEvent + ( + Event *ev, + float time, + int flags + ) + + { + int evnum; + ClassDef *c; + Event *event; + +#ifdef GAME_DLL + if ( LoadingSavegame ) + { + // while technically not bad, if we got here we have an event that is being posted while loading which is a bad thing + assert( 0 ); + if ( !ev->info.inuse ) + { + delete ev; + } + else + { + EVENT_Error( ERR_DROP, "PostEvent : Event '%s' is still in use during loading.\n", ev->getName().c_str() ); + } + + return; + } +#endif + + if ( !Event::EventSystemStarted ) + { + assert( 0 ); + return; + } + + evnum = ( int )*ev; + c = this->classinfo(); + if ( evnum >= c->numEvents ) + { + ev->Error( "Event out of response range for class '%s'. Event probably invalid or allocated late.\n", getClassname() ); + return; + } + + if ( !c->responseLookup[ evnum ] ) + { + // we don't need it so lets delete it + delete ev; + return; + } + + LL_Remove( ev, next, prev ); + + ev->SetSourceObject( this ); + ev->time = EVENT_time + time; + ev->flags = flags; + + event = EventQueue->next; + while( ( event != EventQueue ) && ( ev->time >= event->time ) ) + { + event = event->next; + } + + LL_Add( event, ev, next, prev ); + numEvents++; + } + +qboolean Listener::PostponeEvent + ( + Event &ev, + float time + ) + + { + Event *event; + Event *node; + int eventnum; + + assert( EventQueue ); + assert( EventQueue->next ); + + eventnum = ( int )ev; + + event = EventQueue->next; + while( event != EventQueue ) + { + if ( ( event->GetSourceObject() == this ) && ( ( int )*event == eventnum ) ) + { + event->time += time; + + node = event->next; + while( ( node != EventQueue ) && ( event->time >= node->time ) ) + { + node = node->next; + } + + LL_Remove( event, next, prev ); + LL_Add( node, event, next, prev ); + + return true; + } + event = event->next; + } + + return false; + } + +void Listener::CancelEventsOfType + ( + Event *ev + ) + + { + Event *event; + Event *next; + int eventnum; + + assert( EventQueue ); + assert( EventQueue->next ); + + event = EventQueue->next; + + eventnum = (int)*ev; + while( event != EventQueue ) + { + next = event->next; + if ( ( event->GetSourceObject() == this ) && ( (int)*event == eventnum ) ) + { + LL_Remove( event, next, prev ); + numEvents--; + delete event; + } + event = next; + } + } + +void Listener::CancelFlaggedEvents + ( + int flags + ) + + { + Event *event; + Event *next; + + assert( EventQueue ); + assert( EventQueue->next ); + + event = EventQueue->next; + + while( event != EventQueue ) + { + next = event->next; + if ( ( event->GetSourceObject() == this ) && ( event->flags & flags ) ) + { + LL_Remove( event, next, prev ); + numEvents--; + delete event; + } + event = next; + } + } + + +void Listener::CancelPendingEvents + ( + void + ) + + { + Event *event; + Event *next; + + assert( EventQueue ); + assert( EventQueue->next ); + + event = EventQueue->next; + + while( event != EventQueue ) + { + next = event->next; + if ( event->GetSourceObject() == this ) + { + LL_Remove( event, next, prev ); + numEvents--; + delete event; + } + event = next; + } + } + +qboolean Listener::ProcessPendingEvents + ( + void + ) + + { + Event *event; + qboolean processedEvents; + float t; + + assert( EventQueue ); + assert( EventQueue->next ); + assert( EventQueue->prev ); + + processedEvents = false; + + t = EVENT_time + 0.001; + + event = EventQueue->next; + while( event != EventQueue ) + { + Listener * obj; + + assert( event ); + + obj = event->GetSourceObject(); + + if ( event->time > t ) + { + break; + } + + if ( obj != this ) + { + // traverse normally + event = event->next; + } + else + { + // the event is removed from its list and temporarily added to the active list + LL_Remove( event, next, prev ); + numEvents--; + LL_Add( ActiveEvents, event, next, prev ); + + + // ProcessEvent will dispose of this event when it is done + obj->ProcessEvent( event ); + + // start over, since can't guarantee that we didn't process any previous or following events + event = EventQueue->next; + + processedEvents = true; + } + } + + return processedEvents; + } + +Listener::~Listener() + { + if ( Event::EventSystemStarted ) + CancelPendingEvents(); + } + +void L_ClearEventList + ( + void + ) + + { + Event *event; + + // go through active and event queue lists + while( !LL_Empty( EventQueue, next, prev ) ) + { + event = EventQueue->next; + numEvents--; + LL_Remove( event, next, prev ); + delete event; + } + + while( !LL_Empty( ActiveEvents, next, prev ) ) + { + event = ActiveEvents->next; + LL_Remove( event, next, prev ); + delete event; + } + + numEvents = 0; + } + +void L_ProcessPendingEvents + ( + void + ) + + { + Event *event; + float t; + int num; + int maxevents; + + assert( EventQueue ); + assert( EventQueue->next ); + assert( EventQueue->prev ); + + maxevents = ( int )g_eventlimit->integer; + + num = 0; + t = EVENT_time + 0.001; + while( !LL_Empty( EventQueue, next, prev ) ) + { + Listener * obj; + + event = EventQueue->next; + + assert( event ); + + obj = event->GetSourceObject(); + + assert( obj ); + + if ( event->time > t ) + { + break; + } + + // the event is removed from its list and temporarily added to the active list + LL_Remove( event, next, prev ); + numEvents--; + LL_Add( ActiveEvents, event, next, prev ); + + + // ProcessEvent will dispose of this event when it is done + obj->ProcessEvent( event ); + + // Don't allow ourselves to stay in here too long. An abnormally high number + // of events being processed is evidence of an infinite loop of events. + num++; + if ( num > maxevents ) + { + EVENT_Printf( "Event overflow. Possible infinite loop in script. " + "Enable g_showevents to trace. Aborting frame.\n" ); + break; + } + } + + if ( g_eventstats->integer ) + { + if ( g_eventstats->integer == 1 ) + { + EVENT_Printf( "finds %d, searches %d, num first search %d, avg %f\n", + Event::numfinds, Event::numcompares, Event::numfirstsearch, + ( float )Event::numcompares / ( float )Event::numfinds ); + } + else if ( g_eventstats->integer == 2 ) + { + EVENT_Printf( "pending %5d free %5d active+pending %4d\n", + numEvents, numFreeEvents, numFreeEvents + numEvents ); + } + } + } + +#ifdef GAME_DLL + +void Event::SetConsoleEdict + ( + gentity_t *consoleedict + ) + + { + // linenumber does double duty in the case of the console commands + if ( consoleedict ) + { + info.linenumber = consoleedict->s.number; + } + else + { + // default to player 1 + info.linenumber = 0; + } + } + +gentity_t *Event::GetConsoleEdict + ( + void + ) + + { + // linenumber does double duty in the case of the console commands + if ( ( info.source != EV_FROM_CONSOLE ) || ( info.linenumber < 0 ) || ( info.linenumber >= game.maxclients ) ) + { + // default to player 1 for release + return &g_entities[ 0 ]; + } + + return &g_entities[ info.linenumber ]; + } + +void L_ArchiveEvents + ( + Archiver &arc + ) + + { + Event *event; + int num; + + assert( EventQueue ); + assert( EventQueue->next ); + assert( EventQueue->prev ); + + num = 0; + for( event = EventQueue->next; event != EventQueue; event = event->next ) + { + Listener * obj; + + assert( event ); + + obj = event->GetSourceObject(); + + assert( obj ); + + if ( obj->isSubclassOf( Entity ) && + ( ( ( Entity * )obj )->flags & FL_DONTSAVE ) ) + { + continue; + } + + num++; + } + + arc.ArchiveInteger( &num ); + for( event = EventQueue->next; event != EventQueue; event = event->next ) + { + Listener * obj; + + assert( event ); + + obj = event->GetSourceObject(); + + assert( obj ); + + if ( obj->isSubclassOf( Entity ) && + ( ( ( Entity * )obj )->flags & FL_DONTSAVE ) ) + { + continue; + } + + arc.ArchiveEvent( event ); + arc.ArchiveFloat( &event->time ); + arc.ArchiveInteger( &event->flags ); + } + } + +void L_UnarchiveEvents + ( + Archiver &arc + ) + + { + Event *e; + int i; + + // the FreeEvents list would already be allocated at this point + // clear out any events that may exist + L_ClearEventList(); + + arc.ArchiveInteger( &numEvents ); + for( i = 0; i < numEvents; i++ ) + { + e = new Event(); + LL_Remove( e, next, prev ); + arc.ArchiveEvent( e ); + arc.ArchiveFloat( &e->time ); + arc.ArchiveInteger( &e->flags ); + + LL_Add( EventQueue, e, next, prev ); + } + } +#endif + +void Event::InitializeDocumentation + ( + void + ) + { + Event * ePtr; + int i; + + for( i = 1; i <= eventDefList->NumObjects(); i++ ) + { + ePtr = eventDefList->ObjectAt( i ); + ePtr->SetupDocumentation(); + } + } + +void Event::ShutdownDocumentation + ( + void + ) + { + Event * ePtr; + int i; + + for( i = 1; i <= eventDefList->NumObjects(); i++ ) + { + ePtr = eventDefList->ObjectAt( i ); + ePtr->DeleteDocumentation(); + } + } + + +void L_InitEvents + ( + void + ) + + { + if ( Event::EventSystemStarted ) + { + assert( 0 ); + L_ShutdownEvents(); + } + + Event::lastevent = 0; + Event::numfinds = 0; + Event::numcompares = 0; + Event::numfirstsearch = 0; + Event_totalmemallocated = 0; + +#if defined( GAME_DLL ) + g_showevents = gi.cvar ( "g_showevents", "0", 0 ); + g_eventlimit = gi.cvar ( "g_eventlimit", "5000", 0 ); + g_timeevents = gi.cvar ( "g_timeevents", "0", 0 ); + g_watch = gi.cvar ( "g_watch", "0", 0 ); + g_eventstats = gi.cvar ( "g_eventstats", "0", 0 ); +#elif defined( CGAME_DLL ) + g_showevents = cgi.Cvar_Get ( "cg_showevents", "0", 0 ); + g_eventlimit = cgi.Cvar_Get ( "cg_eventlimit", "500", 0 ); + g_timeevents = cgi.Cvar_Get ( "cg_timeevents", "0", 0 ); + g_eventstats = cgi.Cvar_Get ( "cg_eventstats", "0", 0 ); +#else + g_showevents = Cvar_Get ( "cl_showevents", "0", 0 ); + g_eventlimit = Cvar_Get ( "cl_eventlimit", "500", 0 ); + g_timeevents = Cvar_Get ( "cl_timeevents", "0", 0 ); + g_eventstats = Cvar_Get ( "cl_eventstats", "0", 0 ); +#endif + + BuildEventResponses(); + + Event::InitializeEventLists(); + + L_ClearEventList(); + + // setup the documentation on all the events + Event::InitializeDocumentation(); + + // Sort the list before we go on since we won't be adding any more events + Event::SortEventList(); + + // the event system has started + Event::EventSystemStarted = true; + } + +void L_ShutdownEvents + ( + void + ) + + { + int i; + + if ( !Event::EventSystemStarted ) + return; + + Event::ShutdownEventLists(); + + // deletes all the documentation + Event::ShutdownDocumentation(); + + if ( Event::commandList ) + { + for ( i=Event::commandList->NumObjects(); i>0; i-- ) + { + str *s; + + s = Event::commandList->ObjectAt( i ); + assert( s ); + if ( s ) + delete s; + } + delete Event::commandList; + Event::commandList = NULL; + } + + if ( Event::eventDefList ) + { + delete Event::eventDefList; + Event::eventDefList = NULL; + } + + if ( Event::flagList ) + { + delete Event::flagList; + Event::flagList = NULL; + } + + if ( Event::sortedList ) + { + delete Event::sortedList; + Event::sortedList = NULL; + } + + // say it is now shutdown + Event::EventSystemStarted = false; + } diff --git a/source/source/cgame/listener.h b/source/source/cgame/listener.h new file mode 100644 index 0000000..481ffb2 --- /dev/null +++ b/source/source/cgame/listener.h @@ -0,0 +1,1208 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/listener.h $ +// $Revision:: 36 $ +// $Author:: Aldie $ +// $Date:: 7/25/00 11:32p $ +// +// Copyright (C) 1998 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source is may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/listener.h $ +// +// 36 7/25/00 11:32p Aldie +// Made some changes to the memory system and fixed a memory allocation bug in +// Z_TagMalloc. Also changed a lot of classes to subclass from Class. +// +// 35 6/22/00 6:34p Markd +// fixed =operator assignment bug +// +// 34 6/22/00 3:45p Markd +// fixed a bunch of saved game issues +// +// 33 6/14/00 11:18a Markd +// cleaned up code using Intel compiler +// +// 32 5/30/00 7:06p Markd +// saved games 4th pass +// +// 31 5/24/00 3:14p Markd +// first phase of save/load games +// +// 30 4/29/00 3:26p Markd +// fleshed out the rest of the event/class documentation +// +// 29 4/26/00 7:55p Markd +// Added more documentation code into various systems +// +// 28 4/13/00 7:04p Aldie +// Fixed bug for animation events where the anim was greater than 255. Added +// animframe and animnumber to Event. +// +// 27 3/16/00 10:50a Markd +// Fixed some bad syntax in headers that exhibited itself in non-visualc +// compilers +// +// 26 1/06/00 11:10p Jimdose +// cleaning up unused code +// +// 25 12/15/99 11:45a Markd +// made Event's Classes and also freed up safe pointers at the appropriate +// times +// +// 24 12/11/99 5:51p Markd +// First wave of bug fixes after q3a gold merge +// +// 23 12/11/99 3:37p Markd +// q3a gold checkin, first time +// +// 22 11/11/99 3:54p Jimdose +// added EVENT_TORSO_ANIM +// +// 21 10/19/99 7:52p Markd +// Removed three part model system +// +// 20 10/12/99 11:09a Morbid +// UI merge back to FAKK +// +// 19 10/07/99 3:02p Steven +// Removed defaults for event constructor and added a new event constructor +// that only takes a const char * as a parm. +// +// 18 10/06/99 3:09p Steven +// Added dumpevents command. +// +// 17 10/05/99 2:03p Markd +// Added warning about files being in multiple projects +// +// 16 10/03/99 4:50p Markd +// removed str& constructor from listener +// +// 15 10/02/99 6:51p Markd +// Put in backend work for event documentation and fixed a lot of event +// documentation bugs +// +// 14 10/01/99 4:52p Markd +// Made Warning level 4 work on all projects +// +// 13 10/01/99 3:49p Markd +// fixed some level 4 warnings +// +// 12 9/29/99 3:10p Markd +// fixed listener problems +// +// 11 9/29/99 2:49p Morbid +// +// 10 9/28/99 7:13p Markd +// moved __LISTENER define up to the top of the file +// +// 9 9/28/99 5:31p Markd +// Successfully merged class.h, listener.h and vector.h into all three modules, +// cgame, fgame and client +// +// 8 9/28/99 5:15p Markd +// Fixed more merge bugs with sharing class, vector and listener between three +// modules +// +// 7 9/28/99 4:26p Markd +// merged listener, class and vector between 3 projects +// +// 6 9/28/99 10:12a Markd +// fixed some event issues +// +// 5 9/27/99 5:44p Markd +// began documentation and cleanup phase after merge +// +// 4 9/16/99 7:48p Jimdose +// made SetConsoleEdict use 0 based players +// +// 3 9/16/99 7:48p Jimdose +// fixed GetConsoleEdict to use 0 based players +// +// 2 9/16/99 11:18a Markd +// Continuing merge of code, not functional yet but closer +// +// 1 9/10/99 10:54a Jimdose +// +// 1 9/08/99 3:16p Aldie +// +// 14 9/02/99 2:33p Markd +// Added cache ability to entities +// +// 13 8/28/99 3:34p Jimdose +// Added EventVar +// All event args now have type information and use lazy evaluation +// +// 12 8/27/99 8:25p Markd +// added pengingevents and fixed some event holes +// +// 11 8/27/99 3:30p Markd +// put in event caching system so that events are reused +// +// 10 8/19/99 12:16p Jimdose +// added event stats +// added lru check to FindEvent +// +// 9 8/09/99 5:07p Aldie +// More changes to accomodate weapons system +// +// DESCRIPTION: +// +// WARNING: This file is shared between fgame, cgame and possibly the user interface. +// It is instanced in each one of these directories because of the way that SourceSafe works. +// + +// +// this has to be placed in front of the __LISTENER_H__ +// if it is not, listener.cpp will not compile +// +#if defined( GAME_DLL ) +// +// game dll specific defines +// +#include "g_local.h" + +#endif + +#ifndef __LISTENER_H__ +#define __LISTENER_H__ + +#if defined( GAME_DLL ) +// +// game dll specific defines +// +#define EVENT_DebugPrintf gi.DebugPrintf +#define EVENT_DPrintf gi.DPrintf +#define EVENT_Printf gi.Printf +#define EVENT_time level.time +#define EVENT_realtime gi.Milliseconds() +#define EVENT_Error gi.Error + +#define EVENT_FILENAME "events.txt" + +class Entity; +class ScriptVariable; +class ScriptThread; +class Archiver; + +#elif defined ( CGAME_DLL ) +// +// cgame dll specific defines +// +#include "cg_local.h" +#include "vector.h" +#include "str.h" +#include "../qcommon/qcommon.h" + +#define EVENT_DebugPrintf cgi.DebugPrintf +#define EVENT_DPrintf cgi.Printf +#define EVENT_Printf cgi.Printf +#define EVENT_time ( ( ( float )cg.time / 1000.0f ) ) +#define EVENT_realtime cgi.Milliseconds() +#define EVENT_Error cgi.Error + +#define EVENT_FILENAME "cg_events.txt" + +#elif defined ( UI_LIB ) + +#include "../fgame/q_shared.h" +#include "vector.h" +#include "str.h" +#include "../qcommon/qcommon.h" +#include "ui_local.h" + +#define EVENT_DebugPrintf Com_DebugPrintf +#define EVENT_DPrintf Com_Printf +#define EVENT_Printf Com_Printf +#define EVENT_time ( ( ( float )cls.realtime / 1000.0f ) ) +#define EVENT_realtime Sys_Milliseconds() +#define EVENT_Error Com_Error + +#define EVENT_FILENAME "ui_events.txt" + +#else + +// +// client specific defines +// +#include "../fgame/q_shared.h" +#include "vector.h" +#include "str.h" +#include "../qcommon/qcommon.h" + +#define EVENT_DebugPrintf Com_DebugPrintf +#define EVENT_DPrintf Com_Printf +#define EVENT_Printf Com_Printf +#define EVENT_time ( ( ( float )cls.realtime / 1000.0f ) ) +#define EVENT_realtime Sys_Milliseconds() +#define EVENT_Error Com_Error + +#define EVENT_FILENAME "cl_events.txt" +#endif + +#include "class.h" +#include "container.h" + +typedef enum + { + EV_FROM_CODE, + EV_FROM_CONSOLE, + EV_FROM_SCRIPT, + EV_FROM_ANIMATION + } eventsource_t; + +// Posted Event Flags +#define EVENT_LEGS_ANIM (1<<0) // this event is associated with an animation for the legs +#define EVENT_TORSO_ANIM (1<<1) // this event is associated with an animation for the torso +#define EVENT_DIALOG_ANIM (1<<2) // this event is associated with an animation for dialog lip syncing + + +// Event flags +#define EV_CONSOLE (1<<0) // Allow entry from console +#define EV_CHEAT (1<<1) // Only allow entry from console if cheats are enabled +#define EV_HIDE (1<<2) // Hide from eventlist +#define EV_CACHE (1<<3) // This event is used to cache data in + +#define EV_DEFAULT -1 // default flags + +#define INUSE_BITS 2 +#define MAX_EVENT_USE ( ( 1 << INUSE_BITS ) - 1 ) + +typedef enum + { + IS_STRING, + IS_VECTOR, + IS_BOOLEAN, + IS_INTEGER, + IS_FLOAT, + IS_ENTITY, + IS_SCRIPTVARIABLE + } vartype; + +#define DIRTY_STRING ( 1 << 0 ) +#define DIRTY_VECTOR ( 1 << 1 ) +#define DIRTY_INTEGER ( 1 << 2 ) +#define DIRTY_FLOAT ( 1 << 3 ) + +#define DIRTY_ALL ( 0x7fff ) + +class EventVar : public Class + { + private: + short type; + short dirtyFlags; + str stringValue; + Vector vectorValue; + int intValue; + float floatValue; + + public: + + EventVar() + { + type = IS_INTEGER; + dirtyFlags = DIRTY_ALL; + intValue = 0; + floatValue = 0; + }; + + EventVar( EventVar &ev ) + { + type = ev.type; + dirtyFlags = ev.dirtyFlags; + intValue = ev.intValue; + floatValue = ev.floatValue; + }; + + EventVar( const char *text ); + EventVar( str &text ); + + EventVar( int val ) + { + type = IS_INTEGER; + dirtyFlags = DIRTY_ALL & ~DIRTY_INTEGER; + intValue = val; + }; + + EventVar( float val ) + { + type = IS_FLOAT; + dirtyFlags = DIRTY_ALL & ~DIRTY_FLOAT; + floatValue = val; + }; + + EventVar( Vector &vec ) + { + type = IS_VECTOR; + dirtyFlags = DIRTY_ALL & ~DIRTY_VECTOR; + vectorValue = vec; + }; + +#ifdef GAME_DLL + EventVar( Entity *ent ); +#endif + + const char *GetToken( Event &ev ); + const char *GetString( Event &ev ); + qboolean GetBoolean( Event &ev ); + int GetInteger( Event &ev ); + float GetFloat( Event &ev ); + Vector GetVector( Event &ev ); +#ifdef GAME_DLL + Entity *GetEntity( Event &ev ); + ScriptVariable *GetVariable( Event &ev ); +#endif + + qboolean IsVector( Event &ev ); + qboolean IsNumeric( Event &ev ); + +#ifdef GAME_DLL + void Archive( Archiver &arc ); +#endif + }; + + +class EventArgDef : public Class + { + private: + int type; + str name; + float minRange[ 3 ]; + qboolean minRangeDefault[ 3 ]; + float maxRange[ 3 ]; + qboolean maxRangeDefault[ 3 ]; + qboolean optional; + public: + + EventArgDef() + { + type = IS_INTEGER; + //name = "undefined"; + optional = qfalse; + }; + void Setup( const char * eventName, const char *argName, const char *argType, const char *argRange ); + void PrintArgument( FILE *event_file = NULL ); + void PrintRange( FILE *event_file = NULL ); +#if 0 +#ifdef GAME_DLL + void Archive( Archiver &arc ); +#endif +#endif + }; + + + +#ifndef GAME_DLL +extern "C" + { + // interface functions + void L_ProcessPendingEvents( void ); + void L_ClearEventList( void ); + void L_InitEvents( void ); + void L_ShutdownEvents( void ); + } +#endif + + +class Listener; +typedef SafePtr ListenerPtr; + + +class Event : public Class + { + private: + friend class Listener; + + typedef struct EventInfo + { + unsigned inuse : INUSE_BITS; // must change MAX_EVENT_USE to reflect maximum number stored here + unsigned source : 2; + unsigned flags : 9; + unsigned linenumber : 19; // linenumber does double duty in the case of the console commands + } EventInfo_t; + + int eventnum; + EventInfo info; + const char *name; + const char *formatspec; + const char *argument_names; + const char *documentation; + Container *data; + Container *definition; + int threadnum; + short anim_number; + short anim_frame; + SafePtr m_sourceobject; + + //Listener *obj; + float time; + int flags; + + Event( int num ); + static void initCommandList( void ); + static void InitializeEventLists( void ); + static void ShutdownEventLists( void ); + static void InitializeDocumentation( void ); + static void ShutdownDocumentation( void ); + + static int numfinds; + static int numfirstsearch; + static int numcompares; + static int lastevent; + static bool EventSystemStarted; + + friend void L_ProcessPendingEvents( void ); + friend void L_ClearEventList( void ); + friend void L_InitEvents( void ); + friend void L_ShutdownEvents( void ); + +#ifdef GAME_DLL + friend void L_ArchiveEvents( Archiver &arc ); + friend void L_UnarchiveEvents( Archiver &arc ); + +#endif + + static Container *commandList; + static Container *flagList; + static Container *sortedList; + static Container *eventDefList; + static qboolean dirtylist; + + static int compareEvents( const void *arg1, const void *arg2 ); + static void SortEventList( void ); + static int FindEvent( const char *name ); + static int FindEvent( str &name ); + static void PrintEvent( Event *ev ); + + public: + CLASS_PROTOTYPE( Event ); + + Event *next; // next event in the list, used for event recycling + Event *prev; // previous event int the list, used for event recycling + + void * operator new( size_t ); + void operator delete( void * ); + + static int NumEventCommands( void ); + static void ListCommands( const char *mask = NULL ); + static void ListDocumentation( const char *mask, qboolean print_to_file = qfalse ); + static void PendingEvents( const char *mask = NULL ); + static void PrintEventDocumentation( Event * event, FILE *event_file = NULL, qboolean html = qfalse ); + static int MapSortedEventIndex( int index ); + + Event(); + Event( Event &ev ); + Event( Event *ev ); + Event + ( + const char *command, + int flags, + const char *formatspec, + const char *argument_names, + const char *documentation + ); + Event( const char *command ); + Event( str &command ); + ~Event(); + + void SetupDocumentation( void ); + void DeleteDocumentation( void ); + void PrintDocumentation( FILE *event_file = NULL, qboolean html = qfalse ); + + str getName( void ); + + void SetSource( eventsource_t source ); + void SetLineNumber( int linenumber ); + void SetSourceObject( Listener *source ); + Listener *GetSourceObject( void ); + SafePtr *GetSourceObjectPointer( void ); + + eventsource_t GetSource( void ); + int GetLineNumber( void ); + int GetAnimationNumber( void ); + int GetAnimationFrame( void ); + void SetAnimationNumber( int anim ); + void SetAnimationFrame( int frame ); + + int GetFlags( void ); + + void Error( const char *fmt, ... ); + + static Event Find( const char *command ); + static qboolean Exists( const char *command ); + static Event Find( str &command ); + + Event& printInfo(void); + + friend bool operator==( const Event &a, const Event &b ); + friend bool operator!=( const Event &a, const Event &b ); + void operator=( const Event &ev ); + + operator int(); + operator const char *(); + + int NumArgs( void ); + + qboolean IsVectorAt( int pos ); + qboolean IsEntityAt( int pos ); + qboolean IsNumericAt( int pos ); + + const char *GetToken( int pos ); + const char *GetString( int pos ); + int GetInteger( int pos ); + float GetFloat( int pos ); + Vector GetVector( int pos ); + bool GetBoolean( int pos ); + + void AddToken( const char *text ); + void AddTokens( int argc, const char **argv ); + void AddString( const char *text ); + void AddString( str &text ); + void AddInteger( int val ); + void AddFloat( float val ); + void AddVector( Vector &vec ); + +#ifdef GAME_DLL + void AddEntity( Entity *ent ); + Entity *GetEntity( int pos ); + ScriptVariable *GetVariable( int pos ); + void SetThread( ScriptThread *thread ); + ScriptThread *GetThread( void ); + void SetConsoleEdict( gentity_t *consoleedict ); + gentity_t *GetConsoleEdict( void ); + + virtual void Archive( Archiver &arc ); +#endif + }; + +extern Event NullEvent; +extern Event EV_Remove; + +class Listener; + +class Listener : public Class + { + private: + void ScriptRemove( Event *e ); + + protected: + qboolean CheckEventFlags( Event *event ); + + public: + CLASS_PROTOTYPE( Listener ); + + ~Listener(); + void Remove( Event *e ); + qboolean ValidEvent( Event &e ); + qboolean ValidEvent( const char *name ); + qboolean EventPending( Event &ev ); + qboolean ProcessEvent( Event *event ); + qboolean ProcessEvent( Event &event ); + void PostEvent( Event *event, float time, int flags = 0 ); + void PostEvent( Event &event, float time, int flags = 0 ); + qboolean PostponeEvent( Event &event, float time ); + qboolean PostponeEvent( Event *event, float time ); + void CancelEventsOfType( Event *event ); + void CancelEventsOfType( Event &event ); + void CancelFlaggedEvents( int flags ); + void CancelPendingEvents( void ); + qboolean ProcessPendingEvents( void ); + }; + +inline void Event::SetSourceObject + ( + Listener *source + ) + + { + m_sourceobject = source; + } + +inline Listener *Event::GetSourceObject + ( + void + ) + + { + return m_sourceobject; + } + +inline SafePtr *Event::GetSourceObjectPointer + ( + void + ) + + { + return &m_sourceobject; + } + +inline qboolean Event::Exists + ( + const char *command + ) + + { + int num; + str c; + + if ( !commandList ) + { + initCommandList(); + } + + c = command; + num = FindEvent( c ); + if ( num ) + { + return true; + } + + return false; + } + + +inline Event Event::Find + ( + const char *command + ) + + { + int num; + str c; + + if ( !commandList ) + { + initCommandList(); + } + + c = command; + num = FindEvent( c ); + if ( num ) + { + Event ev( num ); + return ev; + } + + return NullEvent; + } + +inline Event Event::Find + ( + str &command + ) + + { + int num; + + if ( !commandList ) + { + initCommandList(); + } + + num = FindEvent( command ); + if ( num ) + { + Event ev( num ); + return ev; + } + + return NullEvent; + } + +inline void Event::SetSource + ( + eventsource_t source + ) + + { + info.source = ( unsigned )source; + } + +inline void Event::SetLineNumber + ( + int linenumber + ) + + { + info.linenumber = linenumber; + } + +inline eventsource_t Event::GetSource + ( + void + ) + + { + return ( eventsource_t )info.source; + } + +inline int Event::GetAnimationNumber + ( + void + ) + + { + return anim_number; + } + +inline int Event::GetAnimationFrame + ( + void + ) + + { + return anim_frame; + } + +inline void Event::SetAnimationNumber + ( + int anim + ) + + { + anim_number = anim; + } + +inline void Event::SetAnimationFrame + ( + int frame + ) + + { + anim_frame = frame; + } + +inline int Event::GetLineNumber + ( + void + ) + + { + // linenumber does double duty in the case of the console commands + if ( info.source == EV_FROM_SCRIPT ) + { + return info.linenumber; + } + + return 0; + } + +inline int Event::GetFlags + ( + void + ) + + { + return info.flags; + } + +inline str Event::getName + ( + void + ) + + { + assert( name || !eventnum ); + + if ( !name ) + { + return "NULL"; + } + + return name; + } + +inline Event& Event::printInfo + ( + void + ) + + { + EVENT_DPrintf( "event '%s' is number %d\n", getName().c_str(), eventnum ); + + return *this; + } + +inline bool operator== + ( + const Event &a, + const Event &b + ) + + { + return a.eventnum == b.eventnum; + } + +inline bool operator!= + ( + const Event &a, + const Event &b + ) + + { + return a.eventnum != b.eventnum; + } + +inline void Event::operator= + ( + const Event &ev + ) + { + eventnum = ev.eventnum; + info = ev.info; + if ( ev.data ) + { + int i; + + data = new Container; + data->Resize( ev.data->NumObjects() ); + for( i = 1; i < ev.data->NumObjects(); i++ ) + { + data->AddObject( ev.data->ObjectAt( i ) ); + } + } + name = ev.name; + definition = NULL; + threadnum = ev.threadnum; + anim_number = ev.anim_number; + anim_frame = ev.anim_frame; + m_sourceobject = ev.m_sourceobject; + time = ev.time; + flags = ev.flags; + } + + +inline Event::operator int() + { + return eventnum; + } + +inline Event::operator const char *() + { + return getName().c_str(); + } + +inline int Event::NumArgs + ( + void + ) + + { + if ( !data ) + { + return 0; + } + + return ( data->NumObjects() ); + } + +#ifdef GAME_DLL +inline void Event::AddEntity + ( + Entity *ent + ) + + { + if ( !data ) + { + data = new Container; + data->Resize( 1 ); + } + + + EventVar var( ent ); + data->AddObject( var ); + } +#endif + +inline void Event::AddToken + ( + const char *text + ) + + { + if ( !data ) + { + data = new Container; + data->Resize( 1 ); + } + + EventVar var( text ); + data->AddObject( var ); + } + +inline void Event::AddTokens + ( + int argc, + const char **argv + ) + + { + int i; + + if ( !data ) + { + data = new Container; + data->Resize( argc ); + } + + for( i = 0; i < argc; i++ ) + { + assert( argv[ i ] ); + EventVar var( argv[ i ] ); + data->AddObject( var ); + } + } + +inline void Event::AddString + ( + const char *text + ) + + { + if ( !data ) + { + data = new Container; + data->Resize( 1 ); + } + + EventVar var( text ); + data->AddObject( var ); + } + +inline void Event::AddString + ( + str &text + ) + + { + if ( !data ) + { + data = new Container; + data->Resize( 1 ); + } + + EventVar var( text ); + data->AddObject( var ); + } + +inline void Event::AddInteger + ( + int val + ) + + { + if ( !data ) + { + data = new Container; + data->Resize( 1 ); + } + + EventVar var( val ); + data->AddObject( var ); + } + +inline void Event::AddFloat + ( + float val + ) + + { + if ( !data ) + { + data = new Container; + data->Resize( 1 ); + } + + EventVar var( val ); + data->AddObject( var ); + } + +inline void Event::AddVector + ( + Vector &vec + ) + + { + if ( !data ) + { + data = new Container; + data->Resize( 1 ); + } + + EventVar var( vec ); + data->AddObject( var ); + } + +inline const char *Event::GetToken + ( + int pos + ) + + { + if ( !data || ( pos < 1 ) || ( data->NumObjects() < pos ) ) + { + Error( "Index %d out of range.", pos ); + return ""; + } + + return data->ObjectAt( pos ).GetToken( *this ); + } + +inline const char *Event::GetString + ( + int pos + ) + + { + if ( !data || ( pos < 1 ) || ( data->NumObjects() < pos ) ) + { + Error( "Index %d out of range.", pos ); + return ""; + } + + return data->ObjectAt( pos ).GetString( *this ); + } + +inline int Event::GetInteger + ( + int pos + ) + + { + if ( !data || ( pos < 1 ) || ( data->NumObjects() < pos ) ) + { + Error( "Index %d out of range.", pos ); + return 0; + } + + return data->ObjectAt( pos ).GetInteger( *this ); + } + +inline float Event::GetFloat + ( + int pos + ) + + { + if ( !data || ( pos < 1 ) || ( data->NumObjects() < pos ) ) + { + Error( "Index %d out of range.", pos ); + return 0; + } + + return data->ObjectAt( pos ).GetFloat( *this ); + } + +inline Vector Event::GetVector + ( + int pos + ) + + { + if ( !data || ( pos < 1 ) || ( data->NumObjects() < pos ) ) + { + Error( "Index %d out of range.", pos ); + return vec_zero; + } + + return data->ObjectAt( pos ).GetVector( *this ); + } + +inline bool Event::GetBoolean + ( + int pos + ) + + { + int val; + + val = this->GetInteger( pos ); + + return ( val != 0 ) ? true : false; + } + +#ifdef GAME_DLL + +inline Entity *Event::GetEntity + ( + int pos + ) + + { + if ( !data || ( pos < 1 ) || ( data->NumObjects() < pos ) ) + { + Error( "Index %d out of range.", pos ); + return NULL; + } + + return data->ObjectAt( pos ).GetEntity( *this ); + } + +inline ScriptVariable *Event::GetVariable + ( + int pos + ) + + { + if ( !data || ( pos < 1 ) || ( data->NumObjects() < pos ) ) + { + Error( "Index %d out of range.", pos ); + return NULL; + } + + return data->ObjectAt( pos ).GetVariable( *this ); + } + +#endif + +inline qboolean Listener::ProcessEvent + ( + Event &event + ) + + { + Event *ev; + + ev = new Event( event ); + return ProcessEvent( ev ); + } + +inline void Listener::PostEvent + ( + Event &event, + float time, + int flags + ) + + { + Event *ev; + + ev = new Event( event ); + PostEvent( ev, time, flags ); + } + +inline qboolean Listener::PostponeEvent + ( + Event *event, + float time + ) + + { + return PostponeEvent( *event, time ); + } + +inline void Listener::CancelEventsOfType + ( + Event &event + ) + + { + CancelEventsOfType( &event ); + } + +#endif + diff --git a/source/source/cgame/script.cpp b/source/source/cgame/script.cpp new file mode 100644 index 0000000..eeb3bf2 --- /dev/null +++ b/source/source/cgame/script.cpp @@ -0,0 +1,1038 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/cgame/script.cpp $ +// $Revision:: 4 $ +// $Date:: 7/13/00 10:17a $ +// +// Copyright (C) 1999 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source is may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/cgame/script.cpp $ +// +// 4 7/13/00 10:17a Markd +// fixed a memory leak +// +// 3 3/14/00 3:35p Aldie +// Fix syntax error +// +// 2 3/14/00 3:22p Aldie +// Changed some client side emitter functionality and added func_emitter +// +// 1 9/10/99 10:51a Jimdose +// +// 1 9/09/99 7:51p Jimdose +// +// 3 7/29/99 3:31p Aldie +// Updated to new class system +// +// 2 7/01/99 6:56p Aldie +// Update UI +// +// 1 6/29/99 4:02p Aldie +// +// 1 6/23/99 2:50p Jimdose +// +// DESCRIPTION: +// C++ implementaion of tokenizing text interpretation. Class accepts filename +// to load or pointer to preloaded text data. Standard tokenizing operations +// such as skip white-space, get string, get integer, get float, get m_token, +// and skip line are implemented. +// +// Note: all '//', '#', and ';' are treated as comments. Probably should +// make this behaviour toggleable. +// + +#include "script.h" +#include "../qcommon/qcommon.h" +#include + +#if defined ( CGAME_DLL ) +// +// cgame dll specific defines +// +#include "cg_local.h" + +#define FILE_FS_FreeFile cgi.FS_FreeFile +#define FILE_FS_ReadFile(a,b) cgi.FS_ReadFile(a,b,false) +#define FILE_Malloc cgi.Malloc +#define FILE_Free cgi.Free + +#else + +#define FILE_FS_FreeFile FS_FreeFile +#define FILE_FS_ReadFile FS_ReadFile +#define FILE_Malloc Z_Malloc +#define FILE_Free Z_Free + +#endif + +#define TOKENCOMMENT (';') +//#define TOKENCOMMENT2 ('#') +#define TOKENEOL ('\n') +#define TOKENNULL ('\0') +#define TOKENSPACE (' ') + +CLASS_DECLARATION( Class, Script, NULL ) + { + { NULL, NULL } + }; + +Script::~Script() + { + Close(); + } + +Script::Script() + { + buffer = NULL; + m_script_p = NULL; + m_end_p = NULL; + m_line = 0; + m_releaseBuffer = false; + m_tokenready = false; + memset( m_token, 0, sizeof( m_token ) ); + } + +void Script::Close + ( + void + ) + + { + if ( m_releaseBuffer && buffer ) + { + FILE_Free( buffer ); + } + + buffer = NULL; + m_script_p = NULL; + m_end_p = NULL; + m_line = 0; + m_releaseBuffer = false; + m_tokenready = false; + memset( m_token, 0, sizeof( m_token ) ); + } + +/* +============== += += Filename += +============== +*/ + +const char *Script::Filename + ( + void + ) + + { + return m_filename.c_str(); + } + +/* +============== += += GetLineNumber += +============== +*/ + +int Script::GetLineNumber + ( + void + ) + + { + return m_line; + } + +/* +============== += += Reset += +============== +*/ + +void Script::Reset + ( + void + ) + + { + m_script_p = buffer; + m_line = 1; + m_tokenready = false; + } + +/* +============== += += MarkPosition += +============== +*/ + +void Script::MarkPosition + ( + scriptmarker_t *mark + ) + + { + assert( mark ); + + mark->tokenready = m_tokenready; + mark->offset = m_script_p - buffer; + mark->line = m_line; + strcpy( mark->token, m_token ); + } + +/* +============== += += RestorePosition += +============== +*/ + +void Script::RestorePosition + ( + scriptmarker_t *mark + ) + + { + assert( mark ); + + m_tokenready = mark->tokenready; + m_script_p = buffer + mark->offset; + m_line = mark->line; + strcpy( m_token, mark->token ); + + assert( m_script_p <= m_end_p ); + if ( m_script_p > m_end_p ) + { + m_script_p = m_end_p; + } + } + +/* +============== += += SkipToEOL += +============== +*/ + +bool Script::SkipToEOL + ( + void + ) + + { + if ( m_script_p >= m_end_p ) + { + return true; + } + + while( *m_script_p != TOKENEOL ) + { + if ( m_script_p >= m_end_p ) + { + return true; + } + m_script_p++; + } + return false; + } + +/* +============== += += CheckOverflow += +============== +*/ + +void Script::CheckOverflow + ( + void + ) + + { + if ( m_script_p >= m_end_p ) + { + Com_Error( ERR_DROP, "End of token file reached prematurely reading %s\n", m_filename.c_str() ); + } + } + +/* +============== += += SkipWhiteSpace += +============== +*/ + +void Script::SkipWhiteSpace + ( + bool crossline + ) + + { + // + // skip space + // + CheckOverflow(); + + while( ( *m_script_p <= TOKENSPACE ) || ( *m_script_p == ',' ) ) + { + if ( *m_script_p++ == TOKENEOL ) + { + if ( !crossline ) + { + Com_Error( ERR_DROP, "Line %i is incomplete in file %s\n", m_line, m_filename.c_str() ); + } + + m_line++; + } + CheckOverflow(); + } + } + +bool Script::AtComment + ( + void + ) + + { + if ( m_script_p >= m_end_p ) + { + return false; + } + + if ( *m_script_p == TOKENCOMMENT ) + { + return true; + } + +// if ( *m_script_p == TOKENCOMMENT2 ) + //{ + //return true; + //} + + // Two or more character comment specifiers + if ( ( m_script_p + 1 ) >= m_end_p ) + { + return false; + } + + if ( ( *m_script_p == '/' ) && ( *( m_script_p + 1 ) == '/' ) ) + { + return true; + } + + return false; + } + +/* +============== += += SkipNonToken += +============== +*/ + +void Script::SkipNonToken + ( + bool crossline + ) + + { + // + // skip space and comments + // + SkipWhiteSpace( crossline ); + while( AtComment() ) + { + SkipToEOL(); + SkipWhiteSpace( crossline ); + } + } + +/* +============================================================================= += += Token section += +============================================================================= +*/ + +/* +============== += += TokenAvailable += +============== +*/ + +bool Script::TokenAvailable + ( + bool crossline + ) + + { + if ( m_script_p >= m_end_p ) + { + return false; + } + + while ( 1 ) + { + while ( *m_script_p <= TOKENSPACE ) + { + if ( *m_script_p == TOKENEOL ) + { + if ( crossline==false ) + { + return( false ); + } + m_line++; + } + + m_script_p++; + if ( m_script_p >= m_end_p ) + { + return false; + } + } + + if ( AtComment() ) + { + bool done; + + done = SkipToEOL(); + if ( done ) + { + return false; + } + } + else + { + break; + } + } + + return true; + } + +/* +============== += += CommentAvailable += +============== +*/ + +bool Script::CommentAvailable + ( + bool crossline + ) + + { + const char *searchptr; + + searchptr = m_script_p; + + if ( searchptr >= m_end_p ) + { + return false; + } + + while ( *searchptr <= TOKENSPACE ) + { + if ( ( *searchptr == TOKENEOL ) && ( !crossline ) ) + { + return false; + } + searchptr++; + if ( searchptr >= m_end_p ) + { + return false; + } + } + + return true; + } + + +/* +============== += += UnGet += += Signals that the current token was not used, and should be reported += for the next GetToken. Note that + +GetToken (true); +UnGetToken (); +GetToken (false); + += could cross a line boundary. += +============== +*/ + +void Script::UnGetToken + ( + void + ) + + { + m_tokenready = true; + } + +/* +============== += += Get += +============== +*/ +bool Script::AtString + ( + bool crossline + ) + + { + // + // skip space + // + SkipNonToken( crossline ); + + return ( *m_script_p == '"' ); + } + +/* +============== += += Get += +============== +*/ + +const char *Script::GetToken + ( + bool crossline + ) + + { + char *token_p; + + // is a token already waiting? + if ( m_tokenready ) + { + m_tokenready = false; + return m_token; + } + + // + // skip space + // + SkipNonToken( crossline ); + + // + // copy token + // + + if ( *m_script_p == '"' ) + { + return GetString( crossline ); + } + + token_p = m_token; + while( *m_script_p > TOKENSPACE && *m_script_p != ',' && !AtComment() ) + { + if ( ( *m_script_p == '\\' ) && ( m_script_p < m_end_p - 1 ) ) + { + m_script_p++; + switch( *m_script_p ) + { + case 'n' : *token_p++ = '\n'; break; + case 'r' : *token_p++ = '\n'; break; + case '\'' : *token_p++ = '\''; break; + case '\"' : *token_p++ = '\"'; break; + case '\\' : *token_p++ = '\\'; break; + default: *token_p++ = *m_script_p; break; + } + m_script_p++; + } + else + { + *token_p++ = *m_script_p++; + } + + if ( token_p == &m_token[ MAXTOKEN ] ) + { + Com_Error( ERR_DROP, "Token too large on line %i in file %s\n", m_line, m_filename.c_str() ); + } + + if ( m_script_p == m_end_p ) + { + break; + } + } + + *token_p = 0; + + return m_token; + } + +/* +============== += += GetLine += +============== +*/ + +const char *Script::GetLine + ( + bool crossline + ) + + { + const char *start; + int size; + + // is a token already waiting? + if ( m_tokenready ) + { + m_tokenready = false; + return m_token; + } + + // + // skip space + // + SkipNonToken( crossline ); + + // + // copy token + // + start = m_script_p; + SkipToEOL(); + size = m_script_p - start; + if ( size < MAXTOKEN - 1 ) + { + memcpy( m_token, start, size ); + m_token[ size ] = '\0'; + } + else + { + Com_Error( ERR_DROP, "Token too large on line %i in file %s\n", m_line, m_filename.c_str() ); + } + + return m_token; + } + +/* +============== += += GetRaw += +============== +*/ + +const char *Script::GetRaw + ( + void + ) + + { + const char *start; + int size; + + // + // skip white space + // + SkipWhiteSpace( true ); + + // + // copy token + // + start = m_script_p; + SkipToEOL(); + size = m_script_p - start; + if ( size < MAXTOKEN - 1 ) + { + memset( m_token, 0, sizeof( m_token ) ); + memcpy( m_token, start, size ); + } + else + { + Com_Error( ERR_DROP, "Token too large on line %i in file %s\n", m_line, m_filename.c_str() ); + } + + return m_token; + } + +/* +============== += += GetString += +============== +*/ + +const char *Script::GetString + ( + bool crossline + ) + + { + int startline; + char *token_p; + + // is a token already waiting? + if ( m_tokenready ) + { + m_tokenready = false; + return m_token; + } + + // + // skip space + // + SkipNonToken( crossline ); + + if ( *m_script_p != '"' ) + { + Com_Error( ERR_DROP, "Expecting string on line %i in file %s\n", m_line, m_filename.c_str() ); + } + + m_script_p++; + + startline = m_line; + token_p = m_token; + while( *m_script_p != '"' ) + { + if ( *m_script_p == TOKENEOL ) + { + Com_Error( ERR_DROP, "Line %i is incomplete while reading string in file %s\n", m_line, m_filename.c_str() ); + } + + if ( ( *m_script_p == '\\' ) && ( m_script_p < m_end_p - 1 ) ) + { + m_script_p++; + switch( *m_script_p ) + { + case 'n' : *token_p++ = '\n'; break; + case 'r' : *token_p++ = '\n'; break; + case '\'' : *token_p++ = '\''; break; + case '\"' : *token_p++ = '\"'; break; + case '\\' : *token_p++ = '\\'; break; + default: *token_p++ = *m_script_p; break; + } + m_script_p++; + } + else + { + *token_p++ = *m_script_p++; + } + + if ( m_script_p >= m_end_p ) + { + Com_Error( ERR_DROP, "End of token file reached prematurely while reading string on\n" + "line %d in file %s\n", startline, m_filename.c_str() ); + } + + if ( token_p == &m_token[ MAXTOKEN ] ) + { + Com_Error( ERR_DROP, "String too large on line %i in file %s\n", m_line, m_filename.c_str() ); + } + } + + *token_p = 0; + + // skip last quote + m_script_p++; + + return m_token; + } + +const char *Script::GetExpression + ( + bool crossline + ) + + { + char *token_p; + + // is a token already waiting? + if ( m_tokenready ) + { + m_tokenready = false; + return m_token; + } + + // + // skip space + // + SkipNonToken( crossline ); + + // + // copy token + // + + if ( *m_script_p == '"' ) + { + return GetString( crossline ); + } + + token_p = m_token; + while( *m_script_p != ',' && !AtComment() ) + { + if ( ( *m_script_p == '\\' ) && ( m_script_p < m_end_p - 1 ) ) + { + m_script_p++; + switch( *m_script_p ) + { + case 'n' : *token_p++ = '\n'; break; + case 'r' : *token_p++ = '\n'; break; + case '\'' : *token_p++ = '\''; break; + case '\"' : *token_p++ = '\"'; break; + case '\\' : *token_p++ = '\\'; break; + default: *token_p++ = *m_script_p; break; + } + m_script_p++; + } + else + { + *token_p++ = *m_script_p++; + } + + if ( token_p == &m_token[ MAXTOKEN ] ) + { + Com_Error( ERR_DROP, "Token too large on line %i in file %s\n", m_line, m_filename.c_str() ); + } + + if ( m_script_p == m_end_p ) + { + break; + } + } + + *token_p = 0; + + return m_token; + } + +/* +============== += += GetSpecific += +============== +*/ + +bool Script::GetSpecific + ( + const char *string + ) + + { + do + { + if ( !TokenAvailable( true ) ) + { + return false; + } + GetToken( true ); + } + while( strcmp( m_token, string ) ); + + return true; + } + +/* +============== += += GetInteger += +============== +*/ + +int Script::GetInteger + ( + bool crossline + ) + + { + GetToken( crossline ); + return atoi( m_token ); + } + +/* +============== += += GetDouble += +============== +*/ + +double Script::GetDouble + ( + bool crossline + ) + + { + GetToken( crossline ); + return atof( m_token ); + } + +/* +============== += += GetFloat += +============== +*/ + +float Script::GetFloat + ( + bool crossline + ) + + { + return ( float )GetDouble( crossline ); + } + +/* +============== += += GetVector += +============== +*/ + +Vector Script::GetVector + ( + bool crossline + ) + + { + return Vector( GetFloat( crossline ), GetFloat( crossline ), GetFloat( crossline ) ); + } + +/* +=================== += += LinesInFile += +=================== +*/ +int Script::LinesInFile + ( + void + ) + + { + bool temp_tokenready; + const char *temp_script_p; + int temp_line; + char temp_token[ MAXTOKEN ]; + int numentries; + + temp_tokenready = m_tokenready; + temp_script_p = m_script_p; + temp_line = m_line; + strcpy( temp_token, m_token ); + + numentries = 0; + + Reset(); + while( TokenAvailable( true ) ) + { + GetLine( true ); + numentries++; + } + + m_tokenready = temp_tokenready; + m_script_p = temp_script_p; + m_line = temp_line; + strcpy( m_token, temp_token ); + + return numentries; + } + +/* +============== += += Parse += +============== +*/ + +void Script::Parse + ( + char *data, + int length, + const char *name + ) + + { + Close(); + + buffer = data; + Reset(); + m_end_p = m_script_p + length; + this->length = length; + m_filename = name; + } + +/* +============== += += Load += +============== +*/ + +void Script::LoadFile + ( + const char *name + ) + + { + int length; + char *buf; + + Close(); + + length = FILE_FS_ReadFile( name, (void **)&buf ); + + if ( length == -1 ) + { + error( "LoadFile", "Couldn't load %s\n", name ); + } + + buffer = ( char * )FILE_Malloc( length ); + memcpy( buffer, buf, length ); + FILE_FS_FreeFile( buf ); + + Parse( buffer, length, name ); + m_releaseBuffer = true; + } + +const char *Script::Token + ( + void + ) + + { + return m_token; + } diff --git a/source/source/cgame/script.h b/source/source/cgame/script.h new file mode 100644 index 0000000..fe1a73d --- /dev/null +++ b/source/source/cgame/script.h @@ -0,0 +1,158 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/client/script.h $ +// $Revision:: 2 $ +// $Date:: 9/28/99 4:26p $ +// +// Copyright (C) 1999 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source is may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/client/script.h $ +// +// 2 9/28/99 4:26p Markd +// merged listener, class and vector between 3 projects +// +// 1 9/10/99 10:51a Jimdose +// +// 1 9/09/99 7:51p Jimdose +// +// 2 7/01/99 6:56p Aldie +// Update UI +// +// 1 6/29/99 4:02p Aldie +// +// 1 6/23/99 2:50p Jimdose +// +// DESCRIPTION: +// C++ implementaion of tokenizing text interpretation. Class accepts filename +// to load or pointer to preloaded text data. Standard tokenizing operations +// such as skip white-space, get string, get integer, get float, get token, +// and skip line are implemented. +// +// Note: all '//', '#', and ';' are treated as comments. Probably should +// make this behaviour toggleable. +// + +#ifndef __SCRIPT_H__ +#define __SCRIPT_H__ + +#include "class.h" +#include "vector.h" +#include "str.h" + +#define MAXTOKEN 256 + +typedef struct + { + bool tokenready; + int offset; + int line; + char token[ MAXTOKEN ]; + } scriptmarker_t; + +class Script : public Class + { + protected: + bool m_tokenready; + + str m_filename; + const char *m_script_p; + const char *m_end_p; + + int m_line; + char m_token[ MAXTOKEN ]; + + bool m_releaseBuffer; + + bool AtComment( void ); + void CheckOverflow( void ); + + public: + char *buffer; + int length; + + CLASS_PROTOTYPE( Script ); + + ~Script(); + Script(); + void Close( void ); + const char *Filename( void ); + int GetLineNumber( void ); + void Reset( void ); + void MarkPosition( scriptmarker_t *mark ); + void RestorePosition( scriptmarker_t *mark ); + bool SkipToEOL( void ); + void SkipWhiteSpace( bool crossline ); + void SkipNonToken( bool crossline ); + bool TokenAvailable( bool crossline ); + bool CommentAvailable( bool crossline ); + void UnGetToken( void ); + bool AtString( bool crossline ); + const char *GetToken( bool crossline ); + const char *GetLine( bool crossline ); + const char *GetRaw( void ); + const char *GetString( bool crossline ); + const char *GetExpression( bool crossline ); + bool GetSpecific( const char *string ); + int GetInteger( bool crossline ); + double GetDouble( bool crossline ); + float GetFloat( bool crossline ); + Vector GetVector( bool crossline ); + int LinesInFile( void ); + void Parse( char *data, int length, const char *name ); + void LoadFile( const char *name ); + const char *Token( void ); +#if 0 + virtual void Archive( Archiver &arc ); + virtual void Unarchive( Archiver &arc ); +#endif + }; + +#if 0 +inline void Script::Archive + ( + Archiver &arc + ) + { + Class::Archive( arc ); + + arc.WriteString( m_filename ); + arc.WriteBoolean( m_tokenready ); + // + // save out current pointer as an offset + // + arc.WriteInteger( m_script_p - buffer ); + arc.WriteInteger( m_line ); + arc.WriteRaw( m_token, sizeof( m_token ) ); + } + +inline void Script::Unarchive + ( + Archiver &arc + ) + { + int i; + + Class::Unarchive( arc ); + + arc.ReadString( &m_filename ); + // + // load the file in + // + LoadFile( m_filename.c_str() ); + + arc.ReadBoolean( &m_tokenready ); + arc.ReadInteger( &i ); + // + // restore the script pointer + // + m_script_p = buffer + i; + arc.ReadInteger( &m_line ); + arc.ReadRaw( m_token, sizeof( m_token ) ); + } +#endif + +#endif diff --git a/source/source/cgame/str.cpp b/source/source/cgame/str.cpp new file mode 100644 index 0000000..cd48ad1 --- /dev/null +++ b/source/source/cgame/str.cpp @@ -0,0 +1,657 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/str.cpp $ +// $Revision:: 9 $ +// $Author:: Jimdose $ +// $Date:: 3/22/00 3:22p $ +// +// Copyright (C) 1997 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source is may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/str.cpp $ +// +// 9 3/22/00 3:22p Jimdose +// moved len from str to strdata +// +// 8 3/17/00 3:47p Markd +// changed ordering of include files to avoid sprintf error +// +// 7 10/06/99 10:01a Markd +// Fixed compiler warnings +// +// 6 10/05/99 2:03p Markd +// Added warning about files being in multiple projects +// +// 5 10/04/99 5:26p Morbid +// +// 4 10/03/99 3:48p Markd +// Added client and cgame listener and class documentation events +// +// 3 9/29/99 4:38p Morbid +// Added snprintf +// +// 2 9/24/99 1:55p Morbid +// Strings from Uber +// +// 1 9/10/99 10:55a Jimdose +// +// 1 9/08/99 3:16p Aldie +// +// DESCRIPTION: +// Simple, DLL portable string class +// +// WARNING: This file is shared between fgame, cgame and possibly the user interface. +// It is instanced in each one of these directories because of the way that SourceSafe works. +// + +#include "str.h" +#include +#include +#include +#include + +#ifdef _WIN32 +#pragma warning(disable : 4244) // 'conversion' conversion from 'type1' to 'type2', possible loss of data +#pragma warning(disable : 4710) // function 'blah' not inlined +#endif + +static const int STR_ALLOC_GRAN = 20; + +char *str::tolower + ( + char *s1 + ) + + { + char *s; + + s = s1; + while( *s ) + { + *s = ::tolower( *s ); + s++; + } + + return s1; + } + +char *str::toupper + ( + char *s1 + ) + + { + char *s; + + s = s1; + while( *s ) + { + *s = ::toupper( *s ); + s++; + } + + return s1; + } + +int str::icmpn + ( + const char *s1, + const char *s2, + int n + ) + + { + int c1; + int c2; + + do + { + c1 = *s1++; + c2 = *s2++; + + if ( !n-- ) + { + // strings are equal until end point + return 0; + } + + if ( c1 != c2 ) + { + if ( c1 >= 'a' && c1 <= 'z' ) + { + c1 -= ( 'a' - 'A' ); + } + + if ( c2 >= 'a' && c2 <= 'z' ) + { + c2 -= ( 'a' - 'A' ); + } + + if ( c1 < c2 ) + { + // strings less than + return -1; + } + else if ( c1 > c2 ) + { + // strings greater than + return 1; + } + } + } + while( c1 ); + + // strings are equal + return 0; + } + +int str::icmp + ( + const char *s1, + const char *s2 + ) + + { + int c1; + int c2; + + do + { + c1 = *s1++; + c2 = *s2++; + + if ( c1 != c2 ) + { + if ( c1 >= 'a' && c1 <= 'z' ) + { + c1 -= ( 'a' - 'A' ); + } + + if ( c2 >= 'a' && c2 <= 'z' ) + { + c2 -= ( 'a' - 'A' ); + } + + if ( c1 < c2 ) + { + // strings less than + return -1; + } + else if ( c1 > c2 ) + { + // strings greater than + return 1; + } + } + } + while( c1 ); + + // strings are equal + return 0; + } + +int str::cmpn + ( + const char *s1, + const char *s2, + int n + ) + + { + int c1; + int c2; + + do + { + c1 = *s1++; + c2 = *s2++; + + if ( !n-- ) + { + // strings are equal until end point + return 0; + } + + if ( c1 < c2 ) + { + // strings less than + return -1; + } + else if ( c1 > c2 ) + { + // strings greater than + return 1; + } + } + while( c1 ); + + // strings are equal + return 0; + } + +int str::cmp + ( + const char *s1, + const char *s2 + ) + + { + int c1; + int c2; + + do + { + c1 = *s1++; + c2 = *s2++; + + if ( c1 < c2 ) + { + // strings less than + return -1; + } + else if ( c1 > c2 ) + { + // strings greater than + return 1; + } + } + while( c1 ); + + // strings are equal + return 0; + } + +/* +============ +IsNumeric + +Checks a string to see if it contains only numerical values. +============ +*/ +bool str::isNumeric + ( + const char *str + ) + + { + int len; + int i; + bool dot; + + if ( *str == '-' ) + { + str++; + } + + dot = false; + len = strlen( str ); + for( i = 0; i < len; i++ ) + { + if ( !isdigit( str[ i ] ) ) + { + if ( ( str[ i ] == '.' ) && !dot ) + { + dot = true; + continue; + } + return false; + } + } + + return true; + } + +str operator+ + ( + const str& a, + const float b + ) + + { + char text[ 20 ]; + + str result( a ); + + sprintf( text, "%f", b ); + result.append( text ); + + return result; + } + +str operator+ + ( + const str& a, + const int b + ) + + { + char text[ 20 ]; + + str result( a ); + + sprintf( text, "%d", b ); + result.append( text ); + + return result; + } + +str operator+ + ( + const str& a, + const unsigned b + ) + + { + char text[ 20 ]; + + str result( a ); + + sprintf( text, "%u", b ); + result.append( text ); + + return result; + } + +str& str::operator+= + ( + const float a + ) + + { + char text[ 20 ]; + + sprintf( text, "%f", a ); + append( text ); + + return *this; + } + +str& str::operator+= + ( + const int a + ) + + { + char text[ 20 ]; + + sprintf( text, "%d", a ); + append( text ); + + return *this; + } + +str& str::operator+= + ( + const unsigned a + ) + + { + char text[ 20 ]; + + sprintf( text, "%u", a ); + append( text ); + + return *this; + } + +void str::CapLength + ( + int newlen + ) + + { + assert ( m_data ); + + if ( length() <= newlen ) + return; + + EnsureDataWritable (); + + m_data->data[newlen] = 0; + m_data->len = newlen; + } + +void str::EnsureDataWritable + ( + void + ) + + { + assert ( m_data ); + strdata *olddata; + int len; + + if ( !m_data->refcount ) + return; + + olddata = m_data; + len = length(); + + m_data = new strdata; + + EnsureAlloced ( len + 1, false ); + strncpy ( m_data->data, olddata->data, len+1 ); + m_data->len = len; + + olddata->DelRef (); + } + +void str::EnsureAlloced + ( + int amount, + bool keepold + ) + + { + if ( !m_data ) + m_data = new strdata; + + // Now, let's make sure it's writable + EnsureDataWritable (); + + char *newbuffer; + bool wasalloced = ( m_data->alloced != 0 ); + + if ( amount < m_data->alloced ) + return; + + assert ( amount ); + + if ( amount == 1 ) + { + m_data->alloced = 1; + } + else + { + int newsize, mod; + + mod = amount % STR_ALLOC_GRAN; + + if ( !mod ) + newsize = amount; + else + newsize = amount + STR_ALLOC_GRAN - mod; + + m_data->alloced = newsize; + } + + newbuffer = new char[m_data->alloced]; + + if ( wasalloced && keepold ) + { + strcpy ( newbuffer, m_data->data ); + } + + if ( m_data->data ) + { + delete [] m_data->data; + } + + m_data->data = newbuffer; + } + +void str::BackSlashesToSlashes + ( + void + ) + + { + int i; + + EnsureDataWritable (); + + for ( i=0; i < m_data->len; i++ ) + { + if ( m_data->data[i] == '\\' ) + m_data->data[i] = '/'; + } + } + +void str::snprintf + ( + char *dst, + int size, + const char *fmt, + ... + ) + + { + char buffer[0x10000]; + int len; + va_list argptr; + + va_start (argptr,fmt); + len = vsprintf (buffer,fmt,argptr); + va_end (argptr); + + assert ( len < size ); + + strncpy (dst, buffer, size-1); + } + +#ifdef _WIN32 +#pragma warning(disable : 4189) // local variable is initialized but not referenced +#endif + +/* +================= +TestStringClass + +This is a fairly rigorous test of the str class's functionality. +Because of the fairly global and subtle ramifications of a bug occuring +in this class, it should be run after any changes to the class. +Add more tests as functionality is changed. Tests should include +any possible bounds violation and NULL data tests. +================= +*/ +void TestStringClass + ( + void + ) + + { + char ch; // ch == ? + str *t; // t == ? + str a; // a.len == 0, a.data == "\0" + str b; // b.len == 0, b.data == "\0" + str c( "test" ); // c.len == 4, c.data == "test\0" + str d( c ); // d.len == 4, d.data == "test\0" + str e( reinterpret_cast(NULL) ); + // e.len == 0, e.data == "\0" ASSERT! + int i; // i == ? + + i = a.length(); // i == 0 + i = c.length(); // i == 4 + + const char *s1 = a.c_str(); // s1 == "\0" + const char *s2 = c.c_str(); // s2 == "test\0" + + t = new str(); // t->len == 0, t->data == "\0" + delete t; // t == ? + + b = "test"; // b.len == 4, b.data == "test\0" + t = new str( "test" ); // t->len == 4, t->data == "test\0" + delete t; // t == ? + + a = c; // a.len == 4, a.data == "test\0" +// a = ""; + a = NULL; // a.len == 0, a.data == "\0" ASSERT! + a = c + d; // a.len == 8, a.data == "testtest\0" + a = c + "wow"; // a.len == 7, a.data == "testwow\0" + a = c + reinterpret_cast(NULL); + // a.len == 4, a.data == "test\0" ASSERT! + a = "this" + d; // a.len == 8, a.data == "thistest\0" + a = reinterpret_cast(NULL) + d; + // a.len == 4, a.data == "test\0" ASSERT! + a += c; // a.len == 8, a.data == "testtest\0" + a += "wow"; // a.len == 11, a.data == "testtestwow\0" + a += reinterpret_cast(NULL); + // a.len == 11, a.data == "testtestwow\0" ASSERT! + + a = "test"; // a.len == 4, a.data == "test\0" + ch = a[ 0 ]; // ch == 't' + ch = a[ -1 ]; // ch == 0 ASSERT! + ch = a[ 1000 ]; // ch == 0 ASSERT! + ch = a[ 0 ]; // ch == 't' + ch = a[ 1 ]; // ch == 'e' + ch = a[ 2 ]; // ch == 's' + ch = a[ 3 ]; // ch == 't' + ch = a[ 4 ]; // ch == '\0' ASSERT! + ch = a[ 5 ]; // ch == '\0' ASSERT! + + a[ 1 ] = 'b'; // a.len == 4, a.data == "tbst\0" + a[ -1 ] = 'b'; // a.len == 4, a.data == "tbst\0" ASSERT! + a[ 0 ] = '0'; // a.len == 4, a.data == "0bst\0" + a[ 1 ] = '1'; // a.len == 4, a.data == "01st\0" + a[ 2 ] = '2'; // a.len == 4, a.data == "012t\0" + a[ 3 ] = '3'; // a.len == 4, a.data == "0123\0" + a[ 4 ] = '4'; // a.len == 4, a.data == "0123\0" ASSERT! + a[ 5 ] = '5'; // a.len == 4, a.data == "0123\0" ASSERT! + a[ 7 ] = '7'; // a.len == 4, a.data == "0123\0" ASSERT! + + a = "test"; // a.len == 4, a.data == "test\0" + b = "no"; // b.len == 2, b.data == "no\0" + + i = ( a == b ); // i == 0 + i = ( a == c ); // i == 1 + + i = ( a == "blow" ); // i == 0 + i = ( a == "test" ); // i == 1 + i = ( a == NULL ); // i == 0 ASSERT! + + i = ( "test" == b ); // i == 0 + i = ( "test" == a ); // i == 1 + i = ( NULL == a ); // i == 0 ASSERT! + + i = ( a != b ); // i == 1 + i = ( a != c ); // i == 0 + + i = ( a != "blow" ); // i == 1 + i = ( a != "test" ); // i == 0 + i = ( a != NULL ); // i == 1 ASSERT! + + i = ( "test" != b ); // i == 1 + i = ( "test" != a ); // i == 0 + i = ( NULL != a ); // i == 1 ASSERT! + + a = "test"; // a.data == "test" + b = a; // b.data == "test" + + a = "not"; // a.data == "not", b.data == "test" + + a = b; // a.data == b.data == "test" + + a += b; // a.data == "testtest", b.data = "test" + + a = b; + + a[1] = '1'; // a.data = "t1st", b.data = "test" + } + +#ifdef _WIN32 +#pragma warning(default : 4189) // local variable is initialized but not referenced +#pragma warning(disable : 4514) // unreferenced inline function has been removed +#endif diff --git a/source/source/cgame/str.h b/source/source/cgame/str.h new file mode 100644 index 0000000..672541f --- /dev/null +++ b/source/source/cgame/str.h @@ -0,0 +1,839 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/str.h $ +// $Revision:: 15 $ +// $Author:: Aldie $ +// $Date:: 7/25/00 11:32p $ +// +// Copyright (C) 1997 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source is may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/str.h $ +// +// 15 7/25/00 11:32p Aldie +// Made some changes to the memory system and fixed a memory allocation bug in +// Z_TagMalloc. Also changed a lot of classes to subclass from Class. +// +// 14 6/14/00 3:57p Markd +// fixed bug +// +// 13 6/14/00 3:50p Markd +// Cleaned up more Intel Compiler warnings +// +// 12 6/14/00 11:18a Markd +// cleaned up code using Intel compiler +// +// 11 5/25/00 4:29p Markd +// made archive a friend class of strings +// +// 10 3/22/00 3:23p Jimdose +// moved len from str to strdata +// +// 9 3/21/00 2:44p Jimdose +// fixed a bug where assigning the string to itself would corrupt the object +// +// 8 3/17/00 3:44p Markd +// added float, int and unsigned constructors +// +// 7 10/28/99 12:17p Morbid +// Fixed various const-ness issues with the compare functions +// +// 6 10/06/99 10:01a Markd +// Fixed compiler warnings +// +// 5 10/05/99 2:03p Markd +// Added warning about files being in multiple projects +// +// 4 9/29/99 4:38p Morbid +// Added snprintf +// +// 3 9/24/99 1:55p Morbid +// Strings from Uber +// +// 2 9/24/99 11:03a Morbid +// Added CapLength () +// +// 1 9/10/99 10:55a Jimdose +// +// 1 9/08/99 3:16p Aldie +// +// DESCRIPTION: +// Simple, DLL portable string class +// +// WARNING: This file is shared between fgame, cgame and possibly the user interface. +// It is instanced in each one of these directories because of the way that SourceSafe works. +// + +#ifndef __STR_H__ +#define __STR_H__ + +#include +#include +#include + +#ifdef _WIN32 +#pragma warning(disable : 4710) // function 'blah' not inlined +#endif + +void TestStringClass (); + +class strdata + { + public: + strdata () : len( 0 ), refcount ( 0 ), data ( NULL ), alloced ( 0 ) {} + ~strdata () + { + if ( data ) + delete [] data; + } + + void AddRef () { refcount++; } + bool DelRef () // True if killed + { + refcount--; + if ( refcount < 0 ) + { + delete this; + return true; + } + + return false; + } + + char *data; + int refcount; + int alloced; + int len; + }; + +#if 1 +class __declspec( dllexport ) str +#else +class str : public Class +#endif + { + protected: + + friend class Archiver; + strdata *m_data; + void EnsureAlloced ( int, bool keepold = true ); + void EnsureDataWritable (); + + public: + ~str(); + str(); + str( const char *text ); + str( const str& string ); + str( const str string, int start, int end ); + str( const char ch ); + str( const int num ); + str( const float num ); + str( const unsigned num ); + + + int length( void ) const; + const char * c_str( void ) const; + + void append( const char *text ); + void append( const str& text ); + + char operator[]( int index ) const; + char& operator[]( int index ); + + void operator=( const str& text ); + void operator=( const char *text ); + + friend str operator+( const str& a, const str& b ); + friend str operator+( const str& a, const char *b ); + friend str operator+( const char *a, const str& b ); + + friend str operator+( const str& a, const float b ); + friend str operator+( const str& a, const int b ); + friend str operator+( const str& a, const unsigned b ); + friend str operator+( const str& a, const bool b ); + friend str operator+( const str& a, const char b ); + + str& operator+=( const str& a ); + str& operator+=( const char *a ); + str& operator+=( const float a ); + str& operator+=( const char a ); + str& operator+=( const int a ); + str& operator+=( const unsigned a ); + str& operator+=( const bool a ); + + friend bool operator==( const str& a, const str& b ); + friend bool operator==( const str& a, const char *b ); + friend bool operator==( const char *a, const str& b ); + + friend bool operator!=( const str& a, const str& b ); + friend bool operator!=( const str& a, const char *b ); + friend bool operator!=( const char *a, const str& b ); + + operator const char * () const; + + int icmpn( const char *text, int n ) const; + int icmpn( const str& text, int n ) const; + int icmp( const char *text ) const; + int icmp( const str& text ) const; + int cmpn( const char *text, int n ) const; + int cmpn( const str& text, int n ) const; + + void tolower( void ); + void toupper( void ); + + static char *tolower( char *s1 ); + static char *toupper( char *s1 ); + + static int icmpn( const char *s1, const char *s2, int n ); + static int icmp( const char *s1, const char *s2 ); + static int cmpn( const char *s1, const char *s2, int n ); + static int cmp( const char *s1, const char *s2 ); + + static void snprintf ( char *dst, int size, const char *fmt, ... ); + + static bool isNumeric( const char *str ); + bool isNumeric( void ) const; + + void CapLength ( int ); + + void BackSlashesToSlashes (); + }; + + +inline char str::operator[]( int index ) const + { + assert ( m_data ); + + if ( !m_data ) + return 0; + + // don't include the '/0' in the test, because technically, it's out of bounds + assert( ( index >= 0 ) && ( index < m_data->len ) ); + + // In release mode, give them a null character + // don't include the '/0' in the test, because technically, it's out of bounds + if ( ( index < 0 ) || ( index >= m_data->len ) ) + { + return 0; + } + + return m_data->data[ index ]; + } + +inline int str::length( void ) const + { + return ( m_data != NULL ) ? m_data->len : 0; + } + +inline str::~str() + { + if ( m_data ) + { + m_data->DelRef (); + m_data = NULL; + } + } + +inline str::str() : m_data ( NULL ) + { + EnsureAlloced ( 1 ); + m_data->data[ 0 ] = 0; + } + +inline str::str + ( + const char *text + ) : m_data ( NULL ) + + { + int len; + + assert( text ); + + if ( text ) + { + len = strlen( text ); + EnsureAlloced ( len + 1 ); + strcpy( m_data->data, text ); + m_data->len = len; + } + else + { + EnsureAlloced ( 1 ); + m_data->data[ 0 ] = 0; + m_data->len = 0; + } + } + +inline str::str + ( + const str& text + ) : m_data ( NULL ) + + { + m_data = text.m_data; + m_data->AddRef (); + } + +inline str::str + ( + const str text, + int start, + int end + ) : m_data ( NULL ) + + { + int i; + int len; + + if ( end > text.length() ) + { + end = text.length(); + } + + if ( start > text.length() ) + { + start = text.length(); + } + + len = end - start; + if ( len < 0 ) + { + len = 0; + } + + EnsureAlloced ( len + 1 ); + + for( i = 0; i < len; i++ ) + { + m_data->data[ i ] = text[ start + i ]; + } + + m_data->data[ len ] = 0; + m_data->len = len; + } + +inline str::str + ( + const char ch + ) : m_data ( NULL ) + + { + EnsureAlloced ( 2 ); + + m_data->data[ 0 ] = ch; + m_data->data[ 1 ] = 0; + m_data->len = 1; + } + +inline str::str + ( + const float num + ) : m_data ( NULL ) + + { + char text[ 32 ]; + int len; + + sprintf( text, "%.3f", num ); + len = strlen( text ); + EnsureAlloced( len + 1 ); + strcpy( m_data->data, text ); + m_data->len = len; + } + +inline str::str + ( + const int num + ) : m_data ( NULL ) + + { + char text[ 32 ]; + int len; + + sprintf( text, "%d", num ); + len = strlen( text ); + EnsureAlloced( len + 1 ); + strcpy( m_data->data, text ); + m_data->len = len; + } + +inline str::str + ( + const unsigned num + ) : m_data ( NULL ) + + { + char text[ 32 ]; + int len; + + sprintf( text, "%u", num ); + len = strlen( text ); + EnsureAlloced( len + 1 ); + strcpy( m_data->data, text ); + m_data->len = len; + } + +inline const char *str::c_str( void ) const + { + assert( m_data ); + + return m_data->data; + } + +inline void str::append + ( + const char *text + ) + + { + int len; + + assert( text ); + + if ( text ) + { + len = length(); + len += strlen( text ); + EnsureAlloced( len + 1 ); + + strcat( m_data->data, text ); + m_data->len = len; + } + } + +inline void str::append + ( + const str& text + ) + + { + int len; + + len = length(); + len += text.length(); + EnsureAlloced ( len + 1 ); + + strcat ( m_data->data, text.c_str () ); + m_data->len = len; + } + + +inline char& str::operator[] + ( + int index + ) + + { + // Used for result for invalid indices + static char dummy = 0; + assert ( m_data ); + + // We don't know if they'll write to it or not + // if it's not a const object + EnsureDataWritable (); + + if ( !m_data ) + return dummy; + + // don't include the '/0' in the test, because technically, it's out of bounds + assert( ( index >= 0 ) && ( index < m_data->len ) ); + + // In release mode, let them change a safe variable + // don't include the '/0' in the test, because technically, it's out of bounds + if ( ( index < 0 ) || ( index >= m_data->len ) ) + { + return dummy; + } + + return m_data->data[ index ]; + } + +inline void str::operator= + ( + const str& text + ) + + { + // adding the reference before deleting our current reference prevents + // us from deleting our string if we are copying from ourself + text.m_data->AddRef(); + m_data->DelRef(); + m_data = text.m_data; + } + +inline void str::operator= + ( + const char *text + ) + + { + int len; + + assert( text ); + + if ( !text ) + { + // safe behaviour if NULL + EnsureAlloced ( 1, false ); + m_data->data[0] = 0; + m_data->len = 0; + return; + } + + if ( !m_data ) + { + len = strlen ( text ); + EnsureAlloced( len + 1, false ); + strcpy ( m_data->data, text ); + m_data->len = len; + return; + } + + if ( text == m_data->data ) + return; // Copying same thing. Punt. + + // If we alias and I don't do this, I could corrupt other strings... This + // will get called with EnsureAlloced anyway + EnsureDataWritable (); + + // Now we need to check if we're aliasing.. + if ( text >= m_data->data && text <= m_data->data + m_data->len ) + { + // Great, we're aliasing. We're copying from inside ourselves. + // This means that I don't have to ensure that anything is alloced, + // though I'll assert just in case. + int diff = text - m_data->data; + int i; + + assert ( strlen ( text ) < (unsigned) m_data->len ); + + for ( i = 0; text[i]; i++ ) + { + m_data->data[i] = text[i]; + } + + m_data->data[i] = 0; + + m_data->len -= diff; + + return; + } + + len = strlen( text ); + EnsureAlloced ( len + 1, false ); + strcpy( m_data->data, text ); + m_data->len = len; + } + +inline str operator+ + ( + const str& a, + const str& b + ) + + { + str result( a ); + + result.append( b ); + + return result; + } + +inline str operator+ + ( + const str& a, + const char *b + ) + + { + str result( a ); + + result.append( b ); + + return result; + } + +inline str operator+ + ( + const char *a, + const str& b + ) + + { + str result( a ); + + result.append( b ); + + return result; + } + +inline str operator+ + ( + const str& a, + const bool b + ) + + { + str result( a ); + + result.append( b ? "true" : "false" ); + + return result; + } + +inline str operator+ + ( + const str& a, + const char b + ) + + { + char text[ 2 ]; + + text[ 0 ] = b; + text[ 1 ] = 0; + + return a + text; + } + +inline str& str::operator+= + ( + const str& a + ) + + { + append( a ); + return *this; + } + +inline str& str::operator+= + ( + const char *a + ) + + { + append( a ); + return *this; + } + +inline str& str::operator+= + ( + const char a + ) + + { + char text[ 2 ]; + + text[ 0 ] = a; + text[ 1 ] = 0; + append( text ); + + return *this; + } + +inline str& str::operator+= + ( + const bool a + ) + + { + append( a ? "true" : "false" ); + return *this; + } + +inline bool operator== + ( + const str& a, + const str& b + ) + + { + return ( !strcmp( a.c_str(), b.c_str() ) ); + } + +inline bool operator== + ( + const str& a, + const char *b + ) + + { + assert( b ); + if ( !b ) + { + return false; + } + return ( !strcmp( a.c_str(), b ) ); + } + +inline bool operator== + ( + const char *a, + const str& b + ) + + { + assert( a ); + if ( !a ) + { + return false; + } + return ( !strcmp( a, b.c_str() ) ); + } + +inline bool operator!= + ( + const str& a, + const str& b + ) + + { + return !( a == b ); + } + +inline bool operator!= + ( + const str& a, + const char *b + ) + + { + return !( a == b ); + } + +inline bool operator!= + ( + const char *a, + const str& b + ) + + { + return !( a == b ); + } + +inline int str::icmpn + ( + const char *text, + int n + ) const + + { + assert( m_data ); + assert( text ); + + return str::icmpn( m_data->data, text, n ); + } + +inline int str::icmpn + ( + const str& text, + int n + ) const + + { + assert( m_data ); + assert( text.m_data ); + + return str::icmpn( m_data->data, text.m_data->data, n ); + } + +inline int str::icmp + ( + const char *text + ) const + + { + assert( m_data ); + assert( text ); + + return str::icmp( m_data->data, text ); + } + +inline int str::icmp + ( + const str& text + ) const + + { + assert( c_str () ); + assert( text.c_str () ); + + return str::icmp( c_str () , text.c_str () ); + } + +inline int str::cmpn + ( + const char *text, + int n + ) const + + { + assert( c_str () ); + assert( text ); + + return str::cmpn( c_str () , text, n ); + } + +inline int str::cmpn + ( + const str& text, + int n + ) const + + { + assert( c_str () ); + assert( text.c_str () ); + + return str::cmpn( c_str () , text.c_str () , n ); + } + +inline void str::tolower + ( + void + ) + + { + assert( m_data ); + + EnsureDataWritable (); + + str::tolower( m_data->data ); + } + +inline void str::toupper + ( + void + ) + + { + assert( m_data ); + + EnsureDataWritable (); + + str::toupper( m_data->data ); + } + +inline bool str::isNumeric + ( + void + ) const + + { + assert( m_data ); + return str::isNumeric( m_data->data ); + } + +inline str::operator const char * + ( + void + ) const + + { + return c_str (); + } + +#endif diff --git a/source/source/cgame/tr_types.h b/source/source/cgame/tr_types.h new file mode 100644 index 0000000..b3a1ba8 --- /dev/null +++ b/source/source/cgame/tr_types.h @@ -0,0 +1,335 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/cgame/tr_types.h $ +// $Revision:: 24 $ +// $Author:: Markd $ +// $Date:: 6/28/00 7:34p $ +// +// Copyright (C) 1998 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/cgame/tr_types.h $ +// +// 24 6/28/00 7:34p Markd +// Increased EXTENSIONS string size +// +// 23 6/20/00 11:55a Markd +// changed frames from bytes to shorts +// +// 22 3/31/00 11:45a Markd +// Added skyportal toggling support +// +// 21 3/17/00 6:37p Markd +// fixed 8 bit anim bug +// +// 20 3/04/00 2:47p Markd +// Made dynamic light types into bits so that they could be combined +// +// 19 2/25/00 12:31p Markd +// Added additive dynamic light support +// +// 18 2/21/00 7:02p Markd +// started adding old-school dlights and sky_alpha support +// +// 17 2/14/00 5:41p Jimdose +// added uselegs to refEntity_t +// +// 16 12/11/99 3:37p Markd +// q3a gold checkin, first time +// +// 15 11/11/99 11:35a Jimdose +// added usetorso tp refEntity_t +// +// 14 11/10/99 2:16p Jimdose +// added torso animation variables to refEntity_t +// +// 13 10/29/99 6:52p Jimdose +// added bone controllers +// +// 12 10/26/99 6:29p Jimdose +// added animation blending vars to refEntity_t +// +// 11 10/25/99 12:19p Jimdose +// made head and torso angles local to each entity +// +// 10 10/19/99 7:52p Markd +// Removed three part model system +// +// 9 10/14/99 4:51p Jimdose +// added head_angles and torso_angles to refdef_t +// +// 8 10/05/99 6:01p Aldie +// Added headers +// +// DESCRIPTION: +// Renderer types + +#ifndef __TR_TYPES_H +#define __TR_TYPES_H + + +#define MAX_DLIGHTS 32 // can't be increased, because bit flags are used on surfaces +#define MAX_ENTITIES 1023 // can't be increased without changing drawsurf bit packing +#define MAX_POINTS 32 +#define MAX_SPRITES 1024 + +// refdef flags +#define RDF_NOWORLDMODEL 1 // used for player configuration screen +#define RDF_HYPERSPACE 4 // teleportation effect + +typedef struct + { + float pos[2]; + float size[2]; + } letterloc_t; + +typedef struct + { + int indirection[256]; + letterloc_t locations[256]; + char name[255]; + float height; + float aspectRatio; + void *shader; + int trhandle; // the last renderer handle this font used + } fontheader_t; + +typedef struct { + vec3_t xyz; + float st[2]; + byte modulate[4]; +} polyVert_t; + +typedef struct poly_s { + qhandle_t hShader; + int numVerts; + polyVert_t *verts; +} poly_t; + +typedef enum { + RT_MODEL, + RT_POLY, + RT_SPRITE, + RT_BEAM, + RT_RAIL_CORE, + RT_RAIL_RINGS, + RT_LIGHTNING, + RT_PORTALSURFACE, // doesn't draw anything, just info for portals + + RT_MAX_REF_ENTITY_TYPE +} refEntityType_t; + +typedef enum { + lensflare = ( 1 << 0 ), + viewlensflare = ( 1 << 1 ), + additive = ( 1 << 2 ) +} dlighttype_t; + +struct tikiFrame_s; +struct dtiki_s; + +typedef struct { + refEntityType_t reType; + + int renderfx; + + qhandle_t hModel; // opaque type outside refresh + + // most recent data + vec3_t lightingOrigin; // so multi-part models can be lit identically (RF_LIGHTING_ORIGIN) + float shadowPlane; // projection shadows go here, stencils go slightly lower + + vec3_t axis[3]; // rotation vectors + qboolean nonNormalizedAxes; // axis are not normalized, i.e. they have scale + float origin[3]; // also used as MODEL_BEAM's "from" + int anim; // animation + int oldanim; // old animation + short oldframe; // old frame + short frame; // also used as MODEL_BEAM's diameter + float scale; // scale of the thing + + qboolean useAngles; + + // torso animation + int torso_anim; // animation + int torso_oldanim; // old animation + short torso_frame; + short torso_oldframe; // old frame + + // data for animation cross-blending + float crossblend_lerp; + float crossblend_backlerp; // 0.0 = current, 1.0 = old + + int crossblend_anim; // crossblend animation + short crossblend_frame; // crossblend anim frame + short crossblend_oldframe; // crossblend anim old frame + int uselegs; // non-zero means use leg animation + + float torso_crossblend_lerp; + float torso_crossblend_backlerp; // 0.0 = current, 1.0 = old + + int torso_crossblend_anim; // crossblend animation + short torso_crossblend_frame; // crossblend anim frame + short torso_crossblend_oldframe; // crossblend anim old frame + int usetorso; // non-zero means use torso animation + + // previous data for frame interpolation + float oldorigin[3]; // also used as MODEL_BEAM's "to" + float backlerp; // 0.0 = current, 1.0 = old + float torso_backlerp; // 0.0 = current, 1.0 = old + + // texturing + int skinNum; // inline skin index + qhandle_t customSkin; // NULL for default skin + qhandle_t customShader; // use one image for the entire thing + + // misc + byte shaderRGBA[4]; // colors used by colorSrc=vertex shaders + float shaderTexCoord[2]; // texture coordinates used by tcMod=vertex modifiers + float shaderTime; // subtracted from refdef time to control effect start times + + int entityNumber; // the real entity number + + byte surfaces[MAX_MODEL_SURFACES]; // the surface state of the entity + short shader_data[ 2 ]; // data passed in from shader manipulation + + int bone_tag[ NUM_BONE_CONTROLLERS ]; + vec4_t bone_quat[ NUM_BONE_CONTROLLERS ]; + + // renderer use only + struct tikiFrame_s *of, + *nf; + struct dtiki_s *tiki; + int bonestart; + + // extra sprite information + float radius; + float rotation; + +} refEntity_t; + +#define MAX_RENDER_STRINGS 8 +#define MAX_RENDER_STRING_LENGTH 32 + +typedef struct { + int x, y, width, height; + float fov_x, fov_y; + vec3_t vieworg; + vec3_t viewaxis[3]; // transformation matrix + + // time in milliseconds for shader effects and other time dependent rendering issues + int time; + + int rdflags; // RDF_NOWORLDMODEL, etc + + // 1 bits will prevent the associated area from rendering at all + byte areamask[MAX_MAP_AREA_BYTES]; + + // text messages for deform text shaders + char text[MAX_RENDER_STRINGS][MAX_RENDER_STRING_LENGTH]; + + // fog stuff + float farplane_distance; + vec3_t farplane_color; + qboolean farplane_cull; + + // sky portal stuff + qboolean sky_portal; + float sky_alpha; + vec3_t sky_origin; + vec3_t sky_axis[ 3 ]; + +} refdef_t; + + +typedef enum { + STEREO_CENTER, + STEREO_LEFT, + STEREO_RIGHT +} stereoFrame_t; + + +/* +** glconfig_t +** +** Contains variables specific to the OpenGL configuration +** being run right now. These are constant once the OpenGL +** subsystem is initialized. +*/ +typedef enum { + TC_NONE, + TC_S3TC +} textureCompression_t; + +typedef enum { + GLDRV_ICD, // driver is integrated with window system + // WARNING: there are tests that check for + // > GLDRV_ICD for minidriverness, so this + // should always be the lowest value in this + // enum set + GLDRV_STANDALONE, // driver is a non-3Dfx standalone driver + GLDRV_VOODOO // driver is a 3Dfx standalone driver +} glDriverType_t; + +typedef enum { + GLHW_GENERIC, // where everthing works the way it should + GLHW_3DFX_2D3D, // Voodoo Banshee or Voodoo3, relevant since if this is + // the hardware type then there can NOT exist a secondary + // display adapter + GLHW_RIVA128, // where you can't interpolate alpha + GLHW_RAGEPRO, // where you can't modulate alpha on alpha textures + GLHW_PERMEDIA2 // where you don't have src*dst +} glHardwareType_t; + + +typedef struct { + char renderer_string[ MAX_STRING_CHARS ]; + char vendor_string[ MAX_STRING_CHARS ]; + char version_string[ MAX_STRING_CHARS ]; + char extensions_string[ MAX_STRING_CHARS * 2 ]; + + int maxTextureSize; // queried from GL + int maxActiveTextures; // multitexture ability + + int colorBits, depthBits, stencilBits; + + glDriverType_t driverType; + glHardwareType_t hardwareType; + + qboolean deviceSupportsGamma; + textureCompression_t textureCompression; + qboolean textureEnvAddAvailable; + + int vidWidth, vidHeight; + // aspect is the screen's physical width / height, which may be different + // than scrWidth / scrHeight if the pixels are non-square + // normal screens should be 4/3, but wide aspect monitors may be 16/9 + float windowAspect; + + int displayFrequency; + + // synonymous with "does rendering consume the entire screen?", therefore + // a Voodoo or Voodoo2 will have this set to TRUE, as will a Win32 ICD that + // used CDS. + qboolean isFullscreen; + qboolean stereoEnabled; + qboolean smpActive; // dual processor +} glconfig_t; + +#if !defined _WIN32 + +#define _3DFX_DRIVER_NAME "libMesaVoodooGL.so.3.1" +#define OPENGL_DRIVER_NAME "libGL.so" + +#else + +#define _3DFX_DRIVER_NAME "3dfxvgl" +#define OPENGL_DRIVER_NAME "opengl32" + +#endif // !defined _WIN32 + + +#endif // __TR_TYPES_H diff --git a/source/source/cgame/vector.h b/source/source/cgame/vector.h new file mode 100644 index 0000000..9508bd3 --- /dev/null +++ b/source/source/cgame/vector.h @@ -0,0 +1,1092 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/vector.h $ +// $Revision:: 12 $ +// $Author:: Jimdose $ +// $Date:: 3/13/00 7:15p $ +// +// Copyright (C) 1997 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source is may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/vector.h $ +// +// 12 3/13/00 7:15p Jimdose +// made normalize return the length +// +// 11 1/24/00 7:53p Jimdose +// removed vec3 +// +// 10 1/22/00 12:28p Jimdose +// added vec3_t conversions for FuzzyEqual and CrossProduct +// +// 9 1/22/00 12:19p Jimdose +// added some missing cases for vec3_t conversion +// +// 8 1/22/00 12:13p Jimdose +// added vec3_t conversions so that .vec3() is no longer needed +// +// 7 1/21/00 7:32p Markd +// Put in fuzzy equal support into script variables +// +// 6 1/05/00 6:39p Jimdose +// AngleVectors now returns left instead of right. +// +// 5 1/05/00 5:29p Jimdose +// made toAngles consitant with vectoangles +// +// 4 12/10/99 11:16a Jimdose +// made right and up optional in AngleVectors +// +// 3 10/05/99 2:03p Markd +// Added warning about files being in multiple projects +// +// 2 9/28/99 4:26p Markd +// merged listener, class and vector between 3 projects +// +// 1 9/10/99 10:55a Jimdose +// +// 1 9/08/99 3:16p Aldie +// +// 4 8/28/99 3:40p Jimdose +// changed all doubles to floats +// +// DESCRIPTION: +// C++ implemention of a Vector object. Handles standard vector operations +// such as addition, subtraction, normalization, scaling, dot product, +// cross product, length, and decomposition into Euler angles. +// +// WARNING: This file is shared between fgame, cgame and possibly the user interface. +// It is instanced in each one of these directories because of the way that SourceSafe works. +// + +#ifndef __VECTOR_H__ +#define __VECTOR_H__ + +#ifdef GAME_DLL +#include "g_local.h" +#endif + +#include +#include + +#ifdef __Q_FABS__ +#define VECTOR_FABS Q_fabs +#else +#define VECTOR_FABS fabs +#endif + +class Vector + { + public: + float x; + float y; + float z; + + Vector(); + Vector( vec3_t src ); + Vector( float x, float y, float z ); + Vector( const char *text ); + + operator float * (); + + float pitch( void ); + float yaw( void ); + float roll( void ); + float operator[]( int index ) const; + float& operator[]( int index ); + void copyTo( vec3_t vec ); + void setPitch( float x ); + void setYaw( float y ); + void setRoll( float z ); + void setXYZ( float x, float y, float z ); + void operator=( Vector a ); + void operator=( vec3_t a ); + friend Vector operator+( Vector a, Vector b ); + friend Vector operator+( vec3_t a, Vector b ); + friend Vector operator+( Vector a, vec3_t b ); + Vector& operator+=( Vector a ); + friend Vector operator-( Vector a, Vector b ); + friend Vector operator-( vec3_t a, Vector b ); + friend Vector operator-( Vector a, vec3_t b ); + Vector& operator-=( Vector a ); + friend Vector operator*( Vector a, float b ); + friend Vector operator*( float a, Vector b ); + friend float operator*( Vector a, Vector b ); + friend float operator*( vec3_t a, Vector b ); + friend float operator*( Vector a, vec3_t b ); + Vector& operator*=( float a ); + friend int operator==( Vector a, Vector b ); + friend int operator==( vec3_t a, Vector b ); + friend int operator==( Vector a, vec3_t b ); + friend int operator!=( Vector a, Vector b ); + friend int operator!=( vec3_t a, Vector b ); + friend int operator!=( Vector a, vec3_t b ); + int FuzzyEqual( Vector b, float epsilon ); + int FuzzyEqual( vec3_t b, float epsilon ); + Vector& CrossProduct( Vector a, Vector b ); + Vector& CrossProduct( vec3_t a, Vector b ); + Vector& CrossProduct( Vector a, vec3_t b ); + float length( void ); + float normalize( void ); +#if 0 +//FIXME +// Some kind of compiler bug in VC++ prevents this from working. +// Returns result of ( -x, -y, -x ) for some reason + Vector& operator-(); +#endif + friend Vector fabs( Vector a ); + float toYaw( void ); + float toPitch( void ); + Vector toAngles( void ); + void AngleVectors( Vector *forward, Vector *left = NULL, Vector *up = NULL ); + friend Vector LerpVector( Vector w1, Vector w2, float t ); + friend float MaxValue( Vector a ); + }; + +inline float Vector::pitch( void ) { return x; } +inline float Vector::yaw( void ) { return y; } +inline float Vector::roll( void ) { return z; } +inline void Vector::setPitch( float pitch ) { x = pitch; } +inline void Vector::setYaw( float yaw ) { y = yaw; } +inline void Vector::setRoll( float roll ) { z = roll; } + +inline void Vector::copyTo + ( + vec3_t vec + ) + + { + vec[ 0 ] = x; + vec[ 1 ] = y; + vec[ 2 ] = z; + } + +inline float Vector::operator[] + ( + int index + ) const + + { + assert( ( index >= 0 ) && ( index < 3 ) ); + return ( &x )[ index ]; + } + +inline float& Vector::operator[] + ( + int index + ) + + { + assert( ( index >= 0 ) && ( index < 3 ) ); + return ( &x )[ index ]; + } + +inline void Vector::setXYZ + ( + float x, + float y, + float z + ) + + { + this->x = x; + this->y = y; + this->z = z; + } + +inline Vector::Vector() + { + x = 0; + y = 0; + z = 0; + } + +inline Vector::Vector + ( + vec3_t src + ) + + { + x = src[ 0 ]; + y = src[ 1 ]; + z = src[ 2 ]; + } + +inline Vector::Vector + ( + float x, + float y, + float z + ) + + { + this->x = x; + this->y = y; + this->z = z; + } + +inline Vector::Vector + ( + const char *text + ) + + { + if ( text ) + { + sscanf( text, "%f %f %f", &x, &y, &z ); + } + else + { + x = 0; + y = 0; + z = 0; + } + } + +inline Vector::operator float * + ( + void + ) + + { + return &x; + } + +inline void Vector::operator= + ( + Vector a + ) + + { + x = a.x; + y = a.y; + z = a.z; + } + +inline void Vector::operator= + ( + vec3_t a + ) + + { + x = a[ 0 ]; + y = a[ 1 ]; + z = a[ 2 ]; + } + +inline Vector operator+ + ( + Vector a, + Vector b + ) + + { + return Vector( a.x + b.x, a.y + b.y, a.z + b.z ); + } + +inline Vector operator+ + ( + vec3_t a, + Vector b + ) + + { + return Vector( a[ 0 ] + b.x, a[ 1 ] + b.y, a[ 2 ] + b.z ); + } + +inline Vector operator+ + ( + Vector a, + vec3_t b + ) + + { + return Vector( a.x + b[ 0 ], a.y + b[ 1 ], a.z + b[ 2 ] ); + } + +inline Vector& Vector::operator+= + ( + Vector a + ) + + { + x += a.x; + y += a.y; + z += a.z; + + return *this; + } + +inline Vector operator- + ( + Vector a, + Vector b + ) + + { + return Vector( a.x - b.x, a.y - b.y, a.z - b.z ); + } + +inline Vector operator- + ( + vec3_t a, + Vector b + ) + + { + return Vector( a[ 0 ] - b.x, a[ 1 ] - b.y, a[ 2 ] - b.z ); + } + +inline Vector operator- + ( + Vector a, + vec3_t b + ) + + { + return Vector( a.x - b[ 0 ], a.y - b[ 1 ], a.z - b[ 2 ] ); + } + +inline Vector& Vector::operator-= + ( + Vector a + ) + + { + x -= a.x; + y -= a.y; + z -= a.z; + + return *this; + } + +inline Vector operator* + ( + Vector a, + float b + ) + + { + return Vector( a.x * b, a.y * b, a.z * b ); + } + +inline Vector operator* + ( + float a, + Vector b + ) + + { + return b * a; + } + +inline float operator* + ( + Vector a, + Vector b + ) + + { + return a.x * b.x + a.y * b.y + a.z * b.z; + } + +inline float operator* + ( + vec3_t a, + Vector b + ) + + { + return a[ 0 ] * b.x + a[ 1 ] * b.y + a[ 2 ] * b.z; + } + +inline float operator* + ( + Vector a, + vec3_t b + ) + + { + return a.x * b[ 0 ] + a.y * b[ 1 ] + a.z * b[ 2 ]; + } + +inline Vector& Vector::operator*= + ( + float a + ) + + { + x *= a; + y *= a; + z *= a; + + return *this; + } + +inline int Vector::FuzzyEqual + ( + Vector b, + float epsilon + ) + + { + return + ( + ( VECTOR_FABS( x - b.x ) < epsilon ) && + ( VECTOR_FABS( y - b.y ) < epsilon ) && + ( VECTOR_FABS( z - b.z ) < epsilon ) + ); + } + +inline int Vector::FuzzyEqual + ( + vec3_t b, + float epsilon + ) + + { + return + ( + ( VECTOR_FABS( x - b[ 0 ] ) < epsilon ) && + ( VECTOR_FABS( y - b[ 1 ] ) < epsilon ) && + ( VECTOR_FABS( z - b[ 2 ] ) < epsilon ) + ); + } + +inline int operator== + ( + Vector a, + Vector b + ) + + { + return ( ( a.x == b.x ) && ( a.y == b.y ) && ( a.z == b.z ) ); + } + +inline int operator== + ( + vec3_t a, + Vector b + ) + + { + return ( ( a[ 0 ] == b.x ) && ( a[ 1 ] == b.y ) && ( a[ 2 ] == b.z ) ); + } + +inline int operator== + ( + Vector a, + vec3_t b + ) + + { + return ( ( a.x == b[ 0 ] ) && ( a.y == b[ 1 ] ) && ( a.z == b[ 2 ] ) ); + } + +inline int operator!= + ( + Vector a, + Vector b + ) + + { + return ( ( a.x != b.x ) || ( a.y != b.y ) || ( a.z != b.z ) ); + } + +inline int operator!= + ( + vec3_t a, + Vector b + ) + + { + return ( ( a[ 0 ] != b.x ) || ( a[ 1 ] != b.y ) || ( a[ 2 ] != b.z ) ); + } + +inline int operator!= + ( + Vector a, + vec3_t b + ) + + { + return ( ( a.x != b[ 0 ] ) || ( a.y != b[ 1 ] ) || ( a.z != b[ 2 ] ) ); + } + +inline Vector& Vector::CrossProduct + ( + Vector a, + Vector b + ) + + { + x = a.y * b.z - a.z * b.y; + y = a.z * b.x - a.x * b.z; + z = a.x * b.y - a.y * b.x; + + return *this; + } + +inline Vector& Vector::CrossProduct + ( + vec3_t a, + Vector b + ) + + { + x = a[ 1 ] * b.z - a[ 2 ] * b.y; + y = a[ 2 ] * b.x - a[ 0 ] * b.z; + z = a[ 0 ] * b.y - a[ 1 ] * b.x; + + return *this; + } + +inline Vector& Vector::CrossProduct + ( + Vector a, + vec3_t b + ) + + { + x = a.y * b[ 2 ] - a.z * b[ 1 ]; + y = a.z * b[ 0 ] - a.x * b[ 2 ]; + z = a.x * b[ 1 ] - a.y * b[ 0 ]; + + return *this; + } + +inline float Vector::length + ( + void + ) + + { + float length; + + length = x * x + y * y + z * z; + return ( float )sqrt( length ); + } + +inline float Vector::normalize + ( + void + ) + + { + float length, ilength; + + length = this->length(); + if ( length ) + { + ilength = 1 / length; + x *= ilength; + y *= ilength; + z *= ilength; + } + + return length; + } + +#if 0 +//FIXME +// Some kind of compiler bug in VC++ prevents this from working. +// Returns result of ( -x, -y, -x ) for some reason +inline Vector& Vector::operator-() + { + return Vector( -x, -y, -z ); + } +#endif + +inline Vector fabs + ( + Vector a + ) + + { + return Vector( VECTOR_FABS( a.x ), VECTOR_FABS( a.y ), VECTOR_FABS( a.z ) ); + } + +inline float MaxValue + ( + Vector a + ) + + { + float maxy; + float maxz; + float max; + + max = VECTOR_FABS( a.x ); + maxy = VECTOR_FABS( a.y ); + maxz = VECTOR_FABS( a.z ); + + if ( maxy > max ) + { + max = maxy; + } + if ( maxz > max ) + { + max = maxz; + } + return max; + } + +inline float Vector::toYaw + ( + void + ) + + { + float yaw; + + if ( ( y == 0 ) && ( x == 0 ) ) + { + yaw = 0; + } + else + { + yaw = ( float )( ( int )( atan2( y, x ) * 180 / M_PI ) ); + if ( yaw < 0 ) + { + yaw += 360; + } + } + + return yaw; + } + +inline float Vector::toPitch + ( + void + ) + + { + float forward; + float pitch; + + if ( ( x == 0 ) && ( y == 0 ) ) + { + if ( z > 0 ) + { + pitch = 90; + } + else + { + pitch = 270; + } + } + else + { + forward = ( float )sqrt( x * x + y * y ); + pitch = ( float )( ( int )( atan2( z, forward ) * 180 / M_PI ) ); + if ( pitch < 0 ) + { + pitch += 360; + } + } + + return pitch; + } + +inline Vector Vector::toAngles + ( + void + ) + + { + float forward; + float yaw, pitch; + + if ( ( x == 0 ) && ( y == 0 ) ) + { + yaw = 0; + if ( z > 0 ) + { + pitch = 90; + } + else + { + pitch = 270; + } + } + else + { + yaw = atan2( y, x ) * 180 / M_PI; + if ( yaw < 0 ) + { + yaw += 360; + } + + forward = ( float )sqrt( x * x + y * y ); + pitch = atan2( z, forward ) * 180 / M_PI; + if ( pitch < 0 ) + { + pitch += 360; + } + } + + return Vector( -pitch, yaw, 0 ); + } + +inline void Vector::AngleVectors + ( + Vector *forward, + Vector *left, + Vector *up + ) + + { + float angle; + static float sr, sp, sy, cr, cp, cy; // static to help MS compiler fp bugs + + angle = yaw() * ( M_PI * 2 / 360 ); + sy = sin( angle ); + cy = cos( angle ); + + angle = pitch() * ( M_PI * 2 / 360 ); + sp = sin( angle ); + cp = cos( angle ); + + angle = roll() * ( M_PI * 2 / 360 ); + sr = sin( angle ); + cr = cos( angle ); + + if ( forward ) + { + forward->setXYZ( cp * cy, cp * sy, -sp ); + } + + if ( left ) + { + left->setXYZ( sr * sp * cy + cr * -sy, sr * sp * sy + cr * cy, sr * cp ); + } + + if ( up ) + { + up->setXYZ( cr * sp * cy + -sr * -sy, cr * sp * sy + -sr * cy, cr * cp ); + } + } + + +#define LERP_DELTA 1e-6 +inline Vector LerpVector + ( + Vector w1, + Vector w2, + float t + ) + { + float omega, cosom, sinom, scale0, scale1; + + w1.normalize(); + w2.normalize(); + + cosom = w1 * w2; + if ( ( 1.0 - cosom ) > LERP_DELTA ) + { + omega = acos( cosom ); + sinom = sin( omega ); + scale0 = sin( ( 1.0 - t ) * omega ) / sinom; + scale1 = sin( t * omega ) / sinom; + } + else + { + scale0 = 1.0 - t; + scale1 = t; + } + + return ( w1 * scale0 + w2 * scale1 ); + } + +class Quat + { + public: + float x; + float y; + float z; + float w; + + Quat(); + Quat( Vector angles ); + Quat( float scrMatrix[ 3 ][ 3 ] ); + Quat( float x, float y, float z, float w ); + + float *vec4( void ); + float operator[]( int index ) const; + float& operator[]( int index ); + void set( float x, float y, float z, float w ); + void operator=( Quat a ); + friend Quat operator+( Quat a, Quat b ); + Quat& operator+=( Quat a ); + friend Quat operator-( Quat a, Quat b ); + Quat& operator-=( Quat a ); + friend Quat operator*( Quat a, float b ); + friend Quat operator*( float a, Quat b ); + Quat& operator*=( float a ); + friend int operator==( Quat a, Quat b ); + friend int operator!=( Quat a, Quat b ); + float length( void ); + Quat& normalize( void ); + Quat operator-(); + Vector toAngles( void ); + }; + +inline float Quat::operator[] + ( + int index + ) const + + { + assert( ( index >= 0 ) && ( index < 4 ) ); + return ( &x )[ index ]; + } + +inline float& Quat::operator[] + ( + int index + ) + + { + assert( ( index >= 0 ) && ( index < 4 ) ); + return ( &x )[ index ]; + } + +inline float *Quat::vec4 + ( + void + ) + + { + return &x; + } + +inline void Quat::set + ( + float x, + float y, + float z, + float w + ) + + { + this->x = x; + this->y = y; + this->z = z; + this->w = w; + } + +inline Quat::Quat() + { + x = 0; + y = 0; + z = 0; + w = 0; + } + +inline Quat::Quat + ( + Vector Angles + ) + + { + EulerToQuat( Angles, this->vec4() ); + } + +inline Quat::Quat + ( + float srcMatrix[ 3 ][ 3 ] + ) + + { + MatToQuat( srcMatrix, this->vec4() ); + } + +inline Quat::Quat + ( + float x, + float y, + float z, + float w + ) + + { + this->x = x; + this->y = y; + this->z = z; + this->w = w; + } + +inline void Quat::operator= + ( + Quat a + ) + + { + x = a.x; + y = a.y; + z = a.z; + w = a.w; + } + +inline Quat operator+ + ( + Quat a, + Quat b + ) + + { + return Quat( a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w ); + } + +inline Quat& Quat::operator+= + ( + Quat a + ) + + { + x += a.x; + y += a.y; + z += a.z; + w += a.w; + + return *this; + } + +inline Quat operator- + ( + Quat a, + Quat b + ) + + { + return Quat( a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w ); + } + +inline Quat& Quat::operator-= + ( + Quat a + ) + + { + x -= a.x; + y -= a.y; + z -= a.z; + w -= a.w; + + return *this; + } + +inline Quat operator* + ( + Quat a, + float b + ) + + { + return Quat( a.x * b, a.y * b, a.z * b, a.w * b ); + } + +inline Quat operator* + ( + float a, + Quat b + ) + + { + return b * a; + } + +inline Quat& Quat::operator*= + ( + float a + ) + + { + x *= a; + y *= a; + z *= a; + w *= a; + + return *this; + } + +inline int operator== + ( + Quat a, + Quat b + ) + + { + return ( ( a.x == b.x ) && ( a.y == b.y ) && ( a.z == b.z ) && ( a.w == b.w ) ); + } + +inline int operator!= + ( + Quat a, + Quat b + ) + + { + return ( ( a.x != b.x ) || ( a.y != b.y ) || ( a.z != b.z ) && ( a.w != b.w ) ); + } + +inline float Quat::length + ( + void + ) + + { + float length; + + length = x * x + y * y + z * z + w * w; + return ( float )sqrt( length ); + } + +inline Quat& Quat::normalize + ( + void + ) + + { + float length, ilength; + + length = this->length(); + if ( length ) + { + ilength = 1 / length; + x *= ilength; + y *= ilength; + z *= ilength; + w *= ilength; + } + + return *this; + } + +inline Quat Quat::operator-() + { + return Quat( -x, -y, -z, -w ); + } + +inline Vector Quat::toAngles + ( + void + ) + + { + float m[ 3 ][ 3 ]; + vec3_t angles; + + QuatToMat( this->vec4(), m ); + MatrixToEulerAngles( m, angles ); + return Vector( angles ); + } + +extern Vector vec_zero; + +#undef VECTOR_FABS + +#endif /* Vector.h */ diff --git a/source/source/fgame/PlayerStart.cpp b/source/source/fgame/PlayerStart.cpp new file mode 100644 index 0000000..c786df9 --- /dev/null +++ b/source/source/fgame/PlayerStart.cpp @@ -0,0 +1,172 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/PlayerStart.cpp $ +// $Revision:: 11 $ +// $Author:: Markd $ +// $Date:: 7/03/00 8:53p $ +// +// Copyright (C) 1997 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source is may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/PlayerStart.cpp $ +// +// 11 7/03/00 8:53p Markd +// fixed player start bug +// +// 10 7/02/00 6:46p Markd +// added spawn thread to PlayerStart +// +// 9 6/14/00 3:50p Markd +// Cleaned up more Intel Compiler warnings +// +// 8 1/15/00 3:57p Markd +// Eliminated multiple "angle" events and replaced them with EV_SetAngle +// +// 7 12/17/99 6:35p Jimdose +// changed spawnarg code +// added Level class for spawning and map control +// got rid of unused or superflous variables +// changed setjmp/longjmp calls to try/throw/catch exception handling +// +// 6 11/04/99 10:03a Markd +// complete overhaul of the camera system +// +// 5 10/13/99 11:59a Phook +// +// 4 10/13/99 11:52a Phook +// adjusted the bounding box of player starts +// +// 3 9/28/99 9:51a Markd +// fixed default flags +// +// 2 9/27/99 5:45p Markd +// began documentation and cleanup phase after merge +// +// 1 9/10/99 10:54a Jimdose +// +// 1 9/08/99 3:16p Aldie +// +// 11 7/08/99 4:28p Markd +// Removed obsolete QUAKED functions +// +// 10 6/17/99 1:20p Phook +// Made the player starts 96 units tall +// +// 9 6/11/99 1:23p Phook +// +// 8 6/11/99 12:58p Phook +// Changed from SINED comments to QUAKED +// +// 7 6/11/99 12:46p Phook +// EClass color changes +// +// DESCRIPTION: +// Player start location entity declarations +// + +#include "g_local.h" +#include "entity.h" +#include "trigger.h" +#include "PlayerStart.h" + +/*****************************************************************************/ +/*QUAKED info_player_start (0.75 0.75 0) (-16 -16 0) (16 16 96) + +The normal starting point for a level. + +"angle" - the direction the player should face +"thread" - the thread that should be called when spawned at this position + +******************************************************************************/ + +Event EV_PlayerStart_SetThread + ( + "thread", + EV_DEFAULT, + "s", + "thread", + "Set the thread to execute when this player start is used" + ); + +CLASS_DECLARATION( Entity, PlayerStart, "info_player_start" ) + { + { &EV_SetAngle, SetAngle }, + { &EV_PlayerStart_SetThread, SetThread }, + { NULL, NULL } + }; + +void PlayerStart::SetAngle + ( + Event *ev + ) + + { + angles = Vector( 0, ev->GetFloat( 1 ), 0 ); + } + +void PlayerStart::SetThread + ( + Event *ev + ) + + { + thread = ev->GetString( 1 ); + } + +str PlayerStart::getThread + ( + void + ) + + { + return thread; + } + +/*****************************************************************************/ +/* saved out by quaked in region mode + +******************************************************************************/ + +CLASS_DECLARATION( PlayerStart, TestPlayerStart, "testplayerstart" ) + { + { NULL, NULL } + }; + +/*****************************************************************************/ +/*QUAKED info_player_deathmatch (0.75 0.75 1) (-16 -16 0) (16 16 96) + +potential spawning position for deathmatch games + +"angle" - the direction the player should face +"thread" - the thread that should be called when spawned at this position + +******************************************************************************/ + +CLASS_DECLARATION( PlayerStart, PlayerDeathmatchStart, "info_player_deathmatch" ) + { + { NULL, NULL } + }; + +/*****************************************************************************/ +/*QUAKED info_player_intermission (0.75 0.75 0) (-16 -16 0) (16 16 96) + +viewing point in between deathmatch levels + +******************************************************************************/ + +CLASS_DECLARATION( Camera, PlayerIntermission, "info_player_intermission" ) + { + { NULL, NULL } + }; + +PlayerIntermission::PlayerIntermission + ( + ) + + { + currentstate.watch.watchPath = false; + } + diff --git a/source/source/fgame/PlayerStart.h b/source/source/fgame/PlayerStart.h new file mode 100644 index 0000000..541a0a5 --- /dev/null +++ b/source/source/fgame/PlayerStart.h @@ -0,0 +1,83 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/PlayerStart.h $ +// $Revision:: 3 $ +// $Author:: Markd $ +// $Date:: 7/02/00 6:46p $ +// +// Copyright (C) 1997 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source is may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/PlayerStart.h $ +// +// 3 7/02/00 6:46p Markd +// added spawn thread to PlayerStart +// +// 2 12/17/99 6:35p Jimdose +// changed spawnarg code +// added Level class for spawning and map control +// got rid of unused or superflous variables +// changed setjmp/longjmp calls to try/throw/catch exception handling +// +// 1 9/10/99 10:54a Jimdose +// +// 1 9/08/99 3:16p Aldie +// +// 6 7/08/99 4:28p Markd +// Removed obsolete QUAKED functions +// +// DESCRIPTION: +// Player start location entity declarations +// + +#ifndef __PLAYERSTART_H__ +#define __PLAYERSTART_H__ + +#include "g_local.h" +#include "entity.h" +#include "camera.h" +#include "navigate.h" + +class PlayerStart : public Entity + { + private: + str thread; + public: + CLASS_PROTOTYPE( PlayerStart ); + + void SetAngle( Event *ev ); + void SetThread( Event *ev ); + str getThread( void ); + virtual void Archive(Archiver &arc); + }; + +inline void PlayerStart::Archive (Archiver &arc) + { + Entity::Archive( arc ); + + arc.ArchiveString(&thread); + } + +class TestPlayerStart : public PlayerStart + { + public: + CLASS_PROTOTYPE( TestPlayerStart ); + }; + +class PlayerDeathmatchStart : public PlayerStart + { + public: + CLASS_PROTOTYPE( PlayerDeathmatchStart ); + }; + +class PlayerIntermission : public Camera + { + public: + CLASS_PROTOTYPE( PlayerIntermission ); + PlayerIntermission(); + }; + +#endif /* PlayerStart.h */ diff --git a/source/source/fgame/actor.cpp b/source/source/fgame/actor.cpp new file mode 100644 index 0000000..2565137 --- /dev/null +++ b/source/source/fgame/actor.cpp @@ -0,0 +1,12449 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/actor.cpp $ +// $Revision:: 250 $ +// $Author:: Steven $ +// $Date:: 7/29/00 8:33p $ +// +// Copyright (C) 1998 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/actor.cpp $ +// +// 250 7/29/00 8:33p Steven +// Fixed a wakeup problem when loading games. +// +// 249 7/29/00 7:11p Steven +// Made mission fail if you hurt an edenlander. +// +// 248 7/29/00 2:28p Steven +// Made it so LoadStateMap does not turn off think if we are +// loading a level. +// +// 247 7/28/00 9:18p Steven +// Made minimum mass to spawn a big water ampoule 125. +// +// 246 7/28/00 6:56p Steven +// Set boss health back to 0 if ai goes off. +// +// 245 7/28/00 1:22p Steven +// Made save attack longer and names spawned items. +// +// 244 7/27/00 11:46p Steven +// Fixed some depends/dependsnot dialog stuff. +// +// 243 7/27/00 10:53p Steven +// Added always give water stuff, don't make actor go to sleep +// initially if already has a behavior, and changed the teleport +// effect on spawned actors. +// +// 242 7/26/00 8:40p Steven +// Fixed a problem with actors getting stuck because of stepping +// up in the movement. +// +// 241 7/26/00 6:14p Steven +// made it so small actors will not spawn a big water ampoule +// +// 240 7/25/00 9:25p Steven +// Added damage allowed stuff, made set state run entry/exit +// commands, made it so when actors go into AI mode they turn +// sight/sound stuff back on, and fixed some spawning stuff. +// +// 239 7/24/00 6:08p Steven +// Added ignore pain from actors and fixed some direct pathfinding +// issues. +// +// 238 7/24/00 12:15p Steven +// Only update boss health when boss is in ai mode. +// +// 237 7/23/00 7:58p Steven +// Fixed some boss health stuff. +// +// 236 7/23/00 5:59p Steven +// Fixed some checkanimname stuff. +// +// 235 7/23/00 5:12p Steven +// Added check animname. +// +// 234 7/22/00 3:01p Steven +// Added boss health bar stuff. +// +// 233 7/22/00 1:18p Steven +// Added water level stuff. +// +// 232 7/20/00 6:22p Steven +// Tweaked actor spawn items stuff a little. +// +// 231 7/19/00 9:18p Steven +// Fixed checkmovingactorrange. +// +// 230 7/19/00 5:08p Steven +// Added electric water means of death and fixed max gibs when +// dying by gib death. +// +// 229 7/17/00 6:56p Steven +// Fixed a bug in Likes and added the spawning of a big fruit +// item. +// +// 228 7/17/00 4:42p Steven +// Fixed up some plasma stuff in SpawnItem and made it so we won't +// spawn any ammo for weapons the player doesn't have yet. +// +// 227 7/17/00 3:15p Steven +// added increment/decrement num spawns stuff +// +// 226 7/16/00 4:36p Steven +// Moved action level stuff to actor pain and killed. +// +// 225 7/16/00 2:35p Steven +// Moved Julie watching talking actor events to behavior. +// +// 224 7/15/00 3:11p Steven +// Added no pain sounds stuff. +// +// 223 7/15/00 12:47p Steven +// Fixed friend attacking other friends. +// +// 222 7/14/00 5:38p Steven +// Made spawned items not go through playerclips. +// +// 221 7/14/00 4:42p Steven +// Made playdialogs from script have no attenuation and added +// blind/deaf prints to actorinfo. +// +// 220 7/13/00 7:28p Steven +// Fixed some targetname stuff. +// +// 219 7/13/00 6:52p Steven +// Fixed some means of death stuff. +// +// 218 7/13/00 5:42p Steven +// Fixed spawned in items from killing actors. +// +// 217 7/13/00 3:42p Steven +// Added some simple path finding stuff and saved groundtrace +// results so we don't have to checkground. +// +// 216 7/13/00 12:29p Steven +// Added some ignore sound stuff, made actors not do pain sounds +// as much, and make sure gibs don't process their init commands. +// +// 215 7/12/00 3:36p Steven +// Made lots of optimizations to actors. +// +// 214 7/12/00 11:24a Steven +// Fixed some talk mode stuff. +// +// 213 7/11/00 11:08p Markd +// fixed crash bug where spawnitem wasn't being checked for NULL +// pointer +// +// 212 7/11/00 10:16p Markd +// spawned in ammo_plasma instead of ammo_bolt which is no more +// +// 211 7/11/00 7:07p Steven +// Made it so turntowardsenemy would work with killed enemies. +// +// 210 7/10/00 5:10p Steven +// Made it if get an anim command only go to script mode if +// command came from script and fixed stationary actors dying +// correctly. +// +// 209 7/07/00 6:34p Steven +// If actor is immmune to mod don't overwrite mod if already set +// this frame amd added more fail level stuff. +// +// 208 7/06/00 4:43p Steven +// Made sure when reposting an event to save the thread also and +// made sure to set the currentBehavior when restoring a mode. +// +// 207 7/06/00 12:59p Steven +// Made a way to stimuli an attack without it attacking the entity +// that caused it pain and made spawned actors fade out almost +// immediately. +// +// 206 7/06/00 9:23a Steven +// Added damage angles stuff. +// +// 205 7/06/00 7:47a Steven +// Added enemy on ground check. +// +// 204 7/05/00 5:17p Steven +// Added part of the code to make the player fail the level if she +// kills an innocent. +// +// 203 7/05/00 2:27p Steven +// Fixed reposting of events. +// +// 202 7/03/00 6:58p Steven +// Made actors wakeup instead op just turning on think, added some +// check shield stuff, and made spawned items have a mask of +// MASK_SOLID. +// +// 201 7/02/00 5:55p Steven +// Added SetIdleStateName. +// +// 200 7/02/00 5:08p Steven +// Added SpawnActorAtLocation, cleaned up the SpawnActor stuff and +// made it so all actors could gib if killed with mod of gib +// regardless if a bloodmodel is set. +// +// 199 7/02/00 1:10p Steven +// Added a RunThread event. +// +// 198 7/01/00 6:07p Steven +// Added falling damage for actors and added a bool parm for +// allowfall. +// +// 197 7/01/00 12:01p Steven +// Moved actor droptofloor back to 16 because it was causing some +// problems and added electricsword means of death. +// +// 196 6/30/00 5:05p Steven +// Added on fire check. +// +// 195 6/30/00 11:40a Steven +// Added a blocked check. +// +// 194 6/30/00 10:45a Markd +// added MOVETYPE_STATIONARY and revamped some physics +// +// 193 6/30/00 10:20a Steven +// Added some stuck/off ground stuff and allowed the suicide event +// to keep the old means of death. +// +// 192 6/30/00 7:51a Steven +// Added impact_sever sound call for cutting off a limb. +// +// 191 6/29/00 5:20p Steven +// Added min and max height for in range stuff. +// +// 190 6/28/00 3:11p Steven +// Added level wide ai_off and made actors being touched use +// STIMULI_SIGHT instead of STILUMI_PAIN. +// +// 189 6/27/00 5:44p Steven +// Made actors drop a little farther at start(32 now), made actors +// not broadcast sound in pain if dead or immune to the damage, +// changed notsolidmask from DEADSOLID TO SOLID, and made actors +// not do babble dialog for at least 5 seconds after a cinematic. +// +// 188 6/26/00 5:50p Markd +// re-did some renderfx commands, fixed anti-sb juice stuff +// +// 187 6/26/00 4:51p Steven +// Fixed some active/sleep list issues. +// +// 186 6/26/00 12:21p Steven +// Printing out better info on stuck warning. +// +// 185 6/24/00 7:00p Steven +// Fixed SaveAttack not tracing far enough, made InitState only +// get called if a valid state is set and fixed the loading parm +// in LoadStateMap. +// +// 184 6/24/00 11:21a Steven +// Added check to constructor that doesn't let event get posted if +// loading a savegame and fixed some loading savegame issues with +// dead actors. +// +// 183 6/22/00 5:32p Steven +// Added StopDialog stuff and fixed gibs from processing server +// commands. +// +// 182 6/21/00 4:21p Steven +// Improved checkcanflytoenemy. +// +// 181 6/20/00 7:00p Steven +// Changed saved_anim_event and last_anim_event to strings from +// event pointers. +// +// 180 6/20/00 12:16p Steven +// Added some SetMask stuff and made it so actors won't babble to +// players when they have weapons out. +// +// 179 6/19/00 6:19p Steven +// Added die completely stuff, added can bleed after death stuff, +// added actors getting pissed at the player touching them, and +// now make actors make noise when they take pain or die. +// +// 178 6/17/00 4:03p Steven +// Added GetStateAnims stuff. +// +// 177 6/17/00 11:09a Steven +// Made it so actors spawned from other actors have their +// targetname set to the parents targetname + _spawned. +// +// 176 6/15/00 6:55p Steven +// Added moving head while talking stuff. +// +// 175 6/14/00 2:50p Markd +// removed unused variable +// +// 174 6/13/00 3:46p Steven +// Added gibbing of actors when killed with a means of death of +// gib and fixed a problem with blind actors never thinking. +// +// 173 6/10/00 1:48p Steven +// Added statemap caching. +// +// 172 6/09/00 2:25p Steven +// Made melee weapons always do normal pain not small pain. +// +// 171 6/08/00 1:43p Steven +// Added minimum melee height and immortal events. +// +// 170 6/07/00 5:32p Steven +// Added ignore monster clip stuff. +// +// 169 6/06/00 2:35p Steven +// Improved Likes a little bit, made it so the client doesn't +// process animation commands on a dead actor, fixed IsBlind, +// added check no path, and improved ChangeType. +// +// 168 6/03/00 6:53p Steven +// Added actor blind stuff and added some farplane stuff to make +// sure actors wakeup and go back to sleep better. +// +// 167 6/03/00 3:46p Aldie +// Added in g_debugtargets for debugging targetnames and targets +// +// 166 6/01/00 3:18p Steven +// Added some changetype stuff, change some of the findenemy stuff +// a little, and added a check for in water. +// +// 165 5/31/00 3:55p Steven +// Another actor save game pass. +// +// 164 5/27/00 2:29p Steven +// Added attack actors stuff, added targetable stuff and added +// check player range. +// +// 163 5/26/00 6:19p Steven +// Added a gotoprevstage proc, added set attackable by actors, +// added a final height variable to MeleeEvent, added +// ShouldAttackEntity and made CanWalkTo use MASK_PATHSOLID +// instead of MASK_SOLID. +// +// 162 5/25/00 1:48p Steven +// Moved the rest of the max_gibs stuff to sentient. +// +// 161 5/23/00 6:42p Steven +// Moved small gib stuff to sentient. +// +// 160 5/23/00 10:18a Steven +// Made actors take a little time before doing babble dialog (half +// second or so) and added more items to actor random item spawns. +// +// 159 5/20/00 4:46p Steven +// Added sendcommand stuff, made pushing not assert gravity on +// flying actors, and added small pain to possible other part +// flags check. +// +// 158 5/19/00 3:42p Steven +// Added a noclip check. +// +// 157 5/19/00 11:24a Steven +// Moved little gibs to client side and some small clean up. +// +// 156 5/11/00 11:11a Steven +// Added pushing actors stuff, added chargewater attack, and did +// some cleanup. +// +// 155 5/10/00 10:31a Steven +// Fixed actors running in mid air, merged new TryMove stuff in, +// got rid of a trace in TryMove, added a can walk on others +// variable, added com_blood stuff, optimized CheckGround and +// FindEnemy stuff and made CanWalkTo take into account the final +// height compared to the specified position. +// +// 154 5/05/00 6:23p Steven +// Fixed a actorthread bug when the thread is not found and made +// it so fire will cause actors pain again. +// +// 153 5/05/00 2:13p Steven +// Made it so for now actors don't do pain when on fire. +// +// 152 5/04/00 2:07p Steven +// More finishing move stuff. +// +// 151 5/04/00 12:46p Steven +// Finishing move stuff. +// +// 150 5/03/00 11:49a Steven +// Made it so actors wouldn't do babble dialog if the player is +// moving. +// +// 149 5/02/00 3:13p Steven +// Fixed a bug in SpawnBloodyGibs and added player watching actors +// that talk to her. +// +// 148 5/01/00 2:45p Steven +// Added allow fall stuff, made it so we don't try to wake an +// already awake actor, made it so only a little bit of the pain +// stuff is processed for dead actors, and added volume and +// minimum distance to the playdialog stuff. +// +// 147 4/28/00 5:37p Steven +// Stop detaching things on death, always fade (don't worry about +// inventory), added an optional number of gibs parameter to +// SpawnBloodyGibs, and added saving of the last known position of +// the enemy. +// +// 146 4/25/00 10:10a Steven +// Made turntowardsenemy set the actor's roll to 0. +// +// 145 4/24/00 2:43p Steven +// Fixed the initial state not getting initialized correctly. +// +// 144 4/21/00 5:39p Steven +// Added some bounceoff stuff (mostly for fleshbinder's shield), +// added spawning of items on actor death stuff and optimized +// CanWalkTo a lot. +// +// 143 4/20/00 11:33a Steven +// Added stun stuff, made it so if monsters are notsolid in the +// first place they contents won't be set to corpse on death, made +// sure suicide set the actor's health to 0, and made sure the +// fade out flag is set properly. +// +// 142 4/15/00 11:49a Steven +// Added spawnbloodygibs, added setmaxgibs and cleaned up some +// blood stuff. +// +// 141 4/14/00 3:58p Steven +// Added a staysolid event. +// +// 140 4/14/00 11:15a Steven +// Made it so could do kickback and animation movement when dead. +// +// 139 4/14/00 10:35a Steven +// Fixed some minor pain threshold stuff, made it so KilledEffects +// doesn't overwrite the actor's name and made blood splat size +// scale with the actor size. +// +// 138 4/13/00 5:33p Steven +// Added a deathsink event, made it so only actors with deathsink +// turned on sink into ground after death and added a nomask event +// for the ghosts. +// +// 137 4/12/00 6:59p Steven +// Added an addhealth event and made the actors pain event always +// process even if the damage done is 0. +// +// 136 4/12/00 2:39p Steven +// Made it so named gibs don't spawn if the actor is fadig out. +// +// 135 4/11/00 6:56p Steven +// Got gibs to sink into ground correctly. +// +// 134 4/11/00 6:36p Steven +// Added deathshrink stuff. +// +// 133 4/11/00 5:42p Steven +// Sinking into ground and fading out work. +// +// 132 4/11/00 4:00p Steven +// Added attack_min_height to MeleeAttack. +// +// 131 4/11/00 3:07p Steven +// Cleaned up a bunch of spawn stuff and merged SpawnGib and +// SpawnGibAtTag. +// +// 130 4/11/00 10:31a Steven +// Cleaned up some gib stuff. +// +// 129 4/10/00 6:52p Steven +// Redid death state to be able to have more levels and to process +// entry and exit commands, made sure the ACTOR_FLAG_SPAWN_FAILED +// flag is always set properly, made it so gibs don't process +// animation commands on the client and made it so gibs use their +// angles not their bind masters. +// +// 128 4/10/00 10:51a Steven +// Fixed the throwing of shglieks by actors. +// +// 127 4/08/00 3:51p Steven +// Added a SpawnGibAtTag (temporarily, will be merged with +// SpawnGib soon), added attackmode stuff again, don't spawn gibs +// if fading out, added gibing/hurting of dead monsters, lots of +// general gib work, fixed actors not being able to get off of +// other actors and made ai_off kick the actor out of ai mode and +// NULL out the currentEnemy. +// +// 126 4/06/00 3:34p Steven +// Fixed a typo. +// +// 125 4/06/00 2:57p Steven +// Added death size event. +// +// 124 4/05/00 6:17p Steven +// Added in real support for gravity based projectiles. +// +// 123 4/04/00 6:54p Steven +// Added ResetHead event, started some projectile attack changes, +// added NoLerpThisFrame to the WarpTo event and added some tweaks +// to gibs. +// +// 122 4/03/00 1:56p Steven +// Added a way to set & unset the fly flag and made lighter +// creatures gibs go further. +// +// 121 4/01/00 4:33p Steven +// Added chackname. +// +// 120 4/01/00 2:39p Steven +// Added checkcanflytoenemy. +// +// 119 4/01/00 1:19p Steven +// Fixed up some gib stuff. +// +// 118 4/01/00 11:10a Steven +// Added checkenemydead and initialized use_gravity flag. +// +// 117 3/31/00 4:57p Steven +// Tweaked GetNearestEnemy a little and fixed actors not falling +// to the ground when killed. +// +// 116 3/31/00 1:01p Steven +// Added GetRandomEnemy (for recruiter). +// +// 115 3/30/00 2:02p Steven +// Added SpawnBlood, added usegravity, added save attack to +// FireBullet, some gib work, and fixed some movement issues. +// +// 114 3/28/00 6:48p Steven +// Added optional tag_name to TestAttack. +// +// 113 3/28/00 1:16p Steven +// Added range to bullet attack, fixed some noise heard stuff, and +// imprved checkhasthing so that you could check mulitple things +// at once. +// +// 112 3/24/00 6:31p Steven +// Fixed another TryMove issue, fixed actors going to sleep that +// have the max_inactive_time set to 0, changes the size parameter +// in SpawnActor to width & height, and started adding a better +// CheckBottom. +// +// 111 3/22/00 10:35a Steven +// Added SpawnNamedGib and GotoStage, fixed an event leak, and +// fixed some actor movement issues. +// +// 110 3/20/00 6:07p Steven +// Moved max_mouth_angle stuff to sentient, made it so actor knows +// when behavior's animations are done, and added setmouthangle. +// +// 109 3/18/00 4:15p Steven +// Added an allowhangback event, added a check for allowhangback, +// and fixed a TryMove issue. +// +// 108 3/18/00 3:12p Steven +// Fixed some anim_done issues, added a flag to keep track if the +// actor has been started yet or not, and made sure the +// attackplayer command was only received after the actor is +// started. +// +// 107 3/18/00 1:16p Steven +// Added FireBullet to actor and added pain_angles stuff. +// +// 106 3/17/00 2:37p Steven +// Made it so dead actors don't care about falling off edges. +// +// 105 3/17/00 11:49a Steven +// Added jumping stuff. +// +// 104 3/14/00 12:06p Steven +// Added walkwatch stuff. +// +// 103 3/13/00 4:42p Steven +// Added in the rest of the has_thing check. +// +// 102 3/13/00 2:31p Steven +// Added a can_shoot_enemy check, fixed the starting position in +// CanShootFrom, added a warning to SetState if the state doesn't +// exist, and added a check to PlayDialog to make sure the actor +// has a currentState if setting a new one. +// +// 101 3/11/00 4:11p Steven +// Added have thing stuff, added direction to pain, and made sure +// actors don't think before they are fully spawned. +// +// 100 3/11/00 2:17p Steven +// Added stun stuff (so the AI knows when the player is incapable +// of doing anything :) +// +// 99 3/11/00 12:04p Steven +// Added a check in SpawnActor to make sure the new actor isn't +// spawned inside of anything. +// +// 98 3/11/00 11:33a Steven +// Moved all actor booleans to 1 actor flags variable. +// +// 97 3/09/00 11:41a Steven +// Fixed a problem in checkcanseeenemy when having no +// currentEnemy. +// +// 96 3/08/00 6:41p Steven +// Fixed up checkcanseeenemy and made sure all bones of an actor +// are reset back to their normal position when the actor dies. +// +// 95 3/07/00 4:56p Steven +// Added bounce off stuff. +// +// 94 3/07/00 11:49a Steven +// Added checkenemyinfov. +// +// 93 3/04/00 11:49a Steven +// Added a stuck flag and added a check for it. +// +// 92 3/03/00 5:24p Steven +// Added fast_bullet stuff and made it so actors that are +// activated will automatically attack the player. +// +// 91 3/02/00 6:40p Steven +// Made which blood model to use a parameter to gib. +// +// 90 3/02/00 11:01a Steven +// Cleaned up some gib stuff, fixed a velocity problem with +// actors, and added checkenemyrelativeyaw. +// +// 89 2/29/00 12:21p Steven +// Fixed a problem with starting actorthreads (and going to AI +// mode in the middle of it) and took out actor droptofloor stuff +// temporarily. +// +// 88 2/28/00 11:18a Steven +// Fixed up some drop to ground stuff. +// +// 87 2/26/00 3:46p Steven +// Added some more stuff to stuck actor. +// +// 86 2/26/00 3:32p Steven +// Print a message if actors start stuck in the ground and make it +// very obvious something is wrong :) +// +// 85 2/26/00 2:56p Steven +// Fixed up some jump issues with actors. +// +// 84 2/26/00 11:22a Steven +// Added partial immobile flag. +// +// 83 2/25/00 7:02p Steven +// Added a way for actors to notify others of their kind when they +// are killed. +// +// 82 2/24/00 5:55p Steven +// Fixed a typo in the event documentation. +// +// 81 2/24/00 5:34p Steven +// Fixed up some event documentation. +// +// 80 2/24/00 5:10p Steven +// Fixed up some of the removing anim done events, added a speed +// parm to headwatch and added offset to spawnactor. +// +// 79 2/24/00 1:59p Steven +// Now make sure to get rid of all anim done events when ending a +// behavior and make sure actors won't go to talk mode while in a +// cinematic. +// +// 78 2/23/00 5:50p Steven +// Made it so the endthread command also ends the current behavior +// if in script mode. +// +// 77 2/23/00 5:09p Steven +// Fixed some bugs. +// +// 76 2/23/00 11:43a Steven +// Moved utility behaviors into actor and added entry and exit +// commands. +// +// 75 2/21/00 6:26p Steven +// Added an endthread event and made using the fov an option in +// the can see enemy check. +// +// 74 2/18/00 6:54p Steven +// Added warpto command, did lots move improvements of movement +// and path finding, cleaned up some ai to idle mode stuff, and +// fixed idle thread stuff. +// +// 73 2/17/00 6:26p Aldie +// Fixed naming conventions for weapon hand and also added various +// attachtotag functionality for weapons that attach to different +// tags depending on which hand they are wielded in. +// +// 72 2/17/00 5:42p Steven +// Lots of movement and path finding improvements. +// +// 71 2/16/00 6:44p Steven +// Fixed a bug in CanShootFrom (was negating the pitch still). +// +// 70 2/16/00 10:41a Steven +// Added small pain stuff, made sure actors would not go to AI +// mode if they don't have a statemap, and made sure actors don't +// go to sleep when they shouldn't. +// +// 69 2/14/00 3:32p Steven +// Added checks so an actor can tell what weapons the player is +// using and fixed a crash bug if an actor has no statemap but a +// state is set. +// +// 68 2/11/00 6:40p Steven +// Added pickup/throw stuff, added damage once stuff, added small +// pain stuff, and fixed some bugs. +// +// 67 2/09/00 10:34a Steven +// Added events to allow an actor's clipmask to be changed. +// +// 66 2/08/00 4:53p Steven +// Made it so actors would only try to go to talk mode if they +// have babble dialog. +// +// 65 2/08/00 11:59a Steven +// Added stuff to let actor know he had blocked a hit. +// +// 64 2/08/00 11:38a Steven +// Some general cleanup, added a state name to idle event, added a +// state name to playdialog event, and added a checkheld check. +// +// 63 2/04/00 3:11p Aldie +// Changed sword attack method for water usage +// +// 62 2/04/00 1:56p Steven +// Added a lot on the different modes (AI, script, idle and talk). +// +// 61 2/02/00 1:33p Steven +// Added headwatching stuff, tweaked meleeevent a little more, +// fixed up some init problems, made non-moving actors die +// properly, and fixed checkmovingactorrange stuff. +// +// 60 1/28/00 12:04p Steven +// Added another debug message for dialog stuff. +// +// 59 1/28/00 11:18a Steven +// Added a debug message if a dailog is played and no lip file is +// found. +// +// 58 1/27/00 2:50p Steven +// Improved all actor's vision distance, fixed various bugs and +// added checkincomingmeleeattackstart and +// checkincomingprojectilestart. +// +// 57 1/26/00 9:53a Markd +// Changed FOV command to an fov command +// +// 56 1/25/00 6:32p Steven +// Added knockback to melee event. +// +// 55 1/25/00 11:09a Steven +// Renamed health_less check to health. +// +// 54 1/24/00 6:55p Steven +// Made sure actors will fall if spawned off the ground and added +// support to limit the number of actors an actor can spawn. +// +// 53 1/22/00 5:07p Steven +// Added knockback to meleeattack. +// +// 52 1/22/00 1:43p Markd +// Fixed attached entity bug +// +// 51 1/22/00 12:42p Jimdose +// got rid of calls to vec3() +// +// 50 1/21/00 8:07p Aldie +// Fixed a link error - bad! +// +// 49 1/21/00 6:44p Steven +// Cleaned up idle_thread stuff, added tempstate ability, and +// added open door support for actors. +// +// 48 1/20/00 6:57p Markd +// removed get_lip functions and merged them with SoundLength and +// SoundAmplitudes +// +// 47 1/20/00 6:54p Aldie +// Removed bloodsplats until we do them the right way +// +// 46 1/20/00 12:19p Steven +// Fixed a problem in the checkmeansofdeath conditional. +// +// 45 1/19/00 8:56p Steven +// Improved location of spawned actors from the spawnactor +// command. +// +// 44 1/19/00 7:46p Aldie +// Fixed func_spawns of various types and removed some unused misc +// classes +// +// 43 1/19/00 6:33p Steven +// Added kill_thread stuff. +// +// 42 1/19/00 12:08p Steven +// Added to dialog stuff so that a specific sound could be played, +// fixed anim_done never being set on the first animation and +// fixed death a little. +// +// 41 1/17/00 10:20p Jimdose +// Rewrote state system initialization. Made conditionals defined +// with array. +// Made Evaluate functions early exit +// +// 40 1/14/00 5:06p Markd +// Removed surface num, tri_num and damage_multiplier from +// multiple functions and events +// +// 39 1/14/00 5:01p Steven +// Added stage stuff. +// +// 38 1/13/00 7:07p Steven +// Lots and lots of cleanup and fixed lip syncing. +// +// 37 1/07/00 6:33p Steven +// Stopped using dummy.tik for gibs. +// +// 36 1/06/00 6:49p Steven +// Removed need for dummy.tik and added a can jump to enemy ai +// check. +// +// 35 1/05/00 7:25p Jimdose +// made angle functions all use the same coordinate system +// AngleVectors now returns left instead of right +// no longer need to invert pitch +// +// 34 1/05/00 6:43p Steven +// More work on spawngib and fixed some traces. +// +// 33 1/05/00 3:07p Jimdose +// got rid of inverted pitch in MyGunAngles +// +// 32 1/05/00 1:53p Steven +// Added a lot to the spawn gib stuff, fixed the turning speed +// issue, and fixed a death state problem. +// +// 31 12/22/99 5:11p Steven +// Added incoming melee and incoming projectiles checks, fixed +// CanWalkTo a little and readded turn speed stuff. +// +// 30 12/20/99 6:50p Steven +// Moved jumpxy to sentient and clened up some stuff. +// +// 29 12/17/99 8:26p Jimdose +// got rid of unused vars and functions +// +// 28 12/17/99 5:40p Steven +// Added actor jump event. +// +// 27 12/07/99 6:09p Aldie +// Added weapon charging +// +// 26 12/01/99 4:56p Markd +// fixed some reference versus pointer issues with RandomAnimate +// and NewAnim +// +// 25 12/01/99 3:12p Steven +// Added an onground check and made it so dead flying actors +// always fall to the ground. +// +// 24 11/19/99 4:54p Steven +// Added some deathfade stuff back in. +// +// 23 11/19/99 4:29p Steven +// Minor fixes. +// +// 22 11/19/99 11:30a Steven +// Fixed AnimSame, added commands so actors could tell each other +// to do things, and added a health less than check for ai. +// +// 21 11/12/99 6:22p Steven +// Made state flags available to other part entities and added a +// attack_vector to melee attacks. +// +// 20 11/10/99 6:10p Steven +// Added means of death to melee attack, stopped prethinking on +// dead actors, and fixed a bug dealing with actors going back to +// sleep. +// +// 19 11/05/99 5:24p Steven +// Added attack_width to melee attacks. +// +// 18 10/28/99 6:34p Steven +// Fixed a bug where the actor would go to sleep when doing +// scripting. +// +// 17 10/27/99 10:26a Steven +// Added only shootable contents stuff. +// +// 16 10/21/99 5:26p Markd +// removed head_modelindex +// +// 15 10/21/99 5:24p Steven +// General AI work. +// +// 14 10/19/99 7:52p Markd +// Removed three part model system +// +// 13 10/19/99 7:10p Steven +// Lots of AI work. +// +// 12 10/11/99 7:50p Steven +// Major cleanup, made it so scripting and ai could co-exist, and +// fixed some actor bugs. +// +// 11 10/07/99 5:34p Steven +// Some stimuli work and some event documentation. +// +// 10 10/01/99 4:51p Markd +// Made Warning level 4 work on all projects +// +// 9 10/01/99 1:39p Steven +// Event formatting. +// +// 8 9/27/99 5:44p Markd +// began documentation and cleanup phase after merge +// +// 6 9/22/99 4:47p Markd +// fixed more G_GetEntity, G_FindClass and G_GetNextEntity bugs +// +// 5 9/21/99 7:51p Markd +// Fixed a lot of entitynum_none issues +// +// 4 9/20/99 5:23p Steven +// Added a canwalkto method and fixed a collision issue (ownerNum +// not being initialized). +// +// 3 9/16/99 4:47p Jimdose +// removed unused melee code +// +// 2 9/16/99 11:18a Markd +// Continuing merge of code, not functional yet but closer +// +// 1 9/10/99 10:53a Jimdose +// +// 1 9/08/99 3:15p Aldie +// +// 61 9/02/99 3:24p Steven +// Added an ECTS hack for creatures liking each other. +// +// 60 9/01/99 8:15p Steven +// Took out some old gas plant stuff. +// +// 59 9/01/99 3:49p Jimdose +// made checkmovingactorrange use findclientsinradius and only +// check active actors instead of findradius to try to reduce the +// cpu hit. +// +// 58 8/31/99 9:20p Steven +// Made actors melee attack range larger. +// +// 57 8/31/99 2:42p Steven +// Fixed some actor threading issues and added death state +// machine. +// +// 56 8/28/99 6:35p Steven +// More speed up. +// +// 55 8/28/99 6:35p Steven +// Made some checks only check 4 times a second and got rid of +// some more actor thread stuff. +// +// 54 8/28/99 11:42a Steven +// Cleanup and some spinning plant stuff. +// +// 53 8/27/99 5:03p Steven +// More general AI work. +// +// 52 8/24/99 11:24a Steven +// More general AI work. +// +// 51 8/18/99 3:28p Jimdose +// added cylindrical collision detection +// +// 50 8/17/99 5:08p Markd +// Changed all FS_ReadFile's to FS_ReadFileEx's in game code +// +// 49 8/17/99 4:58p Steven +// Some animation work for the AI. +// +// 48 8/16/99 10:29a Steven +// More general work on AI. +// +// 47 8/11/99 8:33p Steven +// Added ability to have a fov of 360 (for plants). +// +// 46 8/11/99 8:00p Steven +// Fixed a bug when checking if anims should be changed from the +// state machine. +// +// 45 8/11/99 7:23p Steven +// Added a behavior done check for the AI. +// +// 44 8/11/99 5:56p Steven +// More general AI work. +// +// 43 8/06/99 6:53p Jimdose +// changed format of state machine callback functions +// +// 42 8/06/99 6:38p Aldie +// Started removing concept of currentWeapon +// +// 41 8/05/99 9:13a Steven +// New AI stuff. +// +// 40 7/08/99 4:28p Markd +// Removed obsolete QUAKED functions +// +// 39 7/06/99 8:33p Jimdose +// removed unused player code +// added state machine for player animation +// +// DESCRIPTION: +// Base class for character AI. +// + +#include "g_local.h" +#include "actor.h" +#include "behavior.h" +#include "scriptmaster.h" +#include "doors.h" +#include "gibs.h" +#include "misc.h" +#include "specialfx.h" +#include "object.h" +#include "scriptslave.h" +#include "explosion.h" +#include "misc.h" +#include "playerstart.h" +#include "characterstate.h" +#include "weaputils.h" +#include "shield.h" +#include "player.h" + +//#define DEBUG_PRINT + +Container SleepList; +Container ActiveList; + +#define TURN_SPEED 20 + +Event EV_Actor_Sleep + ( + "sleep", + EV_DEFAULT, + NULL, + NULL, + "Put the actor to sleep." + ); +Event EV_Actor_Wakeup + ( + "wakeup", + EV_DEFAULT, + NULL, + NULL, + "Wake up the actor." + ); +Event EV_Actor_Fov + ( + "fov", + EV_CONSOLE, + "f", + "fov", + "Sets the actor's field of view (fov)." + ); +Event EV_Actor_VisionDistance + ( + "visiondistance", + EV_DEFAULT, + "f", + "vision_distance", + "Sets the distance the actor can see." + ); +Event EV_Actor_Start + ( + "start", + EV_DEFAULT, + NULL, + NULL, + "Initializes the actor a little, " + "it is not meant to be called from script." + ); +Event EV_Actor_Dead + ( + "dead", + EV_DEFAULT, + NULL, + NULL, + "Does everything necessary when an actor dies, " + "it is not meant to be called from script." + ); +Event EV_Actor_Friend + ( + "friend", + EV_DEFAULT, + NULL, + NULL, + "Makes the actor allied to the player." + ); +Event EV_Actor_Civilian + ( + "civilian", + EV_DEFAULT, + NULL, + NULL, + "Makes the actor nuetral to all, runs from danger." + ); +Event EV_Actor_Enemy + ( + "enemy", + EV_DEFAULT, + NULL, + NULL, + "Makes the actor an enemy to the player." + ); +Event EV_Actor_Monster + ( + "monster", + EV_DEFAULT, + NULL, + NULL, + "Makes the actor an enemy to player, civilians, and inanimate objects." + ); +Event EV_Actor_Animal + ( + "animal", + EV_DEFAULT, + NULL, + NULL, + "Makes the actor neutral to all." + ); +Event EV_Actor_Inanimate + ( + "inanimate", + EV_DEFAULT, + NULL, + NULL, + "Makes the actor an inanimate object." + ); +Event EV_Actor_SetEnemyType + ( + "enemytype", + EV_DEFAULT, + "s", + "enemytype", + "Sets the name of this actor's enemy type." + ); +Event EV_Actor_Swim + ( + "swim", + EV_DEFAULT, + NULL, + NULL, + "Specifies actor as being able to swim." + ); +Event EV_Actor_Fly + ( + "fly", + EV_DEFAULT, + "B", + "fly_bool", + "Specifies actor as being able to fly (optional bool can turn fly on or off)." + ); +Event EV_Actor_NotLand + ( + "noland", + EV_DEFAULT, + NULL, + NULL, + "Specifies actor as not being able to walk on land." + ); +Event EV_Actor_Thread + ( + "thread", + EV_DEFAULT, + "s", + "label", + "Sets which thread to use for this actor." + ); +Event EV_Actor_RunThread + ( + "runthread", + EV_DEFAULT, + "s", + "label", + "Runs the specified thread." + ); +Event EV_Actor_EndThread + ( + "endthread", + EV_DEFAULT, + NULL, + NULL, + "Ends the actors thread." + ); +Event EV_Actor_Statemap + ( + "statemap", + EV_DEFAULT, + "sS", + "statemap_name state_name", + "Sets which statemap file to use and optionally what the first state to go to." + ); +Event EV_Actor_IfEnemyVisible + ( + "ifenemyvisible", + EV_DEFAULT, + "SSSSSS", + "token1 token2 token3 token4 token5 token6", + "Process the following command if enemy is visible" + ); +Event EV_Actor_IfNear + ( + "ifnear", + EV_DEFAULT, + "sfSSSSSS", + "name distance token1 token2 token3 token4 token5 token6", + "Process the following command if enemy is within specified distance" + ); +Event EV_Actor_ForwardSpeed + ( + "forwardspeed", + EV_DEFAULT, + "f", + "forwardspeed", + "Sets the actor's forward speed." + ); +Event EV_Actor_Idle + ( + "idle", + EV_DEFAULT, + "S", + "state_name", + "Tells the actor to go into idle mode." + ); +Event EV_Actor_LookAt + ( + "lookat", + EV_DEFAULT, + "e", + "ent", + "Specifies an entity to look at." + ); +Event EV_Actor_TurnTo + ( + "turnto", + EV_DEFAULT, + "f", + "direction", + "Specifies the direction to look in." + ); +Event EV_Actor_HeadWatch + ( + "headwatch", + EV_DEFAULT, + "eF", + "entity_to_watch max_speed", + "Actor watches the specified entity by turning his head." + ); +Event EV_Actor_ResetHead + ( + "resethead", + EV_DEFAULT, + "F", + "max_speed", + "Actor resets its head back to looking forwards." + ); +Event EV_Actor_FinishedBehavior + ( + "finishedbehavior", + EV_DEFAULT, + NULL, + NULL, + "Ends the current behavior, " + "it is not meant to be called from script." + ); +Event EV_Actor_NotifyBehavior + ( + "notifybehavior", + EV_DEFAULT, + NULL, + NULL, + "Notifies the current behavior of an event," + "it is not meant to be called from script." + ); +Event EV_Actor_WalkTo + ( + "walkto", + EV_DEFAULT, + "sS", + "pathnode anim_name", + "Actor walks to specified path node" + ); +Event EV_Actor_WalkWatch + ( + "walkwatch", + EV_DEFAULT, + "seS", + "pathnode entity anim_name", + "Actor walks to specified path node and watches the specified entity" + ); +Event EV_Actor_WarpTo + ( + "warpto", + EV_DEFAULT, + "s", + "node_name", + "Warps the actor to the specified node" + ); +Event EV_Actor_JumpTo + ( + "jumpto", + EV_DEFAULT, + "SSSSSS", + "token1 token2 token3 token4 token5 token6", + "Actor jumps to specified path node" + ); +Event EV_Actor_RunTo + ( + "runto", + EV_DEFAULT, + "SSSSSS", + "token1 token2 token3 token4 token5 token6", + "Actor runs to specified path node" + ); +Event EV_Actor_PickupEnt + ( + "pickupent", + EV_DEFAULT, + "es", + "entity_to_pickup pickup_anim_name", + "Makes actor pick up the specified entity" + ); +Event EV_Actor_ThrowEnt + ( + "throwent", + EV_DEFAULT, + "s", + "throw_anim_name", + "Makes actor throw the entity in hands" + ); +Event EV_Actor_Anim + ( + "anim", + EV_DEFAULT, + "s", + "anim_name", + "Starts the PlayAnim behavior." + ); +Event EV_Actor_Attack + ( + "attack", + EV_DEFAULT, + "e", + "ent", + "Makes the actor attack the specified entity." + ); +Event EV_Actor_AttackPlayer + ( + "attackplayer", + EV_DEFAULT, + NULL, + NULL, + "Makes enemies of all the players." + ); +Event EV_Actor_ReserveNode + ( + "reservenode", + EV_DEFAULT, + "vf", + "pos time", + "Reserves a path node for the specified amount of time." + ); +Event EV_Actor_ReleaseNode + ( + "releasenode", + EV_DEFAULT, + "v", + "pos", + "Releases a path node from being reserved." + ); +Event EV_Actor_IfCanHideAt + ( + "ifcanhideat", + EV_DEFAULT, + "vSSSSSS", + "pos token1 token2 token3 token4 token5 token6", + "Processes command if actor can hide at specified position." + ); +Event EV_Actor_IfEnemyWithin + ( + "ifenemywithin", + EV_DEFAULT, + "fSSSSSS", + "distance token1 token2 token3 token4 token5 token6", + "Processes command if actor is within distance of its current enemy." + ); +Event EV_Actor_Remove + ( + "remove_useless", + EV_DEFAULT, + NULL, + NULL, + "Removes a useless dead body from the game." + ); +Event EV_Actor_Melee + ( + "melee", + EV_DEFAULT, + "FSSVFIF", + "damage tag_name means_of_death attack_vector knockback use_pitch_to_enemy attack_min_height", + "Makes the actor do a melee attack.\n" + " attack_vector = \"width length height\"" + ); +Event EV_Actor_PainThreshold + ( + "painthreshold", + EV_DEFAULT, + "f", + "pain_threshold", + "Sets the actor's pain threshold." + ); +Event EV_Actor_SetKillThread + ( + "killthread", + EV_DEFAULT, + "s", + "kill_thread", + "Sets the actor's kill thread." + ); +Event EV_Actor_EyePositionOffset + ( + "eyeoffset", + EV_DEFAULT, + "v", + "eyeoffset", + "Sets the actor's eye position." + ); +Event EV_Actor_DeathFade + ( + "deathfade", + EV_DEFAULT, + NULL, + NULL, + "Makes the actor fade when dead." + ); +Event EV_Actor_DeathShrink + ( + "deathshrink", + EV_DEFAULT, + NULL, + NULL, + "Makes the actor shrink when dead." + ); +Event EV_Actor_DeathSink + ( + "deathsink", + EV_DEFAULT, + NULL, + NULL, + "Makes the actor sink into the ground when dead." + ); +Event EV_Actor_StaySolid + ( + "staysolid", + EV_DEFAULT, + NULL, + NULL, + "Makes the actor stay solid after death." + ); +Event EV_Actor_NoChatter + ( + "nochatter", + EV_DEFAULT, + NULL, + NULL, + "Makes the actor not chatter." + ); +Event EV_Actor_TurnSpeed + ( + "turnspeed", + EV_DEFAULT, + "f", + "turnspeed", + "Sets the actor's turnspeed." + ); +Event EV_Actor_WatchOffset + ( + "watchoffset", + EV_DEFAULT, + "v", + "offset", + "Sets the actor's watch offset." + ); +Event EV_Anim_Done + ( + "anim_done", + EV_DEFAULT, + NULL, + NULL, + "Called when the actor's animation is done, " + "it is not meant to be called from script." + ); +Event EV_Actor_ProjAttack + ( + "proj", + EV_DEFAULT, + "ssIBF", + "tag_name projectile_name number_of_tags arc_bool speed", + "Fires a projectile from the actor towards the current enemy." + ); +Event EV_Actor_BulletAttack + ( + "bullet", + EV_DEFAULT, + "sB", + "tag_name use_current_pitch", + "Fires a bullet from the actor from the specified tag towards the current enemy." + ); +Event EV_Actor_Active + ( + "active", + EV_DEFAULT, + "i", + "active_flag", + "Specifies whether the actor's is active or not." + ); +Event EV_Actor_SpawnGib + ( + "spawngib", + EV_DEFAULT, + "vffssSSSSSSSS", + "offset final_pitch width cap_name surface_name1 surface_name2 surface_name3 surface_name4 surface_name5 surface_name6 surface_name7 surface_name8 surface_name9" , + "Spawns a body part." + ); +Event EV_Actor_SpawnGibAtTag + ( + "spawngibattag", + EV_DEFAULT, + "sffssSSSSSSSS", + "tag_name final_pitch width cap_name surface_name1 surface_name2 surface_name3 surface_name4 surface_name5 surface_name6 surface_name7 surface_name8 surface_name9" , + "Spawns a body part." + ); +Event EV_Actor_SpawnNamedGib + ( + "spawnnamedgib", + EV_DEFAULT, + "ssff", + "gib_name tag_name final_pitch width", + "Spawns a body named gib." + ); +Event EV_Actor_SpawnBlood + ( + "spawnblood", + EV_DEFAULT, + "ssB", + "blood_name tag_name use_last_spawn_result" , + "Spawns blood at the specified tag." + ); +Event EV_Actor_AIOn + ( + "ai_on", + EV_DEFAULT, + NULL, + NULL, + "Turns the AI on for this actor." + ); +Event EV_Actor_AIOff + ( + "ai_off", + EV_DEFAULT, + NULL, + NULL, + "Turns the AI off for this actor." + ); +Event EV_Actor_AIDeaf + ( + "ai_deaf", + EV_DEFAULT, + NULL, + NULL, + "Makes the actor ignore sounds." + ); +Event EV_Actor_AIDumb + ( + "ai_dumb", + EV_DEFAULT, + NULL, + NULL, + "Makes the actor ignore sounds and sight." + ); +Event EV_Actor_Deaf + ( + "deaf", + EV_DEFAULT, + NULL, + NULL, + "Makes the actor permanently deaf (will always ignore sounds)." + ); +Event EV_Actor_Blind + ( + "blind", + EV_DEFAULT, + NULL, + NULL, + "Makes the actor permanently blind (will never try to see)." + ); +Event EV_Actor_SetIdleThread + ( + "setidlethread", + EV_DEFAULT, + "s", + "thread", + "Sets the thread that will be run if this actor gets back to the idle state again." + ); +Event EV_Actor_SetMaxInactiveTime + ( + "max_inactive_time", + EV_DEFAULT, + "f", + "max_inactive_time", + "Sets the maximum amount of time an actor will stay idle before going to sleep.\n" + "Also sepecifies the maximum amount of time an actor will keep looking for an\n" + "enemy that the actor can no longer see." + ); +Event EV_ActorRegisterParts + ( + "register_parts", + EV_DEFAULT, + "ei", + "entity forward", + "Registers the passed in part as another part of this actor and specifies\n" + "whether or not to forward this message to the other parts." + ); +Event EV_ActorRegisterSelf + ( + "register_self", + EV_DEFAULT, + NULL, + NULL, + "Starts registration process for multi-entity actors" + ); +Event EV_ActorName + ( + "name", + EV_DEFAULT, + "s", + "name", + "Specifies the name of this actor type." + ); +Event EV_ActorPartName + ( + "part_name", + EV_DEFAULT, + "s", + "part_name", + "Specifies the name of this part (implying that this is a multi-part creature." + ); +Event EV_ActorSetupTriggerField + ( + "trigger_field", + EV_DEFAULT, + "vv", + "min max", + "Specifies to create a trigger field around the actor of the specified size." + ); +Event EV_ActorTriggerTouched + ( + "trigger_touched", + EV_DEFAULT, + "e", + "ent", + "Notifies the actor that its trigger field has been touched." + ); +Event EV_ActorOnlyShootable + ( + "only_shootable", + EV_DEFAULT, + NULL, + NULL, + "Makes the actor solid only to projectiles." + ); +Event EV_ActorIncomingProjectile + ( + "incoming_proj", + EV_DEFAULT, + "e", + "ent", + "Notifies the actor of an incoming projectile." + ); +Event EV_ActorSpawnActor + ( + "spawnactor", + EV_DEFAULT, + "ssibffF", + "model_name tag_name how_many attack width height spawn_offset", + "Spawns the specified number of actors." + ); +Event EV_ActorSpawnActorAtLocation + ( + "spawnactoratlocation", + EV_DEFAULT, + "ssibff", + "model_name pathnode_name how_many_path_nodes attack width height", + "Spawns the specified actor at the specified pathnode." + ); +Event EV_Actor_AddDialog + ( + "dialog", + EV_DEFAULT, + "sSSSSSS", + "alias token1 token2 token3 token4 token5 token6", + "Add a dialog to this sentient." + ); +Event EV_Actor_DialogDone + ( + "dialogdone", + EV_DEFAULT, + NULL, + NULL, + "Called when the sentient's dialog is done, " + "it is not meant to be called from script." + ); +Event EV_Actor_PlayDialog + ( + "playdialog", + EV_DEFAULT, + "SSE", + "sound_file state_name user", + "Plays a dialog." + ); +Event EV_Actor_StopDialog + ( + "stopdialog", + EV_DEFAULT, + NULL, + NULL, + "Stops the actor's dialog." + ); +Event EV_Actor_AllowTalk + ( + "allowtalk", + EV_DEFAULT, + "i", + "allow_bool", + "Sets whether or not the actor will bother to talk to the player." + ); +Event EV_Actor_AllowHangBack + ( + "allowhangback", + EV_DEFAULT, + "i", + "allow_bool", + "Sets whether or not the actor will bother to hang back." + ); +Event EV_Actor_SolidMask + ( + "solidmask", + EV_DEFAULT, + NULL, + NULL, + "Makes the actor use a solid mask." + ); +Event EV_Actor_NotSolidMask + ( + "notsolidmask", + EV_DEFAULT, + NULL, + NULL, + "Makes the actor use a nonsolid mask." + ); +Event EV_Actor_NoMask + ( + "nomask", + EV_DEFAULT, + NULL, + NULL, + "Makes the actor use a mask of 0." + ); +Event EV_Actor_SetMask + ( + "setmask", + EV_DEFAULT, + "s", + "mask_name", + "Sets the actor's mask to the specified mask." + ); +Event EV_Actor_Pickup + ( + "actor_pickup", + EV_DEFAULT, + "s", + "tag_name", + "Makes the actor pickup current pickup_ent (should only be called from a tiki)." + ); +Event EV_Actor_Throw + ( + "actor_throw", + EV_DEFAULT, + "s", + "tag_name", + "Makes the actor throw whatever is in its hand (should only be called from a tiki)." + ); +Event EV_Actor_DamageOnceStart + ( + "damage_once_start", + EV_DEFAULT, + NULL, + NULL, + "Makes the actor only do melee damage at most once during this attack." + ); +Event EV_Actor_DamageOnceStop + ( + "damage_once_stop", + EV_DEFAULT, + NULL, + NULL, + "Specifies that the actor is done with the damage once event." + ); +Event EV_Actor_GetNearestEnemy + ( + "getnearestenemy", + EV_DEFAULT, + NULL, + NULL, + "Sets currentEnemy to the nearest enemy." + ); +Event EV_Actor_GetRandomEnemy + ( + "getrandomenemy", + EV_DEFAULT, + "f", + "range", + "Sets currentEnemy to a random enemy in range." + ); +Event EV_Actor_DamageEnemy + ( + "damageenemy", + EV_DEFAULT, + "f", + "damage", + "Damages the current enemy by the specified amount." + ); +Event EV_Actor_TurnTowardsEnemy + ( + "turntowardsenemy", + EV_DEFAULT, + NULL, + NULL, + "Turns the actor towards the current enemy." + ); +Event EV_Actor_Suicide + ( + "suicide", + EV_DEFAULT, + NULL, + NULL, + "Makes the actor commit suicide." + ); +Event EV_Actor_GotoNextStage + ( + "gotonextstage", + EV_DEFAULT, + NULL, + NULL, + "Makes the actor goto his next stage." + ); +Event EV_Actor_GotoPrevStage + ( + "gotoprevstage", + EV_DEFAULT, + NULL, + NULL, + "Makes the actor goto his previous stage." + ); +Event EV_Actor_GotoStage + ( + "gotostage", + EV_DEFAULT, + "i", + "stage_number", + "Makes the actor goto the specified stage." + ); +Event EV_Actor_NotifyOthersAtDeath + ( + "notifyothersatdeath", + EV_DEFAULT, + NULL, + NULL, + "Makes the actor notify other actors of the same type when killed." + ); +Event EV_Actor_SetBounceOff + ( + "bounceoff", + EV_DEFAULT, + NULL, + NULL, + "Makes projectiles bounce off of actor (if they can't damage actor)." + ); +Event EV_Actor_SetHaveThing + ( + "havething", + EV_DEFAULT, + "ib", + "thing_number have_bool", + "Sets whether or not the actor has this thing number." + ); +Event EV_Actor_SetUseGravity + ( + "usegravity", + EV_DEFAULT, + "b", + "use_gravity", + "Tells the actor whether or not to use gravity for this animation." + ); +Event EV_Actor_SetDeathSize + ( + "deathsize", + EV_DEFAULT, + "vv", + "min max", + "Sets the actors new size for death." + ); +Event EV_Actor_Fade + ( + "actorfade", + EV_DEFAULT, + NULL, + NULL, + "Makes the actor fade out." + ); +Event EV_Actor_AttackMode + ( + "attackmode", + EV_DEFAULT, + "b", + "attack_bool", + "Makes the actor go directly into attacking the player if bool is true." + ); +Event EV_Actor_AddHealth + ( + "addhealth", + EV_DEFAULT, + "ff", + "health_to_add maxhealth", + "Adds health to the actor." + ); +Event EV_Actor_BounceOff + ( + "bounceoffevent", + EV_DEFAULT, + "v", + "object_origin", + "Lets the actor know something just bounces off of it." + ); +Event EV_Actor_SetBounceOffEffect + ( + "bounceoffeffect", + EV_DEFAULT, + "s", + "bounce_off_effect_name", + "Sets the name of the effect to play when something bounces off the actor." + ); +Event EV_Actor_AddSpawnItem + ( + "spawnitem", + EV_DEFAULT, + "s", + "spawn_item_name", + "Adds this names item to what will be spawned when this actor is killed." + ); +Event EV_Actor_SetSpawnChance + ( + "spawnchance", + EV_DEFAULT, + "f", + "spawn_chance", + "Sets the chance that this actor will spawn something when killed." + ); +Event EV_Actor_ClearSpawnItems + ( + "clearspawnitems", + EV_DEFAULT, + NULL, + NULL, + "Clears the list of items to spawn when this actor is killed." + ); +Event EV_Actor_SetAllowFall + ( + "allowfall", + EV_DEFAULT, + "B", + "allow_fall_bool", + "Makes the actor ignore falls when trying to move." + ); +Event EV_Actor_SetCanBeFinishedBy + ( + "canbefinishedby", + EV_DEFAULT, + "sSSSSS", + "mod1 mod2 mod3 mod4 mod5 mod6", + "Adds to the can be finished by list for this actor." + ); +Event EV_Actor_SetFeetWidth + ( + "feetwidth", + EV_DEFAULT, + "f", + "feet_width", + "Sets the width of the feet for this actor if different than the bounding box size." + ); +Event EV_Actor_SetCanWalkOnOthers + ( + "canwalkonothers", + EV_DEFAULT, + NULL, + NULL, + "Allows the actor to walk on top of others." + ); +Event EV_Actor_Push + ( + "push", + EV_DEFAULT, + "v", + "dir", + "Pushes the actor in the specified direction." + ); +Event EV_Actor_Pushable + ( + "pushable", + EV_DEFAULT, + NULL, + NULL, + "Sets whether or not an actor can be pushed out of the way." + ); +Event EV_Actor_ChargeWater + ( + "chargewater", + EV_DEFAULT, + "ff", + "damage range", + "Does a charge water attack." + ); +Event EV_Actor_SendCommand + ( + "sendcommand", + EV_DEFAULT, + "ss", + "command part_name", + "Sends a command to another one of its parts." + ); +Event EV_Actor_SetAttackableByActors + ( + "attackablebyactors", + EV_DEFAULT, + "b", + "attackable_by_actors", + "Sets whether or not this actor is allowed to be attacked by other actors." + ); +Event EV_Actor_SetAttackActors + ( + "attackactors", + EV_DEFAULT, + NULL, + NULL, + "Sets this actor to attack other actors." + ); +Event EV_Actor_SetTargetable + ( + "targetable", + EV_DEFAULT, + "b", + "should_target", + "Sets whether or not this actor should be targetable by the player." + ); +Event EV_Actor_ChangeType + ( + "changetype", + EV_DEFAULT, + "s", + "new_model_name", + "Changes the actor to the specified new type of actor." + ); +Event EV_Actor_IgnoreMonsterClip + ( + "ignoremonsterclip", + EV_DEFAULT, + NULL, + NULL, + "Makes the actor ignore monster clip brushes." + ); +Event EV_Actor_MinimumMeleeHeight + ( + "minmeleeheight", + EV_DEFAULT, + "f", + "minimum_height", + "Sets the minimum height a melee attack has to be to hurt the actor." + ); +Event EV_Actor_SetDamageAngles + ( + "damageangles", + EV_DEFAULT, + "f", + "damage_angles", + "Sets the the angles where the actor can be hurt (like fov)." + ); +Event EV_Actor_Immortal + ( + "immortal", + EV_DEFAULT, + "b", + "immortal_bool", + "Sets whether or not the actor is immortal or not." + ); +Event EV_Actor_HeadTwitch + ( + "headtwitch", + EV_DEFAULT, + "B", + "end", + "Makes the actors head twitch a little(used while talking)." + ); +Event EV_Actor_HeadTwitchEveryFrame + ( + "headtwitcheveryframe", + EV_DEFAULT, + NULL, + NULL, + "Makes the actors head twitch a little(used while talking)." + ); +Event EV_Actor_SetDieCompletely + ( + "diecompletely", + EV_DEFAULT, + "b", + "die_bool", + "Sets whether or not the actor dies completely (if he doesn't he mostly just" + " runs his kill_thread)." + ); +Event EV_Actor_SetBleedAfterDeath + ( + "bleed_after_death", + EV_DEFAULT, + "b", + "bleed_bool", + "Sets whether or not the actor will bleed after dying." + ); +Event EV_Actor_IgnorePlacementWarning + ( + "ignore_placement_warning", + EV_DEFAULT, + "s", + "warning_string", + "Makes the specified placement warning not get printed for this actor." + ); +Event EV_Actor_SetIdleStateName + ( + "set_idle_state_name", + EV_DEFAULT, + "s", + "new_idle_state_name", + "Sets the actor's new idle state name." + ); +Event EV_Actor_SetNotAllowedToKill + ( + "not_allowed_to_kill", + EV_DEFAULT, + NULL, + NULL, + "Player fails the level if he kills an actor with this set." + ); +Event EV_Actor_TouchTriggers + ( + "touchtriggers", + EV_DEFAULT, + "b", + "touch_triggers_bool", + "Sets whether or not this actor can touch triggers or not." + ); +Event EV_Actor_IgnoreWater + ( + "ignorewater", + EV_DEFAULT, + "b", + "ignore_water_bool", + "Sets whether or not this actor will ignore water when moving." + ); +Event EV_Actor_NeverIgnoreSounds + ( + "neverignoresounds", + EV_DEFAULT, + NULL, + NULL, + "Makes the actor always listen to sounds even if it already has an enemy." + ); +Event EV_Actor_SimplePathfinding + ( + "simplepathfinding", + EV_DEFAULT, + NULL, + NULL, + "Makes the actor use simplier path finding." + ); +Event EV_Actor_NoPainSounds + ( + "nopainsounds", + EV_DEFAULT, + NULL, + NULL, + "Makes the actor not broadcast sounds (AI stimuli) when taking pain or killed." + ); +Event EV_Actor_IncrementNumSpawns + ( + "incrementnumspawns", + EV_DEFAULT, + NULL, + NULL, + "Increments the number of spawns this actor has." + ); +Event EV_Actor_DecrementNumSpawns + ( + "decrementnumspawns", + EV_DEFAULT, + NULL, + NULL, + "Decrements the number of spawns this actor has." + ); +Event EV_Actor_SetWaterLevel + ( + "waterlevel", + EV_DEFAULT, + "f", + "waterlevel", + "Sets the actor's water level." + ); +Event EV_Actor_UpdateBossHealth + ( + "updatebosshealth", + EV_DEFAULT, + "f", + "waterlevel", + "Tells the actor to update the bosshealth cvar each time it thinks." + ); +Event EV_Actor_SetMaxBossHealth + ( + "maxbosshealth", + EV_DEFAULT, + "f", + "max_boss_health", + "Sets the actor's max boss health." + ); +Event EV_Actor_IgnorePainFromActors + ( + "ignorepainfromactors", + EV_DEFAULT, + NULL, + NULL, + "Makes this actor ignore pain from other actors." + ); +Event EV_Actor_DamageAllowed + ( + "damageallowed", + EV_DEFAULT, + "b", + "damage_allowed", + "Turns melee damage on and off." + ); +Event EV_Actor_AlwaysGiveWater + ( + "alwaysgivewater", + EV_DEFAULT, + "b", + "give_water", + "Turns the always give water bool on off (gives water from soul sucker weapon)." + ); + + +CLASS_DECLARATION( Sentient, Actor, "monster_generic" ) + { + { &EV_Activate, ActivateEvent }, + { &EV_Use, UseEvent }, + + { &EV_Actor_Sleep, Sleep }, + { &EV_Actor_Wakeup, Wakeup }, + + { &EV_Actor_Start, Start }, + { &EV_Pain, Pain }, + { &EV_Killed, Killed }, + { &EV_Actor_Dead, Dead }, + { &EV_Actor_Suicide, Suicide }, + + { &EV_Actor_ForwardSpeed, ForwardSpeedEvent }, + + { &EV_Actor_Fov, SetFov }, + { &EV_Actor_VisionDistance, SetVisionDistance }, + + { &EV_Actor_Friend, FriendEvent }, + { &EV_Actor_Civilian, CivilianEvent }, + { &EV_Actor_Enemy, EnemyEvent }, + { &EV_Actor_Monster, MonsterEvent }, + { &EV_Actor_Animal, AnimalEvent }, + { &EV_Actor_Inanimate, InanimateEvent }, + { &EV_Actor_SetEnemyType, SetEnemyType }, + + { &EV_Actor_Swim, SwimEvent }, + { &EV_Actor_Fly, FlyEvent }, + { &EV_Actor_NotLand, NotLandEvent }, + + { &EV_Actor_Thread, SetThread }, + { &EV_Actor_RunThread, RunThread }, + { &EV_Actor_EndThread, EndThread }, + + { &EV_Actor_Statemap, LoadStateMap }, + + { &EV_Actor_IfEnemyVisible, IfEnemyVisibleEvent }, + { &EV_Actor_IfNear, IfNearEvent }, + { &EV_Actor_Idle, IdleEvent }, + { &EV_Actor_LookAt, LookAt }, + { &EV_Actor_TurnTo, TurnToEvent }, + { &EV_Actor_HeadWatch, HeadWatchEvent }, + { &EV_Actor_ResetHead, ResetHeadEvent }, + { &EV_Actor_FinishedBehavior, FinishedBehavior }, + { &EV_Actor_NotifyBehavior, NotifyBehavior }, + { &EV_Actor_WalkTo, WalkTo }, + { &EV_Actor_WalkWatch, WalkWatch }, + { &EV_Actor_JumpTo, JumpToEvent }, + { &EV_Actor_RunTo, RunTo }, + { &EV_Actor_WarpTo, WarpTo }, + { &EV_Actor_Anim, Anim }, + { &EV_Actor_Attack, AttackEntity }, + { &EV_Actor_AttackPlayer, AttackPlayer }, + { &EV_Actor_Remove, RemoveUselessBody }, + + { &EV_Actor_ReserveNode, ReserveNodeEvent }, + { &EV_Actor_ReleaseNode, ReleaseNodeEvent }, + { &EV_Actor_IfCanHideAt, IfCanHideAtEvent }, + { &EV_Actor_IfEnemyWithin, IfEnemyWithinEvent }, + + { &EV_HeardSound, HeardSound }, + + { &EV_Actor_Melee, MeleeEvent }, + + { &EV_Actor_PainThreshold, SetPainThresholdEvent }, + { &EV_Actor_SetKillThread, SetKillThreadEvent }, + { &EV_SetHealth, SetHealth }, + { &EV_Actor_AddHealth, AddHealth }, + { &EV_Actor_EyePositionOffset, EyeOffset }, + { &EV_Actor_DeathFade, DeathFadeEvent }, + { &EV_Actor_DeathShrink, DeathShrinkEvent }, + { &EV_Actor_DeathSink, DeathSinkEvent }, + { &EV_Actor_StaySolid, StaySolidEvent }, + { &EV_Actor_NoChatter, NoChatterEvent }, + { &EV_Actor_TurnSpeed, SetTurnSpeed }, + { &EV_Actor_WatchOffset, SetWatchOffset }, + + { &EV_ScriptThread_Goto, GotoEvent }, + + { &EV_Actor_SetMaxInactiveTime, SetMaxInactiveTime }, + + { &EV_Anim_Done, AnimDone }, + + { &EV_Actor_ProjAttack, FireProjectile }, + { &EV_Actor_BulletAttack, FireBullet }, + + { &EV_Actor_Active, Active }, + + { &EV_Actor_SpawnGib, SpawnGib }, + { &EV_Actor_SpawnGibAtTag, SpawnGibAtTag }, + { &EV_Actor_SpawnNamedGib, SpawnNamedGib }, + { &EV_Actor_SpawnBlood, SpawnBlood }, + + { &EV_Actor_AIOn, TurnAIOn }, + { &EV_Actor_AIOff, TurnAIOff }, + + { &EV_Actor_AIDeaf, Deaf }, + { &EV_Actor_Deaf, PermanentDeaf }, + { &EV_Actor_Blind, PermanentBlind }, + { &EV_Actor_AIDumb, Dumb }, + + { &EV_Actor_SetIdleThread, SetIdleThread }, + + { &EV_ActorRegisterParts, RegisterParts }, + { &EV_ActorRegisterSelf, RegisterSelf }, + { &EV_ActorName, Name }, + { &EV_ActorPartName, PartName }, + { &EV_Actor_SendCommand, SendCommand }, + + { &EV_ActorSetupTriggerField, SetupTriggerField }, + { &EV_ActorTriggerTouched, TriggerTouched }, + { &EV_ActorOnlyShootable, OnlyShootable }, + + { &EV_ActorIncomingProjectile, IncomingProjectile }, + + { &EV_ActorSpawnActor, SpawnActorAtTag }, + { &EV_ActorSpawnActorAtLocation, SpawnActorAtLocation }, + + { &EV_Actor_AddDialog, AddDialog }, + { &EV_Actor_DialogDone, DialogDone }, + { &EV_Actor_PlayDialog, PlayDialog }, + { &EV_Actor_StopDialog, StopDialog }, + { &EV_Sentient_SetMouthAngle, SetMouthAngle }, + + { &EV_Actor_AllowTalk, AllowTalk }, + { &EV_Actor_AllowHangBack, AllowHangBack }, + + { &EV_Actor_SolidMask, SolidMask }, + { &EV_Actor_IgnoreMonsterClip, IgnoreMonsterClip }, + { &EV_Actor_NotSolidMask, NotSolidMask }, + { &EV_Actor_NoMask, NoMask }, + { &EV_Actor_SetMask, SetMask }, + + { &EV_Actor_PickupEnt, PickupEnt }, + { &EV_Actor_ThrowEnt, ThrowEnt }, + + { &EV_Actor_Pickup, Pickup }, + { &EV_Actor_Throw, Throw }, + + { &EV_Actor_DamageOnceStart, DamageOnceStart }, + { &EV_Actor_DamageOnceStop, DamageOnceStop }, + + { &EV_Actor_GetNearestEnemy, GetNearestEnemy }, + { &EV_Actor_GetRandomEnemy, GetRandomEnemy }, + { &EV_Actor_DamageEnemy, DamageEnemy }, + { &EV_Actor_TurnTowardsEnemy, TurnTowardsEnemy }, + + { &EV_Actor_GotoNextStage, GotoNextStage }, + { &EV_Actor_GotoPrevStage, GotoPrevStage }, + { &EV_Actor_GotoStage, GotoStage }, + + { &EV_Actor_NotifyOthersAtDeath, NotifyOthersAtDeath }, + + { &EV_Actor_SetBounceOff, SetBounceOff }, + { &EV_Actor_BounceOff, BounceOffEvent }, + { &EV_Actor_SetBounceOffEffect, SetBounceOffEffect }, + + { &EV_Actor_SetHaveThing, SetHaveThing }, + + { &EV_Actor_SetUseGravity, SetUseGravity }, + { &EV_Actor_SetAllowFall, SetAllowFall }, + + { &EV_Actor_SetDeathSize, SetDeathSize }, + + { &EV_Actor_Fade, FadeEvent }, + + { &EV_Actor_AttackMode, AttackModeEvent }, + + { &EV_Stun, StunEvent }, + + { &EV_Actor_AddSpawnItem, AddSpawnItem }, + { &EV_Actor_SetSpawnChance, SetSpawnChance }, + { &EV_Actor_ClearSpawnItems, ClearSpawnItems }, + + { &EV_Actor_SetCanBeFinishedBy, SetCanBeFinishedBy }, + + { &EV_Actor_SetFeetWidth, SetFeetWidth }, + { &EV_Actor_SetCanWalkOnOthers, SetCanWalkOnOthers }, + + { &EV_Actor_Push, Push }, + { &EV_Actor_Pushable, Pushable }, + + { &EV_Actor_ChargeWater, ChargeWater }, + { &EV_Actor_SetAttackableByActors, SetAttackableByActors }, + { &EV_Actor_SetAttackActors, SetAttackActors }, + + { &EV_Actor_SetTargetable, SetTargetable }, + + { &EV_Actor_ChangeType, ChangeType }, + + { &EV_Actor_MinimumMeleeHeight, MinimumMeleeHeight }, + { &EV_Actor_SetDamageAngles, SetDamageAngles }, + + { &EV_Actor_Immortal, SetImmortal }, + + { &EV_Actor_HeadTwitch, HeadTwitch }, + { &EV_Actor_HeadTwitchEveryFrame, HeadTwitchEveryFrame }, + + { &EV_Actor_SetDieCompletely, SetDieCompletely }, + { &EV_Actor_SetBleedAfterDeath, SetBleedAfterDeath }, + + { &EV_Actor_IgnorePlacementWarning, IgnorePlacementWarning }, + + { &EV_Actor_SetIdleStateName, SetIdleStateName }, + + { &EV_Actor_SetNotAllowedToKill, SetNotAllowedToKill }, + + { &EV_Actor_TouchTriggers, TouchTriggers }, + { &EV_Actor_IgnoreWater, IgnoreWater }, + { &EV_Actor_NeverIgnoreSounds, NeverIgnoreSounds }, + + { &EV_Actor_SimplePathfinding, SimplePathfinding }, + + { &EV_Actor_NoPainSounds, NoPainSounds }, + + { &EV_Actor_IncrementNumSpawns, IncrementNumSpawns }, + { &EV_Actor_DecrementNumSpawns, DecrementNumSpawns }, + + { &EV_Actor_SetWaterLevel, SetWaterLevel }, + + { &EV_Actor_UpdateBossHealth, UpdateBossHealth }, + { &EV_Actor_SetMaxBossHealth, SetMaxBossHealth }, + + { &EV_Actor_IgnorePainFromActors, IgnorePainFromActors }, + + { &EV_Actor_DamageAllowed, DamageAllowed }, + + { &EV_Actor_AlwaysGiveWater, AlwaysGiveWater }, + + { &EV_Touch, Touched }, + + { NULL, NULL } + }; + +//*********************************************************************************************** +// +// Initialization functions +// +//*********************************************************************************************** + +Actor::Actor() + { + Event *immunity_event; + + + // don't spawn monsters in deathmatch + if ( deathmatch->integer || nomonsters->integer ) + { + PostEvent( EV_Remove, EV_REMOVE ); + return; + } + + // + // make sure this is a modelanim entity + // + edict->s.eType = ET_MODELANIM; + + actortype = IS_ENEMY; + + setSolidType( SOLID_BBOX ); + setMoveType( MOVETYPE_STEP ); + + actorrange_time = 0; + + actor_flags1 = 0; + actor_flags2 = 0; + + canseeenemy_time = 0; + SetActorFlag( ACTOR_FLAG_LAST_CANSEEENEMY, false ); + SetActorFlag( ACTOR_FLAG_LAST_CANSEEENEMY_NOFOV, false ); + + health = 100; + max_health = health; + takedamage = DAMAGE_AIM; + mass = 200; + deadflag = DEAD_NO; + + edict->clipmask = MASK_MONSTERSOLID; + edict->svflags |= SVF_MONSTER; + edict->ownerNum = ENTITYNUM_NONE; + + forwardspeed = 0; //FIXME + + statemap = NULL; + SetActorFlag( ACTOR_FLAG_INACTIVE, false ); + SetActorFlag( ACTOR_FLAG_ANIM_DONE, false ); + currentState = NULL; + state_time = level.time; + times_done = 0; + SetActorFlag( ACTOR_FLAG_STATE_DONE_TIME_VALID, false ); + SetActorFlag( ACTOR_FLAG_AI_ON, true ); + stimuli = STIMULI_ALL; + permanent_stimuli = STIMULI_ALL; + last_enemy_sight_time = 0; + next_enemy_try_sight_time = 0; + next_try_sleep_time = 0; + last_time_active = 0; + next_player_near = 0; + + bullet_hits = 0; + + saved_anim_event_name = ""; + + mode = ACTOR_MODE_IDLE; + + state_flags = 0; + + max_inactive_time = MAX_INACTIVE_TIME; + + num_of_spawns = 0; + + SetActorFlag( ACTOR_FLAG_NOISE_HEARD, false ); + + noise_time = 0; + SetActorFlag( ACTOR_FLAG_INVESTIGATING, false ); + + dialog_list = NULL; + SetActorFlag( ACTOR_FLAG_DIALOG_PLAYING, false ); + dialog_done_time = 0; + + stage = 1; + + SetActorFlag( ACTOR_FLAG_NOTIFY_OTHERS_AT_DEATH, false ); + SetActorFlag( ACTOR_FLAG_ALLOW_TALK, true ); + SetActorFlag( ACTOR_FLAG_ALLOW_HANGBACK, true ); + SetActorFlag( ACTOR_FLAG_DAMAGE_ONCE_ON, false ); + SetActorFlag( ACTOR_FLAG_BOUNCE_OFF, false ); + + SetActorFlag( ACTOR_FLAG_HAS_THING1, false ); + SetActorFlag( ACTOR_FLAG_HAS_THING2, false ); + SetActorFlag( ACTOR_FLAG_HAS_THING3, false ); + SetActorFlag( ACTOR_FLAG_HAS_THING4, false ); + + SetActorFlag( ACTOR_FLAG_LAST_ATTACK_HIT, true ); + + SetActorFlag( ACTOR_FLAG_SPAWN_FAILED, false ); + + SetActorFlag( ACTOR_FLAG_FADING_OUT, false ); + + SetActorFlag( ACTOR_FLAG_USE_GRAVITY, true ); + SetActorFlag( ACTOR_FLAG_ALLOW_FALL, false ); + + SetActorFlag( ACTOR_FLAG_STUNNED, false ); + + SetActorFlag( ACTOR_FLAG_PUSHABLE, false ); + + lastmove = STEPMOVE_OK; + + gunoffset = "0 0 44"; + + behavior = NULL; + path = NULL; + + newanimnum = -1; + newanim = ""; + newanimevent = NULL; + last_anim_event_name = ""; + + vision_distance = 1536; + + fov = 150; + fovdot = cos( fov * 0.5 * M_PI / 180.0 ); + + eyeoffset = "0 0 0"; + eyeposition = "0 0 64"; + + SetActorFlag( ACTOR_FLAG_DEATHFADE, false ); + SetActorFlag( ACTOR_FLAG_DEATHSHRINK, false ); + SetActorFlag( ACTOR_FLAG_DEATHSINK, false ); + SetActorFlag( ACTOR_FLAG_NOCHATTER, false ); + + SetActorFlag( ACTOR_FLAG_STAYSOLID, false ); + + SetActorFlag( ACTOR_FLAG_FINISHED, false ); + SetActorFlag( ACTOR_FLAG_IN_LIMBO, false ); + + SetActorFlag( ACTOR_FLAG_CAN_WALK_ON_OTHERS, false ); + + SetActorFlag( ACTOR_FLAG_LAST_TRY_TALK, false ); + + SetActorFlag( ACTOR_FLAG_ATTACKABLE_BY_ACTORS, true ); + SetActorFlag( ACTOR_FLAG_ATTACK_ACTORS, false ); + + SetActorFlag( ACTOR_FLAG_TARGETABLE, true ); + + SetActorFlag( ACTOR_FLAG_IMMORTAL, false ); + + SetActorFlag( ACTOR_FLAG_ALLOWED_TO_KILL, true ); + + turnspeed = TURN_SPEED; + + if ( com_blood->integer ) + { + flags |= FL_BLOOD; + flags |= FL_DIE_GIBS; + } + + // don't talk all at once initially + + chattime = G_Random( 20 ); + nextsoundtime = 0; + + //trig = NULL; + SetActorFlag( ACTOR_FLAG_DEATHGIB, false ); + + // default pain_threshold + pain_threshold = 20; + + startpos = origin; + + next_drown_time = 0; + air_finished = level.time + 5; + last_jump_time = 0; + + groundentity = NULL; + velocity = "0 0 -20"; + + CheckWater(); + + setSize( "-16 -16 0", "16 16 116" ); + showModel(); + + SetActorFlag( ACTOR_FLAG_STARTED, false ); + + spawn_chance = 0; + + feet_width = 0; + + next_find_enemy_time = 0; + + saved_mode = ACTOR_MODE_NONE; + + minimum_melee_height = -100; + damage_angles = 0; + + real_head_pitch = 0; + SetActorFlag( ACTOR_FLAG_TURNING_HEAD, false ); + + SetActorFlag( ACTOR_FLAG_DIE_COMPLETELY, true ); + + SetActorFlag( ACTOR_FLAG_BLEED_AFTER_DEATH, true ); + + next_pain_sound_time = 0; + + SetActorFlag( ACTOR_FLAG_IGNORE_STUCK_WARNING, false ); + SetActorFlag( ACTOR_FLAG_IGNORE_OFF_GROUND_WARNING, false ); + + SetActorFlag( ACTOR_FLAG_TOUCH_TRIGGERS, true ); + + SetActorFlag( ACTOR_FLAG_IGNORE_WATER, false ); + + SetActorFlag( ACTOR_FLAG_NEVER_IGNORE_SOUNDS, false ); + + SetActorFlag( ACTOR_FLAG_SIMPLE_PATHFINDING, false ); + + SetActorFlag( ACTOR_FLAG_NO_PAIN_SOUNDS, false ); + + // All actors start immune to falling damage + + immunity_event = new Event( EV_Sentient_AddImmunity ); + immunity_event->AddString( "falling" ); + ProcessEvent( immunity_event ); + + water_level = 0; + + SetActorFlag( ACTOR_FLAG_UPDATE_BOSS_HEALTH, false ); + max_boss_health = 0; + + SetActorFlag( ACTOR_FLAG_IGNORE_PAIN_FROM_ACTORS, false ); + + SetActorFlag( ACTOR_FLAG_DAMAGE_ALLOWED, true ); + + SetActorFlag( ACTOR_FLAG_ALWAYS_GIVE_WATER, false ); + + if ( !LoadingSavegame ) + PostEvent( EV_Actor_Start, EV_POSTSPAWN ); + } + +Actor::~Actor() + { + if ( actorthread ) + { + actorthread->ProcessEvent( EV_ScriptThread_End ); + actorthread = NULL; + } + + if ( SleepList.ObjectInList( ( Actor * )this ) ) + { + SleepList.RemoveObject( ( Actor * )this ); + } + + if ( ActiveList.ObjectInList( ( Actor * )this ) ) + { + ActiveList.RemoveObject( ( Actor * )this ); + } + + if ( behavior ) + { + delete behavior; + behavior = NULL; + } + + if ( path ) + { + delete path; + path = NULL; + } + + /* if ( trig ) + { + delete trig; + trig = NULL; + } */ + + FreeDialogList(); + } + +void Actor::Sleep + ( + void + ) + + { + // inanimate actors don't target enemies + if ( actortype == IS_INANIMATE ) + { + return; + } + + if ( !SleepList.ObjectInList( ( Actor * )this ) ) + SleepList.AddObject( ( Actor * )this ); + + if ( ActiveList.ObjectInList( ( Actor * )this ) ) + ActiveList.RemoveObject( ( Actor * )this ); + + currentEnemy = NULL; + flags &= ~FL_THINK; + last_enemy_sight_time = 0; + } + +void Actor::Sleep + ( + Event *ev + ) + + { + Sleep(); + } + +void Actor::Wakeup + ( + void + ) + + { + // See if already awake + + if ( flags & FL_THINK && !LoadingSavegame ) + return; + + // inanimate actors don't target enemies + if ( actortype == IS_INANIMATE ) + { + return; + } + + if ( SleepList.ObjectInList( ( Actor * )this ) ) + SleepList.RemoveObject( ( Actor * )this ); + + if ( !ActiveList.ObjectInList( ( Actor * )this ) ) + ActiveList.AddObject( ( Actor * )this ); + + flags |= FL_THINK; + } + +void Actor::Wakeup + ( + Event *ev + ) + + { + Wakeup(); + } + +void Actor::Start + ( + Event *ev + ) + + { + trace_t trace; + Vector end; + Vector start; + qboolean stuck; + str monster_name; + + // Register with other parts of self if there are any + + if ( target.length() > 0 ) + PostEvent( EV_ActorRegisterSelf, FRAMETIME ); + + // add them to the active list (they will be removed by sleep). + ActiveList.AddObject( ( Actor * )this ); + + // Drop actor to the ground + + stuck = false; + + start = origin + Vector( "0 0 1" ); + end = origin; + end[ 2 ] -= 16; + + trace = G_Trace( start, mins, maxs, end, this, MASK_SOLID, false, "Actor::start" ); + + if ( trace.startsolid || trace.allsolid ) + { + stuck = true; + } + else if ( !( flags & FL_FLY ) ) + { + setOrigin( trace.endpos ); + groundentity = trace.ent; + } + + if ( name.length() ) + monster_name = name; + else + monster_name = getClassID(); + + if ( trace.fraction == 1 && movetype == MOVETYPE_STATIONARY && !GetActorFlag( ACTOR_FLAG_IGNORE_OFF_GROUND_WARNING ) ) + { + gi.DPrintf( "%s (%d) off of ground at '%5.1f %5.1f %5.1f'\n", monster_name.c_str(), entnum, origin.x, origin.y, origin.z ); + } + + if ( stuck && !GetActorFlag( ACTOR_FLAG_IGNORE_STUCK_WARNING ) ) + { + groundentity = world->edict; + + gi.DPrintf( "%s (%d) stuck in world at '%5.1f %5.1f %5.1f'\n", monster_name.c_str(), entnum, origin.x, origin.y, origin.z ); + } + + last_origin = origin; + + SetActorFlag( ACTOR_FLAG_HAVE_MOVED, false ); + + last_ground_z = origin.z; + + if ( !behavior || currentBehavior == "Idle" ) + Sleep(); + + SetActorFlag( ACTOR_FLAG_STARTED, true ); + } + +//*********************************************************************************************** +// +// Vision functions +// +//*********************************************************************************************** + +qboolean Actor::WithinVisionDistance + ( + Entity *ent + ) + { + float distance; + + // Use whichever is less : the actor's vision distance or the distance of the farplane (fog) + + if ( (world->farplane_distance != 0) && (world->farplane_distance < vision_distance) ) + distance = world->farplane_distance; + else + distance = vision_distance; + + return WithinDistance( ent, distance ); + } + +inline qboolean Actor::InFOV + ( + Vector pos, + float check_fov, + float check_fovdot + ) + { + Vector delta; + float dot; + + if ( check_fov == 360 ) + return true; + + delta = pos - EyePosition(); + + if ( !delta.x && !delta.y ) + { + // special case for straight up and down + return true; + } + + // give better vertical vision + delta.z = 0; + + delta.normalize(); + dot = DotProduct( orientation[ 0 ], delta ); + + return ( dot > check_fovdot ); + } + +inline qboolean Actor::InFOV + ( + Vector pos + ) + + { + return InFOV( pos, fov, fovdot ); + } + +inline qboolean Actor::InFOV + ( + Entity *ent + ) + + { + return InFOV( ent->centroid ); + } + +inline qboolean Actor::CanSeeFOV + ( + Entity *ent + ) + + { + return InFOV( ent ) && CanSeeFrom( origin, ent ); + } + +inline qboolean Actor::CanSeeFrom + ( + Vector pos, + Entity *ent + ) + + { + trace_t trace; + Vector p; + + p = ent->centroid; + + // Check if he's visible + trace = G_Trace( pos + eyeposition, vec_zero, vec_zero, p, this, MASK_OPAQUE, false, "Actor::CanSeeFrom 1" ); + if ( trace.fraction == 1.0 || trace.ent == ent->edict ) + { + return true; + } + + // Check if his head is visible + p.z = ent->absmax.z; + trace = G_Trace( pos + eyeposition, vec_zero, vec_zero, p, this, MASK_OPAQUE, false, "Actor::CanSeeFrom 2" ); + if ( trace.fraction == 1.0 || trace.ent == ent->edict ) + { + return true; + } + + return false; + } + +qboolean Actor::CanSee + ( + Entity *ent + ) + + { + return CanSeeFrom( origin, ent ); + } + +qboolean Actor::EnemyCanSeeMeFrom + ( + Vector pos + ) + + { + Vector d; + Vector p1; + Vector p2; + + + if ( !IsEntityAlive( currentEnemy ) ) + { + return false; + } + + if ( WithinVisionDistance( currentEnemy ) ) + { + // To check if we're visible, I create a plane that intersects the actor + // and is perpendicular to the delta vector between the actor and his enemy. + // I place four points on this plane that "frame" the actor and check if + // the enemy can see any of those points. + d = currentEnemy->centroid - pos; + d.z = 0; + d.normalize(); + p1.x = -d.y; + p1.y = d.x; + p1 *= max( size.x, size.y ) * 1.44 * 0.5; + p2 = p1; + + p1.z = mins.z; + p2.z = maxs.z; + if ( CanSeeFrom( pos + p1, currentEnemy ) ) + { + return true; + } + if ( CanSeeFrom( pos + p2, currentEnemy ) ) + { + return true; + } + + p1.z = -p1.z; + p2.z = -p2.z; + if ( CanSeeFrom( pos - p1, currentEnemy ) ) + { + return true; + } + if ( CanSeeFrom( pos - p2, currentEnemy ) ) + { + return true; + } + } + + return false; + } + +qboolean Actor::CanSeeEnemyFrom + ( + Vector pos + ) + + { + if ( !IsEntityAlive( currentEnemy ) ) + { + return false; + } + + if ( WithinVisionDistance( currentEnemy ) && CanSeeFrom( pos, currentEnemy ) ) + { + return true; + } + + return false; + } + +qboolean Actor::CanReallySee + ( + Entity *ent + ) + + { + if ( !IsEntityAlive( ent ) ) + return false; + + if ( WithinVisionDistance( ent ) && CanSeeFOV( ent ) ) + return true; + + return false; + } + +//*********************************************************************************************** +// +// Combat functions +// +//*********************************************************************************************** + +void Actor::IncomingProjectile + ( + Event *ev + ) + { + incoming_proj = ev->GetEntity( 1 ); + incoming_time = level.time + .1; //+ G_Random( .1 ); + } + +void Actor::FireProjectile + ( + Event *ev + ) + + { + Vector orig; + Vector dir; + str tag_name; + str projectile_name; + int number_of_tags = 1; + qboolean arc = false; + float speed = 0; + + if ( !currentEnemy ) + return; + + tag_name = ev->GetString( 1 ); + projectile_name = ev->GetString( 2 ); + + if ( ev->NumArgs() > 2 ) + number_of_tags = ev->GetInteger( 3 ); + + if ( ev->NumArgs() > 3 ) + arc = ev->GetBoolean( 4 ); + + if ( ev->NumArgs() > 4 ) + speed = ev->GetFloat( 5 ); + + // Find the closest tag + + if ( !GetClosestTag( tag_name, number_of_tags, currentEnemy->centroid, &orig ) ) + { + // Could not find the tag so just use the centroid of the actor + orig[0] = edict->centroid[0]; + orig[1] = edict->centroid[1]; + orig[2] = edict->centroid[2]; + } + + // Add projectile to world + + dir = currentEnemy->centroid - orig; + + if ( arc ) + { + Vector xydir; + float traveltime; + float vertical_speed; + Vector proj_velocity; + + xydir = dir; + xydir.z = 0; + + if ( speed == 0 ) + speed = 500; + + traveltime = xydir.length() / speed; + + vertical_speed = ( dir.z / traveltime ) + ( 0.5f * gravity * sv_gravity->value * traveltime ); + + xydir.normalize(); + + proj_velocity = speed * xydir; + proj_velocity.z = vertical_speed; + + speed = proj_velocity.length(); + proj_velocity.normalize(); + dir = proj_velocity; + } + + dir.normalize(); + + ProjectileAttack( orig, dir, this, projectile_name.c_str(), 1.0f, speed ); + + SaveAttack( orig, dir ); + } + +void Actor::FireBullet + ( + Event *ev + ) + + { + str tag_name; + qboolean use_current_pitch; + float range = 1000; + float damage; + float knockback; + str means_of_death_string; + int means_of_death; + Vector spread; + Vector pos; + Vector forward; + Vector left; + Vector right; + Vector up; + Vector attack_angles; + Vector dir; + Vector enemy_angles; + + tag_name = ev->GetString( 1 ); + use_current_pitch = ev->GetBoolean( 2 ); + damage = ev->GetFloat( 3 ); + knockback = ev->GetFloat( 4 ); + means_of_death_string = ev->GetString( 5 ); + spread = ev->GetVector( 6 ); + + if ( ev->NumArgs() > 6 ) + range = ev->GetFloat( 7 ); + + // Get the position where the bullet starts + + GetTag( tag_name, &pos, &forward, &left, &up ); + + right = left * -1; + + // Get the real pitch of the bullet attack + + if ( !use_current_pitch && currentEnemy ) + { + attack_angles = forward.toAngles(); + + dir = currentEnemy->centroid - pos; + enemy_angles = dir.toAngles(); + + attack_angles[PITCH] = enemy_angles[PITCH]; + + attack_angles.AngleVectors( &forward, &left, &up ); + + right = left * -1; + } + + means_of_death = MOD_string_to_int( means_of_death_string ); + + BulletAttack( pos, forward, right, up, range, damage, knockback, 0, means_of_death, spread, 1, this ); + + SaveAttack( pos, forward ); + } + +void Actor::SaveAttack + ( + Vector orig, + Vector dir + ) + { + Vector attack_mins; + Vector attack_maxs; + Vector end; + trace_t trace; + qboolean hit; + Entity *ent; + + if ( !currentEnemy ) + { + SetActorFlag( ACTOR_FLAG_LAST_ATTACK_HIT, true ); + return; + } + + // Do trace + + attack_mins = Vector( -1,-1,-1 ); + attack_maxs = Vector( 1,1,1 ); + + end = orig + dir * 8192; + + trace = G_Trace( orig, attack_mins, attack_maxs, end, this, MASK_SHOT, false, "Actor::SaveAttack" ); + + // See what we hit + + last_attack_entity_hit = NULL; + + if ( trace.ent ) + { + ent = trace.ent->entity; + + if ( ent == currentEnemy ) + { + hit = true; + } + else if ( ent->isSubclassOf( Entity ) && ent != world ) + { + last_attack_entity_hit = ent; + last_attack_entity_hit_pos = ent->origin; + hit = false; + } + else + { + hit = false; + } + } + else + { + hit = false; + } + + // Do an extra check because of NOCLIP + + if ( currentEnemy->movetype == MOVETYPE_NOCLIP ) + hit = true; + + // Save last attack info + + last_attack_pos = origin; + + if ( currentEnemy ) + last_attack_enemy_pos = currentEnemy->origin; + + SetActorFlag( ACTOR_FLAG_LAST_ATTACK_HIT, hit ); + } + +qboolean Actor::TestAttack( str tag_name ) + { + qboolean hit; + trace_t trace; + Vector attack_mins; + Vector attack_maxs; + Vector start; + + + // Make sure we still have an enemy and he is hitable + + if ( !currentEnemy ) + return false; + + if ( currentEnemy->movetype == MOVETYPE_NOCLIP ) + return false; + + // Make sure we won't hit any friends + + attack_mins = Vector( -1,-1,-1 ); + attack_maxs = Vector( 1,1,1 ); + + if ( tag_name.length() ) + { + GetTag( tag_name.c_str(), &start ); + } + else + { + start = centroid; + } + + trace = G_Trace( start, attack_mins, attack_maxs, currentEnemy->centroid, this, MASK_SHOT, false, "Actor::TestAttack" ); + + if ( trace.ent && trace.ent->entity != currentEnemy && trace.ent->entity->isSubclassOf( Sentient ) && !IsEnemy( trace.ent->entity ) ) + return false; + + // See if we hit last time + + hit = GetActorFlag( ACTOR_FLAG_LAST_ATTACK_HIT ); + + if ( hit ) + return true; + + // Didn't hit last time so see if anything has changed + + // See if actor has moved + + if ( last_attack_pos != origin ) + return true; + + // See if enemy has moved + + if ( last_attack_enemy_pos != currentEnemy->origin ) + return true; + + // See if entity in the way has moved + + if ( last_attack_entity_hit && last_attack_entity_hit_pos != last_attack_entity_hit->origin ) + return true; + + // See if entity in the way was a door and has opened + + if ( last_attack_entity_hit && last_attack_entity_hit->isSubclassOf( Entity ) ) + { + Door *door; + + door = (Door *)(Entity *)last_attack_entity_hit; + + if ( door->isOpen() ) + return true; + } + + // See if entity in the way has become non-solid + + if ( last_attack_entity_hit && last_attack_entity_hit->edict->solid == SOLID_NOT ) + return true; + + // Nothing has changed so this attack should fail too + + return false; + } + +void Actor::MeleeEvent + ( + Event *ev + ) + + { + Vector pos; + Vector end; + Vector dir; + float damage = 20; + qboolean success; + str tag_name; + Vector attack_vector; + float attack_width = 0; + float attack_max_height = 0; + float attack_min_height = 0; + float attack_length = 100; + str means_of_death_string; + meansOfDeath_t means_of_death; + float knockback; + qboolean use_pitch_to_enemy = false; + float attack_final_height; + + + // See if we should really attack + + if ( GetActorFlag( ACTOR_FLAG_DAMAGE_ONCE_ON ) && GetActorFlag( ACTOR_FLAG_DAMAGE_ONCE_DAMAGED ) ) + return; + + if ( !GetActorFlag( ACTOR_FLAG_DAMAGE_ALLOWED ) ) + return; + + // Get all of the parameters + + if ( ev->NumArgs() > 0 ) + damage = ev->GetFloat( 1 ); + + if ( ev->NumArgs() > 1 ) + tag_name = ev->GetString( 2 ); + + if ( ev->NumArgs() > 2 ) + means_of_death_string = ev->GetString( 3 ); + + if ( ev->NumArgs() > 3 ) + { + attack_vector = ev->GetVector( 4 ); + + attack_width = attack_vector[0]; + attack_length = attack_vector[1]; + attack_max_height = attack_vector[2]; + } + + if ( ev->NumArgs() > 4 ) + { + knockback = ev->GetFloat( 5 ); + } + else + { + knockback = damage * 8; + } + + if ( ev->NumArgs() > 5 ) + { + use_pitch_to_enemy = ev->GetInteger( 6 ); + } + + if ( ev->NumArgs() > 6 ) + attack_min_height = ev->GetFloat( 7 ); + else + attack_min_height = -attack_max_height; + + if ( ev->NumArgs() > 7 ) + attack_final_height = ev->GetFloat( 8 ); + else + attack_final_height = 50; + + if ( tag_name.length() && GetTag( tag_name.c_str(), &pos, &dir ) ) + { + end = pos + dir * attack_length; + } + else + { + pos = edict->centroid; + dir = orientation[0]; + dir.normalize(); + end = pos + dir * attack_length; + + if ( attack_length ) + end[2] += attack_final_height; + } + + if ( use_pitch_to_enemy ) + { + if ( currentEnemy ) + { + Vector enemy_dir; + Vector angles; + Vector enemy_angles; + float length; + + dir = end - pos; + length = dir.length(); + angles = dir.toAngles(); + + enemy_dir = currentEnemy->centroid - pos; + enemy_angles = enemy_dir.toAngles(); + + angles[PITCH] = enemy_angles[PITCH]; + angles.AngleVectors( &dir ); + end = pos + dir * length; + } + } + + if ( means_of_death_string.length() > 0 ) + means_of_death = (meansOfDeath_t)MOD_string_to_int( means_of_death_string ); + else + means_of_death = MOD_CRUSH; + + // Do the actual attack + + success = MeleeAttack( pos, end, damage, this, means_of_death, attack_width, attack_min_height, attack_max_height, knockback ); + + if ( success ) + { + AddStateFlag( STATE_FLAG_MELEE_HIT ); + + if ( GetActorFlag( ACTOR_FLAG_DAMAGE_ONCE_ON ) ) + SetActorFlag( ACTOR_FLAG_DAMAGE_ONCE_DAMAGED, true ); + } + } + +void Actor::ChargeWater + ( + Event *ev + ) + + { + int cont; + float damage; + float radius; + Entity *ent; + int brushnum; + int entity_brushnum; + float real_damage; + Vector dir; + float dist; + + // See if we are standing in water + + cont = gi.pointcontents( origin, 0 ); + + if ( !(cont & MASK_WATER) ) + return; + + // Get parms + + damage = ev->GetFloat( 1 ); + radius = ev->GetFloat( 2 ); + + if ( !damage || !radius ) + return; + + // Determine what brush we are in + + brushnum = gi.pointbrushnum( origin, 0 ); + + // Find everything in radius + + ent = NULL; + + for( ent = findradius( ent, origin, radius ) ; ent ; ent = findradius( ent, origin, radius ) ) + { + if ( ent->takedamage ) + { + entity_brushnum = gi.pointbrushnum( origin, 0 ); + + if ( brushnum == entity_brushnum ) + { + dir = ent->origin - origin; + dist = dir.length(); + + if ( dist < radius ) + { + real_damage = damage - damage * ( dist / radius ); + ent->Damage( this, this, real_damage, origin, dir, vec_zero, 0, 0, MOD_ELECTRICWATER ); + } + } + } + } + } + +void Actor::DamageOnceStart + ( + Event *ev + ) + + { + SetActorFlag( ACTOR_FLAG_DAMAGE_ONCE_ON, true ); + SetActorFlag( ACTOR_FLAG_DAMAGE_ONCE_DAMAGED, false ); + } + +void Actor::DamageOnceStop + ( + Event *ev + ) + + { + SetActorFlag( ACTOR_FLAG_DAMAGE_ONCE_ON, false ); + } + +void Actor::DamageAllowed + ( + Event *ev + ) + + { + SetActorFlag( ACTOR_FLAG_DAMAGE_ALLOWED, ev->GetBoolean( 1 ) ); + } + +qboolean Actor::CanShootFrom + ( + Vector pos, + Entity *ent, + qboolean usecurrentangles + ) + + { + int mask; + Vector delta; + Vector start; + Vector end; + float len; + trace_t trace; + Entity *t; + Vector ang; + + if ( usecurrentangles ) + { + Vector dir; + + // Fixme ? + //start = pos + GunPosition() - origin; + start = pos + centroid - origin; + end = ent->centroid; + end.z += ( ent->absmax.z - ent->centroid.z ) * 0.75f; + delta = end - start; + ang = delta.toAngles(); + ang.x = ang.x; + ang.y = angles.y; + len = delta.length(); + ang.AngleVectors( &dir, NULL, NULL ); + dir *= len; + end = start + dir; + } + else + { + // Fixme ? + //start = pos + GunPosition() - origin; + start = pos + centroid - origin; + end = ent->centroid; + end.z += ( ent->absmax.z - ent->centroid.z ) * 0.75f; + delta = end - start; + len = delta.length(); + } + + // shoot past the guy we're shooting at + end += delta * 4; + + // Check if he's visible + mask = MASK_SHOT; + trace = G_Trace( start, vec_zero, vec_zero, end, this, mask, false, "Actor::CanShootFrom" ); + if ( trace.startsolid ) + { + return false; + } + + // see if we hit anything at all + if ( !trace.ent ) + { + return false; + } + + // If we hit the guy we wanted, then shoot + if ( trace.ent == ent->edict ) + { + return true; + } + + // If we hit someone else we don't like, then shoot + t = trace.ent->entity; + if ( IsEnemy( t ) ) + { + return true; + } + + // if we hit something breakable, check if shooting it will + // let us shoot someone. + if ( t->isSubclassOf( Object ) || + t->isSubclassOf( ScriptModel ) ) + { + trace = G_Trace( Vector( trace.endpos ), vec_zero, vec_zero, end, t, mask, false, "Actor::CanShootFrom 2" ); + if ( trace.startsolid ) + { + return false; + } + // see if we hit anything at all + if ( !trace.ent ) + { + return false; + } + + // If we hit the guy we wanted, then shoot + if ( trace.ent == ent->edict ) + { + return true; + } + + // If we hit someone else we don't like, then shoot + if ( IsEnemy( trace.ent->entity ) ) + { + return true; + } + + // Forget it then + return false; + } + + return false; + } + +qboolean Actor::CanShoot + ( + Entity *ent, + qboolean usecurrentangles + ) + + { + return CanShootFrom( origin, ent, usecurrentangles ); + } + +qboolean Actor::EntityHasFireType + ( + Entity *ent, + firetype_t fire_type + ) + + { + Player *player; + Weapon *weapon; + firetype_t weapon_fire_type; + + + if ( !ent ) + return false; + + if ( !ent->isSubclassOf( Player ) ) + return true; + + player = (Player *)(Entity *)ent; + + // Try left hand + + weapon = player->GetActiveWeapon( WEAPON_LEFT ); + + if ( weapon ) + { + weapon_fire_type = weapon->GetFireType( FIRE_PRIMARY ); + + if ( weapon_fire_type == fire_type ) + return true; + } + + // Try right hand + + weapon = player->GetActiveWeapon( WEAPON_RIGHT ); + + if ( weapon ) + { + weapon_fire_type = weapon->GetFireType( FIRE_PRIMARY ); + + if ( weapon_fire_type == fire_type ) + return true; + } + + // Try dual weapons + + weapon = player->GetActiveWeapon( WEAPON_DUAL ); + + if ( weapon ) + { + weapon_fire_type = weapon->GetFireType( FIRE_PRIMARY ); + + if ( weapon_fire_type == fire_type ) + return true; + } + + return false; + } + +void Actor::DamageEnemy + ( + Event *ev + ) + { + float damage = 0; + + if ( ev->NumArgs() > 0 ) + damage = ev->GetFloat( 1 ); + + if ( ( damage > 0 ) && currentEnemy ) + currentEnemy->Damage( this, this, damage, vec_zero, vec_zero, vec_zero, 0, 0, MOD_CRUSH ); + } + +void Actor::TurnTowardsEnemy + ( + Event *ev + ) + { + Vector dir; + Vector new_angles; + + if ( currentEnemy && !(currentEnemy->flags & FL_NOTARGET) ) + { + dir = currentEnemy->centroid - origin; + new_angles = dir.toAngles(); + + angles[YAW] = new_angles[YAW]; + angles[ROLL] = 0; + setAngles( angles ); + } + } + +void Actor::AttackModeEvent + ( + Event *ev + ) + { + qboolean attack_bool; + + attack_bool = ev->GetBoolean( 1 ); + + if ( attack_bool ) + { + ProcessEvent( EV_Actor_AttackPlayer ); + } + } + +qboolean Actor::ShouldAttackEntity + ( + Entity *ent + ) + + { + if ( !ent || !ent->isSubclassOf( Sentient ) || Likes( ent ) ) + return false; + + if ( ent->isSubclassOf( Actor ) ) + { + Actor *act = (Actor *)ent; + + if ( GetActorFlag( ACTOR_FLAG_IGNORE_PAIN_FROM_ACTORS ) ) + return false; + + if ( !act->GetActorFlag( ACTOR_FLAG_ATTACKABLE_BY_ACTORS ) ) + return false; + } + + return true; + } + +void Actor::SetAttackableByActors + ( + Event *ev + ) + + { + qboolean bool; + + bool = ev->GetBoolean( 1 ); + + SetActorFlag( ACTOR_FLAG_ATTACKABLE_BY_ACTORS, bool ); + } + +void Actor::SetAttackActors + ( + Event *ev + ) + + { + SetActorFlag( ACTOR_FLAG_ATTACK_ACTORS, true ); + } + +void Actor::MinimumMeleeHeight + ( + Event *ev + ) + + { + minimum_melee_height = ev->GetFloat( 1 ); + } + +void Actor::SetDamageAngles + ( + Event *ev + ) + + { + damage_angles = ev->GetFloat( 1 ); + } + +void Actor::SetImmortal + ( + Event *ev + ) + + { + qboolean bool; + + if ( ev->NumArgs() > 0 ) + bool = ev->GetBoolean( 1 ); + else + bool = true; + + SetActorFlag( ACTOR_FLAG_IMMORTAL, bool ); + } + +qboolean Actor::IsImmortal + ( + void + ) + + { + return GetActorFlag( ACTOR_FLAG_IMMORTAL ); + } + +//*********************************************************************************************** +// +// Actor type script commands +// +//*********************************************************************************************** + +void Actor::FriendEvent + ( + Event *ev + ) + + { + actortype = IS_FRIEND; + } + +void Actor::CivilianEvent + ( + Event *ev + ) + + { + actortype = IS_CIVILIAN; + } + +void Actor::EnemyEvent + ( + Event *ev + ) + + { + actortype = IS_ENEMY; + } + +void Actor::InanimateEvent + ( + Event *ev + ) + + { + actortype = IS_INANIMATE; + // + // clear the monster flag so triggers are not triggered + // + edict->svflags &= ~SVF_MONSTER; + // + // don't make them move + // + setMoveType( MOVETYPE_STATIONARY ); + // + // don't make it bleed + // + flags &= ~FL_BLOOD; + // + // don't make it gib + // + flags &= ~FL_DIE_GIBS; + } + +void Actor::MonsterEvent + ( + Event *ev + ) + + { + actortype = IS_MONSTER; + } + +void Actor::AnimalEvent + ( + Event *ev + ) + + { + actortype = IS_ANIMAL; + } + +void Actor::SetEnemyType + ( + Event *ev + ) + { + enemytype = ev->GetString( 1 ); + } + +//*********************************************************************************************** +// +// Enemy management +// +//*********************************************************************************************** + +void Actor::FindEnemy + ( + void + ) + { + Entity *player; + + // don't target while player is not in the game or he's in notarget + player = g_entities[ 0 ].entity; + if ( !player || ( player->flags & FL_NOTARGET ) ) + { + return; + } + + if ( !GetActorFlag( ACTOR_FLAG_ATTACK_ACTORS ) ) + { + if ( Hates( player ) && ( ( last_enemy_sight_time && CanSee( player ) ) || CanReallySee( player ) ) ) + Stimuli( STIMULI_SIGHT, player, true ); + } + else + { + Entity *entity_to_attack; + + entity_to_attack = FindNearestEnemy(); + + if ( entity_to_attack ) + Stimuli( STIMULI_SIGHT, entity_to_attack, true ); + } + } + +Entity *Actor::FindNearestEnemy( void ) + { + Entity *ent_in_range; + int i; + Vector delta; + gentity_t *ed; + float best_dist = -1; + float dist; + Entity *nearest_enemy = NULL; + + + // Go through clients + + for( i = 0 ; i < game.maxclients; i++ ) + { + ed = &g_entities[ i ]; + + if ( !ed->inuse || !ed->entity ) + continue; + + ent_in_range = ed->entity; + + if ( IsEntityAlive( ent_in_range ) ) + { + delta = origin - ent_in_range->centroid; + + dist = delta * delta; + + if ( dist < best_dist || best_dist == -1 ) + { + if ( Hates( ent_in_range) && CanSee( ent_in_range ) ) + { + nearest_enemy = ent_in_range; + best_dist = dist; + } + } + } + } + + // Go through actors now + + for( i = 1; i <= ActiveList.NumObjects(); i++ ) + { + ent_in_range = ActiveList.ObjectAt( i ); + + if ( + ( ent_in_range->movetype != MOVETYPE_STATIONARY ) && + ( ent_in_range->movetype != MOVETYPE_NONE ) && + ( this != ent_in_range ) && + ( ent_in_range->health > 0 ) && + !( ent_in_range->flags & FL_NOTARGET ) + ) + { + delta = origin - ent_in_range->centroid; + + dist = delta * delta; + + if ( dist < best_dist || best_dist == -1 ) + { + if ( !Likes( ent_in_range) && CanSee( ent_in_range ) ) + { + nearest_enemy = ent_in_range; + best_dist = dist; + } + } + } + } + + return nearest_enemy; + } + +void Actor::GetNearestEnemy + ( + Event *ev + ) + { + currentEnemy = FindNearestEnemy(); + } + +#define MAX_RANDOM_ENTS 10 + +void Actor::GetRandomEnemy + ( + Event *ev + ) + { + float max_distance; + float max_distance2; + Entity *ent_in_range; + int i; + Vector delta; + gentity_t *ed; + float dist; + Entity *ents_found[MAX_RANDOM_ENTS]; + int number_of_ents_found = 0; + + + // Get the maximum distance that we will look for enemies + + max_distance = ev->GetFloat( 1 ) ; + max_distance2 = max_distance * max_distance; + + // Go through clients + + for( i = 0 ; i < game.maxclients; i++ ) + { + if ( number_of_ents_found >= MAX_RANDOM_ENTS ) + break; + + ed = &g_entities[ i ]; + + if ( !ed->inuse || !ed->entity ) + continue; + + ent_in_range = ed->entity; + + if ( IsEntityAlive( ent_in_range ) ) + { + delta = origin - ent_in_range->centroid; + + dist = delta * delta; + + if ( dist < max_distance2 ) + { + if ( CanSee( ent_in_range ) ) + { + ents_found[number_of_ents_found] = ent_in_range; + number_of_ents_found++; + } + } + } + } + + // Go through actors now + + for( i = 1; i <= ActiveList.NumObjects(); i++ ) + { + if ( number_of_ents_found >= MAX_RANDOM_ENTS ) + break; + + ent_in_range = ActiveList.ObjectAt( i ); + + if ( + ( ent_in_range->movetype != MOVETYPE_STATIONARY ) && + ( ent_in_range->movetype != MOVETYPE_NONE ) && + ( this != ent_in_range ) && + ( ent_in_range->health > 0 ) && + !( ent_in_range->flags & FL_NOTARGET ) && + ent_in_range->isSubclassOf( Actor ) + ) + { + Actor *act = (Actor *)ent_in_range; + + if ( act->actortype == IS_FRIEND && act->dialog_list ) + { + delta = origin - ent_in_range->centroid; + + dist = delta * delta; + + if ( dist < max_distance2 ) + { + if ( CanSee( ent_in_range ) ) + { + ents_found[number_of_ents_found] = ent_in_range; + number_of_ents_found++; + } + } + } + } + } + + if ( number_of_ents_found ) + currentEnemy = ents_found[ (int)G_Random( number_of_ents_found ) ]; + else + currentEnemy = NULL; + } + +qboolean Actor::HasEnemies + ( + void + ) + + { + return ( currentEnemy != NULL ); + } + +qboolean Actor::IsEnemy + ( + Entity *ent + ) + + { + return ( ent != NULL ) && ( currentEnemy == ent ); + } + +void Actor::MakeEnemy + ( + Entity *ent, + qboolean force + ) + + { + // Don't get mad at things that can't be hurt or the world + + if ( !ent || ( ent == world ) || ( ent == this ) || ( ent->flags & FL_NOTARGET ) || ( ent->takedamage == DAMAGE_NO ) ) + return; + + if ( !currentEnemy || force ) + { + currentEnemy = ent; + last_enemy_sight_time = level.time; + } + + Wakeup(); + } + +void Actor::ClearEnemies + ( + void + ) + + { + currentEnemy = NULL; + Sleep(); + } + + +qboolean Actor::Likes + ( + Entity *ent + ) + + { + Actor *act; + + if ( ent->isClient() ) + { + return ( actortype == IS_FRIEND ); + } + + if ( actortype == IS_MONSTER ) + { + // Monsters don't like anyone + return false; + } + + if ( ent->isSubclassOf( Actor ) ) + { + act = ( Actor * )ent; + + if ( act->enemytype == enemytype ) + return true; + + if ( act->actortype != actortype ) + return false; + else if ( actortype == IS_FRIEND ) + return true; + } + + return false; +} + +qboolean Actor::Hates + ( + Entity *ent + ) + + { + Actor *act; + + assert( ent ); + if ( !ent ) + { + return false; + } + + if ( ent->isClient() ) + { + return ( actortype != IS_CIVILIAN ) && ( actortype != IS_FRIEND ); + } + else if ( ent->isSubclassOf( Actor ) && ( actortype != IS_INANIMATE ) ) + { + act = ( Actor * )ent; + if ( ( act->actortype <= IS_ENEMY ) && ( actortype <= IS_ENEMY ) ) + { + return false; + } + if ( ( act->actortype == IS_FRIEND ) && ( actortype <= IS_ENEMY ) ) + { + return true; + } + if ( ( act->actortype <= IS_ENEMY ) && ( actortype == IS_FRIEND ) ) + { + return true; + } + } + + return false; + } + +//*********************************************************************************************** +// +// Targeting functions +// +//*********************************************************************************************** + +qboolean Actor::CloseToEnemy + ( + Vector pos, + float howclose + ) + + { + if ( !IsEntityAlive( currentEnemy ) ) + { + return false; + } + + if ( WithinDistance( currentEnemy, howclose ) ) + { + return true; + } + + return false; + } + +void Actor::EyeOffset + ( + Event *ev + ) + { + eyeposition -= eyeoffset; + eyeoffset = ev->GetVector( 1 ); + eyeposition += eyeoffset; + } + +qboolean Actor::EntityInRange + ( + Entity *ent, + float range, + float min_height, + float max_height + ) + + { + float r; + Vector delta; + float height_diff; + + // Make sure the entity is alive + + if ( !IsEntityAlive( ent ) ) + { + return false; + } + + // See if the entity is in range + + delta = ent->centroid - centroid; + + if ( max_height != 0 || min_height != 0 ) + { + height_diff = delta[ 2 ]; + + if ( ( height_diff < min_height ) || ( height_diff > max_height ) ) + { + return false; + } + + delta[ 2 ] = 0; + } + + r = delta * delta; + + return ( r < range * range ); + } + +//*********************************************************************************************** +// +// Thread management +// +//*********************************************************************************************** + +void Actor::SetupThread + ( + str filename, + str label + ) + { + + if ( actorthread ) + return; + + actorthread = Director.CreateThread( filename.c_str(), MODEL_SCRIPT ); + + if ( actorthread ) + { + if ( label.length() ) + { + if ( !actorthread->Goto( label.c_str() ) ) + { + gi.DPrintf( "Label '%s' not found in %s.", label.c_str(), filename.c_str() ); + return; + } + } + + ProcessScript( actorthread ); + } + } + +void Actor::ProcessScript + ( + ScriptThread *thread, + Event *ev + ) + + { + thread->Vars()->SetVariable( "self", this ); + thread->Vars()->SetVariable( "origin", origin ); + thread->Vars()->SetVariable( "yaw", angles.y ); + thread->Vars()->SetVariable( "health", health ); + thread->Vars()->SetVariable( "startpos", startpos ); + + if ( currentEnemy ) + { + thread->Vars()->SetVariable( "enemy", currentEnemy ); + } + else + { + thread->Vars()->SetVariable( "enemy", "" ); + } + + if ( ev ) + { + thread->ProcessEvent( ev ); + } + else + { + thread->ProcessEvent( EV_ScriptThread_Execute ); + } + } + +inline ScriptVariable *Actor::SetVariable + ( + const char *name, + float value + ) + + { + if ( actorthread ) + { + return actorthread->Vars()->SetVariable( name, value ); + } + + return NULL; + } + +inline ScriptVariable *Actor::SetVariable + ( + const char *name, + int value + ) + + { + if ( actorthread ) + { + return actorthread->Vars()->SetVariable( name, value ); + } + + return NULL; + } + +inline ScriptVariable *Actor::SetVariable + ( + const char *name, + const char *text + ) + + { + if ( actorthread ) + { + return actorthread->Vars()->SetVariable( name, text ); + } + + return NULL; + } + +inline ScriptVariable *Actor::SetVariable + ( + const char *name, + str &text + ) + + { + if ( actorthread ) + { + return actorthread->Vars()->SetVariable( name, text.c_str() ); + } + + return NULL; + } + +inline ScriptVariable *Actor::SetVariable + ( + const char *name, + Entity *ent + ) + + { + if ( actorthread ) + { + return actorthread->Vars()->SetVariable( name, ent ); + } + + return NULL; + } + +inline ScriptVariable *Actor::SetVariable + ( + const char *name, + Vector &vec + ) + + { + if ( actorthread ) + { + return actorthread->Vars()->SetVariable( name, vec ); + } + + return NULL; + } + +//*********************************************************************************************** +// +// State machine functions +// +//*********************************************************************************************** + +void Actor::SetIdleStateName + ( + Event *ev + ) + { + idle_state_name = ev->GetString( 1 ); + } + +void Actor::SetState( const char *state_name ) + { + ClassDef *cls; + int i; + Event *e; + + if ( !statemap ) + return; + + if ( deadflag ) + return; + + if ( currentState ) + currentState->ProcessExitCommands( this ); + + currentState = statemap->FindState( state_name ); + state_time = level.time; + + // Set the behavior + + if ( currentState ) + { + cls = getClass( currentState->getBehaviorName() ); + + if ( cls ) + { + if ( currentState->numBehaviorParms() ) + { + e = new Event( EV_Behavior_Args ); + + for ( i = 1 ; i <= currentState->numBehaviorParms() ; i++ ) + e->AddString( currentState->getBehaviorParm( i ) ); + + SetBehavior( ( Behavior * )cls->newInstance(), e ); + } + else + { + SetBehavior( ( Behavior * )cls->newInstance() ); + } + } + + InitState(); + currentState->ProcessEntryCommands( this ); + } + else + { + gi.DPrintf( "State %s not found\n", state_name ); + } + } + +void Actor::InitState + ( + void + ) + + { + float min_time; + float max_time; + + + min_time = currentState->getMinTime(); + max_time = currentState->getMaxTime(); + + if ( (min_time != -1) && (max_time != -1) ) + { + SetActorFlag( ACTOR_FLAG_STATE_DONE_TIME_VALID, true ); + + state_done_time = level.time + min_time + G_Random( max_time - min_time ); + } + else + { + SetActorFlag( ACTOR_FLAG_STATE_DONE_TIME_VALID, false ); + } + + state_time = level.time; + times_done = 0; + + ClearStateFlags(); + command = ""; + + SetActorFlag( ACTOR_FLAG_ANIM_DONE, false ); + SetActorFlag( ACTOR_FLAG_NOISE_HEARD, false ); + } + +void Actor::LoadStateMap + ( + Event *ev + ) + + { + str anim_name; + qboolean loading; + + + // Load the new state map + + statemap_name = ev->GetString( 1 ); + + conditionals.FreeObjectList(); + statemap = GetStatemap( statemap_name, ( Condition * )Conditions, &conditionals, false ); + + // Set the first state + + if ( ev->NumArgs() > 1 ) + idle_state_name = ev->GetString( 2 ); + else + idle_state_name = "IDLE"; + + if ( ev->NumArgs() > 2 ) + loading = ev->GetBoolean( 3 ); + else + loading = false; + + // Initialize the actors first animation + + if ( !loading ) + { + SetState( idle_state_name.c_str() ); + + if ( currentState ) + anim_name = currentState->getLegAnim( *this, &conditionals ); + + if ( anim_name == "" && !newanim.length() ) + anim_name = "idle"; + + SetAnim( anim_name.c_str(), EV_Anim_Done ); + ChangeAnim(); + + flags &= ~FL_THINK; + } + } + +void Actor::ProcessActorStateMachine( void ) + { + int count; + ClassDef *cls = NULL; + str behavior_arg; + const char *currentanim; + str behavior_name; + State *laststate; + + count = 0; + + if ( deadflag || !currentState ) + return; + + if ( mode != ACTOR_MODE_AI && mode != ACTOR_MODE_IDLE ) + return; + + do + { + // Since we could get into an infinite loop here, do a check to make sure we don't. + + count++; + if ( count > 10 ) + { + gi.DPrintf( "Possible infinite loop in state '%s'\n", currentState->getName() ); + if ( count > 20 ) + { + gi.Error( ERR_DROP, "Stopping due to possible infinite state loop\n" ); + break; + } + } + + // Determine the next state to go to + + laststate = currentState; + currentState = currentState->Evaluate( *this, &conditionals ); + + // Change the behavior if the state has changed + + if ( laststate != currentState ) + { + // Process exit commands of the last state + + laststate->ProcessExitCommands( this ); + + // Process entry commands of the new state + + currentState->ProcessEntryCommands( this ); + + // Setup the new behavior + + behavior_name = currentState->getBehaviorName(); + + if ( behavior_name.length() ) + cls = getClass( currentState->getBehaviorName() ); + + if ( cls ) + { + if ( currentState->numBehaviorParms() ) + { + int i; + Event *e = new Event( EV_Behavior_Args ); + + for ( i = 1 ; i <= currentState->numBehaviorParms() ; i++ ) + e->AddString( currentState->getBehaviorParm( i ) ); + + SetBehavior( ( Behavior * )cls->newInstance(), e ); + } + else + { + SetBehavior( ( Behavior * )cls->newInstance() ); + } + } + else if ( behavior_name.length() ) + { + gi.DPrintf( "Invalid behavior name %s\n", behavior_name.c_str() ); + } + + // Initialize some stuff for changing states + + InitState(); + } + + // Change the animation if it has changed + + currentanim = currentState->getLegAnim( *this, &conditionals ); + + if ( currentanim[0] != 0 && strcmp( animname, currentanim ) != 0 ) + SetAnim( currentanim, EV_Anim_Done ); + } + while( laststate != currentState ); + } + +//*********************************************************************************************** +// +// Thread based script commands +// +//*********************************************************************************************** + +void Actor::RunThread + ( + Event *ev + ) + + { + str thread_name; + ScriptThread *thread; + + + thread_name = ev->GetString( 1 ); + + thread = ExecuteThread( thread_name.c_str(), false ); + + if ( thread ) + ProcessScript( thread, NULL ); + else + warning( "RunThread", "could not process thread" ); + } + +void Actor::SetThread + ( + Event *ev + ) + + { + ScriptThread *thread; + str label; + + if ( mode == ACTOR_MODE_AI ) + return; + + thread = ev->GetThread(); + label = ev->GetString( 1 ); + + if ( !thread ) + return; + + if ( mode != ACTOR_MODE_TALK ) + StartMode( ACTOR_MODE_SCRIPT ); + + SetThread( thread->Filename(), label ); + + if ( mode == ACTOR_MODE_TALK ) + { + saved_mode = ACTOR_MODE_SCRIPT; + saved_actorthread = actorthread; + actorthread = NULL; + return; + } + } + +void Actor::SetThread + ( + str filename, + str label + ) + + { + str start; + + + if ( filename.length() == 0 || label.length() == 0 ) + return; + + if ( !actorthread ) + { + SetupThread( filename, label ); + } + else + { + start = filename + "::" + label; + + if ( actorthread->Goto( start.c_str() ) ) + { + ProcessScript( actorthread ); + } + else + gi.DPrintf( "Label '%s' not found. Couldn't change thread.", start.c_str() ); + } + } + +void Actor::EndThread + ( + Event *ev + ) + + { + if ( actorthread ) + { + actorthread->ProcessEvent( EV_ScriptThread_End ); + actorthread = NULL; + + if ( mode == ACTOR_MODE_SCRIPT ) + { + if ( behavior ) + EndBehavior(); + } + } + } + +//*********************************************************************************************** +// +// Behavior management +// +//*********************************************************************************************** + +void Actor::SendMoveDone( ScriptThread *script_thread ) + { + Event *event; + + if ( script_thread ) + { + event = new Event( EV_MoveDone ); + event->AddEntity( this ); + script_thread->PostEvent( event, FRAMETIME ); + } + } + +void Actor::EndBehavior + ( + void + ) + + { + ScriptThread *t; + Event *event; + + + if ( behavior ) + { + behavior->End( *this ); + delete behavior; + behavior = NULL; + + if ( scriptthread ) + { + t = scriptthread; + scriptthread = NULL; + + if ( actorthread ) + { + event = new Event( EV_MoveDone ); + event->AddEntity( this ); + ProcessScript( actorthread, event ); + } + + if ( t != actorthread ) + { + event = new Event( EV_MoveDone ); + event->AddEntity( this ); + t->ProcessEvent( event ); + } + } + } + + // Prevent previous behaviors from stopping the next behavior + CancelEventsOfType( EV_Actor_FinishedBehavior ); + } + +void Actor::SetBehavior + ( + Behavior *newbehavior, + Event *startevent, + ScriptThread *newthread + ) + + { + if ( ( deadflag ) && ( actortype != IS_INANIMATE ) ) + { + // Delete the unused stuff + + if ( newbehavior ) + delete newbehavior; + if ( startevent ) + delete startevent; + + return; + } + + // End any previous behavior, but don't call EV_MoveDone if we're using the same thread, + // or we'll end THIS behavior + if ( scriptthread == newthread ) + { + scriptthread = NULL; + } + EndBehavior(); + + behavior = newbehavior; + if ( behavior ) + { + //flags |= FL_THINK; + Wakeup(); + + if ( startevent ) + { + behavior->ProcessEvent( startevent ); + } + currentBehavior = behavior->getClassname(); + behavior->Begin( *this ); + scriptthread = newthread; + } + } + +void Actor::FinishedBehavior + ( + Event *ev + ) + + { + EndBehavior(); + } + +void Actor::NotifyBehavior + ( + Event *ev + ) + + { + if ( behavior ) + { + behavior->ProcessEvent( EV_Behavior_AnimDone ); + SetActorFlag( ACTOR_FLAG_ANIM_DONE, true ); + } + } + +//*********************************************************************************************** +// +// Path and node management +// +//*********************************************************************************************** + +PathNode *Actor::NearestNodeInPVS + ( + Vector pos + ) + + { + Vector delta; + PathNode *node; + PathNode *bestnode; + float bestdist; + float dist; + int number_nodes; + int i; + MapCell *cell; + Vector min; + Vector max; + + + cell = PathManager.GetNodesInCell( pos ); + + if ( !cell ) + return NULL; + + number_nodes = cell->NumNodes(); + + bestnode = NULL; + bestdist = 999999999; // greater than ( 8192 * sqr(2) ) ^ 2 -- maximum squared distance + + for( i = 0; i < number_nodes; i++ ) + { + node = ( PathNode * )cell->GetNode( i ); + + if ( !node ) + continue; + + delta = node->origin - pos; + + // get the distance squared (faster than getting real distance) + dist = delta * delta; + + if ( ( dist < bestdist ) && gi.inPVS( node->origin, pos ) ) + { + bestnode = node; + bestdist = dist; + + // if we're close enough, early exit + if ( dist < 16 ) + break; + } + } + + return bestnode; + } + +void Actor::SetPath + ( + Path *newpath + ) + + { + if ( path && ( path != newpath ) ) + { + delete path; + } + path = newpath; + } + +void Actor::ReserveNodeEvent + ( + Event *ev + ) + + { + PathNode *node; + Vector pos; + + pos = ev->GetVector( 1 ); + node = PathManager.NearestNode( pos, this ); + + if ( node && ( !node->entnum || ( node->entnum == entnum ) || ( node->occupiedTime < level.time ) ) ) + { + // Mark node as occupied for a short time + node->occupiedTime = level.time + ev->GetFloat( 2 ); + node->entnum = entnum; + } + } + +void Actor::ReleaseNodeEvent + ( + Event *ev + ) + + { + PathNode *node; + Vector pos; + + pos = ev->GetVector( 1 ); + node = PathManager.NearestNode( pos, this ); + + if ( node && ( node->entnum == entnum ) ) + { + node->occupiedTime = 0; + node->entnum = 0; + } + } + +//*********************************************************************************************** +// +// Animation control functions +// +//*********************************************************************************************** + +void Actor::RemoveAnimDoneEvent( void ) + { + SetAnimDoneEvent( NULL ); + + if ( newanimevent ) + { + delete newanimevent; + newanimevent = NULL; + } + + last_anim_event_name = ""; + } + +void Actor::ChangeAnim + ( + void + ) + + { + float time; + Vector totalmove; + + if ( newanimnum == -1 ) + { + return; + } + + // If we're changing to the same anim, don't restart the animation + if ( newanimnum == CurrentAnim() && animname == newanim) + { + SetAnimDoneEvent( newanimevent ); + } + else + { + animname = newanim; + + time = gi.Anim_Time( edict->s.modelindex, newanimnum ); + gi.Anim_Delta( edict->s.modelindex, newanimnum, totalmove ); + + totalmove *= edict->s.scale; + totallen = totalmove.length(); + + // always have a valid move direction + if ( totallen > 0.01 ) + { + movespeed = totallen / time; + animdir = totalmove * ( 1 / totallen ); + } + else + { + if ( forwardspeed ) + { + movespeed = forwardspeed; + } + else + { + movespeed = 1; + } + animdir = Vector( 1, 0, 0 ); + } + + MatrixTransformVector( animdir, orientation, movedir ); + movevelocity = movedir * movespeed; + + + NewAnim( newanimnum, newanimevent ); + } + + // clear the new anim variables + newanimnum = -1; + newanim = ""; + newanimevent = NULL; + } + +void Actor::AnimDone + ( + Event *ev + ) + + { + SetActorFlag( ACTOR_FLAG_ANIM_DONE, true ); + } + +qboolean Actor::SetAnim + ( + str anim, + Event *ev + ) + + { + int num; + + num = gi.Anim_Random( edict->s.modelindex, anim.c_str() ); + if ( num != -1 ) + { + newanim = anim; + newanimnum = num; + + if ( newanimevent ) + delete newanimevent; + + newanimevent = ev; + + if ( newanimevent ) + last_anim_event_name = newanimevent->getName(); + else + last_anim_event_name = ""; + + if ( actortype == IS_INANIMATE ) + { + // inanimate objects change anims immediately + ChangeAnim(); + } + + return true; + } + + // kill the event + if ( ev ) + { + delete ev; + } + + return false; + } + +qboolean Actor::SetAnim + ( + str anim, + Event &ev + ) + + { + Event * event; + + //last_anim_event = &ev; + + event = new Event( ev ); + return SetAnim( anim, event ); + } + +void Actor::Anim + ( + Event *ev + ) + + { + Event *e; + + if ( !ModeAllowed( ACTOR_MODE_SCRIPT ) ) + { + if ( mode == ACTOR_MODE_TALK ) + PostEvent( *ev, FRAMETIME ); + else if ( mode == ACTOR_MODE_AI ) + SendMoveDone( ev->GetThread() ); + return; + } + + if ( ( deadflag ) && ( actortype != IS_INANIMATE ) ) + { + return; + } + + e = new Event( EV_Behavior_Args ); + + e->SetSource( ev->GetSource() ); + + if ( ev->GetSource() == EV_FROM_SCRIPT ) + { + StartMode( ACTOR_MODE_SCRIPT ); + + e->SetThread( ev->GetThread() ); + e->SetLineNumber( ev->GetLineNumber() ); + } + + e->AddToken( ev->GetToken( 1 ) ); + + SetBehavior( new PlayAnim, e, ev->GetThread() ); + } + +//*********************************************************************************************** +// +// Script commands +// +//*********************************************************************************************** + +void Actor::IdleEvent + ( + Event *ev + ) + + { + const char *state_name; + + if ( !ModeAllowed( ACTOR_MODE_IDLE ) ) + { + if ( mode == ACTOR_MODE_TALK ) + RepostEvent( ev, EV_Actor_Idle ); + return; + } + + if ( ev->NumArgs() > 0 ) + state_name = ev->GetString( 1 ); + else + state_name = idle_state_name; + + SetState( state_name ); + + StartMode( ACTOR_MODE_IDLE ); + } + +void Actor::LookAt + ( + Event *ev + ) + + { + Entity *ent; + TurnTo *turnTo; + + if ( !ModeAllowed( ACTOR_MODE_SCRIPT ) ) + { + if ( mode == ACTOR_MODE_TALK ) + RepostEvent( ev, EV_Actor_LookAt ); + else if ( mode == ACTOR_MODE_AI ) + SendMoveDone( ev->GetThread() ); + return; + } + + StartMode( ACTOR_MODE_SCRIPT ); + + ent = ev->GetEntity( 1 ); + if ( ent && ent != world ) + { + turnTo = new TurnTo; + turnTo->SetTarget( ent ); + SetBehavior( turnTo, NULL, ev->GetThread() ); + } + } + +void Actor::TurnToEvent + ( + Event *ev + ) + + { + TurnTo *turnTo; + + if ( !ModeAllowed( ACTOR_MODE_SCRIPT ) ) + { + if ( mode == ACTOR_MODE_TALK ) + RepostEvent( ev, EV_Actor_TurnTo ); + else if ( mode == ACTOR_MODE_AI ) + SendMoveDone( ev->GetThread() ); + return; + } + + StartMode( ACTOR_MODE_SCRIPT ); + + turnTo = new TurnTo; + turnTo->SetDirection( ev->GetFloat( 1 ) ); + + SetBehavior( turnTo, NULL, ev->GetThread() ); + } + +void Actor::HeadWatchEvent + ( + Event *ev + ) + + { + Event *event; + + if ( !ModeAllowed( ACTOR_MODE_SCRIPT ) ) + { + if ( mode == ACTOR_MODE_TALK ) + RepostEvent( ev, EV_Actor_HeadWatch ); + else if ( mode == ACTOR_MODE_AI ) + SendMoveDone( ev->GetThread() ); + return; + } + + StartMode( ACTOR_MODE_SCRIPT ); + + event = new Event( EV_Behavior_Args ); + event->AddEntity( ev->GetEntity( 1 ) ); + + if ( ev->NumArgs() > 1 ) + event->AddFloat( ev->GetFloat( 2 ) ); + + SetBehavior( new HeadWatch, event, ev->GetThread() ); + } + +void Actor::ResetHeadEvent + ( + Event *ev + ) + + { + Event *event; + + if ( !ModeAllowed( ACTOR_MODE_SCRIPT ) ) + { + if ( mode == ACTOR_MODE_TALK ) + RepostEvent( ev, EV_Actor_ResetHead ); + else if ( mode == ACTOR_MODE_AI ) + SendMoveDone( ev->GetThread() ); + return; + } + + StartMode( ACTOR_MODE_SCRIPT ); + + event = new Event( EV_Behavior_Args ); + event->AddEntity( NULL ); + + if ( ev->NumArgs() > 0 ) + event->AddFloat( ev->GetFloat( 1 ) ); + + SetBehavior( new HeadWatch, event, ev->GetThread() ); + } + +void Actor::WalkTo + ( + Event *ev + ) + + { + Event *e; + + + if ( !ModeAllowed( ACTOR_MODE_SCRIPT ) ) + { + if ( mode == ACTOR_MODE_TALK ) + RepostEvent( ev, EV_Actor_WalkTo ); + else if ( mode == ACTOR_MODE_AI ) + SendMoveDone( ev->GetThread() ); + return; + } + + StartMode( ACTOR_MODE_SCRIPT ); + + e = new Event( EV_Behavior_Args ); + + e->SetSource( ev->GetSource() ); + + if ( ev->GetSource() == EV_FROM_SCRIPT ) + { + e->SetThread( ev->GetThread() ); + e->SetLineNumber( ev->GetLineNumber() ); + } + + if ( ev->NumArgs() > 1 ) + e->AddString( ev->GetString( 2 ) ); + else + e->AddString( "walk" ); + + if ( ev->NumArgs() > 0 ) + e->AddToken( ev->GetToken( 1 ) ); + + SetBehavior( new GotoPathNode, e, ev->GetThread() ); + } + +void Actor::WalkWatch + ( + Event *ev + ) + + { + Event *e; + + + if ( ev->NumArgs() < 2 ) + return; + + if ( !ModeAllowed( ACTOR_MODE_SCRIPT ) ) + { + if ( mode == ACTOR_MODE_TALK ) + RepostEvent( ev, EV_Actor_WalkWatch ); + else if ( mode == ACTOR_MODE_AI ) + SendMoveDone( ev->GetThread() ); + return; + } + + StartMode( ACTOR_MODE_SCRIPT ); + + e = new Event( EV_Behavior_Args ); + + e->SetSource( ev->GetSource() ); + + if ( ev->GetSource() == EV_FROM_SCRIPT ) + { + e->SetThread( ev->GetThread() ); + e->SetLineNumber( ev->GetLineNumber() ); + } + + // Get animation name + + if ( ev->NumArgs() > 2 ) + e->AddString( ev->GetString( 3 ) ); + else + e->AddString( "walk" ); + + // Get the node to walk to + + e->AddToken( ev->GetToken( 1 ) ); + + // Get the entity to watch + + e->AddEntity( ev->GetEntity( 2 ) ); + + SetBehavior( new GotoPathNode, e, ev->GetThread() ); + } + +void Actor::RunTo + ( + Event *ev + ) + + { + Event *e; + int i; + int n; + + if ( !ModeAllowed( ACTOR_MODE_SCRIPT ) ) + { + if ( mode == ACTOR_MODE_TALK ) + RepostEvent( ev, EV_Actor_RunTo ); + else if ( mode == ACTOR_MODE_AI ) + SendMoveDone( ev->GetThread() ); + return; + } + + StartMode( ACTOR_MODE_SCRIPT ); + + e = new Event( EV_Behavior_Args ); + + e->SetSource( ev->GetSource() ); + + if ( ev->GetSource() == EV_FROM_SCRIPT ) + { + e->SetThread( ev->GetThread() ); + e->SetLineNumber( ev->GetLineNumber() ); + } + + e->AddString( "run" ); + + n = ev->NumArgs(); + + for( i = 1; i <= n; i++ ) + { + e->AddToken( ev->GetToken( i ) ); + } + + SetBehavior( new GotoPathNode, e, ev->GetThread() ); + } + +void Actor::WarpTo + ( + Event *ev + ) + + { + PathNode *goal_node; + + if ( !ModeAllowed( ACTOR_MODE_SCRIPT ) ) + { + if ( mode == ACTOR_MODE_TALK ) + RepostEvent( ev, EV_Actor_WarpTo ); + return; + } + + if ( ev->NumArgs() > 0 ) + { + goal_node = AI_FindNode( ev->GetString( 1 ) ); + + if ( goal_node ) + { + origin = goal_node->origin; + setOrigin( origin ); + + angles = goal_node->angles; + setAngles( angles ); + + NoLerpThisFrame(); + } + } + } + +void Actor::PickupEnt + ( + Event *ev + ) + + { + Event *e; + + if ( !ModeAllowed( ACTOR_MODE_SCRIPT ) ) + { + if ( mode == ACTOR_MODE_TALK ) + RepostEvent( ev, EV_Actor_PickupEnt ); + else if ( mode == ACTOR_MODE_AI ) + SendMoveDone( ev->GetThread() ); + return; + } + + StartMode( ACTOR_MODE_SCRIPT ); + + e = new Event( EV_Behavior_Args ); + + e->SetSource( ev->GetSource() ); + + if ( ev->GetSource() == EV_FROM_SCRIPT ) + { + e->SetThread( ev->GetThread() ); + e->SetLineNumber( ev->GetLineNumber() ); + } + + e->AddEntity( ev->GetEntity( 1 ) ); + e->AddString( ev->GetString( 2 ) ); + + SetBehavior( new PickupEntity, e, ev->GetThread() ); + } + +void Actor::ThrowEnt + ( + Event *ev + ) + + { + Event *e; + + if ( !ModeAllowed( ACTOR_MODE_SCRIPT ) ) + { + if ( mode == ACTOR_MODE_TALK ) + RepostEvent( ev, EV_Actor_ThrowEnt ); + else if ( mode == ACTOR_MODE_AI ) + SendMoveDone( ev->GetThread() ); + return; + } + + StartMode( ACTOR_MODE_SCRIPT ); + + e = new Event( EV_Behavior_Args ); + + e->SetSource( ev->GetSource() ); + + if ( ev->GetSource() == EV_FROM_SCRIPT ) + { + e->SetThread( ev->GetThread() ); + e->SetLineNumber( ev->GetLineNumber() ); + } + + e->AddString( ev->GetString( 1 ) ); + + SetBehavior( new ThrowEntity, e, ev->GetThread() ); + } + +void Actor::AttackEntity + ( + Event *ev + ) + + { + Entity *ent; + + if ( ( deadflag ) && ( actortype != IS_INANIMATE ) ) + { + return; + } + + ent = ev->GetEntity( 1 ); + + // don't get mad at things that can't be hurt or the world + if ( + ent && + ( ent != world ) && + ( ent->takedamage != DAMAGE_NO ) + ) + + { + ClearEnemies(); + Stimuli( STIMULI_SCRIPT, ent, true ); + } + } + +void Actor::AttackPlayer + ( + Event *ev + ) + + { + int i; + gentity_t *ent; + + if ( !GetActorFlag( ACTOR_FLAG_STARTED ) ) + { + PostEvent( *ev, FRAMETIME ); + return; + } + + if ( ( deadflag ) && ( actortype != IS_INANIMATE ) ) + { + return; + } + + ClearEnemies(); + + // make enemies of all the players + for( i = 0; i < maxclients->integer; i++ ) + { + ent = &g_entities[ i ]; + if ( !ent->inuse || !ent->client || !ent->entity ) + { + continue; + } + + Stimuli( STIMULI_SCRIPT, ent->entity, true ); + } + } + +void Actor::JumpToEvent + ( + Event *ev + ) + + { + Event *e; + int i; + int n; + + if ( !ModeAllowed( ACTOR_MODE_SCRIPT ) ) + { + if ( mode == ACTOR_MODE_TALK ) + PostEvent( *ev, FRAMETIME ); + else if ( mode == ACTOR_MODE_AI ) + SendMoveDone( ev->GetThread() ); + return; + } + + StartMode( ACTOR_MODE_SCRIPT ); + + e = new Event( EV_Behavior_Args ); + + e->SetSource( ev->GetSource() ); + + if ( ev->GetSource() == EV_FROM_SCRIPT ) + { + e->SetThread( ev->GetThread() ); + e->SetLineNumber( ev->GetLineNumber() ); + } + + //e->AddString( "jump" ); + + n = ev->NumArgs(); + + for( i = 1; i <= n; i++ ) + { + e->AddToken( ev->GetToken( i ) ); + } + + SetBehavior( new JumpToPathNode, e, ev->GetThread() ); + } + +void Actor::GotoEvent + ( + Event *ev + ) + + { + // This command was added because it was a common mistake when writing actor scripts + // to say "local.self goto label". Since we're such nice guys, we'll print a warning + // and send it on the the calling thread. :) + ScriptThread *thread; + + thread = ev->GetThread(); + if ( thread ) + { + gi.DPrintf( "Actor recieved 'goto' command. Passing to thread.\n" ); + thread->ProcessEvent( ev ); + } + else + { + // should never happen, but say something anyways. + gi.DPrintf( "Actor recieved 'goto' command. Thread is NULL.\n" ); + } + } + +void Actor::RepostEvent + ( + Event *ev, + Event &event_type + ) + { + Event *event; + int i; + str token; + + event = new Event( event_type ); + + for( i = 1 ; i <= ev->NumArgs() ; i++ ) + { + token = ev->GetString( i ); + event->AddString( token.c_str() ); + } + + event->SetThread( ev->GetThread() ); + + PostEvent( event, FRAMETIME ); + } + +//*********************************************************************************************** +// +// Script conditionals +// +//*********************************************************************************************** + +void Actor::IfEnemyVisibleEvent + ( + Event *ev + ) + + { + ScriptThread *thread; + + thread = ev->GetThread(); + assert( thread ); + if ( !thread ) + { + return; + } + + if ( CanSeeEnemyFrom( origin ) ) + { + thread->ProcessCommandFromEvent( ev, 1 ); + } + } + +void Actor::IfNearEvent + ( + Event *ev + ) + + { + ScriptThread *thread; + Entity *ent; + Entity *bestent; + float bestdist; + float dist; + str name; + Vector delta; + float distance; + TargetList *tlist; + int n; + int i; + + thread = ev->GetThread(); + assert( thread ); + if ( !thread ) + { + return; + } + + name = ev->GetString( 1 ); + distance = ev->GetFloat( 2 ); + + if ( name[ 0 ] == '*' ) + { + ent = ev->GetEntity( 1 ); + if ( WithinDistance( ent, distance ) ) + { + SetVariable( "other", ent ); + thread->ProcessCommandFromEvent( ev, 3 ); + } + } + else if ( name[ 0 ] == '$' ) + { + bestent = NULL; + bestdist = distance * distance; + + tlist = world->GetTargetList( str( &name[ 1 ] ) ); + n = tlist->list.NumObjects(); + for( i = 1; i <= n; i++ ) + { + ent = tlist->list.ObjectAt( i ); + delta = centroid - ent->centroid; + dist = delta * delta; + if ( dist <= bestdist ) + { + bestent = ent; + bestdist = dist; + } + } + + if ( bestent ) + { + SetVariable( "other", bestent ); + thread->ProcessCommandFromEvent( ev, 3 ); + } + } + else + { + bestent = NULL; + bestdist = distance * distance; + + ent = NULL; + + for( ent = findradius( ent, origin, distance ) ; ent ; ent = findradius( ent, origin, distance ) ) + { + if ( ent->inheritsFrom( name.c_str() ) ) + { + delta = centroid - ent->centroid; + dist = delta * delta; + if ( dist <= bestdist ) + { + bestent = ent; + bestdist = dist; + } + } + } + + if ( bestent ) + { + SetVariable( "other", bestent ); + thread->ProcessCommandFromEvent( ev, 3 ); + } + } + } + +void Actor::IfCanHideAtEvent + ( + Event *ev + ) + + { + PathNode *node; + Vector pos; + ScriptThread *thread; + + thread = ev->GetThread(); + assert( thread ); + if ( !thread ) + { + return; + } + + pos = ev->GetVector( 1 ); + node = PathManager.NearestNode( pos, this ); + + if ( node && ( node->nodeflags & ( AI_DUCK | AI_COVER ) ) && !CanSeeEnemyFrom( pos ) ) + { + if ( !node->entnum || ( node->entnum == entnum ) || ( node->occupiedTime < level.time ) ) + { + thread->ProcessCommandFromEvent( ev, 2 ); + } + } + } + +void Actor::IfEnemyWithinEvent + ( + Event *ev + ) + + { + ScriptThread *thread; + + if ( !currentEnemy ) + { + return; + } + + thread = ev->GetThread(); + assert( thread ); + if ( !thread ) + { + return; + } + + if ( WithinDistance( currentEnemy, ev->GetFloat( 1 ) ) ) + { + thread->ProcessCommandFromEvent( ev, 2 ); + } + } + +//*********************************************************************************************** +// +// Sound reaction functions +// +//*********************************************************************************************** + +void Actor::NoPainSounds + ( + Event *ev + ) + + { + SetActorFlag( ACTOR_FLAG_NO_PAIN_SOUNDS, true ); + } + +void Actor::HeardSound + ( + Event *ev + ) + + { + Vector location; + + location = ev->GetVector( 2 ); + + Stimuli( STIMULI_SOUND, location ); + } + +qboolean Actor::IgnoreSounds + ( + void + ) + + { + if ( GetActorFlag( ACTOR_FLAG_NEVER_IGNORE_SOUNDS ) ) + return false; + + if ( currentEnemy && flags & FL_THINK ) + return true; + + if ( !( stimuli & STIMULI_SOUND ) ) + return true; + + return false; + } + +void Actor::NeverIgnoreSounds + ( + Event *ev + ) + { + SetActorFlag( ACTOR_FLAG_NEVER_IGNORE_SOUNDS, true ); + } + +//*********************************************************************************************** +// +// Pain and death related functions +// +//*********************************************************************************************** + +void Actor::Pain + ( + Event *ev + ) + + { + float damage; + Entity *ent; + int mod; + Vector direction; + Vector position; + Vector dir; + State *tempState; + + + damage = ev->GetFloat( 1 ); + ent = ev->GetEntity( 2 ); + mod = ev->GetInteger( 3 ); + position = ev->GetVector( 4 ); + direction = ev->GetVector( 5 ); + + // Add to the players action level + + if ( damage && !deadflag && ent && ent->isSubclassOf( Player ) ) + { + Player *player = (Player *)ent; + + player->IncreaseActionLevel( damage / 4 ); + } + + if ( deadflag ) + { + // Do gib stuff + + if ( statemap ) + { + tempState = statemap->FindState( "GIB" ); + + if ( tempState ) + tempState = tempState->Evaluate( *this, &conditionals ); + + if ( tempState ) + { + tempState->ProcessEntryCommands( this ); + } + } + return; + } + + if ( damage > 0 && next_pain_sound_time <= level.time && !GetActorFlag( ACTOR_FLAG_NO_PAIN_SOUNDS ) ) + { + next_pain_sound_time = level.time + 0.4 + G_Random( 0.2 ); + BroadcastSound(); + } + + if ( !GetActorFlag( ACTOR_FLAG_ALLOWED_TO_KILL ) && ent && ent->isSubclassOf( Player ) ) + { + if ( damage >= pain_threshold ) + G_MissionFailed(); + } + else + { + if ( ShouldAttackEntity( ent ) ) + Stimuli( STIMULI_PAIN, ent, true ); + else + StimuliNoAttack( STIMULI_PAIN ); + } + + if ( mod == MOD_BULLET && behavior && currentBehavior == "Pain" ) + { + bullet_hits++; + } + + // Determine which pain flags to set + + AddStateFlag( STATE_FLAG_SMALL_PAIN ); + + if ( damage < pain_threshold ) + { + if ( G_Random( 1 ) < damage / pain_threshold ) + { + if ( means_of_death == MOD_SWORD || means_of_death == MOD_AXE || means_of_death == MOD_FIRESWORD || + means_of_death == MOD_ELECTRICSWORD ) + pain_type = PAIN_BIG; + else + pain_type = PAIN_SMALL; + AddStateFlag( STATE_FLAG_IN_PAIN ); + } + } + else + { + pain_type = PAIN_BIG; + AddStateFlag( STATE_FLAG_IN_PAIN ); + } + + // Determine pain angles + + if ( Vector( position - centroid ).length() > 1 ) + dir = centroid - position; + else + dir = direction; + + dir = dir * -1; + + pain_angles = dir.toAngles(); + + pain_angles[YAW] = AngleNormalize180( angles[YAW] - pain_angles[YAW] ); + pain_angles[PITCH] = AngleNormalize180( angles[PITCH] - pain_angles[PITCH] ); + } + +void Actor::StunEvent + ( + Event *ev + ) + + { + float time; + + time = ev->GetFloat( 1 ); + + SetActorFlag( ACTOR_FLAG_STUNNED, true ); + + stunned_end_time = level.time + time; + } + +void Actor::CheckStun + ( + void + ) + + { + if ( GetActorFlag( ACTOR_FLAG_STUNNED ) && stunned_end_time <= level.time ) + SetActorFlag( ACTOR_FLAG_STUNNED, false ); + } + +void Actor::Dead + ( + Event *ev + ) + + { + Vector min, max; + + // stop animating + StopAnimatingAtEnd(); + + edict->s.eFlags |= EF_DONT_PROCESS_COMMANDS; + + if ( !groundentity && ( velocity != vec_zero ) && ( movetype != MOVETYPE_STATIONARY ) ) + { + // wait until we hit the ground + PostEvent( EV_Actor_Dead, FRAMETIME ); + return; + } + + // don't allow them to fly, think, or swim anymore + flags &= ~( FL_THINK | FL_SWIM | FL_FLY ); + + deadflag = DEAD_DEAD; + setMoveType( MOVETYPE_NONE ); + setOrigin( origin ); + + if ( trigger ) + { + trigger->ProcessEvent( EV_Remove ); + } + + if ( spawnparent ) + PostEvent( EV_Actor_Fade, .5 ); + else + PostEvent( EV_Actor_Fade, 10 ); + } + +void Actor::KilledEffects + ( + Entity *attacker + ) + + { + Entity *ent; + Event *event; + str target_name; + + if ( g_debugtargets->integer ) + { + G_DebugTargets( this, "Actor::KilledEffects" ); + } + + // + // kill the killtargets + // + target_name = KillTarget(); + if ( target_name && strcmp( target_name, "" ) ) + { + ent = NULL; + do + { + ent = G_FindTarget( ent, target_name ); + if ( !ent ) + { + break; + } + ent->PostEvent( EV_Remove, 0 ); + } + while ( 1 ); + } + + // + // fire targets + // + target_name = Target(); + if ( target_name && strcmp( target_name, "" ) ) + { + ent = NULL; + do + { + ent = G_FindTarget( ent, target_name ); + if ( !ent ) + { + break; + } + + event = new Event( EV_Activate ); + event->AddEntity( attacker ); + ent->PostEvent( event, 0 ); + } + while ( 1 ); + } + // + // see if we have a kill_thread + // + if ( kill_thread.length() > 1 ) + { + ScriptThread * thread; + + // + // create the thread, but don't start it yet + // + thread = ExecuteThread( kill_thread, false ); + if ( thread ) + { + ProcessScript( thread, NULL ); + } + else + { + warning( "Killed", "could not process kill_thread" ); + } + } + } + +void Actor::Killed + ( + Event *ev + ) + + { + Vector position; + ClassDef *cls; + str deathanim; + str newdeathanim; + Entity *attacker; + float damage; + + + attacker = ev->GetEntity( 1 ); + damage = ev->GetFloat( 2 ); + + if ( !GetActorFlag( ACTOR_FLAG_ALLOWED_TO_KILL ) && attacker && attacker->isSubclassOf( Player ) ) + G_MissionFailed(); + + // Update boss health if necessary + + if ( GetActorFlag( ACTOR_FLAG_UPDATE_BOSS_HEALTH ) && max_boss_health ) + { + char bosshealth_string[20]; + sprintf( bosshealth_string, "%.5f", health / max_boss_health ); + gi.cvar_set( "bosshealth", bosshealth_string ); + } + + // Add to the players action level + + if ( damage && attacker && attacker->isSubclassOf( Player ) ) + { + Player *player = (Player *)attacker; + + player->IncreaseActionLevel( damage / 4 ); + } + + KilledEffects( attacker ); + + if ( next_pain_sound_time <= level.time && !GetActorFlag( ACTOR_FLAG_NO_PAIN_SOUNDS ) ) + { + next_pain_sound_time = level.time + 0.4 + G_Random( 0.2 ); + BroadcastSound(); + } + + if ( !GetActorFlag( ACTOR_FLAG_DIE_COMPLETELY ) ) + return; + + // See if means of death should be bumped up from MOD_BULLET to MOD_FAST_BULLET + + if ( means_of_death == MOD_BULLET ) + { + if ( bullet_hits < 5 ) + bullet_hits = 0; + + if ( G_Random( 100 ) < bullet_hits * 10 ) + means_of_death = MOD_FAST_BULLET; + } + + // Make sure all bones are put back in their normal positions + + if ( edict->s.bone_tag[ ACTOR_MOUTH_TAG ] != -1 ) + SetControllerAngles( ACTOR_MOUTH_TAG, vec_zero ); + + if ( edict->s.bone_tag[ ACTOR_HEAD_TAG ] != -1 ) + SetControllerAngles( ACTOR_HEAD_TAG, vec_zero ); + + if ( edict->s.bone_tag[ ACTOR_TORSO_TAG ] != -1 ) + SetControllerAngles( ACTOR_TORSO_TAG, vec_zero ); + + // Stop behavior + + cls = getClass( "idle" ); + SetBehavior( ( Behavior * )cls->newInstance() ); + + // don't allow them to fly or swim anymore + flags &= ~( FL_SWIM | FL_FLY ); + + deadflag = DEAD_DYING; + + groundentity = NULL; + + edict->svflags |= SVF_DEADMONSTER; + + if ( !GetActorFlag( ACTOR_FLAG_STAYSOLID ) ) + { + edict->clipmask = MASK_DEADSOLID; + + if ( edict->solid != SOLID_NOT ) + setContents( CONTENTS_CORPSE ); + } + + // Stop the actor from talking + + if ( GetActorFlag( ACTOR_FLAG_DIALOG_PLAYING ) ) + { + CancelEventsOfType( EV_SetControllerAngles ); + StopSound( CHAN_DIALOG ); + } + + // Setup the default death animation + + deathanim = "death"; + + // See if this actor has a death state in its state machine + + if ( statemap ) + { + int count = 0; + State *temp_state; + State *last_temp_state = NULL; + str temp_anim; + + temp_state = statemap->FindState( "DEATH" ); + + if ( temp_state ) + { + do + { + count++; + if ( count > 10 ) + { + gi.Error( ERR_DROP, "Stopping due to possible infinite state loop in death state\n" ); + break; + } + + // Process the current state + + if ( last_temp_state != temp_state ) + { + // Get the new animation name + + temp_anim = temp_state->getLegAnim( *this, &conditionals ); + + if ( temp_anim.length() ) + newdeathanim = temp_anim; + + // Process exit commands of the last state + + if ( last_temp_state ) + last_temp_state->ProcessExitCommands( this ); + + // Process the entry commands of the new state + + temp_state->ProcessEntryCommands( this ); + } + + // Determine the next state to go to + + last_temp_state = temp_state; + temp_state = temp_state->Evaluate( *this, &conditionals ); + } + while ( last_temp_state != temp_state ); + } + + if ( newdeathanim.length() > 0 ) + deathanim = newdeathanim; + } + + // Play the death animation + + SetAnim( deathanim, EV_Actor_Dead ); + ChangeAnim(); + + // See if we were spawned by another actor + + if ( spawnparent ) + { + spawnparent->num_of_spawns--; + } + + // See if we should notify others + + if ( GetActorFlag( ACTOR_FLAG_NOTIFY_OTHERS_AT_DEATH ) ) + NotifyOthersOfDeath(); + + SpawnItems(); + + if ( means_of_death == MOD_GIB ) + { + Event *event; + int i; + + if ( blood_model.length() == 0 ) + blood_model = "fx_bspurt.tik"; + + if ( max_gibs == 0 ) + max_gibs = 4; + + for( i = 0 ; i < 4 ; i++ ) + { + event = new Event( EV_Sentient_SpawnBloodyGibs ); + event->AddInteger( max_gibs ); + ProcessEvent( event ); + } + + PostEvent( EV_Remove, 0 ); + } + } + +void Actor::SetDieCompletely + ( + Event *ev + ) + { + SetActorFlag( ACTOR_FLAG_DIE_COMPLETELY, ev->GetBoolean( 1 ) ); + } + +void Actor::SetBleedAfterDeath + ( + Event *ev + ) + { + SetActorFlag( ACTOR_FLAG_BLEED_AFTER_DEATH, ev->GetBoolean( 1 ) ); + } + +void Actor::SpawnGib + ( + Event *ev + ) + { + RealSpawnGib( false, ev ); + } + +void Actor::SpawnGibAtTag + ( + Event *ev + ) + { + RealSpawnGib( true, ev ); + } + +void Actor::RealSpawnGib + ( + qboolean use_tag, + Event *ev + ) + { + str tag_name; + Gib *gib; + Mover *ent = NULL; + Vector final_gib_offset; + Vector orig; + Vector dir; + int current_arg; + float final_pitch; + float vel; + trace_t trace; + float time; + float pitch_change; + float pitch_vel; + str attach_tag_name; + Vector offset; + str cap_name; + float width; + const char *current_arg_str; + int current_surface; + const char *current_surface_name; + qboolean use_blood; + str blood_name; + str blood_splat_name; + str blood_model_name; + float blood_splat_size; + Vector gib_mins; + Vector gib_maxs; + float m; + qboolean at_least_one_visible_surface = false; + int surface_length; + int tagnum; + orientation_t or; + float raw_offset; + Vector raw_offset_dir; + Vector real_tag_pos; + Vector real_tag_dir; + Vector real_tag_angles; + + + SetActorFlag( ACTOR_FLAG_SPAWN_FAILED, true ); + + if ( !com_blood->integer ) + return; + + if ( GetActorFlag( ACTOR_FLAG_FADING_OUT ) ) + return; + + if ( ev->NumArgs() < 5 ) + return; + + if ( use_tag ) + { + attach_tag_name = ev->GetString( 1 ); + raw_offset = ev->GetFloat( 2 ); + width = ev->GetFloat( 3 ); + + // Get all the tag information + + tagnum = gi.Tag_NumForName( edict->s.modelindex, attach_tag_name.c_str() ); + + if ( tagnum == -1 ) + return; + + GetRawTag( tagnum, &or ); + GetTag( tagnum, &real_tag_pos, &real_tag_dir ); + + real_tag_angles = real_tag_dir.toAngles(); + + // Determine the final pitch of the gib + + final_pitch = AngleNormalize180( angles[PITCH] - real_tag_angles[PITCH] ); + + // Determine the offset of the gib + + raw_offset_dir = or.axis[0]; + + offset = or.origin; + offset += raw_offset * raw_offset_dir; + MatrixTransformVector( offset, orientation, orig ); + orig += origin; + } + else + { + offset = ev->GetVector( 1 ); + final_pitch = ev->GetFloat( 2 ); + width = ev->GetFloat( 3 ); + + MatrixTransformVector( offset, orientation, orig ); + orig += origin; + } + + // Determine the mass + + m = mass; + + if ( m < 50 ) + m = 50; + else if ( m > 250 ) + m = 250; + + // Determine which blood spurt & splat to use for the gib + + blood_name = GetBloodSpurtName(); + blood_splat_name = GetBloodSplatName(); + blood_splat_size = GetBloodSplatSize(); + + if ( blood_name.length() && blood_splat_name.length() ) + use_blood = true; + else + use_blood = false; + + if ( GetActorFlag( ACTOR_FLAG_BLEED_AFTER_DEATH ) ) + blood_model_name = blood_model; + + // Get the mins and maxs for this gib + + gib_mins = Vector( -width, -width, -width ); + gib_maxs = Vector( width, width, width ); + + // Make sure we can spawn in a gib here + + trace = G_Trace( orig, gib_mins, gib_maxs, orig, NULL, MASK_DEADSOLID, false, "spawngib" ); + + if ( trace.allsolid || trace.startsolid ) + return; + + // Make sure at least one of the surfaces is not hidden + + for( current_arg = 5 ; current_arg <= ev->NumArgs() ; current_arg++ ) + { + current_arg_str = ev->GetString( current_arg ); + + for( current_surface = 0 ; current_surface < numsurfaces ; current_surface++ ) + { + current_surface_name = gi.Surface_NumToName( edict->s.modelindex, current_surface ); + + if ( current_arg_str[ strlen( current_arg_str ) - 1 ] == '*' ) + surface_length = strlen( current_arg_str ) - 1; + else + surface_length = strlen( current_arg_str ); + + if ( Q_stricmpn( current_surface_name, current_arg_str, surface_length ) == 0 ) + { + if ( !( edict->s.surfaces[ current_surface ] & MDL_SURFACE_NODRAW ) ) + at_least_one_visible_surface = true; + } + } + } + + if ( !at_least_one_visible_surface ) + return; + + // Determine time till it hits the ground + + vel = 100 + G_Random( 200 * ( 2 - ( (m - 50) / 200) ) ); + + time = SpawnGetTime( vel , orig, gib_mins, gib_maxs ); + + // Flip final pitch 180 degrees? + + if ( G_Random() > .5 ) + { + final_pitch += 180; + final_pitch = AngleNormalize360( final_pitch ); + } + + // Calculate the pitch change and velocity + + pitch_change = AngleNormalize180( final_pitch - angles[PITCH] ); + pitch_vel = pitch_change / time; + + // Spawn in the hidden gib + + gib = new Gib( "", use_blood, blood_name, blood_model_name, blood_splat_name, blood_splat_size, final_pitch ); + + gib->setOrigin( orig ); + + gib->angles[PITCH] = angles[PITCH]; + gib->angles[ROLL] = 0; + + if ( use_tag ) + gib->angles[YAW] = real_tag_angles[YAW]; + else + gib->angles[YAW] = angles[YAW]; + + gib->setAngles( gib->angles ); + + gib->velocity = Vector( G_CRandom( 150 * ( 2 - ( (m - 50) / 200) ) ), G_CRandom( 150 * ( 2 - ( (m - 50) / 200) ) ), vel ); + gib->avelocity = Vector( pitch_vel, G_CRandom( 300 ), 0 ); + + gib->setSize( gib_mins, gib_maxs ); + + gib->edict->svflags |= SVF_DEADMONSTER; + gib->edict->clipmask = MASK_DEADSOLID; + + gib->setSolidType( SOLID_BBOX ); + gib->setContents( CONTENTS_SHOOTABLE_ONLY ); + gib->link(); + + // Spawn in the visible gib + + ent = new Mover; + ent->setModel( model ); + + // Make sure the init stuff in the tiki get processed now + + //ent->ProcessPendingEvents(); + ent->CancelPendingEvents(); + + // Make sure no cleint side commands are processed + + ent->edict->s.eFlags |= EF_DONT_PROCESS_COMMANDS; + + // Set the animation to the current anim & frame of the actor + + ent->RandomAnimate( AnimName() ); + ent->SetFrame( CurrentFrame() ); + + ent->setAngles( angles ); + ent->bind( gib, true ); + ent->gravity = 0; + + final_gib_offset = offset * -1; + ent->setOrigin( final_gib_offset ); + + ent->setMoveType( MOVETYPE_BOUNCE ); + ent->setSolidType( SOLID_NOT ); + ent->showModel(); + + // Hide all of the surfaces on the gib + + ent->SurfaceCommand( "all", "+nodraw" ); + + cap_name = ev->GetString( 4 ); + + // Show the cap surface on the gib and the actor + + if ( cap_name.length() ) + { + ent->SurfaceCommand( cap_name.c_str(), "-nodraw" ); + + SurfaceCommand( cap_name.c_str(), "-nodraw" ); + } + + // Show and hide all of the rest of the necessary surfaces + + for ( current_arg = 5 ; current_arg <= ev->NumArgs() ; current_arg++ ) + { + current_arg_str = ev->GetString( current_arg ); + + if ( current_arg_str[ strlen( current_arg_str ) - 1 ] == '*' ) + surface_length = strlen( current_arg_str ) - 1; + else + surface_length = strlen( current_arg_str ); + + for( current_surface = 0 ; current_surface < numsurfaces ; current_surface++ ) + { + current_surface_name = gi.Surface_NumToName( edict->s.modelindex, current_surface ); + + if ( Q_stricmpn( current_surface_name, current_arg_str, surface_length ) == 0 ) + { + if ( !( edict->s.surfaces[ current_surface ] & MDL_SURFACE_NODRAW ) ) + { + // Show this surface on the gib + ent->SurfaceCommand( current_surface_name, "-nodraw" ); + + // Hide this surface on the actor + SurfaceCommand( current_surface_name, "+nodraw" ); + } + } + } + } + + // Make sure the gibs go away after a while + + if ( GetActorFlag( ACTOR_FLAG_DEATHFADE ) ) + { + ent->PostEvent( EV_Fade, 10 ); + gib->PostEvent( EV_Fade, 10.5 ); + } + else if ( GetActorFlag( ACTOR_FLAG_DEATHSHRINK ) ) + { + ent->PostEvent( EV_FadeOut, 10 ); + gib->PostEvent( EV_FadeOut, 10.5 ); + } + else + { + ent->PostEvent( EV_Unbind, 10 ); + ent->PostEvent( EV_DeathSinkStart, 12 ); + gib->PostEvent( EV_Remove, 10.5 ); + } + + // Mark the spawn as being successful + + SetActorFlag( ACTOR_FLAG_SPAWN_FAILED, false ); + + // Play the severed sound + + ent->Sound( "impact_sever", CHAN_BODY ); + } + +void Actor::SpawnNamedGib + ( + Event *ev + ) + { + str gib_name; + str tag_name; + Gib *gib; + Vector orig; + float final_pitch; + float vel; + trace_t trace; + float time; + float pitch_change; + float pitch_vel; + float width; + Vector gib_mins; + Vector gib_maxs; + + + SetActorFlag( ACTOR_FLAG_SPAWN_FAILED, true ); + + if ( !com_blood->integer ) + return; + + if ( GetActorFlag( ACTOR_FLAG_FADING_OUT ) ) + return; + + // Get all of the parameters + + gib_name = ev->GetString( 1 ); + tag_name = ev->GetString( 2 ); + final_pitch = ev->GetFloat( 3 ); + width = ev->GetFloat( 4 ); + + // Get the tag position + + GetTag( tag_name, &orig ); + + // Get the mins and maxs for this gib + + gib_mins = Vector( -width, -width, -width ); + gib_maxs = Vector( width, width, width ); + + // Make sure we can spawn in a gib here + + trace = G_Trace( orig, gib_mins, gib_maxs, orig, NULL, MASK_DEADSOLID, false, "spawnnamedgib1" ); + + if ( trace.allsolid || trace.startsolid ) + SetActorFlag( ACTOR_FLAG_SPAWN_FAILED, true ); + + // Determine time till it hits the ground + + vel = 200 + G_Random( 200 ); + + time = SpawnGetTime( vel , orig, gib_mins, gib_maxs ); + + pitch_change = AngleNormalize180( final_pitch - angles[PITCH] ); + pitch_vel = pitch_change / time; + + // Spawn the gib + + gib = new Gib( gib_name, false, "", "", "", final_pitch ); + + gib->setOrigin( orig ); + gib->setAngles( angles ); + + gib->velocity = Vector( G_CRandom( 100 ), G_CRandom( 100 ), vel ); + gib->avelocity = Vector( pitch_vel, G_CRandom( 300 ), 0 ); + + gib->edict->svflags |= SVF_DEADMONSTER; + gib->edict->clipmask = MASK_DEADSOLID; + + gib->setSolidType( SOLID_BBOX ); + gib->setContents( CONTENTS_CORPSE ); + + // Make sure the gib goes away after a while + + if ( GetActorFlag( ACTOR_FLAG_DEATHFADE ) ) + gib->PostEvent( EV_Fade, 10 ); + else if ( GetActorFlag( ACTOR_FLAG_DEATHSHRINK ) ) + gib->PostEvent( EV_FadeOut, 10 ); + else + gib->PostEvent( EV_DeathSinkStart, 10 ); + + // Mark the spawn as being successful + + SetActorFlag( ACTOR_FLAG_SPAWN_FAILED, false ); + } + +float Actor::SpawnGetTime( float vel, Vector orig, Vector gib_mins, Vector gib_maxs ) + { + float grav; + Vector end_pos; + Vector dir; + float time; + float other; + trace_t trace; + float dist; + + grav = -sv_gravity->value; + + end_pos = orig; + end_pos[2] = -10000; + + trace = G_Trace( orig, gib_mins, gib_maxs, end_pos, NULL, MASK_DEADSOLID, false, "SpawnGetTime" ); + + end_pos = trace.endpos; + + dir = end_pos - orig; + dist = dir.length(); + + time = ( (grav / -20) - vel ) / grav; + + other = sqrt( (grav / 20 + vel) * (grav / 20 + vel) - (2 * grav * dist) ); + + time = time - other / grav; + + return time; + } + +void Actor::SpawnBlood + ( + Event *ev + ) + { + str blood_name; + str tag_name; + qboolean use_last_result = false; + Event *attach_event; + + + if ( !com_blood->integer ) + return; + + blood_name = ev->GetString( 1 ); + tag_name = ev->GetString( 2 ); + + // See if we care about the last spawn working or not + + if ( ev->NumArgs() > 2 ) + use_last_result = ev->GetBoolean( 3 ); + + if ( use_last_result && GetActorFlag( ACTOR_FLAG_SPAWN_FAILED ) ) + return; + + // Spawn the blood + + attach_event = (Event *)new Event( EV_AttachModel ); + + attach_event->AddString( blood_name ); + attach_event->AddString( tag_name ); + attach_event->AddInteger( 1 ); + attach_event->AddString( "" ); + attach_event->AddInteger( 0 ); + attach_event->AddInteger( 5 ); + PostEvent( attach_event, 0 ); + } + +void Actor::RemoveUselessBody + ( + Event *ev + ) + + { + /* if ( trig ) + { + trig->PostEvent( EV_Remove, 0 ); + trig = NULL; + } */ + + CancelEventsOfType( EV_Sentient_UselessCheck ); + PostEvent( EV_FadeOut, 5); + } + +void Actor::SetPainThresholdEvent + ( + Event *ev + ) + + { + //pain_threshold = ( ev->GetFloat( 1 ) ) * skill->value * 0.66f; + pain_threshold = ( ev->GetFloat( 1 ) ); + } + +void Actor::SetKillThreadEvent + ( + Event *ev + ) + + { + kill_thread = ev->GetString( 1 ); + } + +void Actor::DeathFadeEvent + ( + Event *ev + ) + + { + SetActorFlag( ACTOR_FLAG_DEATHFADE, true ); + } + +void Actor::DeathShrinkEvent + ( + Event *ev + ) + + { + SetActorFlag( ACTOR_FLAG_DEATHSHRINK, true ); + } + +void Actor::DeathSinkEvent + ( + Event *ev + ) + + { + SetActorFlag( ACTOR_FLAG_DEATHSINK, true ); + } + +void Actor::StaySolidEvent + ( + Event *ev + ) + + { + SetActorFlag( ACTOR_FLAG_STAYSOLID, true ); + } + +void Actor::Suicide + ( + Event *ev + ) + + { + Event *event; + qboolean use_last_mod; + + health = 0; + + if ( ev->NumArgs() > 0 ) + use_last_mod = ev->GetBoolean( 1 ); + else + use_last_mod = false; + + if ( !use_last_mod ) + means_of_death = MOD_SUICIDE; + + event = new Event( EV_Killed ); + event->AddEntity( this ); + event->AddInteger( 0 ); + event->AddEntity( this ); + event->AddInteger( MOD_SUICIDE ); + ProcessEvent( event ); + } + +void Actor::SetDeathSize + ( + Event *ev + ) + + { + Vector death_min; + Vector death_max; + trace_t trace; + + death_min = ev->GetVector( 1 ); + death_max = ev->GetVector( 2 ); + + // Make sure actor will not be stuck if we change the bounding box + + trace = G_Trace( origin, death_min, death_max, origin, this, edict->clipmask, false, "Actor::SetDeathSize" ); + + if ( !trace.startsolid ) + { + setSize( death_min, death_max ); + return; + } + + // Try again, calculate a smaller death bounding box + + death_min = (death_min + mins) * .5; + death_max = (death_max + maxs) * .5; + + trace = G_Trace( origin, death_min, death_max, origin, this, edict->clipmask, false, "Actor::SetDeathSize2" ); + + if ( !trace.startsolid ) + setSize( death_min, death_max ); + } + +void Actor::FadeEvent + ( + Event *ev + ) + { + SetActorFlag( ACTOR_FLAG_FADING_OUT, true ); + + if ( GetActorFlag( ACTOR_FLAG_DEATHFADE ) ) + ProcessEvent( EV_Fade ); + else if ( GetActorFlag( ACTOR_FLAG_DEATHSHRINK ) ) + ProcessEvent( EV_FadeOut ); + else if ( GetActorFlag( ACTOR_FLAG_DEATHSINK ) ) + ProcessEvent( EV_DeathSinkStart ); + else + SetActorFlag( ACTOR_FLAG_FADING_OUT, false ); + } + +//*********************************************************************************************** +// +// Movement functions +// +//*********************************************************************************************** + +void Actor::SimplePathfinding + ( + Event *ev + ) + { + SetActorFlag( ACTOR_FLAG_SIMPLE_PATHFINDING, true ); + } + +void Actor::SetCanWalkOnOthers + ( + Event *ev + ) + + { + SetActorFlag( ACTOR_FLAG_CAN_WALK_ON_OTHERS, true ); + } + +void Actor::SetFeetWidth + ( + Event *ev + ) + + { + feet_width = ev->GetFloat( 1 ); + } + +void Actor::ForwardSpeedEvent + ( + Event *ev + ) + + { + forwardspeed = ev->GetFloat( 1 ); + } + +void Actor::SwimEvent + ( + Event *ev + ) + + { + flags &= ~FL_FLY; + flags |= FL_SWIM; + } + +void Actor::FlyEvent + ( + Event *ev + ) + + { + if ( ev->NumArgs() == 0 ) + { + // Turn flying on + flags &= ~FL_SWIM; + flags |= FL_FLY; + } + else + { + if ( ev->GetBoolean( 1 ) ) + { + // Turn flying on + flags &= ~FL_SWIM; + flags |= FL_FLY; + } + else + { + // Turn flying off + flags &= ~FL_FLY; + } + } + } + +void Actor::NotLandEvent + ( + Event *ev + ) + + { + flags &= FL_SWIM | FL_FLY; + } + +qboolean Actor::CanMoveTo + ( + Vector pos + ) + + { + Vector min; + trace_t trace; + Vector start; + Vector end; + Vector s; + + s = Vector( 0, 0, STEPSIZE ); + start = origin + s; + end = pos + s; + trace = G_Trace( start, mins, maxs, end, this, edict->clipmask, false, "Actor::CanMoveTo" ); + if ( trace.fraction == 1 ) + { + return true; + } + return false; + } + +qboolean Actor::CanWalkTo + ( + Vector pos, + int entnum + ) + + { + trace_t trace; + Vector dir; + float length; + float i; + float j; + Vector bottom; + Vector current_loc; + Vector last_loc; + float trace_step; + float small_trace_step; + float last_height; + Vector real_pos; + + + // Calculate the real position we have to get to + + if ( entnum != ENTITYNUM_NONE ) + { + Vector temp_dir; + float temp_length; + + temp_dir = pos - origin; + temp_length = temp_dir.length(); + + temp_length -= sqrt( maxs.x * maxs.x * 2 ) + 5; + + if ( temp_length < 0 ) + temp_length = 0; + + temp_dir.normalize(); + temp_dir *= temp_length; + + real_pos = origin + temp_dir; + } + else + { + real_pos = pos; + } + + + // Do simple CanWalkTo if specified + + if ( GetActorFlag( ACTOR_FLAG_SIMPLE_PATHFINDING ) ) + { + current_loc = origin; + current_loc[2] += STEPSIZE; + last_loc = real_pos; + last_loc[2] += STEPSIZE; + trace = G_Trace( current_loc, mins, maxs, last_loc, this, MASK_PATHSOLID, false, "Actor::CanWalkTo_Simple" ); + + if ( trace.fraction == 1 ) + return true; + else + return false; + } + + // Find the vector to walk + + dir = real_pos - origin; + length = dir.length(); + dir.normalize(); + + // Find the step amount + + trace_step = maxs[0] * 2; + + // Make sure trace_step is divisible by 8 + + trace_step = ( (int)(trace_step / 8 ) ) * 8; + + if ( trace_step < 8 ) + trace_step = 8; + + small_trace_step = 8; + + // Test each step to see if the ground is not too far below + + last_height = origin[2]; + + for( i = 0 ; i < length ; i += trace_step ) + { + last_loc = current_loc; + + current_loc = origin + dir * i; + current_loc[2] = last_height + STEPSIZE; + + bottom = current_loc; + + if ( !GetActorFlag( ACTOR_FLAG_ALLOW_FALL ) ) + bottom[2] = last_height - STEPSIZE; + else + bottom[2] = last_height - 1000; + + trace = G_Trace( current_loc, mins, maxs, bottom, this, MASK_PATHSOLID, false, "Actor::CanWalkTo1" ); + + if ( !( trace.fraction == 1 || trace.startsolid || trace.allsolid ) && feet_width ) + { + Vector temp_mins; + Vector temp_maxs; + Vector saved_endpos; + + saved_endpos = trace.endpos; + + temp_mins[0] = -feet_width; + temp_mins[1] = -feet_width; + temp_mins[2] = mins[2]; + + temp_maxs[0] = feet_width; + temp_maxs[1] = feet_width; + temp_maxs[2] = maxs[2]; + + trace = G_Trace( current_loc, temp_mins, temp_maxs, bottom, this, MASK_PATHSOLID, false, "Actor::CanWalkTo2" ); + + saved_endpos.copyTo( trace.endpos ); + } + + if ( trace.fraction == 1 || trace.startsolid || trace.allsolid ) + { + // The wide one failed, do the small traces for this segment + + if ( i == 0 || trace_step == small_trace_step ) + return false; + + for( j = small_trace_step ; j <= trace_step ; j += small_trace_step ) + { + current_loc = last_loc + dir * j; + current_loc[2] = last_height + STEPSIZE; + + bottom = current_loc; + bottom[2] = last_height - STEPSIZE; + + trace = G_Trace( current_loc, mins, maxs, bottom, this, MASK_PATHSOLID, false, "Actor::CanWalkTo3" ); + + if ( trace.fraction == 1 || trace.startsolid || trace.allsolid || + ( trace.ent && trace.ent->entity->isSubclassOf( Sentient ) && !GetActorFlag( ACTOR_FLAG_CAN_WALK_ON_OTHERS ) ) ) + return false; + + if ( feet_width ) + { + Vector temp_mins; + Vector temp_maxs; + Vector saved_endpos; + + saved_endpos = trace.endpos; + + temp_mins[0] = -feet_width; + temp_mins[1] = -feet_width; + temp_mins[2] = mins[2]; + + temp_maxs[0] = feet_width; + temp_maxs[1] = feet_width; + temp_maxs[2] = maxs[2]; + + trace = G_Trace( current_loc, temp_mins, temp_maxs, bottom, this, MASK_PATHSOLID, false, "Actor::CanWalkTo4" ); + + saved_endpos.copyTo( trace.endpos ); + } + + last_height = trace.endpos[2]; + } + } + + last_height = trace.endpos[2]; + } + + if ( last_height > pos.z + STEPSIZE * 2 || last_height < pos.z - STEPSIZE * 2 ) + return false; + + return true; + } + +void Actor::CheckWater + ( + void + ) + { + Vector sample[3]; + int cont; + + // + // get waterlevel and type + // + waterlevel = 0; + watertype = 0; + + sample[ 0 ] = origin; + sample[ 2 ] = EyePosition(); + sample[ 1 ] = ( sample[ 0 ] + sample[ 2 ] ) * 0.5f; + + cont = gi.pointcontents( sample[ 0 ], 0 ); + + if (cont & MASK_WATER) + { + watertype = cont; + waterlevel = 1; + cont = gi.pointcontents( sample[ 2 ], 0 ); + if (cont & MASK_WATER) + { + waterlevel = 3; + } + else + { + cont = gi.pointcontents( sample[ 1 ], 0 ); + if (cont & MASK_WATER) + { + waterlevel = 2; + } + } + } + } + +#define MAX_PITCH 75 + +void Actor::Accelerate + ( + Vector steering + ) + + { + // limit the actor's turnrate + + if ( steering.y > turnspeed ) + steering.y = turnspeed; + else if ( steering.y < -turnspeed ) + steering.y = -turnspeed; + + angles.y += steering.y; + + if ( frame_delta.x > 4 ) + { + // make him lean into the turn a bit + angles.z = movespeed * ( 0.4f / 320.0f ) * steering.y; + + if ( ( flags & FL_FLY ) || ( ( flags & FL_SWIM ) && waterlevel > 0 ) ) + { + angles.z = bound( angles.z, -2, 2 ); + } + else + { + angles.z = bound( angles.z, -5, 5 ); + } + } + else + { + angles.z = 0; + } + +#if 0 + if ( ( flags & FL_FLY ) || ( ( flags & FL_SWIM ) && waterlevel > 0 ) ) + { + //angles.x = bound( angles.x, -MAX_PITCH, MAX_PITCH ); + } +#endif + + setAngles( angles ); + } + +void Actor::CalcMove + ( + void + ) + + { + if ( total_delta != vec_zero ) + { + MatrixTransformVector( total_delta, orientation, move ); + total_delta = vec_zero; + } + else + { + move = vec_zero; + } + + // force movement if forwardspeed is set + if ( forwardspeed ) + { + if ( move == vec_zero ) + { + move = orientation[ 0 ]; + } + else + { + move.normalize(); + } + + animdir = move; + movedir = move; + movespeed = forwardspeed; + move *= movespeed * FRAMETIME; + totallen = forwardspeed; + movevelocity = movedir * movespeed; + } + } + +void Actor::setAngles + ( + Vector ang + ) + + { + Sentient::setAngles( ang ); + MatrixTransformVector( animdir, orientation, movedir ); + movevelocity = movedir * movespeed; + } + +stepmoveresult_t Actor::WaterMove + ( + void + ) + + { + Vector oldorg; + Vector neworg; + trace_t trace; + int oldwater; + + if ( ( totallen <= 0.01f ) || ( move == vec_zero ) ) + { + return STEPMOVE_OK; + } + + // try the move + oldorg = origin; + neworg = origin + move; + + trace = G_Trace( oldorg, mins, maxs, neworg, this, edict->clipmask, false, "Actor::WaterMove 1" ); + if ( trace.fraction == 0 ) + { + return STEPMOVE_STUCK; + } + + oldwater = waterlevel; + + setOrigin( trace.endpos ); + + CheckWater(); + + // swim monsters don't exit water voluntarily + if ( ( oldwater > 1 ) && ( waterlevel < 2 ) ) + { + waterlevel = oldwater; + setOrigin( oldorg ); + return STEPMOVE_STUCK; + } + + return STEPMOVE_OK; + } + +stepmoveresult_t Actor::AirMove + ( + void + ) + + { + Vector oldorg; + Vector neworg; + trace_t trace; + int oldwater; + + if ( ( totallen <= 0.01f ) || ( move == vec_zero ) ) + { + return STEPMOVE_OK; + } + + // try the move + oldorg = origin; + neworg = origin + move; + + trace = G_Trace( oldorg, mins, maxs, neworg, this, edict->clipmask, false, "Actor::AirMove 1" ); + if ( trace.fraction < 0.0001 ) + { + return STEPMOVE_BLOCKED_BY_WATER; + } + + oldwater = waterlevel; + + setOrigin( trace.endpos ); + + if ( !GetActorFlag( ACTOR_FLAG_IGNORE_WATER ) ) + { + CheckWater(); + + // fly monsters don't enter water voluntarily + if ( !oldwater && waterlevel ) + { + waterlevel = oldwater; + setOrigin( oldorg ); + return STEPMOVE_STUCK; + } + } + + return STEPMOVE_OK; + } + +stepmoveresult_t Actor::TryMove + ( + void + ) + + { + Vector oldorg; + Vector neworg; + Vector end; + trace_t trace; + Door *door; + static Vector step( 0, 0, STEPSIZE ); + qboolean allow_fall; + + + // See if we should bother doing any movement + + if ( velocity != vec_zero && !deadflag ) + { + // We have a velocity so movement of the actor is done in physics + return STEPMOVE_OK; + } + + if ( ( totallen <= 0.01f ) || ( move == vec_zero ) ) + { + return STEPMOVE_OK; + } + + // Try to make the move + + oldorg = origin + step; + neworg = oldorg + move; + trace = G_Trace( oldorg, mins, maxs, neworg, this, edict->clipmask, false, "Actor::TryMove 1" ); + + if ( trace.startsolid ) + { + oldorg = origin; + neworg = oldorg + move; + trace = G_Trace( oldorg, mins, maxs, neworg, this, edict->clipmask, false, "Actor::TryMove 1.5" ); + } + + if ( trace.startsolid || ( trace.fraction < 0.0001f ) ) + { + return STEPMOVE_STUCK; + } + + // If we hit an entity, check what it is + + if ( !deadflag && trace.ent ) + { + // Check if we hit a door + + if ( trace.ent->entity->isSubclassOf( Door ) ) + { + door = ( Door * )trace.ent->entity; + if ( !door->locked && !door->isOpen() ) + { + return STEPMOVE_BLOCKED_BY_DOOR; + } + } + } + + // Don't step down an extra step if gravity is turned off for this actor right now or the actor is dead + + if ( !GetActorFlag( ACTOR_FLAG_USE_GRAVITY ) || deadflag ) + { + // try stepping down + oldorg = trace.endpos; + neworg = oldorg - step; + trace = G_Trace( oldorg, mins, maxs, neworg, this, edict->clipmask, false, "Actor::TryMove 2" ); + + if ( trace.startsolid ) + { + return STEPMOVE_STUCK; + } + + setOrigin( trace.endpos ); + + return STEPMOVE_OK; + } + + // Step down to a step height below our original height to account for gravity + + oldorg = trace.endpos; + neworg = oldorg - step * 2; + trace = G_Trace( oldorg, mins, maxs, neworg, this, edict->clipmask, false, "Actor::TryMove 3" ); + + // Determine if we should allow the actor to fall + + if ( ( flags & FL_PARTIALGROUND ) || + ( groundentity && groundentity->entity && ( groundentity->entity->isSubclassOf( Sentient ) ) ) || + ( GetActorFlag( ACTOR_FLAG_ALLOW_FALL ) ) ) + allow_fall = true; + else + allow_fall = false; + + // Don't voluntarily step on flying monsters + + if ( trace.ent && trace.ent->entity->flags & FL_FLY && !allow_fall ) + return STEPMOVE_BLOCKED_BY_FALL; + + // Don't voluntarilty step on sentients + + if ( trace.ent && trace.ent->entity->isSubclassOf( Sentient ) && + !allow_fall && !GetActorFlag( ACTOR_FLAG_CAN_WALK_ON_OTHERS ) ) + return STEPMOVE_BLOCKED_BY_FALL; + + // Check if the move places us on solid ground + + if ( trace.fraction == 1 ) + { + if ( allow_fall ) + { + // don't let guys get stuck standing on other guys + // if monster had the ground pulled out, go ahead and fall + groundentity = NULL; + } + else + { + // walked off an edge + return STEPMOVE_BLOCKED_BY_FALL; + } + } + + // Make sure ground is not too slopped or we will just slide off + + if ( trace.plane.normal[ 2 ] <= 0.7 && !allow_fall ) + return STEPMOVE_BLOCKED_BY_FALL; + + // If the feet width is set make sure the actor's feet are really on the ground + + if ( feet_width ) + { + Vector temp_mins; + Vector temp_maxs; + Vector saved_endpos; + + saved_endpos = trace.endpos; + + temp_mins[0] = -feet_width; + temp_mins[1] = -feet_width; + temp_mins[2] = mins[2]; + + temp_maxs[0] = feet_width; + temp_maxs[1] = feet_width; + temp_maxs[2] = maxs[2]; + + oldorg = trace.endpos; + neworg = oldorg - step * 3; + trace = G_Trace( oldorg, temp_mins, temp_maxs, neworg, this, edict->clipmask, false, "Actor::TryMove 4" ); + + // Don't voluntarilty step on sentients + + if ( trace.ent && trace.ent->entity->isSubclassOf( Sentient ) && + !allow_fall && !GetActorFlag( ACTOR_FLAG_CAN_WALK_ON_OTHERS ) ) + return STEPMOVE_BLOCKED_BY_FALL; + + if ( trace.fraction == 1 && !allow_fall ) + return STEPMOVE_BLOCKED_BY_FALL; + + saved_endpos.copyTo( trace.endpos ); + } + + // The move is ok + + setOrigin( trace.endpos ); + + // Save the ground information now so we don't have to do it later + + if ( trace.fraction < 1 ) + { + groundentity = trace.ent; + groundplane = trace.plane; + groundcontents = trace.contents; + last_origin = origin; + SetActorFlag( ACTOR_FLAG_HAVE_MOVED, true ); + } + + flags &= ~FL_PARTIALGROUND; // set in Actor::Think + + CheckWater(); + + return STEPMOVE_OK; + } + +void Actor::Push + ( + Event *ev + ) + { + Push( ev->GetVector( 1 ) ); + } + +qboolean Actor::Push + ( + Vector dir + ) + { + Vector oldorg; + Vector neworg; + static Vector step( 0, 0, STEPSIZE ); + trace_t trace; + int i; + + + if ( !GetActorFlag( ACTOR_FLAG_PUSHABLE ) ) + return false; + + for( i = 0 ; i < 5 ; i++ ) + { + oldorg = origin + step; + neworg = oldorg + dir; + + trace = G_Trace( oldorg, mins, maxs, neworg, this, edict->clipmask, false, "Actor::Push 1" ); + + if ( trace.startsolid ) + { + oldorg = origin; + neworg = oldorg + dir; + + trace = G_Trace( oldorg, mins, maxs, neworg, this, edict->clipmask, false, "Actor::Push 2" ); + + if ( trace.startsolid ) + return false; + } + + if ( trace.ent && trace.ent->entity->isSubclassOf( Actor ) ) + { + Actor *act = (Actor *) trace.ent->entity; + act->Push( dir ); + continue; + } + else + break; + } + + if ( trace.endpos == oldorg ) + return false; + + // Step down to a step height below our original height to account for gravity + + oldorg = trace.endpos; + + if ( flags & FL_FLY ) + neworg = oldorg - step; + else + neworg = oldorg - step * 2; + + trace = G_Trace( oldorg, mins, maxs, neworg, this, edict->clipmask, false, "Actor::Push 3" ); + + setOrigin( trace.endpos ); + + return true; + } + +void Actor::Pushable + ( + Event *ev + ) + { + SetActorFlag( ACTOR_FLAG_PUSHABLE, true ); + } + +float Actor::JumpTo + ( + Vector targ, + float speed + ) + { + float traveltime; + float vertical_speed; + Vector target; + Vector dir; + Vector xydir; + + CheckWater(); + // + // if we got a jump, go into that mode + // + traveltime = 0; + if ( speed <= 0 ) + { + speed = movespeed * 1.5f; + if ( speed < (400 * gravity) ) + speed = (400 * gravity); + } + + target = targ; + dir = target - origin; + xydir = dir; + xydir.z = 0; + setAngles( xydir.toAngles() ); + traveltime = xydir.length() / speed; + // + // we add 16 to allow for a little bit higher + // + if ( waterlevel > 2 ) + { + vertical_speed = ( ( dir.z + 16 ) / traveltime ) + ( 0.5f * gravity * 60 * traveltime ); + } + else + { + vertical_speed = ( ( dir.z + 16 ) / traveltime ) + ( 0.5f * gravity * sv_gravity->value * traveltime ); + } + + if ( vertical_speed < 200 ) + vertical_speed = 200; + + xydir.normalize(); + + velocity = speed * xydir; + velocity.z = vertical_speed; + + groundentity = NULL; + + return traveltime; + } + +float Actor::JumpTo + ( + PathNode *goal, + float speed + ) + { + if ( goal ) + return JumpTo( goal->origin, speed ); + else + return 0; + } + +float Actor::JumpTo + ( + Entity *goal, + float speed + ) + { + if ( goal ) + return JumpTo( goal->origin, speed ); + else + return 0; + } + +//*********************************************************************************************** +// +// Debug functions +// +//*********************************************************************************************** + +void Actor::ShowInfo + ( + void + ) + + { + gi.Printf( "\nEntity # : %d\n", entnum ); + gi.Printf( "Class ID : %s\n", getClassID() ); + gi.Printf( "Classname : %s\n", getClassname() ); + gi.Printf( "Name : %s\n", name.c_str() ); + + if ( part_name.length() > 0 ) + gi.Printf( "Part name : %s\n", part_name.c_str() ); + + + gi.Printf( "\n" ); + + gi.Printf( "Targetname : %s\n", TargetName() ); + gi.Printf( "Origin : ( %f, %f, %f )\n", origin.x, origin.y, origin.z ); + gi.Printf( "Bounds : Mins( %.2f, %.2f, %.2f ) Maxs( %.2f, %.2f, %.2f )\n", mins.x, mins.y, mins.z, maxs.x, maxs.y, maxs.z ); + + gi.Printf( "\n" ); + + if ( behavior ) + gi.Printf( "Behavior : %s\n", behavior->getClassname() ); + else + gi.Printf( "Behavior : NULL -- was '%s'\n", currentBehavior.c_str() ); + + if ( currentState ) + gi.Printf( "State : %s\n", currentState->getName() ); + else + gi.Printf( "State : NONE\n" ); + + if ( GetActorFlag( ACTOR_FLAG_AI_ON ) ) + gi.Printf( "AI is ON\n" ); + else + gi.Printf( "AI is OFF\n" ); + + if ( !( permanent_stimuli & STIMULI_SIGHT ) || !( stimuli & STIMULI_SIGHT ) ) + gi.Printf( "Actor is BLIND\n" ); + + if ( !( permanent_stimuli & STIMULI_SOUND ) || !( stimuli & STIMULI_SOUND ) ) + gi.Printf( "Actor is DEAF\n" ); + + if ( flags & FL_THINK ) + gi.Printf( "Think is ON\n" ); + else + gi.Printf( "Think is OFF\n" ); + + if ( mode == ACTOR_MODE_IDLE ) + gi.Printf( "Mode : IDLE\n" ); + else if ( mode == ACTOR_MODE_AI ) + gi.Printf( "Mode : AI\n" ); + else if ( mode == ACTOR_MODE_SCRIPT ) + gi.Printf( "Mode : SCRIPT\n" ); + else if ( mode == ACTOR_MODE_TALK ) + gi.Printf( "Mode : TALK\n" ); + + gi.Printf( "\n" ); + + if ( actorthread ) + { + gi.Printf( "Thread : %s(%d)\n", actorthread->Filename(), actorthread->CurrentLine() ); + } + else + { + gi.Printf( "Thread : NULL\n" ); + } + + gi.Printf( "Actortype : %d\n", actortype ); + + gi.Printf( "Model : %s\n", model.c_str() ); + gi.Printf( "Anim : %s\n", animname.c_str() ); + gi.Printf( "Movespeed : %.2f\n", movespeed ); + gi.Printf( "Health : %f\n", health ); + + gi.Printf( "\ncurrentEnemy: " ); + if ( currentEnemy ) + { + gi.Printf( "%d : '%s'\n", currentEnemy->entnum, currentEnemy->targetname.c_str() ); + } + else + { + gi.Printf( "None\n" ); + } + + gi.Printf( "actortype: %d\n", actortype ); + + switch( deadflag ) + { + case DEAD_NO : + gi.Printf( "deadflag: NO\n" ); + break; + case DEAD_DYING : + gi.Printf( "deadflag: DYING\n" ); + break; + case DEAD_DEAD : + gi.Printf( "deadflag: DEAD\n" ); + break; + case DEAD_RESPAWNABLE : + gi.Printf( "deadflag: RESPAWNABLE\n" ); + break; + + } + + gi.Printf( "\n" ); + if ( behavior ) + { + gi.Printf( "Behavior Info:\n" ); + gi.Printf( "Game time: %f\n", level.time ); + behavior->ShowInfo( *this ); + gi.Printf( "\n" ); + } + } + +//*********************************************************************************************** +// +// Stimuli functions +// +//*********************************************************************************************** + +void Actor::TurnAIOn + ( + Event *ev + ) + { + SetActorFlag( ACTOR_FLAG_AI_ON, true ); + stimuli = STIMULI_ALL; + } + +void Actor::TurnAIOff + ( + Event *ev + ) + { + SetActorFlag( ACTOR_FLAG_AI_ON, false ); + stimuli = STIMULI_NONE; + + if ( mode == ACTOR_MODE_AI ) + { + // Ai is currently on, get out of AI mode + gi.DPrintf( "Forcing an actor (#%d, %s) out of AI mode, this can be dangerous.\n", entnum, name.c_str() ); + EndMode(); + } + } + +void Actor::Deaf + ( + Event *ev + ) + { + stimuli &= ~STIMULI_SOUND; + } + +void Actor::PermanentDeaf + ( + Event *ev + ) + { + permanent_stimuli &= ~STIMULI_SOUND; + } +void Actor::PermanentBlind + ( + Event *ev + ) + { + permanent_stimuli &= ~STIMULI_SIGHT; + } +qboolean Actor::IsBlind + ( + void + ) + { + return ( !( permanent_stimuli & STIMULI_SIGHT ) || !( stimuli & STIMULI_SIGHT ) ); + } + +void Actor::Dumb + ( + Event *ev + ) + { + stimuli &= ~STIMULI_SOUND; + stimuli &= ~STIMULI_SIGHT; + } + +bool Actor::RespondToStimuli( int new_stimuli ) + { + return ( (( new_stimuli & stimuli ) && ( new_stimuli & permanent_stimuli )) || ( new_stimuli == STIMULI_SCRIPT ) ); + } + +void Actor::Stimuli( int new_stimuli, Entity *ent, qboolean force ) + { + if ( RespondToStimuli( new_stimuli ) ) + { + MakeEnemy( ent, force ); + Wakeup(); + ActivateAI(); + } + } + +void Actor::Stimuli( int new_stimuli, Vector pos ) + { + if ( RespondToStimuli( new_stimuli ) ) + { + // Investigate the position + + if ( !GetActorFlag( ACTOR_FLAG_NOISE_HEARD ) ) + { + noise_position = pos; + SetActorFlag( ACTOR_FLAG_NOISE_HEARD, true ); + noise_time = level.time; + } + + Wakeup(); + ActivateAI(); + } + } + +void Actor::StimuliNoAttack( int new_stimuli ) + { + if ( RespondToStimuli( new_stimuli ) ) + { + Wakeup(); + ActivateAI(); + } + } + +void Actor::ActivateAI( void ) + { + if ( !statemap ) + return; + + StartMode( ACTOR_MODE_AI ); + + stimuli = STIMULI_ALL; + + last_time_active = level.time; + + if ( actorthread ) + { + actorthread->ProcessEvent( EV_ScriptThread_End ); + actorthread = NULL; + } + } + +void Actor::SetIdleThread( Event *ev ) + { + idle_thread = ev->GetString( 1 ); + } + +//*********************************************************************************************** +// +// Targeting functions +// +//*********************************************************************************************** + +void AI_TargetPlayer + ( + void + ) + + { + int i; + int n; + Entity *player; + Actor *ent; + + // don't target while player is not in the game or he's in notarget + player = g_entities[ 0 ].entity; + if ( !player || ( player->flags & FL_NOTARGET ) ) + { + return; + } + + // process the list in reverse order in case SleepList is changed + n = SleepList.NumObjects(); + for( i = n; i > 0; i-- ) + { + ent = SleepList.ObjectAt( i ); + + if ( gi.inPVS( player->centroid, ent->centroid ) ) + { + if ( !ent->currentEnemy && ent->Hates( player ) && !ent->IsBlind() && ent->CanReallySee( player ) ) + { + ent->Stimuli( STIMULI_SIGHT, player ); + } + else + { + if ( world->farplane_distance == 0 || Distance( player->centroid, ent->centroid ) < world->farplane_distance ) + ent->Wakeup(); + } + } + } + } + +//*********************************************************************************************** +// +// Actor checks +// +//*********************************************************************************************** + + +qboolean Actor::checkanimname + ( + Conditional &condition + ) + + { + str anim_name_test; + int use_length; + int result; + + anim_name_test = condition.getParm( 1 ); + + if ( condition.numParms() > 1 ) + use_length = atoi( condition.getParm( 2 ) ); + else + use_length = false; + + if ( use_length ) + result = strncmp( animname.c_str(), anim_name_test.c_str(), anim_name_test.length() ); + else + result = strcmp( animname.c_str(), anim_name_test.c_str() ); + + return (result == 0); + } + +qboolean Actor::checkinactive + ( + Conditional &condition + ) + + { + return GetActorFlag( ACTOR_FLAG_INACTIVE ); + } + +qboolean Actor::checkanimdone + ( + Conditional &condition + ) + + { + return GetActorFlag( ACTOR_FLAG_ANIM_DONE ); + } + +qboolean Actor::checkdead + ( + Conditional &condition + ) + + { + return deadflag != 0; + } + +qboolean Actor::checkhaveenemy + ( + Conditional &condition + ) + + { + return IsEntityAlive( currentEnemy ); + } + +qboolean Actor::checkenemydead + ( + Conditional &condition + ) + + { + if ( currentEnemy && ( currentEnemy->deadflag || currentEnemy->health <= 0 ) ) + return true; + + return false; + } + +qboolean Actor::checkenemynoclip + ( + Conditional &condition + ) + + { + if ( currentEnemy && currentEnemy->movetype == MOVETYPE_NOCLIP ) + return true; + + return false; + } + +qboolean Actor::checkcanseeenemy + ( + Conditional &condition + ) + + { + qboolean use_fov = true; + qboolean can_see; + qboolean in_fov; + qboolean real_can_see; + + + if ( condition.numParms() > 0 ) + use_fov = atoi( condition.getParm( 1 ) ); + + // See if we should check again + + if ( canseeenemy_time > level.time ) + { + if ( use_fov ) + return GetActorFlag( ACTOR_FLAG_LAST_CANSEEENEMY ); + else + return GetActorFlag( ACTOR_FLAG_LAST_CANSEEENEMY_NOFOV ); + } + + can_see = true; + in_fov = true; + + // Check to see if we can see enemy + + if ( !IsEntityAlive( currentEnemy ) ) + { + can_see = false; + in_fov = false; + } + + if ( can_see && !WithinVisionDistance( currentEnemy ) ) + can_see = false; + + if ( can_see && !CanSeeFrom( origin, currentEnemy ) ) + can_see = false; + + if ( in_fov && !InFOV( currentEnemy ) ) + in_fov = false; + + // Save can see info + + SetActorFlag( ACTOR_FLAG_LAST_CANSEEENEMY, can_see && in_fov ); + SetActorFlag( ACTOR_FLAG_LAST_CANSEEENEMY_NOFOV, can_see ); + + canseeenemy_time = level.time + 0.2f + G_Random( 0.1f ); + + if ( use_fov ) + real_can_see = GetActorFlag( ACTOR_FLAG_LAST_CANSEEENEMY ); + else + real_can_see = GetActorFlag( ACTOR_FLAG_LAST_CANSEEENEMY_NOFOV ); + + // Save the last known position of our enemy + + if ( real_can_see ) + last_known_enemy_pos = currentEnemy->origin; + + return real_can_see; + } + +qboolean Actor::checkcanshootenemy + ( + Conditional &condition + ) + + { + str tag_name; + + if ( !currentEnemy ) + return false; + + if ( condition.numParms() > 1 ) + tag_name = condition.getParm( 2 ); + + return ( checkcanseeenemy( condition ) && TestAttack( tag_name ) ); + } + +qboolean Actor::checkenemyinfov + ( + Conditional &condition + ) + { + float check_fov; + float check_fovdot; + + + if ( !currentEnemy ) + return false; + + if ( condition.numParms() > 0 ) + { + check_fov = atof( condition.getParm( 1 ) ); + check_fovdot = cos( check_fov * 0.5 * M_PI / 180.0 ); + + return InFOV( currentEnemy->centroid, check_fov, check_fovdot ); + } + else + { + return InFOV( currentEnemy ); + } + } + +qboolean Actor::checkenemyonground + ( + Conditional &condition + ) + { + if ( !currentEnemy ) + return false; + + if ( currentEnemy->groundentity ) + return true; + else + return false; + } + +qboolean Actor::checkenemyrelativeyaw + ( + Conditional &condition + ) + + { + Vector dir; + Vector dir_angles; + float relative_yaw; + float check_yaw; + Vector temp_angles; + + if ( !currentEnemy ) + return false; + + check_yaw = atof( condition.getParm( 1 ) ); + + dir = origin - currentEnemy->origin; + + dir_angles = dir.toAngles(); + + temp_angles = currentEnemy->angles; + + relative_yaw = AngleNormalize180( currentEnemy->angles[YAW] - dir_angles[YAW] ); + + if ( relative_yaw < check_yaw ) + return true; + else + return false; + } + +qboolean Actor::checkcanjumptoenemy + ( + Conditional &condition + ) + + { + return ( currentEnemy && CanWalkTo( currentEnemy->origin, currentEnemy->entnum ) ); + } + +qboolean Actor::checkcanflytoenemy + ( + Conditional &condition + ) + + { + trace_t trace; + + if ( !currentEnemy ) + return false; + + trace = G_Trace( origin, mins, maxs, currentEnemy->centroid, this, edict->clipmask, false, "Actor::checkcanflytoenemy" ); + + if ( trace.startsolid || trace.allsolid ) + return false; + + if ( trace.entityNum == currentEnemy->entnum ) + return true; + + return false; + } + +qboolean Actor::checkinpain + ( + Conditional &condition + ) + + { + return ( state_flags & STATE_FLAG_IN_PAIN ); + } + +qboolean Actor::checksmallpain + ( + Conditional &condition + ) + + { + return ( state_flags & STATE_FLAG_SMALL_PAIN ); + } + +qboolean Actor::checkpainyaw + ( + Conditional &condition + ) + + { + float check_yaw; + + check_yaw = atof( condition.getParm( 1 ) ); + + if ( pain_angles[YAW] <= check_yaw ) + return true; + else + return false; + } + +qboolean Actor::checkpainpitch + ( + Conditional &condition + ) + + { + float check_pitch; + + check_pitch = atof( condition.getParm( 1 ) ); + + if ( pain_angles[PITCH] <= check_pitch ) + return true; + else + return false; + } + +qboolean Actor::checkstunned + ( + Conditional &condition + ) + + { + return GetActorFlag( ACTOR_FLAG_STUNNED ); + } + +qboolean Actor::checkfinished + ( + Conditional &condition + ) + + { + return GetActorFlag( ACTOR_FLAG_FINISHED ); + } + +qboolean Actor::checkmeleehit + ( + Conditional &condition + ) + + { + return ( state_flags & STATE_FLAG_MELEE_HIT ); + } + +qboolean Actor::checkblockedhit + ( + Conditional &condition + ) + + { + return ( state_flags & STATE_FLAG_BLOCKED_HIT ); + } + +qboolean Actor::checkblocked + ( + Conditional &condition + ) + + { + if ( attack_blocked && attack_blocked_time + .75 > level.time ) + return true; + else + return false; + } + +qboolean Actor::checkonfire + ( + Conditional &condition + ) + + { + return on_fire; + } + +qboolean Actor::checkotherdied + ( + Conditional &condition + ) + + { + return ( state_flags & STATE_FLAG_OTHER_DIED ); + } + +qboolean Actor::checkstuck + ( + Conditional &condition + ) + + { + return ( state_flags & STATE_FLAG_STUCK ); + } + +qboolean Actor::checknopath + ( + Conditional &condition + ) + + { + return ( state_flags & STATE_FLAG_NO_PATH ); + } + +qboolean Actor::checkbehaviordone + ( + Conditional &condition + ) + + { + return ( behavior == NULL ); + } + +qboolean Actor::checktimedone + ( + Conditional &condition + ) + + { + if ( GetActorFlag( ACTOR_FLAG_STATE_DONE_TIME_VALID ) ) + { + return ( state_done_time < level.time ); + } + + return false; + } + +qboolean Actor::checkdone + ( + Conditional &condition + ) + + { + return ( checkbehaviordone( condition ) || checktimedone( condition ) ); + } + +qboolean Actor::checkenemyrange + ( + Conditional &condition + ) + + { + float range; + float min_height; + float max_height; + + range = atof( condition.getParm( 1 ) ); + + if ( condition.numParms() > 1 ) + max_height = atof( condition.getParm( 2 ) ); + else + max_height = 0; + + if ( condition.numParms() > 2 ) + min_height = atof( condition.getParm( 3 ) ); + else + min_height = -max_height; + + return EntityInRange( currentEnemy, range, min_height, max_height ); + } + +qboolean Actor::checkplayerrange + ( + Conditional &condition + ) + + { + float range; + float height; + Entity *player; + + range = atof( condition.getParm( 1 ) ); + + if ( condition.numParms() == 2 ) + height = atof( condition.getParm( 2 ) ); + else + height = 0; + + player = g_entities[ 0 ].entity; + + return EntityInRange( player, range, -height, height ); + } + +qboolean Actor::checkmovingactorrange + ( + Conditional &condition + ) + + { + float range; + float height = 0; + float height_diff; + Entity *ent_in_range; + int i; + Vector delta; + float r2; + gentity_t *ed; + float smallest_dist2; + float dist2; + + + // Get distances + range = atof( condition.getParm( 1 ) ); + + if ( condition.numParms() == 2 ) + { + height = atof( condition.getParm( 2 ) ); + } + + r2 = range * range; + + if ( actorrange_time > level.time && height == last_height ) + { + ent_in_range = last_ent; + + if ( IsEntityAlive( ent_in_range ) ) + { + delta = origin - ent_in_range->centroid; + + if ( height ) + { + height_diff = delta[ 2 ]; + delta[ 2 ] = 0; + + if ( ( height_diff < -height ) || ( height_diff > height ) ) + return false; + } + + // dot product returns length squared + if ( ( ( delta * delta ) <= r2 ) && CanSee( ent_in_range ) ) + return true; + } + + return false; + } + + actorrange_time = level.time + 0.2f + G_Random( 0.1f ); + + last_height = height; + last_ent = NULL; + + smallest_dist2 = 99999999; + + // See if any clients are in range + for( i = 0 ; i < game.maxclients; i++ ) + { + ed = &g_entities[ i ]; + + if ( !ed->inuse || !ed->entity ) + { + continue; + } + + ent_in_range = ed->entity; + + if ( IsEntityAlive( ent_in_range ) ) + { + delta = origin - ent_in_range->centroid; + + if ( height > 0 ) + { + height_diff = delta[ 2 ]; + + if ( ( height_diff < -height ) || ( height_diff > height ) ) + { + continue; + } + + delta[ 2 ] = 0; + } + + // dot product returns length squared + + dist2 = delta * delta; + + if ( ( dist2 <= r2 ) && CanSee( ent_in_range ) ) + { + if ( dist2 < smallest_dist2 ) + { + smallest_dist2 = dist2; + last_ent = ent_in_range; + } + } + } + } + + // See if any actors are in range + for( i = 1; i <= ActiveList.NumObjects(); i++ ) + { + ent_in_range = ActiveList.ObjectAt( i ); + + if ( + ( ent_in_range->movetype != MOVETYPE_NONE ) && + ( ent_in_range->movetype != MOVETYPE_STATIONARY ) && + ( this != ent_in_range ) && + ( ent_in_range->health > 0 ) && + !( ent_in_range->flags & FL_NOTARGET ) + ) + { + delta = origin - ent_in_range->centroid; + + if ( height > 0 ) + { + height_diff = delta[ 2 ]; + + if ( ( height_diff < -height ) || ( height_diff > height ) ) + { + continue; + } + + delta[ 2 ] = 0; + } + + // dot product returns length squared + + dist2 = delta * delta; + + if ( ( dist2 <= r2 ) && CanSee( ent_in_range ) ) + { + if ( dist2 < smallest_dist2 ) + { + smallest_dist2 = dist2; + last_ent = ent_in_range; + } + } + } + } + + if ( last_ent ) + return true; + + return false; + } + +qboolean Actor::checkchance + ( + Conditional &condition + ) + + { + float percent_chance; + + percent_chance = atof( condition.getParm( 1 ) ); + + return ( G_Random() < percent_chance ); + } + +qboolean Actor::checkstatetime + ( + Conditional &condition + ) + + { + float time_to_wait; + + time_to_wait = atof( condition.getParm( 1 ) ); + + return ( state_time + time_to_wait < level.time ); + } + +qboolean Actor::checktimesdone + ( + Conditional &condition + ) + + { + return ( times_done == atoi( condition.getParm( 1 ) ) ); + } + +qboolean Actor::checkmeansofdeath + ( + Conditional &condition + ) + + { + int mod; + + mod = MOD_string_to_int( condition.getParm( 1 ) ); + + return ( mod == means_of_death ); + } + +qboolean Actor::checknoiseheard + ( + Conditional &condition + ) + + { + return GetActorFlag( ACTOR_FLAG_NOISE_HEARD ); + } + +qboolean Actor::checkpartstate + ( + Conditional &condition + ) + + { + str part_name; + str state_name; + Actor *part; + + part_name = condition.getParm( 1 ); + state_name = condition.getParm( 2 ); + + part = FindPartActor( part_name ); + + return ( part && strnicmp( part->currentState->getName(), state_name.c_str(), strlen( state_name.c_str() ) ) == 0 ); + } + +qboolean Actor::checkpartflag + ( + Conditional &condition + ) + + { + str part_name; + str flag_name; + unsigned int flag; + int current_part; + part_t *part; + Entity *partent; + Actor *partact; + + part_name = condition.getParm( 1 ); + flag_name = condition.getParm( 2 ); + + if ( stricmp( flag_name, "pain" ) == 0 ) + { + flag = STATE_FLAG_IN_PAIN; + } + else if ( stricmp( flag_name, "small_pain" ) == 0 ) + { + flag = STATE_FLAG_SMALL_PAIN; + } + else if ( stricmp( flag_name, "melee_hit" ) == 0 ) + { + flag = STATE_FLAG_MELEE_HIT; + } + else if ( stricmp( flag_name, "touched" ) == 0 ) + { + flag = STATE_FLAG_TOUCHED; + } + else if ( stricmp( flag_name, "activated" ) == 0 ) + { + flag = STATE_FLAG_ACTIVATED; + } + else if ( stricmp( flag_name, "used" ) == 0 ) + { + flag = STATE_FLAG_USED; + } + else if ( stricmp( flag_name, "twitch" ) == 0 ) + { + flag = STATE_FLAG_TWITCH; + } + else + { + gi.DPrintf( "Unknown flag name (%s) in checkpartflag.", flag_name.c_str() ); + flag = 0; + } + + for( current_part = 1; current_part <= parts.NumObjects(); current_part++ ) + { + part = &parts.ObjectAt( current_part ); + + partent = part->ent; + partact = (Actor *)partent; + + if ( partact && partact->part_name == part_name ) + { + if ( part->state_flags & flag ) + { + return true; + } + } + } + + return false; + } + +qboolean Actor::checkpartdead + ( + Conditional &condition + ) + + { + str part_name; + str state_name; + Actor *part; + + part_name = condition.getParm( 1 ); + + part = FindPartActor( part_name ); + + if ( !part ) + return false; + + return ( part->deadflag || part->health <= 0 ); + } + +qboolean Actor::checknumspawns + ( + Conditional &condition + ) + + { + int check_num; + + check_num = atoi( condition.getParm( 1 ) ); + + return ( num_of_spawns < check_num ); + } + +qboolean Actor::checkcommand + ( + Conditional &condition + ) + + { + return ( command == condition.getParm( 1 ) ); + } + +qboolean Actor::checktouched + ( + Conditional &condition + ) + + { + return state_flags & STATE_FLAG_TOUCHED; + } + +qboolean Actor::checkactivated + ( + Conditional &condition + ) + + { + return state_flags & STATE_FLAG_ACTIVATED; + } + +qboolean Actor::checkused + ( + Conditional &condition + ) + + { + return ( state_flags & STATE_FLAG_USED ); + } + +qboolean Actor::checktwitch + ( + Conditional &condition + ) + + { + return ( state_flags & STATE_FLAG_TWITCH ); + } + +qboolean Actor::checkhealth + ( + Conditional &condition + ) + + { + return health < atof( condition.getParm( 1 ) ); + } + +qboolean Actor::checkonground + ( + Conditional &condition + ) + + { + return groundentity != NULL; + } + +qboolean Actor::checkinwater + ( + Conditional &condition + ) + + { + return (waterlevel > 0 ); + } + +qboolean Actor::checkincomingmeleeattack + ( + Conditional &condition + ) + + { + Entity *enemy_ent; + Sentient *enemy; + trace_t trace; + Vector forward; + Vector end_pos; + + if ( IsEntityAlive( currentEnemy ) ) + { + if ( currentEnemy->isSubclassOf( Sentient ) ) + { + enemy_ent = ( Entity * )currentEnemy; + enemy = ( Sentient * )enemy_ent; + + if ( enemy->in_melee_attack ) + { + enemy->angles.AngleVectors( &forward ); + end_pos = forward * 125 + enemy->centroid; + trace = G_Trace( enemy->centroid, vec_zero, vec_zero, end_pos, enemy, MASK_SHOT, false, "Actor::checkincomingmeleeattack" ); + + if ( trace.entityNum == entnum ) + { + return true; + } + } + } + } + + return false; + } + +qboolean Actor::checkincomingprojectile + ( + Conditional &condition + ) + + { + trace_t trace; + Vector forward; + Vector end_pos; + float time = 0; + float time_left; + Vector dir; + float dist; + + if ( condition.numParms() == 1 ) + { + time = atof( condition.getParm( 1 ) ); + } + + if ( incoming_proj && incoming_time <= level.time ) + { + incoming_proj->angles.AngleVectors( &forward ); + end_pos = forward * 1000 + incoming_proj->centroid; + trace = G_Trace( incoming_proj->centroid, vec_zero, vec_zero, end_pos, incoming_proj, MASK_SHOT, false, "Actor::checkincomingprojectile" ); + + if ( trace.entityNum == entnum ) + { + if ( time ) + { + dir = trace.endpos - incoming_proj->centroid; + dist = dir.length(); + time_left = dist / incoming_proj->velocity.length(); + + return ( time_left <= time ); + } + + return true; + } + } + + return false; + } + +qboolean Actor::checkenemystunned + ( + Conditional &condition + ) + + { + Sentient *enemy; + + + if ( IsEntityAlive( currentEnemy ) ) + { + if ( currentEnemy->isSubclassOf( Sentient ) ) + { + enemy = (Sentient *)(Entity *)currentEnemy; + + if ( enemy->in_stun ) + return true; + } + } + + return false; + } + +qboolean Actor::checkenemyinpath + ( + Conditional &condition + ) + + { + trace_t trace; + Vector end_pos; + + if ( IsEntityAlive( currentEnemy ) ) + { + Vector forward( orientation[ 0 ] ); + + forward *= 1000; + end_pos = origin + forward; + + trace = G_Trace( centroid, vec_zero, vec_zero, end_pos, this, MASK_SHOT, false, "Actor::checkenemyinpath" ); + + if ( trace.entityNum == currentEnemy->entnum ) + { + return true; + } + } + + return false; + } + +qboolean Actor::checkstage + ( + Conditional &condition + ) + + { + return ( stage == atoi( condition.getParm( 1 ) ) ); + } + +qboolean Actor::checkheld + ( + Conditional &condition + ) + + { + return ( edict->s.parent != ENTITYNUM_NONE ); + } + +qboolean Actor::checkenemymelee + ( + Conditional &condition + ) + + { + return ( EntityHasFireType( currentEnemy, FT_MELEE ) ); + } + +qboolean Actor::checkenemyranged + ( + Conditional &condition + ) + + { + return ( EntityHasFireType( currentEnemy, FT_BULLET ) || EntityHasFireType( currentEnemy, FT_PROJECTILE ) ); + } + +qboolean Actor::checkenemyshield + ( + Conditional &condition + ) + + { + if ( !currentEnemy ) + return false; + + if ( currentEnemy->isSubclassOf( Player ) ) + { + qboolean care_about_using_shield; + Weapon *weap; + Player *player; + + player = ( Player * )( Entity * )currentEnemy; + + // See if we care if the enemy is currently using a shield + + if ( condition.numParms() > 0 ) + care_about_using_shield = atoi( condition.getParm( 1 ) ); + else + care_about_using_shield = false; + + // See if they have a shield + + weap = player->GetActiveWeapon( WEAPON_LEFT ); + + if ( !weap || !weap->isSubclassOf( Shield ) ) + return false; + + // See if the enemy is using the shield right now (if we care) + + if ( !care_about_using_shield || player->ShieldActive() ) + return true; + } + else if ( currentEnemy->isSubclassOf( Sentient ) ) + { + Sentient *sent = ( Sentient * )( Entity * )currentEnemy; + + // If just a sentient, just return if they are currently blocking + + return sent->in_block; + } + + return false; + } + +qboolean Actor::checkhasthing + ( + Conditional &condition + ) + + { + int thing_number; + int i; + + + for( i = 1 ; i <= condition.numParms() ; i++ ) + { + thing_number = atoi( condition.getParm( i ) ); + + switch( thing_number ) + { + case 1 : + if ( GetActorFlag( ACTOR_FLAG_HAS_THING1 ) ) + return true; + break; + case 2 : + if ( GetActorFlag( ACTOR_FLAG_HAS_THING2 ) ) + return true; + break; + case 3 : + if ( GetActorFlag( ACTOR_FLAG_HAS_THING3 ) ) + return true; + break; + case 4 : + if ( GetActorFlag( ACTOR_FLAG_HAS_THING4 ) ) + return true; + break; + } + } + + return false; + } + +qboolean Actor::checkallowhangback + ( + Conditional &condition + ) + + { + return GetActorFlag( ACTOR_FLAG_ALLOW_HANGBACK ); + } + +qboolean Actor::checkname + ( + Conditional &condition + ) + + { + return ( name == condition.getParm( 1 ) ); + } + +qboolean Actor::returntrue + ( + Conditional &condition + ) + + { + return true; + } + +Condition Actor::Conditions[] = + { + { "default", returntrue }, + { "INACTIVE", checkinactive }, + { "ANIM_DONE", checkanimdone }, + { "DEAD", checkdead }, + + { "HAVE_ENEMY", checkhaveenemy }, + { "ENEMY_DEAD", checkenemydead }, + { "ENEMY_NOCLIP", checkenemynoclip }, + { "CAN_SEE_ENEMY", checkcanseeenemy }, + { "CAN_SHOOT_ENEMY", checkcanshootenemy }, + { "ENEMY_IN_FOV", checkenemyinfov }, + { "ENEMY_RELATIVE_YAW", checkenemyrelativeyaw }, + { "ENEMY_IN_FOV", checkenemyinfov }, + { "ENEMY_ON_GROUND", checkenemyonground }, + + + { "CAN_JUMP_TO_ENEMY", checkcanjumptoenemy }, + { "CAN_FLY_TO_ENEMY", checkcanflytoenemy }, + + { "PAIN", checkinpain }, + { "SMALL_PAIN", checksmallpain }, + { "PAIN_YAW", checkpainyaw }, + { "PAIN_PITCH", checkpainpitch }, + + { "STUNNED", checkstunned }, + { "FINISHED", checkfinished }, + + { "MELEE_HIT", checkmeleehit }, + { "BLOCKED_HIT", checkblockedhit }, + { "BLOCKED", checkblocked }, + { "OTHER_DIED", checkotherdied }, + { "STUCK", checkstuck }, + { "NO_PATH", checknopath }, + + { "ON_FIRE", checkonfire }, + + { "BEHAVIOR_DONE", checkbehaviordone }, + { "TIME_DONE", checktimedone }, + { "DONE", checkdone }, + + { "RANGE", checkenemyrange }, + { "PLAYER_RANGE", checkplayerrange }, + { "CHANCE", checkchance }, + { "MOVING_ACTOR_RANGE", checkmovingactorrange }, + { "STATE_TIME", checkstatetime }, + { "TIMES_DONE", checktimesdone }, + + { "MOD", checkmeansofdeath }, + + { "NOISE_HEARD", checknoiseheard }, + + { "PART_STATE", checkpartstate }, + { "PART_DEAD", checkpartdead }, + { "PART_FLAG", checkpartflag }, + + { "NUM_SPAWNS", checknumspawns }, + + { "COMMAND", checkcommand }, + + { "TOUCHED", checktouched }, + + { "ACTIVATED", checkactivated }, + { "USED", checkused }, + { "TWITCH", checktwitch }, + + { "HEALTH", checkhealth }, + + { "ON_GROUND", checkonground }, + { "IN_WATER", checkinwater }, + + { "INCOMING_MELEE_ATTACK", checkincomingmeleeattack }, + { "INCOMING_PROJECTILE", checkincomingprojectile }, + + { "ENEMY_STUNNED", checkenemystunned }, + + { "ENEMY_IN_PATH", checkenemyinpath }, + + { "STAGE", checkstage }, + + { "HELD", checkheld }, + + { "ENEMY_HAS_MELEE", checkenemymelee }, + { "ENEMY_HAS_RANGED", checkenemyranged }, + { "ENEMY_HAS_SHIELD", checkenemyshield }, + + { "HAS_THING", checkhasthing }, + + { "ALLOW_HANGBACK", checkallowhangback }, + + { "NAME", checkname }, + { "ANIM_NAME", checkanimname }, + + { NULL, NULL }, + }; + +//*********************************************************************************************** +// +// Actor subclasses +// +//*********************************************************************************************** + +Event EV_SpinningPlant_GetClip + ( + "get_clip", + EV_DEFAULT, + NULL, + NULL, + "Gets the clip brush for the spinning plant actor," + "it is not meant to be called from script." + ); + +CLASS_DECLARATION( Actor, SpinningPlant, NULL ) + { + { &EV_SpinningPlant_GetClip, GetClip }, + { NULL, NULL } + }; + +SpinningPlant::SpinningPlant + ( + ) + + { + spinner_model = NULL; + spinner_clip = NULL; + + PostEvent( EV_SpinningPlant_GetClip, 0 ); + } + +void SpinningPlant::GetClip + ( + Event *ev + ) + { + Entity * ent; + + spinner_model = new Mover; + spinner_model->setModel( model ); + spinner_model->setSolidType( SOLID_NOT ); + spinner_model->setOrigin( origin ); + + hideModel(); + setSolidType( SOLID_NOT ); + + if ( target.length() > 0 ) + { + ent = G_FindTarget( this, target.c_str() ); + + if ( ent ) + { + spinner_clip = (Mover *)ent; + } + } + + if ( spinner_clip ) + { + spinner_clip->hideModel(); + spinner_model->bind( spinner_clip ); + } + } + +SpinningPlant::~SpinningPlant() + { + if ( spinner_model ) + { + spinner_model->PostEvent( EV_Remove, 0 ); + spinner_model = NULL; + } + } + +//*********************************************************************************************** +// +// Code for seperate parts +// +//*********************************************************************************************** + +void Actor::RegisterParts + ( + Event *ev + ) + { + Entity *targetent; + qboolean forward; + int current_part; + part_t *forward_part; + part_t new_part; + Event *event; + + targetent = ev->GetEntity( 1 ); + forward = ev->GetInteger( 2 ); + + if ( !targetent ) + return; + + // See if we should tell other parts about each other + + if ( forward ) + { + // Tell all old parts about this new part and tell the new part about all of the old ones + + for ( current_part = 1 ; current_part <= parts.NumObjects() ; current_part++ ) + { + forward_part = &parts.ObjectAt( current_part ); + + if ( forward_part ) + { + // Tell old part about new part + + event = new Event( EV_ActorRegisterParts ); + event->AddEntity( targetent ); + event->AddInteger( false ); + forward_part->ent->PostEvent( event, 0 ); + + // Tell new part about old part + + event = new Event( EV_ActorRegisterParts ); + event->AddEntity( forward_part->ent ); + event->AddInteger( false ); + targetent->PostEvent( event, 0 ); + } + } + } + + // Add this part to our part list + + new_part.ent = targetent; + new_part.state_flags = 0; + + parts.AddObject( new_part ); + } + +void Actor::PartName + ( + Event *ev + ) + { + part_name = ev->GetString( 1 ); + } + +void Actor::RegisterSelf + ( + Event *ev + ) + { + Entity *targetent; + Actor *targetact; + Event *event; + part_t new_part; + + if ( target.length() > 0 ) + { + // Get the target entity + + targetent = G_FindTarget( this, target.c_str() ); + + if ( !targetent ) + return; + + // See if this target entity is a another part of ourselves + + if ( targetent->isSubclassOf( Actor ) ) + { + targetact = (Actor *)targetent; + + if ( name.length() > 0 && targetact->name == name ) + { + // Tell other part about ourselves + + event = new Event( EV_ActorRegisterParts ); + event->AddEntity( this ); + event->AddInteger( true ); + targetent->PostEvent( event, 0 ); + + // Add this part to our part list + + new_part.ent = targetent; + new_part.state_flags = 0; + parts.AddObject( new_part ); + } + } + } + } + +Actor *Actor::FindPartActor( const char *name ) + { + int current_part; + part_t *part; + Entity *partent; + Actor *partact; + + for ( current_part = 1 ; current_part <= parts.NumObjects() ; current_part++ ) + { + part = &parts.ObjectAt( current_part ); + + partent = part->ent; + partact = (Actor *)partent; + + if ( partact && partact->part_name == name ) + return partact; + } + + return NULL; + } + +void Actor::SendCommand + ( + Event *ev + ) + + { + str command; + str part_to_send_to; + int i; + part_t *part; + Actor *partact; + + command = ev->GetString( 1 ); + part_to_send_to = ev->GetString( 2 ); + + if ( command.length() == 0 || part_to_send_to.length() == 0 ) + return; + + for( i = 1 ; i <= parts.NumObjects(); i++ ) + { + part = &parts.ObjectAt( i ); + + partact = ( Actor * )(Entity *)part->ent; + + if ( partact && partact->part_name == part_to_send_to ) + { + partact->command = command; + } + } + } + +//*********************************************************************************************** +// +// Dialog functions +// +//*********************************************************************************************** + +void Actor::AddDialog + ( + Event *ev + ) + + { + DialogNode_t *dialog_node; + + dialog_node = NewDialogNode(); + + if (dialog_node != NULL) + { + // Add the alias name to the dialog + strcpy(dialog_node->alias_name, ev->GetString( 1 )); + + // Add all the other parameters to the dialog + AddDialogParms( dialog_node, ev ); + + // Add the new dialog to this dialog list + dialog_node->next = dialog_list; + dialog_list = dialog_node; + } + } + +DialogNode_t *Actor::NewDialogNode + ( + void + ) + + { + DialogNode_t *dialog_node; + + dialog_node = new DialogNode_t; + memset( dialog_node, 0 , sizeof( DialogNode_t ) ); + dialog_node->random_percent = 1.0; + + return dialog_node; + } + +void Actor::AddDialogParms + ( + DialogNode_t *dialog_node, + Event *ev + ) + + { + const char *token; + int parm_type; + float temp_float; + int current_parm; + int num_parms; + + + if ( dialog_node == NULL ) + return; + + current_parm = 2; + num_parms = ev->NumArgs(); + + // Get all of the parameters + + while( 1 ) + { + if ( current_parm > num_parms ) + break; + + token = ev->GetString( current_parm ); + current_parm++; + + parm_type = DIALOG_PARM_TYPE_NONE; + + if (stricmp(token, "randompick") == 0) + dialog_node->random_flag = qtrue; + else if (stricmp(token, "playerhas") == 0) + parm_type = DIALOG_PARM_TYPE_PLAYERHAS; + else if (stricmp(token, "playerhasnot") == 0) + parm_type = DIALOG_PARM_TYPE_PLAYERHASNOT; + else if (stricmp(token, "has") == 0) + parm_type = DIALOG_PARM_TYPE_HAS; + else if (stricmp(token, "has_not") == 0) + parm_type = DIALOG_PARM_TYPE_HASNOT; + else if (stricmp(token, "depends") == 0) + parm_type = DIALOG_PARM_TYPE_DEPENDS; + else if (stricmp(token, "dependsnot") == 0) + parm_type = DIALOG_PARM_TYPE_DEPENDSNOT; + else if (stricmp(token, "random") == 0) + { + if ( current_parm > num_parms ) + break; + + token = ev->GetString( current_parm ); + current_parm++; + + temp_float = atof(token); + + if ((temp_float >= 0.0) && (temp_float <= 1.0)) + dialog_node->random_percent = temp_float; + else + gi.DPrintf("Random percent out of range for dialog (alias %s)\n", dialog_node->alias_name); + } + else + gi.DPrintf("Unknown parameter for dialog (alias %s)\n", dialog_node->alias_name); + + if (parm_type != DIALOG_PARM_TYPE_NONE) + { + if ( current_parm > num_parms ) + break; + + token = ev->GetString( current_parm ); + current_parm++; + + if (dialog_node->number_of_parms < MAX_DIALOG_PARMS) + { + strcpy(dialog_node->parms[dialog_node->number_of_parms].parm, token); + dialog_node->parms[dialog_node->number_of_parms].type = parm_type; + dialog_node->number_of_parms++; + } + else + { + gi.DPrintf("Too many parms for dialog (alias %s)\n", dialog_node->alias_name); + } + } + } + } + +void Actor::PlayDialog + ( + Event *ev + ) + { + Sentient *user = NULL; + const char *dialog_name = NULL; + const char *state_name = NULL; + float volume = DEFAULT_VOL; + float min_dist = DEFAULT_MIN_DIST; + + if (ev->NumArgs() > 0) + { + dialog_name = ev->GetString( 1 ); + + if ( strcmp( dialog_name, "" ) == 0 ) + dialog_name = NULL; + } + + if ( ev->NumArgs() > 1 ) + volume = ev->GetFloat( 2 ); + + if ( ev->NumArgs() > 2 ) + min_dist = ev->GetFloat( 3 ); + + if ( ev->NumArgs() > 3 ) + { + state_name = ev->GetString( 4 ); + + if ( strcmp( state_name, "" ) == 0 ) + state_name = NULL; + } + + if ( ev->NumArgs() > 4 ) + user = (Sentient *)ev->GetEntity( 5 ); + + // Make sure any playdialog commands from script is full volume + + if ( ev->GetSource() == EV_FROM_SCRIPT ) + min_dist = LEVEL_WIDE_MIN_DIST; + + PlayDialog( user, volume, min_dist, dialog_name, state_name ); + } + +void Actor::PlayDialog + ( + Sentient *user, + float volume, + float min_dist, + const char *dialog_name, + const char *state_name + ) + + { + DialogNode_t *dialog_node; + int good_dialog; + int i; + ScriptVariable *script_var; + + if ( GetActorFlag( ACTOR_FLAG_DIALOG_PLAYING ) ) + return; + + if (dialog_name == NULL) + { + dialog_node = dialog_list; + + while(dialog_node != NULL) + { + // See if we should play the current dialog + + good_dialog = qtrue; + + for(i = 0 ; i < dialog_node->number_of_parms ; i++) + { + // Test to see if this parm passes + + switch(dialog_node->parms[ i ].type) + { + case DIALOG_PARM_TYPE_PLAYERHAS : + if (!user || !user->HasItem(dialog_node->parms[ i ].parm)) + good_dialog = qfalse; + break; + case DIALOG_PARM_TYPE_PLAYERHASNOT : + if (!user || user->HasItem(dialog_node->parms[ i ].parm)) + good_dialog = qfalse; + break; + case DIALOG_PARM_TYPE_HAS : + if (!HasItem(dialog_node->parms[ i ].parm)) + good_dialog = qfalse; + break; + case DIALOG_PARM_TYPE_HASNOT : + if (HasItem(dialog_node->parms[ i ].parm)) + good_dialog = qfalse; + break; + case DIALOG_PARM_TYPE_DEPENDS : + script_var = gameVars.GetVariable( dialog_node->parms[ i ].parm ); + + if ( script_var ) + { + if (!script_var->intValue()) + good_dialog = qfalse; + } + + script_var = levelVars.GetVariable( dialog_node->parms[ i ].parm ); + + if ( script_var ) + { + if (!script_var->intValue()) + good_dialog = qfalse; + } + + break; + case DIALOG_PARM_TYPE_DEPENDSNOT : + script_var = gameVars.GetVariable( dialog_node->parms[ i ].parm ); + + if ( script_var ) + { + if (script_var->intValue()) + good_dialog = qfalse; + } + + script_var = levelVars.GetVariable( dialog_node->parms[ i ].parm ); + + if ( script_var ) + { + if (script_var->intValue()) + good_dialog = qfalse; + } + + break; + } + + // If dialog is already not good go to next dialog + if (!good_dialog) + break; + } + + if ((dialog_node->random_percent < 1.0) && (G_Random() > dialog_node->random_percent)) + { + good_dialog = qfalse; + } + + if (good_dialog) + { + // Found a good dialog now get the real sound name from the alias + + dialog_name = gi.Alias_FindDialog( edict->s.modelindex, dialog_node->alias_name, dialog_node->random_flag, entnum); + + if (dialog_name != NULL) + break; + } + + // Try the next dialog in the list + + dialog_node = dialog_node->next; + } + } + + if (dialog_name != NULL) + { + byte *dialog_amplitudes = NULL; + int number_of_amplitudes = 0; + float dialog_length; + int current_amplitude; + Event *new_event; + float angle; + Vector mouth_angles; + + Sound( dialog_name, CHAN_DIALOG, volume, min_dist ); + SetActorFlag( ACTOR_FLAG_DIALOG_PLAYING, true ); + + dialog_amplitudes = gi.SoundAmplitudes( dialog_name, &number_of_amplitudes ); + dialog_length = gi.SoundLength( dialog_name ); + + dialog_done_time = level.time + dialog_length; + + if (dialog_length > 0) + { + int tag_num; + + if ( state_name != NULL && currentState ) + { + if ( mode == ACTOR_MODE_SCRIPT || mode == ACTOR_MODE_IDLE ) + { + dialog_old_state_name = currentState->getName(); + dialog_state_name = state_name; + + Event *idle_event = new Event( EV_Actor_Idle ); + idle_event->AddString( state_name ); + ProcessEvent( idle_event ); + } + } + + tag_num = gi.Tag_NumForName( edict->s.modelindex, "tag_mouth" ); + + if ( tag_num != -1 ) + { + SetControllerTag( ACTOR_MOUTH_TAG, tag_num ); + + for( current_amplitude = 0 ; current_amplitude < number_of_amplitudes ; current_amplitude++ ) + { + new_event = new Event ( EV_SetControllerAngles ); + + new_event->AddInteger( ACTOR_MOUTH_TAG ); + + angle = ( dialog_amplitudes[current_amplitude] / 256.0 ) * max_mouth_angle; + mouth_angles = vec_zero; + mouth_angles[PITCH] = angle; + + new_event->AddVector( mouth_angles ); + + PostEvent( new_event, current_amplitude * (1.0 / LIP_SYNC_HZ), EVENT_DIALOG_ANIM ); + + if ( current_amplitude % 10 == 0 ) + PostEvent( EV_Actor_HeadTwitch, current_amplitude * (1.0 / LIP_SYNC_HZ), EVENT_DIALOG_ANIM ); + } + } + + PostEvent( EV_Actor_DialogDone, dialog_length ); + + new_event = new Event ( EV_Actor_HeadTwitch ); + new_event->AddInteger( 1 ); + PostEvent( new_event, dialog_length, EVENT_DIALOG_ANIM ); + } + else + { + SetActorFlag( ACTOR_FLAG_DIALOG_PLAYING, false ); + gi.DPrintf( "Lip file not found for dialog %s\n", dialog_name ); + } + } + } + +void Actor::StopDialog + ( + Event *ev + ) + + { + StopSound( CHAN_DIALOG ); + + CancelEventsOfType( EV_SetControllerAngles ); + CancelEventsOfType( EV_Actor_DialogDone ); + CancelEventsOfType( EV_Actor_HeadTwitch ); + CancelEventsOfType( EV_Actor_HeadTwitchEveryFrame ); + + ProcessEvent( EV_Actor_DialogDone ); + } + + +void Actor::HeadTwitch + ( + Event *ev + ) + + { + qboolean end = false; + Vector real_head_angles; + float pitch_change; + float roll_change; + Event *event; + + + if ( ev->NumArgs() > 0 ) + end = ev->GetInteger( 1 ); + + SetControllerTag( ACTOR_HEAD_TAG, gi.Tag_NumForName( edict->s.modelindex, "Bip01 Head" ) ); + + real_head_angles = GetControllerAngles( ACTOR_HEAD_TAG ); + + CancelEventsOfType( EV_Actor_HeadTwitchEveryFrame ); + + if ( end ) + { + // Put head back to normal + + SetControllerTag( ACTOR_HEAD_TAG, gi.Tag_NumForName( edict->s.modelindex, "Bip01 Head" ) ); + + real_head_angles[PITCH] = real_head_pitch; + real_head_angles[ROLL] = 0; + SetControllerAngles( ACTOR_HEAD_TAG, real_head_angles ); + CancelEventsOfType( EV_Actor_HeadTwitch ); + } + else + { + pitch_change = (real_head_pitch + G_CRandom( 6 ) ) - real_head_angles[PITCH]; + roll_change = G_CRandom( 6 ) - real_head_angles[ROLL]; + + event = new Event( EV_Actor_HeadTwitchEveryFrame ); + + event->AddFloat( pitch_change / 10 ); + event->AddFloat( roll_change / 10 ); + + PostEvent( event, FRAMETIME ); + } + } + +void Actor::HeadTwitchEveryFrame + ( + Event *ev + ) + + { + Vector real_head_angles; + float pitch_change; + float roll_change; + + + pitch_change = ev->GetFloat( 1 ); + roll_change = ev->GetFloat( 1 ); + + SetControllerTag( ACTOR_HEAD_TAG, gi.Tag_NumForName( edict->s.modelindex, "Bip01 Head" ) ); + + real_head_angles = GetControllerAngles( ACTOR_HEAD_TAG ); + + if ( GetActorFlag( ACTOR_FLAG_TURNING_HEAD ) ) + { + // Can only change roll + + real_head_angles[ROLL] += roll_change; + SetControllerAngles( ACTOR_HEAD_TAG, real_head_angles ); + } + else + { + real_head_angles[PITCH] += pitch_change; + real_head_angles[ROLL] += roll_change; + SetControllerAngles( ACTOR_HEAD_TAG, real_head_angles ); + } + + PostEvent( *ev, FRAMETIME ); + } + +float Actor::GetDialogRemainingTime + ( + void + ) + + { + if ( GetActorFlag( ACTOR_FLAG_DIALOG_PLAYING ) ) + { + return dialog_done_time - level.time; + } + else + { + return 0; + } + } + +void Actor::FreeDialogList + ( + void + ) + + { + DialogNode_t *dialog_node; + + dialog_node = dialog_list; + + while( dialog_node != NULL ) + { + dialog_list = dialog_node->next; + + delete dialog_node; + + dialog_node = dialog_list; + } + } + +void Actor::DialogDone + ( + Event *ev + ) + + { + SetActorFlag( ACTOR_FLAG_DIALOG_PLAYING, false ); + + if ( dialog_state_name ) + { + dialog_state_name = ""; + + if ( mode != ACTOR_MODE_AI && mode != ACTOR_MODE_TALK ) + { + if ( dialog_old_state_name.length() ) + SetState( dialog_old_state_name.c_str() ); + } + } + } + +void Actor::SetMouthAngle + ( + Event *ev + ) + + { + int tag_num; + float angle_percent; + Vector mouth_angles; + + + angle_percent = ev->GetFloat( 1 ); + + if ( angle_percent < 0 ) + angle_percent = 0; + + if ( angle_percent > 1 ) + angle_percent = 1; + + tag_num = gi.Tag_NumForName( edict->s.modelindex, "tag_mouth" ); + + if ( tag_num != -1 ) + { + SetControllerTag( ACTOR_MOUTH_TAG, tag_num ); + + mouth_angles = vec_zero; + mouth_angles[PITCH] = max_mouth_angle * angle_percent; + + SetControllerAngles( ACTOR_MOUTH_TAG, mouth_angles ); + } + } + +//*********************************************************************************************** +// +// Mode functions +// +//*********************************************************************************************** + + +qboolean Actor::ModeAllowed( int new_mode ) + { + if ( deadflag && actortype != IS_INANIMATE ) + return false; + + if ( new_mode == ACTOR_MODE_SCRIPT || new_mode == ACTOR_MODE_IDLE ) + { + if ( mode == ACTOR_MODE_AI || mode == ACTOR_MODE_TALK ) + return false; + } + else if ( new_mode == ACTOR_MODE_TALK ) + { + if ( mode == ACTOR_MODE_AI || mode == ACTOR_MODE_TALK || actortype != IS_FRIEND || !GetActorFlag( ACTOR_FLAG_ALLOW_TALK ) || + !dialog_list || level.cinematic ) + return false; + } + + return true; + } + +void Actor::StartMode( int new_mode ) + { + if ( new_mode == ACTOR_MODE_TALK ) + { + SaveMode(); + CancelEventsOfType( EV_Actor_FinishedBehavior ); + RemoveAnimDoneEvent(); + } + + mode = new_mode; + } + +void Actor::EndMode( void ) + { + str currentanim; + + if ( mode == ACTOR_MODE_AI ) + { + if ( GetActorFlag( ACTOR_FLAG_UPDATE_BOSS_HEALTH ) && max_boss_health ) + { + char bosshealth_string[20]; + sprintf( bosshealth_string, "%.5f", 0 ); + gi.cvar_set( "bosshealth", bosshealth_string ); + } + + mode = ACTOR_MODE_IDLE; + ProcessEvent( EV_Actor_Idle ); + + currentanim = currentState->getLegAnim( *this, &conditionals ); + + if ( currentanim.length() && currentanim != animname ) + SetAnim( currentanim, EV_Anim_Done ); + + currentEnemy = NULL; + } + else if ( mode == ACTOR_MODE_TALK ) + { + next_player_near = level.time + 5.0; + RestoreMode(); + } + } + +void Actor::SaveMode( void ) + { + if ( mode == ACTOR_MODE_IDLE ) + { + saved_mode = ACTOR_MODE_IDLE; + saved_state_name = currentState->getName(); + } + else if ( mode == ACTOR_MODE_SCRIPT ) + { + saved_mode = ACTOR_MODE_SCRIPT; + saved_behavior = behavior; + saved_scriptthread = scriptthread; + saved_actorthread = actorthread; + saved_anim_name = animname; + saved_anim_event_name = last_anim_event_name; + + behavior = NULL; + scriptthread = NULL; + actorthread = NULL; + } + else + { + gi.DPrintf( "Can't saved specified mode: %d\n", mode ); + } + } + +void Actor::RestoreMode( void ) + { + Event *idle_event; + + if ( saved_mode == ACTOR_MODE_IDLE ) + { + mode = ACTOR_MODE_IDLE; + + idle_event = new Event( EV_Actor_Idle ); + idle_event->AddString( saved_state_name ); + ProcessEvent( idle_event ); + //StartMode( ACTOR_MODE_IDLE ); + } + else if ( saved_mode == ACTOR_MODE_SCRIPT ) + { + StartMode( ACTOR_MODE_SCRIPT ); + + behavior = saved_behavior; + scriptthread = saved_scriptthread; + actorthread = saved_actorthread; + + if ( saved_behavior ) + currentBehavior = saved_behavior->getClassname(); + else + currentBehavior = ""; + + if ( saved_anim_event_name.length() ) + { + Event *event = new Event( saved_anim_event_name.c_str() ); + SetAnim( saved_anim_name, event ); + } + else + SetAnim( saved_anim_name ); + } + else + { + gi.DPrintf( "Can't restore specified mode: %d\n", saved_mode ); + } + + saved_mode = ACTOR_MODE_NONE; + } + + +//*********************************************************************************************** +// +// Finishing functions +// +//*********************************************************************************************** + + +qboolean Actor::CanBeFinished + ( + void + ) + { + // See if actor can be finished by any means of death + + if ( can_be_finsihed_by_mods.NumObjects() > 0 ) + return true; + else + return false; + } + +qboolean Actor::CanBeFinishedBy + ( + int meansofdeath + ) + { + int number_of_mods; + int i; + + // Make sure in limbo + + if ( !InLimbo() ) + return false; + + // Make sure can be finished by this means of death + + number_of_mods = can_be_finsihed_by_mods.NumObjects(); + + for( i = 1 ; i <= number_of_mods ; i++ ) + { + if ( meansofdeath == can_be_finsihed_by_mods.ObjectAt( i ) ) + return true; + } + + return false; + } + +void Actor::SetCanBeFinishedBy + ( + Event *ev + ) + { + str mod_string; + int new_mod; + int number_of_mods; + int i; + + + number_of_mods = ev->NumArgs(); + + for ( i = 1 ; i <= number_of_mods ; i++ ) + { + mod_string = ev->GetString( i ); + + new_mod = MOD_string_to_int( mod_string ); + + if ( new_mod != -1 ) + can_be_finsihed_by_mods.AddObject( new_mod ); + } + } + +void Actor::Finish + ( + int meansofdeath + ) + { + // Make sure we can be finsihed by this means of death + + if ( CanBeFinishedBy( meansofdeath ) ) + { + // Save that the actor is being finished + + SetActorFlag( ACTOR_FLAG_FINISHED, true ); + + // Kill the actor + + ProcessEvent( EV_Actor_Suicide ); + + // Make sure the correct means of death is set + + means_of_death = meansofdeath; + } + else + { + gi.DPrintf( "Actor can't be finished by %d means of death\n", meansofdeath ); + } + } + +void Actor::StartLimbo + ( + void + ) + { + State *temp_state; + qboolean found_state; + + // Make sure we have a little bit of health + + health = 1; + + // Go to the limbo state + + found_state = false; + + if ( statemap ) + { + temp_state = statemap->FindState( "LIMBO" ); + + if ( temp_state ) + { + currentState = temp_state; + InitState(); + found_state = true; + SetActorFlag( ACTOR_FLAG_IN_LIMBO, true ); + } + } + + if ( !found_state ) + { + // Didn't find a limbo state so just die + + ProcessEvent( EV_Actor_Suicide ); + } + } + +qboolean Actor::InLimbo + ( + void + ) + { + return GetActorFlag( ACTOR_FLAG_IN_LIMBO ); + } + + +//*********************************************************************************************** +// +// General functions +// +//*********************************************************************************************** + +void Actor::AlwaysGiveWater + ( + Event *ev + ) + { + SetActorFlag( ACTOR_FLAG_ALWAYS_GIVE_WATER, ev->GetBoolean( 1 ) ); + } + +void Actor::IgnorePainFromActors + ( + Event *ev + ) + { + SetActorFlag( ACTOR_FLAG_IGNORE_PAIN_FROM_ACTORS, true ); + } + +void Actor::UpdateBossHealth + ( + Event *ev + ) + { + SetActorFlag( ACTOR_FLAG_UPDATE_BOSS_HEALTH, true ); + } + +void Actor::SetMaxBossHealth + ( + Event *ev + ) + { + max_boss_health = ev->GetFloat( 1 ); + } + +void Actor::SetWaterLevel + ( + Event *ev + ) + { + water_level = ev->GetFloat( 1 ); + } + +void Actor::IncrementNumSpawns + ( + Event *ev + ) + { + num_of_spawns++; + } + +void Actor::DecrementNumSpawns + ( + Event *ev + ) + { + num_of_spawns--; + + if ( num_of_spawns < 0 ) + num_of_spawns = 0; + } + +void Actor::TouchTriggers + ( + Event *ev + ) + { + SetActorFlag( ACTOR_FLAG_TOUCH_TRIGGERS, ev->GetBoolean( 1 ) ); + } + +void Actor::IgnoreWater + ( + Event *ev + ) + { + SetActorFlag( ACTOR_FLAG_IGNORE_WATER, ev->GetBoolean( 1 ) ); + } + +void Actor::SetNotAllowedToKill + ( + Event *ev + ) + { + SetActorFlag( ACTOR_FLAG_ALLOWED_TO_KILL, false ); + } + +void Actor::IgnorePlacementWarning + ( + Event *ev + ) + + { + str warning; + + warning = ev->GetString( 1 ); + + if ( warning == "stuck" ) + SetActorFlag( ACTOR_FLAG_IGNORE_STUCK_WARNING, true ); + else if ( warning == "off_ground" ) + SetActorFlag( ACTOR_FLAG_IGNORE_OFF_GROUND_WARNING, true ); + } + +void Actor::SetTargetable + ( + Event *ev + ) + + { + qboolean bool; + + bool = ev->GetBoolean( 1 ); + + SetActorFlag( ACTOR_FLAG_TARGETABLE, bool ); + } + +qboolean Actor::CanTarget + ( + void + ) + + { + return GetActorFlag( ACTOR_FLAG_TARGETABLE ); + } + +void Actor::SetSpawnChance + ( + Event *ev + ) + + { + spawn_chance = ev->GetFloat( 1 ); + } + +void Actor::AddSpawnItem + ( + Event *ev + ) + + { + str spawn_item_name; + + spawn_item_name = ev->GetString( 1 ); + + spawn_items.AddObject( spawn_item_name ); + } + +void Actor::ClearSpawnItems + ( + Event *ev + ) + + { + spawn_items.ClearObjectList(); + } + +void Actor::SpawnItems + ( + void + ) + + { + int number_of_spawn_items; + int i; + qboolean spawn_random = false; + str spawn_item_name; + Player *player; + float health_chance; + float water_chance; + float total_chance; + float plasma_chance; + float bullets_chance; + float player_health; + float player_water; + int player_plasma; + int player_bullets; + float random_number; + qboolean has_gun; + qboolean has_crossbow; + + + number_of_spawn_items = spawn_items.NumObjects(); + + // Spawn in all of the items in the spawn_item list + + if ( number_of_spawn_items ) + { + for( i = 1 ; i <= number_of_spawn_items ; i++ ) + { + spawn_item_name = spawn_items.ObjectAt( i ); + + if ( spawn_item_name == "random" ) + spawn_random = true; + else + SpawnItem( spawn_item_name ); + } + } + else + { + spawn_random = true; + } + + // See if we should spawn a random item + + if ( spawn_random ) + { + if ( G_Random( 100 ) < spawn_chance ) + { + // Set up default chances + + health_chance = 1; + water_chance = 1; + plasma_chance = 1; + bullets_chance = 1; + + // See what he player needs + + player = (Player *)g_entities[ 0 ].entity; + + player_health = player->health; + player_water = player->GetWaterPower(); + player_plasma = player->AmmoCount( "Plasma" ); + player_bullets = player->AmmoCount( "Bullet" ); + + has_gun = player->HasItem( "HandGun" ); + has_crossbow = player->HasItem( "Crossbow" ); + + // See if the player is low on health + + if ( player_health <= 50 ) + health_chance *= (60 - player_health) / 10; + + if ( player_water <= 50 ) + water_chance *= (60 - player_water) / 10; + + if ( player_plasma <= 20 ) + plasma_chance *= (30 - player_plasma) / 10; + + if ( !has_crossbow ) + plasma_chance = 0; + + if ( player_bullets <= 50 ) + bullets_chance *= (60 - player_bullets) / 10; + + if ( !has_gun ) + bullets_chance = 0; + + // Choose something randomly + + total_chance = health_chance + water_chance + plasma_chance + bullets_chance; + + random_number = G_Random( total_chance ); + + if ( random_number < health_chance ) + { + if ( G_Random( 10 ) < health_chance ) + SpawnItem( "item_bighealthfruit1.tik" ); + else + SpawnItem( "item_healthfruit1.tik" ); + } + else if ( random_number < health_chance + water_chance ) + { + if ( ( mass > 125 ) && ( G_Random( 4 ) < water_chance ) ) + SpawnItem( "item_bigwaterampoule.tik" ); + else + SpawnItem( "item_waterampoule.tik" ); + } + else if ( random_number < health_chance + water_chance + plasma_chance ) + SpawnItem( "ammo_plasma.tik" ); + else + { + if ( G_Random( 10 ) < bullets_chance ) + SpawnItem( "ammo_uziclip.tik" ); + else + SpawnItem( "ammo_gunclip.tik" ); + } + } + } + } + +void Actor::SpawnItem + ( + str spawn_item_name + ) + + { + SpawnArgs args; + Entity *ent; + Item *item; + + + args.setArg( "model", spawn_item_name ); + ent = args.Spawn(); + + if ( !ent || !ent->isSubclassOf( Item ) ) + return; + + item = (Item *)ent; + + item->setOrigin( centroid ); + + item->ProcessPendingEvents(); + + item->PlaceItem(); + item->setOrigin( centroid ); + item->velocity = Vector( G_CRandom( 100 ), G_CRandom( 100 ), 200 + G_Random( 200 ) ); + item->edict->clipmask = CONTENTS_SOLID | CONTENTS_PLAYERCLIP; + + // Give the new item a targetname + + item->targetname = targetname; + item->targetname += "_item"; + + item->SetTargetName( item->targetname ); + } + +qboolean Actor::CanJump( void ) + { + return ( HasAnim( "jump" ) && HasAnim( "fall" ) && HasAnim( "land" ) ); + } + +void Actor::SetUseGravity + ( + Event *ev + ) + + { + qboolean use_gravity; + + use_gravity = ev->GetBoolean( 1 ); + + SetActorFlag( ACTOR_FLAG_USE_GRAVITY, use_gravity ); + + if ( use_gravity ) + gravity = 1; + else + gravity = 0; + } + +void Actor::SetAllowFall + ( + Event *ev + ) + + { + qboolean allow_fall; + + if ( ev->NumArgs() > 0 ) + allow_fall = ev->GetBoolean( 1 ); + else + allow_fall = true; + + SetActorFlag( ACTOR_FLAG_ALLOW_FALL, allow_fall ); + } + +void Actor::SetHaveThing + ( + Event *ev + ) + + { + int thing_number; + qboolean thing_bool; + + thing_number = ev->GetInteger( 1 ); + thing_bool = ev->GetBoolean( 2 ); + + switch( thing_number ) + { + case 1 : + SetActorFlag( ACTOR_FLAG_HAS_THING1, thing_bool ); + break; + case 2 : + SetActorFlag( ACTOR_FLAG_HAS_THING2, thing_bool ); + break; + case 3 : + SetActorFlag( ACTOR_FLAG_HAS_THING3, thing_bool ); + break; + case 4 : + SetActorFlag( ACTOR_FLAG_HAS_THING4, thing_bool ); + break; + default : + gi.DPrintf( "Has thing %d out of range\n", thing_number ); + return; + } + } + +void Actor::SetActorFlag( int flag, qboolean flag_value ) + { + unsigned int *flags; + int index; + + if ( flag > ACTOR_FLAG_MAX ) + { + gi.DPrintf( "Actor flag %d out of range\n", flag ); + return; + } + + index = flag / 32; + + switch( index ) + { + case 0 : + flags = &actor_flags1; + break; + case 1 : + flags = &actor_flags2; + break; + default : + gi.DPrintf( "Actor flag %d out of range\n", flag ); + return; + } + + if ( flag_value ) + *flags |= 1 << flag; + else + *flags &= ~( 1 << flag ); + } + +qboolean Actor::GetActorFlag( int flag ) + { + unsigned int *flags; + int index; + + if ( flag > ACTOR_FLAG_MAX ) + { + gi.DPrintf( "Actor flag %d out of range\n", flag ); + return false; + } + + index = flag / 32; + + switch( index ) + { + case 0 : + flags = &actor_flags1; + break; + case 1 : + flags = &actor_flags2; + break; + default : + gi.DPrintf( "Actor flag %d out of range\n", flag ); + return false; + } + + if ( *flags & ( 1 << flag ) ) + return true; + else + return false; + } + +void Actor::SetBounceOff + ( + Event *ev + ) + + { + SetActorFlag( ACTOR_FLAG_BOUNCE_OFF, true ); + } + +void Actor::BounceOffEvent + ( + Event *ev + ) + + { + Vector object_origin; + Entity *effect; + Event *event; + + if ( bounce_off_effect.length() ) + { + object_origin = ev->GetVector( 1 ); + + effect = new Animate; + effect->setModel( bounce_off_effect ); + + effect->setOrigin( object_origin ); + effect->setSolidType( SOLID_NOT ); + + event = new Event( EV_Remove ); + effect->PostEvent( event, 5 ); + } + } + +void Actor::SetBounceOffEffect + ( + Event *ev + ) + + { + bounce_off_effect = ev->GetString( 1 ); + } + +void Actor::GotoNextStage + ( + Event *ev + ) + + { + stage++; + } + +void Actor::GotoPrevStage + ( + Event *ev + ) + + { + stage--; + + if ( stage < 1 ) + stage = 1; + } + +void Actor::GotoStage + ( + Event *ev + ) + + { + stage = ev->GetInteger( 1 ); + } + +void Actor::NotifyOthersAtDeath + ( + Event *ev + ) + + { + SetActorFlag( ACTOR_FLAG_NOTIFY_OTHERS_AT_DEATH, true ); + } + +void Actor::NotifyOthersOfDeath + ( + void + ) + + { + int i; + Actor *act; + + for( i = 1; i <= ActiveList.NumObjects(); i++ ) + { + act = ActiveList.ObjectAt( i ); + + if ( name.length() && name == act->name && Vector( act->origin - origin ).length() < 1000 ) + act->AddStateFlag( STATE_FLAG_OTHER_DIED ); + } + } + +void Actor::Pickup + ( + Event *ev + ) + + { + str tag_name; + int tag_num; + Vector new_angles; + + tag_name = ev->GetString( 1 ); + tag_num = gi.Tag_NumForName( edict->s.modelindex, tag_name.c_str() ); + + new_angles = "0 0 0"; + + if ( pickup_ent ) + { + pickup_ent->setAngles( new_angles ); + pickup_ent->attach( entnum, tag_num ); + } + } + +void Actor::Throw + ( + Event *ev + ) + + { + int i; + int num; + Entity *child; + Vector pos; + Vector forward; + str tag_name; + int tag_num; + + + tag_name = ev->GetString( 1 ); + tag_num = gi.Tag_NumForName( edict->s.modelindex, tag_name.c_str() ); + + + for ( i=0,num = numchildren; i < MAX_MODEL_CHILDREN; i++ ) + { + if ( children[i] == ENTITYNUM_NONE ) + { + continue; + } + + child = ( Entity * )G_GetEntity( children[i] ); + + if ( child->edict->s.tag_num == tag_num ) + { + child->detach(); + + child->setSolidType( SOLID_BBOX ); + + child->setAngles( angles ); + + child->groundentity = NULL; + + tag_num = gi.Tag_NumForName( edict->s.modelindex, tag_name.c_str() ); + GetTag( tag_num, &pos, &forward ); + + child->velocity = orientation[0]; + child->velocity *= 500; + + child->velocity.z = 400; + } + + num--; + + if ( !num ) + break; + } + } + +void Actor::SolidMask + ( + Event *ev + ) + + { + edict->clipmask = MASK_MONSTERSOLID; + } + +void Actor::IgnoreMonsterClip + ( + Event *ev + ) + + { + edict->clipmask &= ~CONTENTS_MONSTERCLIP; + } + +void Actor::NotSolidMask + ( + Event *ev + ) + + { + edict->clipmask = MASK_SOLID; + } + +void Actor::NoMask + ( + Event *ev + ) + + { + edict->clipmask = 0; + } + +void Actor::SetMask + ( + Event *ev + ) + + { + str mask_name; + + mask_name = ev->GetString( 1 ); + + if ( mask_name == "monstersolid" ) + edict->clipmask = MASK_MONSTERSOLID; + else if ( mask_name == "deadsolid" ) + edict->clipmask = MASK_DEADSOLID; + else if ( mask_name == "none" ) + edict->clipmask = 0; + else if ( mask_name == "pathsolid" ) + edict->clipmask = MASK_PATHSOLID; + else + gi.DPrintf( "Unknown mask name - %s\n", mask_name.c_str() ); + } + +void Actor::SetWatchOffset + ( + Event *ev + ) + { + watch_offset = ev->GetVector( 1 ); + } + +void Actor::setSize + ( + Vector min, + Vector max + ) + { + min *= edict->s.scale; + max *= edict->s.scale; + Sentient::setSize( min, max ); + } + +void Actor::SetHealth + ( + Event *ev + ) + + { + health = ev->GetFloat( 1 ) * edict->s.scale; + max_health = health; + } + +void Actor::AddHealth + ( + Event *ev + ) + + { + float health_to_add; + float maxhealth; + + + health_to_add = ev->GetFloat( 1 ); + + if ( ev->NumArgs() > 1 ) + maxhealth = ev->GetFloat( 2 ); + else + maxhealth = max_health; + + health += health_to_add; + + if ( health > maxhealth ) + health = maxhealth; + } + +void Actor::SetTurnSpeed + ( + Event *ev + ) + + { + turnspeed = ev->GetFloat( 1 ); + } + +void Actor::SetMaxInactiveTime + ( + Event *ev + ) + { + max_inactive_time = ev->GetFloat( 1 ); + } + +void Actor::SetFov + ( + Event *ev + ) + + { + fov = ev->GetFloat( 1 ); + fovdot = cos( fov * 0.5 * M_PI / 180.0 ); + } + +void Actor::SetVisionDistance + ( + Event *ev + ) + + { + vision_distance = ev->GetFloat( 1 ); + } + +bool Actor::IsEntityAlive + ( + Entity *ent + ) + + { + return ( ent && !ent->deadflag && (ent->health > 0) && !(ent->flags & FL_NOTARGET) && level.ai_on ); + } + +void Actor::Name + ( + Event *ev + ) + { + name = ev->GetString( 1 ); + } + +void Actor::SetupTriggerField + ( + Event *ev + ) + { + Vector min; + Vector max; + TouchField *trig; + + min = ev->GetVector( 1 ); + max = ev->GetVector( 2 ); + + min = min + origin; + max = max + origin; + + trig = new TouchField; + trig->Setup( this, EV_ActorTriggerTouched, min, max, TRIGGER_PLAYERS | TRIGGER_MONSTERS ); + trigger = trig; + } + +void Actor::TriggerTouched + ( + Event *ev + ) + { + Entity *other; + + other = ev->GetEntity( 1 ); + + if ( + ( other->movetype != MOVETYPE_NONE ) && + ( other->movetype != MOVETYPE_STATIONARY ) && + ( IsEntityAlive( other ) ) + ) + AddStateFlag( STATE_FLAG_TOUCHED ); + } + +void Actor::OnlyShootable + ( + Event *ev + ) + + { + setContents( CONTENTS_SHOOTABLE_ONLY ); + link(); + } + +void Actor::AddStateFlag + ( + unsigned int flag + ) + + { + int current_other_part; + part_t *other_part; + Entity *other_ent; + Actor *other_act; + int current_part; + part_t *part; + + + // Update my state flags + + state_flags |= flag; + + // Update all the other parts of my state flags + + for ( current_other_part = 1 ; current_other_part <= parts.NumObjects() ; current_other_part++ ) + { + other_part = &parts.ObjectAt( current_other_part ); + + other_ent = other_part->ent; + other_act = (Actor *)other_ent; + + // Look for ourselves in this part's part list + + for ( current_part = 1 ; current_part <= other_act->parts.NumObjects() ; current_part++ ) + { + part = &other_act->parts.ObjectAt( current_part ); + + if ( part->ent == this ) + { + // Found ourselves, update state flags + + part->state_flags |= flag; + } + } + } + } + +void Actor::ClearStateFlags + ( + void + ) + + { + int current_part; + part_t *part; + + + // Clear my state flags + + state_flags = 0; + + // Clear all the other parts state flags + + for ( current_part = 1 ; current_part <= parts.NumObjects() ; current_part++ ) + { + part = &parts.ObjectAt( current_part ); + + part->state_flags = 0; + } + } + +void Actor::NoChatterEvent + ( + Event *ev + ) + + { + SetActorFlag( ACTOR_FLAG_NOCHATTER, true ); + } + +void Actor::Chatter + ( + const char *snd, + float chance, + float volume, + int channel + ) + + { + str realname; + + if ( GetActorFlag( ACTOR_FLAG_NOCHATTER ) || chattime > level.time ) + { + return; + } + + if ( G_Random( 10 ) > chance ) + { + chattime = level.time + 1 + G_Random( 2 ); + return; + } + + realname = GetRandomAlias( snd ); + if ( realname.length() > 1 ) + { + float delay; + + delay = gi.SoundLength( realname.c_str() ); + + if ( delay < 0 ) + gi.DPrintf( "Lip file not found for dialog %s\n", realname.c_str() ); + + chattime = level.time + delay + 4 + G_Random( 5 ); + Sound( realname, channel, volume ); + } + else + { + // set it into the future, so we don't check it again right away + chattime = level.time + 1; + } + } + +void Actor::ActivateEvent + ( + Event *ev + ) + + { + Entity *ent; + + if ( ( deadflag ) && ( actortype != IS_INANIMATE ) ) + { + return; + } + + ent = ev->GetEntity( 1 ); + SetVariable( "other", ent ); + + ProcessEvent( EV_Actor_AttackPlayer ); + + AddStateFlag( STATE_FLAG_ACTIVATED ); + } + +void Actor::UseEvent + ( + Event *ev + ) + + { + Sentient *user; + Talk *talk; + + + AddStateFlag( STATE_FLAG_USED ); + + if ( !ModeAllowed( ACTOR_MODE_TALK ) ) + return; + + StartMode( ACTOR_MODE_TALK ); + + user = (Sentient *)ev->GetEntity( 1 ); + + talk = new Talk; + talk->SetUser( user ); + SetBehavior( talk ); + } + +void Actor::Think + ( + void + ) + + { + + // Update boss health if necessary + + if ( GetActorFlag( ACTOR_FLAG_UPDATE_BOSS_HEALTH ) && max_boss_health && mode == ACTOR_MODE_AI ) + { + char bosshealth_string[20]; + sprintf( bosshealth_string, "%.5f", health / max_boss_health ); + gi.cvar_set( "bosshealth", bosshealth_string ); + } + + // Check for the ground + + if ( last_origin != origin ) + SetActorFlag( ACTOR_FLAG_HAVE_MOVED, true ); + + if ( !( flags & FL_SWIM ) && !( flags & FL_FLY ) ) + { + if ( GetActorFlag( ACTOR_FLAG_HAVE_MOVED ) || + ( groundentity && groundentity->entity && groundentity->entity->entnum != ENTITYNUM_WORLD ) ) + CheckGround(); + } + + // Do falling stuff + + if ( groundentity ) + { + if ( !Immune( MOD_FALLING ) && !( flags & FL_FLY ) && ( origin.z + 1000 < last_ground_z ) ) + Damage( world, world, 1000, origin, vec_zero, vec_zero, 0, DAMAGE_NO_ARMOR, MOD_FALLING ); + + last_ground_z = origin.z; + } + + last_origin = origin; + + if ( !deadflag ) + { + // Check to see if stunned + + CheckStun(); + + // See if can talk to the player + + TryTalkToPlayer(); + + // Make sure we can still see our enemy + + if ( max_inactive_time && currentEnemy && next_enemy_try_sight_time < level.time && !IsBlind() ) + { + float next_sight_delay; + + next_sight_delay = max_inactive_time / 5 + G_CRandom( 0.5 ); + + if ( next_sight_delay < 1 ) + next_sight_delay = 1; + + next_enemy_try_sight_time = level.time + next_sight_delay; + + if ( !level.ai_on ) + { + last_enemy_sight_time = level.time; + } + else + { + if ( CanSeeEnemyFrom( origin ) ) + last_enemy_sight_time = level.time; + + if ( last_enemy_sight_time + max_inactive_time < level.time ) + currentEnemy = NULL; + } + } + + // If actor doesn't have an enemy right now try to find one + if ( !IsBlind() && !IsEntityAlive ( currentEnemy ) && next_find_enemy_time <= level.time ) + { + if ( level.ai_on ) + FindEnemy(); + next_find_enemy_time = level.time + .8 + G_Random( .4 ); + } + + // Make sure actor is not immobilized + + if ( flags & FL_IMMOBILE || flags & FL_PARTIAL_IMMOBILE ) + { + StopAnimating(); + return; + } + + // Do the state machine for this creature + + ProcessActorStateMachine(); + + // See if we should go back to sleep + + if ( ( mode == ACTOR_MODE_AI || mode == ACTOR_MODE_IDLE ) && !currentEnemy && !GetActorFlag( ACTOR_FLAG_INVESTIGATING ) + && next_try_sleep_time < level.time ) + { + Entity *player; + + next_try_sleep_time = level.time + 1.0; + + player = g_entities[ 0 ].entity; + + if ( mode == ACTOR_MODE_IDLE && player && !(player->flags & FL_NOTARGET) && gi.inPVS( player->centroid, centroid ) && + ( world->farplane_distance == 0 || Distance( player->centroid, centroid ) < world->farplane_distance ) ) + last_time_active = level.time; + + if ( !level.ai_on ) + last_time_active = level.time; + + if ( max_inactive_time && last_time_active + 5 < level.time ) + { + if ( mode == ACTOR_MODE_AI ) + { + EndMode(); + + Sleep(); + + if ( idle_thread.length() > 1 ) + { + //ScriptThread *thread = ExecuteThread( idle_thread, false ); + + actorthread = ExecuteThread( idle_thread, false ); + + if ( actorthread ) + ProcessScript( actorthread, NULL ); + else + warning( "Idle", "could not process idle_thread" ); + } + } + else + { + Sleep(); + } + } + } + else if ( currentEnemy || GetActorFlag( ACTOR_FLAG_INVESTIGATING ) || mode == ACTOR_MODE_SCRIPT || mode == ACTOR_MODE_TALK ) + { + last_time_active = level.time; + } + + if ( actortype == IS_INANIMATE ) + { + if ( behavior && !behavior->Evaluate( *this ) ) + { + // stop thinking + flags &= ~FL_THINK; + EndBehavior(); + + // remove them from the active list + ActiveList.RemoveObject( ( Actor * )this ); + } + return; + } + + eyeposition[ 2 ] = maxs[ 2 ] + eyeoffset[ 2 ]; + //angles.z = 0; + + // Process the current behavior + + if ( behavior && !behavior->Evaluate( *this ) ) + { + if ( stricmp( behavior->getClassname(), "Talk" ) == 0 ) + { + EndBehavior(); + EndMode(); + } + else + { + EndBehavior(); + } + + // Process state machine again because the behavior finished + ProcessActorStateMachine(); + } + + // Reset the animation is done flag + + SetActorFlag( ACTOR_FLAG_ANIM_DONE, false ); + + // Change the animation if necessary + + if ( newanimnum != -1 ) + ChangeAnim(); + } + + // Do the movement + + if ( !(flags & FL_IMMOBILE) && !(flags & FL_PARTIAL_IMMOBILE) ) + { + CalcMove(); + lastmove = STEPMOVE_STUCK; + + if ( flags & FL_SWIM ) + lastmove = WaterMove(); + else if ( flags & FL_FLY ) + lastmove = AirMove(); + else + lastmove = TryMove(); + } + + if ( !deadflag ) + { + // See if we should damage the actor because of waterlevel + + if ( waterlevel == 3 && !( flags & FL_SWIM ) ) + { + // if out of air, start drowning + if ( air_finished < level.time ) + { + // we may have been in a water brush when we spawned, so check our water level again to be sure + CheckWater(); + if ( waterlevel < 3 ) + { + // we're ok, so reset our air + air_finished = level.time + 5; + } + else if ( next_drown_time < level.time && health > 0 ) + { + // drown! + next_drown_time = level.time + 1; + + //Sound( "snd_uwchoke", CHAN_VOICE ); + BroadcastSound(); + + Damage( world, world, 15, origin, vec_zero, vec_zero, 0, DAMAGE_NO_ARMOR, MOD_DROWN ); + } + } + } + else + { + air_finished = level.time + 5; + } + + if ( + ( movetype != MOVETYPE_NONE ) && + ( movetype != MOVETYPE_STATIONARY ) && + GetActorFlag( ACTOR_FLAG_TOUCH_TRIGGERS ) && + GetActorFlag( ACTOR_FLAG_HAVE_MOVED ) + ) + G_TouchTriggers( this ); + + if ( groundentity && ( groundentity->entity != world ) && !M_CheckBottom( this ) ) + { + // G_FixCheckBottom( this ); + flags |= FL_PARTIALGROUND; + } + } + } + +qboolean Actor::GetClosestTag + ( + str tag_name, + int number_of_tags, + Vector target, + Vector *orig + ) + + { + str temp_tag_name; + Vector temp_orig; + Vector diff; + float dist; + float best_dist = -1; + qboolean found = false; + int i; + char number[5]; + + if ( number_of_tags == 1 ) + { + return GetTag( tag_name.c_str(), orig ); + } + + for( i = 1 ; i <= number_of_tags ; i++ ) + { + sprintf( number, "%d", i ); + + temp_tag_name = tag_name + str( number ); + + if ( GetTag( temp_tag_name.c_str(), &temp_orig ) ) + { + diff = target - temp_orig; + dist = diff * diff; + + if ( dist < best_dist || best_dist < 0 ) + { + best_dist = dist; + found = true; + *orig = temp_orig; + } + } + } + + return found; + } + +void Actor::Active + ( + Event *ev + ) + { + int active_flag; + + if ( ev->NumArgs() > 0 ) + { + active_flag = ev->GetInteger( 1 ); + + if ( active_flag ) + SetActorFlag( ACTOR_FLAG_INACTIVE, false ); + else + SetActorFlag( ACTOR_FLAG_INACTIVE, true ); + } + } + +void Actor::SpawnActorAtLocation + ( + Event *ev + ) + { + str model_name; + str pathnode_name; + qboolean attack; + Vector orig; + Vector ang; + float width; + float height; + PathNode *goal; + int number_of_pathnodes; + Animate *effect; + trace_t trace; + Vector spawn_mins; + Vector spawn_maxs; + + + model_name = ev->GetString( 1 ); + pathnode_name = ev->GetString( 2 ); + number_of_pathnodes = ev->GetInteger( 3 ); + attack = ev->GetBoolean( 4 ); + width = ev->GetFloat( 5 ); + height = ev->GetFloat( 6 ); + + // Get the pathnode name to spawn in to + + pathnode_name += (int)( G_Random( number_of_pathnodes ) + 1 ); + + // Find the path node + + goal = AI_FindNode( pathnode_name ); + + if ( !goal ) + { + gi.Printf( "Can't find position %s\n", pathnode_name.c_str() ); + return; + } + + // Set the spawn in position/direction + + orig = goal->origin; + ang = goal->angles; + + spawn_mins.x = -width; + spawn_mins.y = -width; + spawn_mins.z = 0; + + spawn_maxs.x = width; + spawn_maxs.y = width; + spawn_maxs.z = height; + + trace = G_Trace( orig + "0 0 64", spawn_mins, spawn_maxs, orig - "0 0 128", NULL, MASK_PATHSOLID, false, "SpawnActorAtLocation" ); + + if ( trace.allsolid ) + return; + + orig = trace.endpos; + + SpawnActor( model_name, orig, ang, 1, attack, width, height ); + + // Spawn in teleport effect + + effect = new Animate; + effect->setModel( "fx_teleport3.tik" ); + effect->setOrigin( orig ); + effect->setSolidType( SOLID_NOT ); + effect->RandomAnimate( "idle", EV_Remove ); + effect->Sound( "snd_teleport" ); + } + +void Actor::SpawnActorAtTag + ( + Event *ev + ) + { + str model_name; + str tag_name; + int how_many; + qboolean attack; + float spawn_offset = 0; + Vector tag_orig; + Vector tag_dir; + Vector new_orig; + Vector new_dir; + float width; + float height; + + + model_name = ev->GetString( 1 ); + tag_name = ev->GetString( 2 ); + how_many = ev->GetInteger( 3 ); + attack = ev->GetBoolean( 4 ); + width = ev->GetFloat( 5 ); + height = ev->GetFloat( 6 ); + + if ( ev->NumArgs() > 6 ) + spawn_offset = ev->GetFloat( 7 ); + + // Calculate a good origin/angles + + GetTag( tag_name.c_str(), &tag_orig, &tag_dir ); + + new_orig = tag_orig + tag_dir * spawn_offset; + new_dir = tag_dir * -1; + + SpawnActor( model_name, new_orig, new_dir, how_many, attack, width, height ); + } + +void Actor::SpawnActor + ( + str model_name, + Vector orig, + Vector ang, + int how_many, + qboolean attack, + float width, + float height + ) + + { + Actor *new_actor; + int current_actor; + trace_t trace; + Vector spawn_mins; + Vector spawn_maxs; + + + // Make sure this origin is reasonable + + spawn_mins[0] = -width; + spawn_mins[1] = -width; + spawn_mins[2] = 0; + + spawn_maxs[0] = width; + spawn_maxs[1] = width; + spawn_maxs[2] = height; + + //trace = G_Trace( tag_orig, spawn_mins, spawn_maxs, new_orig, this, MASK_MONSTERSOLID, false, "Actor::SpawnActor" ); + trace = G_Trace( orig, spawn_mins, spawn_maxs, orig, NULL, MASK_MONSTERSOLID, false, "Actor::SpawnActor" ); + + if ( trace.fraction != 1 || trace.allsolid ) + return; + + // Spawn in all new actors + + for( current_actor = 0 ; current_actor < how_many ; current_actor++ ) + { + new_actor = new Actor; + new_actor->setModel( model_name ); + + new_actor->setOrigin( orig ); + new_actor->setAngles( ang ); + + // Make new actor attack player if requested + + if ( attack ) + new_actor->PostEvent( EV_Actor_AttackPlayer, 0 ); + + // Update number of spawns + + num_of_spawns++; + + // Save our parent + + new_actor->spawnparent = this; + + // Give the new actor a targetname + + new_actor->targetname = targetname; + new_actor->targetname += "_spawned"; + + new_actor->SetTargetName( new_actor->targetname ); + } + } + +void Actor::TryTalkToPlayer( void ) + { + int player_near = false; + Entity *ent_in_range; + int i; + Vector delta; + gentity_t *ed; + float dist2; + Sentient *user = NULL; + Talk *talk; + + + // See if we should even bother looking for players + + if ( level.cinematic ) + next_player_near = level.time + 5.0; + + if ( deadflag || actortype != IS_FRIEND || next_player_near > level.time || !ModeAllowed( ACTOR_MODE_TALK ) ) + return; + + next_player_near = level.time + .2 + G_Random( .1 ); + + // See if we are near the player + + for( i = 0 ; i < game.maxclients; i++ ) + { + ed = &g_entities[ i ]; + + if ( !ed->inuse || !ed->entity ) + continue; + + ent_in_range = ed->entity; + + if ( EntityHasFireType( ent_in_range, FT_MELEE ) || EntityHasFireType( ent_in_range, FT_BULLET ) || + EntityHasFireType( ent_in_range, FT_PROJECTILE ) ) + continue; + + if ( IsEntityAlive( ent_in_range ) && ent_in_range->velocity == vec_zero ) + { + delta = centroid - ent_in_range->centroid; + + // dot product returns length squared + + dist2 = delta * delta; + + if ( ( dist2 <= 100 * 100 ) && CanSee( ent_in_range ) ) + { + player_near = true; + user = (Sentient *)ent_in_range; + } + } + } + + if ( !player_near ) + { + SetActorFlag( ACTOR_FLAG_LAST_TRY_TALK, false ); + return; + } + + if ( !GetActorFlag( ACTOR_FLAG_LAST_TRY_TALK ) ) + { + SetActorFlag( ACTOR_FLAG_LAST_TRY_TALK, true ); + return; + } + + SetActorFlag( ACTOR_FLAG_LAST_TRY_TALK, false ); + + // Go to talk mode + + StartMode( ACTOR_MODE_TALK ); + + talk = new Talk; + talk->SetUser( user ); + SetBehavior( talk ); + } + +void Actor::AllowTalk( Event *ev ) + { + SetActorFlag( ACTOR_FLAG_ALLOW_TALK, ev->GetBoolean( 1 ) ); + } + +void Actor::AllowHangBack( Event *ev ) + { + SetActorFlag( ACTOR_FLAG_ALLOW_HANGBACK, ev->GetBoolean( 1 ) ); + } + +qboolean Actor::CheckBottom( void ) + { + //Vector test_mins, test_maxs; + Vector start, stop; + trace_t trace; + int x, y; + int corners_ok; + int middle_ok; + float width; + + + width = maxs[0]; + + + //test_mins = origin + mins; + //test_maxs = origin + maxs; + + // First see if the origin is on a solid (this is the really simple test) + + start = origin - Vector(0, 0, 1); + + if ( gi.pointcontents( start, 0 ) == CONTENTS_SOLID ) + return true; + + // Next see if at least 3 corners are on a solid (this is the simple test) + + corners_ok = 0; + + start[ 2 ] = absmin[ 2 ] - 1; + + for( x = 0; x <= 1; x++ ) + { + for( y = 0; y <= 1; y++ ) + { + start[ 0 ] = x ? absmax[ 0 ] : absmin[ 0 ]; + start[ 1 ] = y ? absmax[ 1 ] : absmin[ 1 ]; + + if ( gi.pointcontents( start, 0 ) == CONTENTS_SOLID ) + corners_ok++; + } + } + + if ( corners_ok >= 3 ) + return true; + + // Next do the hard test + + corners_ok = 0; + middle_ok = 0; + + // Test the origin (if it is close to ground is a plus) + + start = origin; + stop = start - Vector(0, 0, width); // Test down as far as the actor is wide + + trace = G_Trace( start, vec_zero, vec_zero, stop, this, (CONTENTS_SOLID|CONTENTS_MONSTERCLIP), false, "CheckBottom 1" ); + + if ( trace.fraction < 1 && trace.plane.normal[2] > .7 ) + middle_ok = 1; + + // Test all of the corners + + for( x = 0; x <= 1; x++ ) + { + for( y = 0; y <= 1; y++ ) + { + start[ 0 ] = x ? absmax[ 0 ] : absmin[ 0 ]; + start[ 1 ] = y ? absmax[ 1 ] : absmin[ 1 ]; + start[ 2 ] = origin[ 2 ]; + + stop = start - Vector(0, 0, 2 * width); + + trace = G_Trace( start, vec_zero, vec_zero, stop, this, (CONTENTS_SOLID|CONTENTS_MONSTERCLIP), false, "CheckBottom 2" ); + + if ( trace.fraction < 1 && trace.plane.normal[2] > .7 ) + corners_ok++; + + if ( ( middle_ok && corners_ok >= 1 ) || ( corners_ok >= 3 ) ) + return true; + } + } + + return false; + } + +void Actor::ChangeType + ( + Event *ev + ) + + { + velocity = vec_zero; + setModel( ev->GetString( 1 ) ); + PostEvent( EV_Actor_Wakeup, FRAMETIME ); + NoLerpThisFrame(); + } + +void Actor::GetStateAnims + ( + Container *c + ) + + { + statemap->GetAllAnims( c ); + } + +void Actor::Touched + ( + Event *ev + ) + { + Entity *other; + + other = ev->GetEntity( 1 ); + + if ( other && other->isSubclassOf( Player ) && !Likes( other ) ) + Stimuli( STIMULI_SIGHT, other, false ); + } + diff --git a/source/source/fgame/actor.h b/source/source/fgame/actor.h new file mode 100644 index 0000000..737d3e8 --- /dev/null +++ b/source/source/fgame/actor.h @@ -0,0 +1,2117 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/actor.h $ +// $Revision:: 142 $ +// $Author:: Steven $ +// $Date:: 7/27/00 10:55p $ +// +// Copyright (C) 1998 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/actor.h $ +// +// 142 7/27/00 10:55p Steven +// Added always give water stuff. +// +// 141 7/25/00 9:26p Steven +// Added damage allowed stuff. +// +// 140 7/24/00 6:08p Steven +// Added ignore pain from actors. +// +// 139 7/23/00 5:12p Steven +// Added check animname. +// +// 138 7/22/00 3:02p Steven +// Added boss health bar stuff. +// +// 137 7/22/00 1:22p Steven +// Added water level archiving. +// +// 136 7/22/00 1:18p Steven +// Added water level stuff. +// +// 135 7/17/00 3:16p Steven +// added increment/decrement num spawns stuff +// +// 134 7/17/00 2:57p Steven +// Made EV_Actor_SetTargetable extern. +// +// 133 7/15/00 3:11p Steven +// Added no pain sounds stuff. +// +// 132 7/13/00 3:43p Steven +// Added simple pathfinding and have moved stuff. +// +// 131 7/13/00 12:33p Steven +// Added ignore sounds stuff. +// +// 130 7/12/00 3:36p Steven +// Made lots of optimizations to actors. +// +// 129 7/06/00 4:44p Steven +// Made sure if no behavior was loaded to set the currentBehavior to "". +// +// 128 7/06/00 12:59p Steven +// Made a way to stimuli an attack without it attacking the entity that caused +// it pain and made spawned actors fade out almost immediately. +// +// 127 7/06/00 9:24a Steven +// Added damage angles stuff. +// +// 126 7/06/00 7:47a Steven +// Added enemy on ground check. +// +// 125 7/05/00 5:17p Steven +// Added part of the code to make the player fail the level if she kills an +// innocent. +// +// 124 7/05/00 2:27p Steven +// Fixed reposting of events. +// +// 123 7/02/00 5:55p Steven +// Added SetIdleStateName. +// +// 122 7/02/00 5:09p Steven +// Some SpawnActor work. +// +// 121 7/02/00 1:10p Steven +// Added a RunThread event. +// +// 120 7/01/00 6:19p Steven +// Added falling stuff. +// +// 119 6/30/00 5:05p Steven +// Added on fire check. +// +// 118 6/30/00 11:40a Steven +// Added a blocked check. +// +// 117 6/30/00 10:20a Steven +// Added some stuck/off ground stuff. +// +// 116 6/29/00 5:21p Steven +// Added min and max height for in range stuff. +// +// 115 6/28/00 3:12p Steven +// Fixed a loadgame bug where I referenced statemap without checking to see if +// it wasn't NULL. +// +// 114 6/26/00 4:52p Steven +// Fixed loading of the current state and forced each actor to sleep or to +// wakeup. +// +// 113 6/24/00 7:01p Steven +// Fixed a loading statemap issue. +// +// 112 6/24/00 11:22a Steven +// Fixed a loadgame issue with statemaps. +// +// 111 6/22/00 5:33p Steven +// Added StopDialog. +// +// 110 6/22/00 3:53p Steven +// Fixed some saving/loading issues. +// +// 109 6/20/00 7:00p Steven +// Changed saved_anim_event and last_anim_event to strings from event pointers. +// +// 108 6/20/00 12:17p Steven +// Added SetMask stuff. +// +// 107 6/19/00 6:21p Steven +// Added die completely, bleed after death, next pain sound time, and touched +// stuff. +// +// 106 6/17/00 4:03p Steven +// Added GetStateAnims stuff. +// +// 105 6/15/00 6:55p Steven +// Added moving head while talking stuff. +// +// 104 6/10/00 1:50p Steven +// Added statemap caching. +// +// 103 6/08/00 1:44p Steven +// Added minimum melee height and immortal events. +// +// 102 6/07/00 5:33p Steven +// Added ignore monster clip stuff. +// +// 101 6/06/00 2:51p Steven +// Added no path stuff. +// +// 100 6/03/00 6:53p Steven +// Added blind stuff. +// +// 99 6/03/00 5:23p Steven +// Added saving of dialog stuff. +// +// 98 6/01/00 3:18p Steven +// Added changetype and checkinwater. +// +// 97 5/31/00 3:55p Steven +// Another actor save game pass. +// +// 96 5/30/00 7:06p Markd +// saved games 4th pass +// +// 95 5/27/00 3:32p Markd +// 2nd pass save games +// +// 94 5/27/00 2:32p Steven +// Added targetable stuff, attack actor stuff, and check player range. +// +// 93 5/26/00 6:21p Steven +// Added attackable by actors stuff, should attack entity, and goto prev stage. +// +// 92 5/24/00 3:13p Markd +// first phase of save/load games +// +// 91 5/23/00 6:43p Steven +// Moved small gib stuff to sentient. +// +// 90 5/23/00 10:18a Steven +// Made actors take a little time before doing babble dialog (half second or +// so) and added more items to actor random item spawns. +// +// 89 5/20/00 4:46p Steven +// Added send command and fixed saving of noise stuff. +// +// 88 5/19/00 3:43p Steven +// Added a noclip check. +// +// 87 5/19/00 11:24a Steven +// Some cleanup and added in saving of actors. +// +// 86 5/11/00 11:12a Steven +// Added pushing stuff and chargewater attack. +// +// 85 5/10/00 10:36a Steven +// Added can walk on others stuff, feet width stuff, last_origin, and +// next_find_enemy_time. +// +// 84 5/04/00 2:07p Steven +// More finishing move stuff. +// +// 83 5/04/00 12:46p Steven +// Finishing move stuff. +// +// 82 5/01/00 2:47p Steven +// Added allow fall and added volume and minimum distance to PlayDialog stuff. +// +// 81 4/28/00 5:38p Steven +// Added a last known enemy position variable. +// +// 80 4/24/00 2:44p Steven +// Fixed the initial state not getting initialized correctly. +// +// 79 4/21/00 5:40p Steven +// Added bounce off stuff and added spawn item stuff. +// +// 78 4/20/00 11:35a Steven +// Added stun stuff. +// +// 77 4/15/00 11:50a Steven +// Added spawnbloodygibs, added setmaxgibs and cleaned up some blood stuff. +// +// 76 4/14/00 3:58p Steven +// Added a staysolid event. +// +// 75 4/13/00 5:33p Steven +// Added a deathsink event, made it so only actors with deathsink turned on +// sink into ground after death and added a nomask event for the ghosts. +// +// 74 4/12/00 6:59p Steven +// Added an addhealth event. +// +// 73 4/11/00 6:37p Steven +// Added deathshrink stuff. +// +// 72 4/11/00 3:07p Steven +// Cleaned up a bunch of spawn stuff and merged SpawnGib and SpawnGibAtTag. +// +// 71 4/08/00 3:58p Steven +// Added fading out stuff, attackmode stuff and SpawnGibAtTag. +// +// 70 4/06/00 2:57p Steven +// Added death size event. +// +// 69 4/04/00 6:54p Steven +// Added ResetHeadEvent. +// +// 68 4/01/00 4:33p Steven +// Added chackname. +// +// 67 4/01/00 2:39p Steven +// Added checkcanflytoenemy. +// +// 66 4/01/00 11:10a Steven +// Added checkenemydead. +// +// 65 3/31/00 5:33p Steven +// Made EV_ActorOnlyShootable extern. +// +// 64 3/31/00 1:01p Steven +// Added GetRandomEnemy (for recruiter). +// +// 63 3/30/00 2:03p Steven +// Added SpawnBlood and added usegravity. +// +// 62 3/28/00 6:48p Steven +// Added optional tag_name to TestAttack. +// +// 61 3/24/00 6:31p Steven +// Started adding a better CheckBottom. +// +// 60 3/22/00 10:35a Steven +// Added SpawnNamedGib and GotoStage. +// +// 59 3/20/00 6:07p Steven +// Moved max_mouth_angle stuff to sentient, added setmouthangle, and got rid of +// idle_thread_label. +// +// 58 3/18/00 4:15p Steven +// Added an allowhangback event and added a check for allowhangback. +// +// 57 3/18/00 3:13p Steven +// Added a flag to keep track if the actor has been started yet or not. +// +// 56 3/18/00 1:16p Steven +// Added FireBullet to actor and added pain_angles stuff. +// +// 55 3/17/00 11:52a Steven +// Added jumping stuff. +// +// 54 3/14/00 12:07p Steven +// Added walkwatch stuff. +// +// 53 3/13/00 2:32p Steven +// Added a can_shoot_enemy check. +// +// 52 3/11/00 4:11p Steven +// Added have thing stuff. +// +// 51 3/11/00 2:16p Steven +// Added stun stuff (so the AI knows when the player is incapable of doing +// anything :) +// +// 50 3/11/00 11:35a Steven +// Moved all actor booleans to 1 actor flags variable. +// +// 49 3/08/00 6:41p Steven +// Fixed up checkcanseeenemy. +// +// 48 3/07/00 4:56p Steven +// Added bounce off stuff. +// +// 47 3/07/00 11:49a Steven +// Added checkenemyinfov. +// +// 46 3/04/00 11:49a Steven +// Added a stuck flag and added a check for it. +// +// 45 3/03/00 5:25p Steven +// Added fast_bullet stuff. +// +// 44 3/02/00 11:01a Steven +// Added checkenemyrelativeyaw. +// +// 43 2/25/00 7:03p Steven +// Added a way for actors to notify others of their kind when they are killed. +// +// 42 2/24/00 5:25p Steven +// Fixed up some of the removing anim done event stuff. +// +// 41 2/23/00 11:44a Steven +// Moved utility behaviors into actor. +// +// 40 2/21/00 6:24p Steven +// Added a torso tag and added an endthread event. +// +// 39 2/18/00 6:54p Steven +// Added warpto command. +// +// 38 2/17/00 5:42p Steven +// Lots of movement and path finding improvements. +// +// 37 2/16/00 10:41a Steven +// Added small pain stuff. +// +// 36 2/14/00 3:32p Steven +// Added checks so an actor can tell what weapons the player is using. +// +// 35 2/11/00 6:40p Steven +// Added pickup/throw stuff, added damage once stuff, and added small pain +// stuff. +// +// 34 2/09/00 10:34a Steven +// Added events to allow an actor's clipmask to be changed. +// +// 33 2/08/00 11:59a Steven +// Added stuff to let actor know he had blocked a hit. +// +// 32 2/08/00 11:38a Steven +// Some general cleanup, added a state name to idle event, added a state name +// to playdialog event, and added a checkheld check. +// +// 31 2/04/00 1:56p Steven +// Added a lot on the different modes (AI, script, idle and talk). +// +// 30 2/02/00 1:34p Steven +// Added head watching stuff and fixed checkmovingactorrange. +// +// 29 1/27/00 2:50p Steven +// Added checkincomingmeleeattackstart and checkincomingprojectilestart. +// +// 28 1/25/00 11:09a Steven +// Renamed health_less check to health. +// +// 27 1/24/00 6:56p Steven +// Added limiting number of spawned stuff by an actor. +// +// 26 1/21/00 6:44p Steven +// Added tempstate ability. +// +// 25 1/19/00 7:46p Aldie +// Fixed func_spawns of various types and removed some unused misc classes +// +// 24 1/19/00 12:10p Steven +// Added a set mouth angle event and cleaned up dialog stuff a little. +// +// 23 1/17/00 10:20p Jimdose +// Rewrote state system initialization. Made conditionals defined with array. +// Made Evaluate functions early exit +// +// 22 1/14/00 5:01p Steven +// Added stage stuff. +// +// 21 1/13/00 7:08p Steven +// Lots and lots of cleanup. +// +// 20 1/05/00 7:25p Jimdose +// made angle functions all use the same coordinate system +// AngleVectors now returns left instead of right +// no longer need to invert pitch +// +// 19 12/22/99 5:11p Steven +// Added incoming melee and incoming projectiles checks, fixed CanWalkTo a +// little and readded turn speed stuff. +// +// 18 12/20/99 6:50p Steven +// Moved jumpxy to sentient. +// +// 17 12/19/99 8:21p Markd +// removed prioritystack.h from the header since it isn't used anymore +// +// 16 12/17/99 8:26p Jimdose +// got rid of unused vars and functions +// +// 15 12/17/99 6:11p Steven +// Added actor jump event. +// +// 14 11/19/99 4:54p Steven +// Added some deathfade stuff back in. +// +// 13 11/19/99 4:20p Steven +// Updated some of the actor saving stuff. +// +// 12 11/19/99 11:31a Steven +// Added commands so actors could tell each other to do things. +// +// 11 11/12/99 6:23p Steven +// Made state flags available to other part entities. +// +// 10 10/28/99 6:33p Markd +// Added fakeplayer ability, also added CloneEntity +// +// 9 10/27/99 10:30a Steven +// Added only shootable contents stuff. +// +// 8 10/21/99 5:24p Steven +// General AI work. +// +// 7 10/19/99 7:11p Steven +// Lots of AI work. +// +// 6 10/11/99 7:51p Steven +// Major cleanup, made it so scripting and ai could co-exist, and fixed some +// actor bugs. +// +// 5 10/07/99 5:34p Steven +// Some stimuli work. +// +// 4 10/01/99 1:39p Steven +// Event formatting. +// +// 3 9/27/99 4:42p Steven +// Fixed an animation/behavior issue dealing with the actor state machine. +// +// 2 9/20/99 5:22p Steven +// Added a canwalkto method. +// +// 1 9/10/99 10:53a Jimdose +// +// 1 9/08/99 3:15p Aldie +// +// 18 8/28/99 11:46a Steven +// Added some spinning plant stuff. +// +// 17 8/24/99 11:27a Steven +// More general AI work. +// +// 16 8/16/99 10:32a Steven +// More general AI work. +// +// 15 8/11/99 5:57p Steven +// More general AI work. +// +// 14 8/05/99 9:15a Steven +// New AI stuff. +// +// +// DESCRIPTION: +// Base class for character AI. +// + +#ifndef __ACTOR_H__ +#define __ACTOR_H__ + +#include "g_local.h" +#include "weapon.h" +#include "sentient.h" +#include "container.h" +#include "stack.h" +#include "navigate.h" +#include "behavior.h" +#include "scriptmaster.h" +#include "characterstate.h" + +extern Event EV_Actor_Start; +extern Event EV_Actor_Dead; +extern Event EV_Actor_LookAt; +extern Event EV_Actor_TurnTo; +extern Event EV_Actor_FinishedBehavior; +extern Event EV_Actor_NotifyBehavior; +extern Event EV_Actor_FinishedMove; +extern Event EV_Actor_FinishedAnim; +extern Event EV_Actor_WalkTo; +extern Event EV_Actor_RunTo; +extern Event EV_Actor_Anim; +extern Event EV_Actor_AttackFinished; +extern Event EV_Actor_Attack; +extern Event EV_Actor_AttackPlayer; +extern Event EV_Actor_AIOn; +extern Event EV_Actor_AIOff; +extern Event EV_Actor_AIDeaf; +extern Event EV_Actor_AIDumb; +extern Event EV_ActorIncomingProjectile; +extern Event EV_Anim_Done; +extern Event EV_ActorOnlyShootable; +extern Event EV_Actor_BounceOff; +extern Event EV_Actor_Push; +extern Event EV_Actor_Statemap; +extern Event EV_Actor_SetTargetable; + +// Bones used by actor + +#define ACTOR_MOUTH_TAG 0 +#define ACTOR_HEAD_TAG 1 +#define ACTOR_TORSO_TAG 2 + +// Dialog stuff + +#define LIP_SYNC_HZ 20.0 + +#define MAX_ALIAS_NAME_LENGTH 32 + +#define MAX_DIALOG_PARAMETERS_LENGTH 100 + +#define MAX_DIALOG_PARM_LENGTH 64 +#define MAX_DIALOG_PARMS 10 + +#define DIALOG_PARM_TYPE_NONE 0 +#define DIALOG_PARM_TYPE_PLAYERHAS 1 +#define DIALOG_PARM_TYPE_PLAYERHASNOT 2 +#define DIALOG_PARM_TYPE_HAS 3 +#define DIALOG_PARM_TYPE_HASNOT 4 +#define DIALOG_PARM_TYPE_DEPENDS 5 +#define DIALOG_PARM_TYPE_DEPENDSNOT 6 + +typedef struct +{ + byte type; + char parm[ MAX_DIALOG_PARM_LENGTH ]; +} DialogParm_t; + +typedef struct DialogNode_s + { + char alias_name[ MAX_ALIAS_NAME_LENGTH ]; + int random_flag; + int number_of_parms; + float random_percent; + DialogParm_t parms[ MAX_DIALOG_PARMS ]; + struct DialogNode_s *next; + } DialogNode_t; + +typedef enum + { + IS_INANIMATE, + IS_MONSTER, + IS_ENEMY, + IS_CIVILIAN, + IS_FRIEND, + IS_ANIMAL, + NUM_ACTORTYPES + } actortype_t; + +// Stimuli types + +#define STIMULI_ALL -1 +#define STIMULI_NONE 0 +#define STIMULI_SIGHT (1<<0) +#define STIMULI_SOUND (1<<1) +#define STIMULI_PAIN (1<<2) +#define STIMULI_SCRIPT (1<<3) + +#define MAX_INACTIVE_TIME 30.0 + +// State flags + +#define STATE_FLAG_IN_PAIN (1<<0) +#define STATE_FLAG_MELEE_HIT (1<<1) +#define STATE_FLAG_TOUCHED (1<<2) +#define STATE_FLAG_ACTIVATED (1<<3) +#define STATE_FLAG_USED (1<<4) +#define STATE_FLAG_TWITCH (1<<5) +#define STATE_FLAG_BLOCKED_HIT (1<<6) +#define STATE_FLAG_SMALL_PAIN (1<<7) +#define STATE_FLAG_OTHER_DIED (1<<8) +#define STATE_FLAG_STUCK (1<<9) +#define STATE_FLAG_NO_PATH (1<<10) + +// Actor modes + +#define ACTOR_MODE_NONE 0 +#define ACTOR_MODE_IDLE 1 +#define ACTOR_MODE_AI 2 +#define ACTOR_MODE_SCRIPT 3 +#define ACTOR_MODE_TALK 4 + +// Pain types + +#define PAIN_SMALL 0 +#define PAIN_BIG 1 + +typedef struct +{ + EntityPtr ent; + unsigned int state_flags; +} part_t; + +// Actor flags + +#define ACTOR_FLAG_NOISE_HEARD 0 +#define ACTOR_FLAG_INVESTIGATING 1 +#define ACTOR_FLAG_DEATHGIB 2 +#define ACTOR_FLAG_DEATHFADE 3 +#define ACTOR_FLAG_NOCHATTER 4 +#define ACTOR_FLAG_INACTIVE 5 +#define ACTOR_FLAG_ANIM_DONE 6 +#define ACTOR_FLAG_STATE_DONE_TIME_VALID 7 +#define ACTOR_FLAG_AI_ON 8 +#define ACTOR_FLAG_LAST_CANSEEENEMY 9 +#define ACTOR_FLAG_LAST_CANSEEENEMY_NOFOV 10 +#define ACTOR_FLAG_DIALOG_PLAYING 11 +#define ACTOR_FLAG_ALLOW_TALK 12 +#define ACTOR_FLAG_DAMAGE_ONCE_ON 13 +#define ACTOR_FLAG_DAMAGE_ONCE_DAMAGED 14 +#define ACTOR_FLAG_BOUNCE_OFF 15 +#define ACTOR_FLAG_NOTIFY_OTHERS_AT_DEATH 16 +#define ACTOR_FLAG_HAS_THING1 17 +#define ACTOR_FLAG_HAS_THING2 18 +#define ACTOR_FLAG_HAS_THING3 19 +#define ACTOR_FLAG_HAS_THING4 20 +#define ACTOR_FLAG_LAST_ATTACK_HIT 21 +#define ACTOR_FLAG_STARTED 22 +#define ACTOR_FLAG_ALLOW_HANGBACK 23 +#define ACTOR_FLAG_USE_GRAVITY 24 +#define ACTOR_FLAG_SPAWN_FAILED 25 +#define ACTOR_FLAG_FADING_OUT 26 +#define ACTOR_FLAG_DEATHSHRINK 27 +#define ACTOR_FLAG_DEATHSINK 28 +#define ACTOR_FLAG_STAYSOLID 29 +#define ACTOR_FLAG_STUNNED 30 +#define ACTOR_FLAG_ALLOW_FALL 31 +#define ACTOR_FLAG_FINISHED 32 +#define ACTOR_FLAG_IN_LIMBO 33 +#define ACTOR_FLAG_CAN_WALK_ON_OTHERS 34 +#define ACTOR_FLAG_PUSHABLE 35 +#define ACTOR_FLAG_LAST_TRY_TALK 36 +#define ACTOR_FLAG_ATTACKABLE_BY_ACTORS 37 +#define ACTOR_FLAG_TARGETABLE 38 +#define ACTOR_FLAG_ATTACK_ACTORS 39 +#define ACTOR_FLAG_IMMORTAL 40 +#define ACTOR_FLAG_TURNING_HEAD 41 +#define ACTOR_FLAG_DIE_COMPLETELY 42 +#define ACTOR_FLAG_BLEED_AFTER_DEATH 43 +#define ACTOR_FLAG_IGNORE_STUCK_WARNING 44 +#define ACTOR_FLAG_IGNORE_OFF_GROUND_WARNING 45 +#define ACTOR_FLAG_ALLOWED_TO_KILL 46 +#define ACTOR_FLAG_TOUCH_TRIGGERS 47 +#define ACTOR_FLAG_IGNORE_WATER 48 +#define ACTOR_FLAG_NEVER_IGNORE_SOUNDS 49 +#define ACTOR_FLAG_SIMPLE_PATHFINDING 50 +#define ACTOR_FLAG_HAVE_MOVED 51 +#define ACTOR_FLAG_NO_PAIN_SOUNDS 52 +#define ACTOR_FLAG_UPDATE_BOSS_HEALTH 53 +#define ACTOR_FLAG_IGNORE_PAIN_FROM_ACTORS 54 +#define ACTOR_FLAG_DAMAGE_ALLOWED 55 +#define ACTOR_FLAG_ALWAYS_GIVE_WATER 56 + + +// The last actor_flag number and this one (ACTOR_FLAG_MAX) should match + +#define ACTOR_FLAG_MAX 56 + +class Actor; + +typedef SafePtr ActorPtr; + +class Actor : public Sentient + { + public: + str newanim; + Event *newanimevent; + int newanimnum; + + stepmoveresult_t lastmove; + float forwardspeed; + + actortype_t actortype; + + //str state; + str animname; + + BehaviorPtr behavior; + str currentBehavior; + + PathPtr path; + + EntityPtr currentEnemy; + + unsigned int actor_flags1; + unsigned int actor_flags2; + + Vector noise_position; + float noise_time; + + float fov; + float fovdot; + float vision_distance; + + Vector startpos; + + Vector move; + Vector movedir; + float movespeed; + Vector movevelocity; + float totallen; + float turnspeed; + Vector animdir; + + float chattime; + float nextsoundtime; + + ThreadPtr scriptthread; + + ThreadPtr actorthread; + //TouchFieldPtr trig; + + float pain_threshold; + + float next_drown_time; + float air_finished; + + str kill_thread; + Vector eyeoffset; + float last_jump_time; + + str statemap_name; + StateMap *statemap; + State *currentState; + + // New stuff for ai + + float state_time; + int times_done; + float state_done_time; + int stimuli; + int permanent_stimuli; + str idle_thread; + float last_enemy_sight_time; + float next_enemy_try_sight_time; + float next_try_sleep_time; + float last_time_active; + + float max_inactive_time; + + str name; + str part_name; + + Container parts; + + EntityPtr trigger; + + str enemytype; + + unsigned int state_flags; + str command; + + EntityPtr incoming_proj; + float incoming_time; + + float actorrange_time; + float last_height; + EntityPtr last_ent; + + float canseeenemy_time; + + int stage; + + int num_of_spawns; + + ActorPtr spawnparent; + + DialogNode_t *dialog_list; + float dialog_done_time; + str dialog_state_name; + str dialog_old_state_name; + + Vector watch_offset; + + int mode; + str idle_state_name; + float next_player_near; + + int saved_mode; + BehaviorPtr saved_behavior; + ThreadPtr saved_scriptthread; + ThreadPtr saved_actorthread; + str saved_anim_name; + str saved_state_name; + str saved_anim_event_name; + + str last_anim_event_name; + + EntityPtr pickup_ent; + + int pain_type; + Vector pain_angles; + int bullet_hits; + + float stunned_end_time; + + Container spawn_items; + float spawn_chance; + + str bounce_off_effect; + + Vector last_attack_pos; + Vector last_attack_enemy_pos; + EntityPtr last_attack_entity_hit; + Vector last_attack_entity_hit_pos; + + Vector last_known_enemy_pos; + + Container can_be_finsihed_by_mods; + + float feet_width; + + Vector last_origin; + + float next_find_enemy_time; + + float minimum_melee_height; + float damage_angles; + + float real_head_pitch; + + float next_pain_sound_time; + + float last_ground_z; + + float water_level; + + float max_boss_health; + + static Condition Conditions[]; + + Container conditionals; + + CLASS_PROTOTYPE( Actor ); + + // Initialization functions + Actor(); + ~Actor(); + void Start( Event *ev ); + + void Sleep( void ); + void Sleep( Event *ev ); + void Wakeup( void ); + void Wakeup( Event *ev ); + + // Vision functions + qboolean WithinVisionDistance( Entity *ent ); + qboolean InFOV( Vector pos, float check_fov, float check_fovdot ); + qboolean InFOV( Vector pos ); + qboolean InFOV( Entity *ent ); + qboolean CanSeeFOV( Entity *ent ); + qboolean CanSeeFrom( Vector pos, Entity *ent ); + qboolean CanSee( Entity *ent ); + qboolean EnemyCanSeeMeFrom( Vector pos ); + qboolean CanSeeEnemyFrom( Vector pos ); + qboolean CanReallySee( Entity *ent ); + + // Combat functions + void MeleeEvent( Event *ev ); + void ChargeWater( Event *ev ); + void DamageOnceStart( Event *ev ); + void DamageOnceStop( Event *ev ); + void DamageAllowed( Event *ev ); + virtual qboolean CanShootFrom( Vector pos, Entity *ent, qboolean usecurrentangles ); + virtual qboolean CanShoot( Entity *ent, qboolean usecurrentangles ); + void FireProjectile( Event *ev ); + void FireBullet( Event *ev ); + void SaveAttack( Vector orig, Vector dir ); + qboolean TestAttack( str tag_name ); + void IncomingProjectile( Event *ev ); + qboolean EntityHasFireType( Entity *ent, firetype_t fire_type ); + void DamageEnemy( Event *ev ); + void TurnTowardsEnemy( Event *ev ); + void AttackModeEvent( Event *ev ); + qboolean ShouldAttackEntity( Entity *ent ); + void SetAttackableByActors( Event *ev ); + void SetAttackActors( Event *ev ); + void MinimumMeleeHeight( Event *ev ); + void SetDamageAngles( Event *ev ); + void SetImmortal( Event *ev ); + qboolean IsImmortal( void ); + + + // Enemy management + void ClearEnemies( void ); + qboolean HasEnemies( void ); + qboolean IsEnemy( Entity *ent ); + void MakeEnemy( Entity *ent, qboolean force = false ); + qboolean Likes( Entity *ent ); + qboolean Hates( Entity *ent ); + void FindEnemy( void ); + Entity *FindNearestEnemy( void ); + void GetNearestEnemy( Event *ev ); + void GetRandomEnemy( Event *ev ); + + // Targeting functions + qboolean CloseToEnemy( Vector pos, float howclose ); + qboolean EntityInRange( Entity *ent, float range, float min_height, float max_height ); + void EyeOffset( Event *ev ); + + // Actor type script commands + void FriendEvent( Event *ev ); + void CivilianEvent( Event *ev ); + void EnemyEvent( Event *ev ); + void InanimateEvent( Event *ev ); + void MonsterEvent( Event *ev ); + void AnimalEvent( Event *ev ); + void SetEnemyType( Event *ev ); + + // State machine functions + void SetIdleStateName( Event *ev ); + void SetState( const char *state_name ); + void InitState( void ); + void LoadStateMap( Event *ev ); + void ProcessActorStateMachine( void ); + + // Thread management + void SetupThread( str filename, str label ); + void EndThread( Event *ev ); + void SetThread( Event *ev ); + void RunThread( Event *ev ); + void SetThread( str filename, str label ); + void ProcessScript( ScriptThread *thread, Event *ev = NULL ); + ScriptVariable *SetVariable( const char *name, float value ); + ScriptVariable *SetVariable( const char *name, int value ); + ScriptVariable *SetVariable( const char *name, const char *text ); + ScriptVariable *SetVariable( const char *name, str &text ); + ScriptVariable *SetVariable( const char *name, Entity *ent ); + ScriptVariable *SetVariable( const char *name, Vector &vec ); + + // Behavior management + void SendMoveDone( ScriptThread *script_thread ); + void EndBehavior( void ); + void SetBehavior( Behavior *newbehavior, Event *argevent = NULL, ScriptThread *thread = NULL ); + void FinishedBehavior( Event *ev ); + void NotifyBehavior( Event *ev ); + + // Path and node management + PathNode *NearestNodeInPVS( Vector pos ); + void SetPath( Path *newpath ); + void ReserveNodeEvent( Event *ev ); + void ReleaseNodeEvent( Event *ev ); + + // Animation control functions + void RemoveAnimDoneEvent( void ); + void ChangeAnim( void ); + qboolean SetAnim( str anim, Event *ev = NULL ); + qboolean SetAnim( str anim, Event &ev ); + void AnimDone( Event *ev ); + + // Script commands + void IdleEvent( Event *ev ); + void LookAt( Event *ev ); + void TurnToEvent( Event *ev ); + void HeadWatchEvent( Event *ev ); + void ResetHeadEvent( Event *ev ); + void WalkTo( Event *ev ); + void WalkWatch( Event *ev ); + void RunTo( Event *ev ); + void WarpTo( Event *ev ); + void PickupEnt( Event *ev ); + void ThrowEnt( Event *ev ); + void AttackEntity( Event *ev ); + void AttackPlayer( Event *ev ); + void JumpToEvent( Event *ev ); + void GotoEvent( Event *ev ); + void Anim( Event *ev ); + void RepostEvent( Event *ev, Event &event_type ); + + // Script conditionals + void IfEnemyVisibleEvent( Event *ev ); + void IfNearEvent( Event *ev ); + void IfCanHideAtEvent( Event *ev ); + void IfEnemyWithinEvent( Event *ev ); + + // Sound reaction functions + void NoPainSounds( Event *ev ); + void HeardSound( Event *ev ); + qboolean IgnoreSounds( void ); + void NeverIgnoreSounds( Event *ev ); + + // Pain and death related functions + void Pain( Event *ev ); + void StunEvent( Event *ev ); + void CheckStun( void ); + void Dead( Event *ev ); + void Killed( Event *ev ); + void KilledEffects( Entity *attacker ); + void SetDieCompletely( Event *ev ); + void SetBleedAfterDeath( Event *ev ); + void RemoveUselessBody( Event *ev ); + void SetPainThresholdEvent( Event *ev ); + void SetKillThreadEvent( Event *ev ); + void DeathFadeEvent( Event *ev ); + void DeathShrinkEvent( Event *ev ); + void DeathSinkEvent( Event *ev ); + void StaySolidEvent( Event *ev ); + void SpawnGib( Event *ev ); + void SpawnGibAtTag( Event *ev ); + void RealSpawnGib( qboolean use_tag, Event *ev ); + void SpawnNamedGib( Event *ev ); + float SpawnGetTime( float vel, Vector orig, Vector gib_mins, Vector gib_maxs ); + void SpawnBlood( Event *ev ); + void Suicide( Event *ev ); + void SetDeathSize( Event *ev ); + void FadeEvent( Event *ev ); + + // Movement functions + void SimplePathfinding( Event *ev ); + void SetCanWalkOnOthers( Event *ev ); + void SetFeetWidth( Event *ev ); + void ForwardSpeedEvent( Event *ev ); + void SwimEvent( Event *ev ); + void FlyEvent( Event *ev ); + void NotLandEvent( Event *ev ); + qboolean CanMoveTo( Vector pos ); + qboolean CanWalkTo( Vector pos, int entnum = ENTITYNUM_NONE ); + void Accelerate( Vector steering ); + void CalcMove( void ); + void setAngles( Vector ang ); + stepmoveresult_t WaterMove( void ); + stepmoveresult_t AirMove( void ); + stepmoveresult_t TryMove( void ); + void Push( Event *ev ); + qboolean Push( Vector dir ); + void Pushable( Event *ev ); + void CheckWater( void ); + float JumpTo( PathNode * goal, float speed ); + float JumpTo( Entity * goal, float speed ); + float JumpTo( Vector targ, float speed ); + + // Debug functions + void ShowInfo( void ); + + // Stimuli functions + void Stimuli( int stimuli, Entity *ent, qboolean force = false ); + void Stimuli( int stimuli, Vector pos ); + void StimuliNoAttack( int stimuli ); + void Deaf( Event *ev ); + void PermanentDeaf( Event *ev ); + void PermanentBlind( Event *ev ); + qboolean IsBlind( void ); + void Dumb( Event *ev ); + //qboolean IsAIActive( void ); + void SetIdleThread( Event *ev ); + bool RespondToStimuli( int new_stimuli ); + void ActivateAI( void ); + void TurnAIOn( Event *ev ); + void TurnAIOff( Event *ev ); + + // Parts functions + + void RegisterParts( Event *ev ); + void RegisterSelf( Event *ev ); + void PartName( Event *ev ); + Actor *FindPartActor( const char *name ); + void SendCommand( Event *ev ); + + // Dialog functions + void AddDialog ( Event *ev ); + DialogNode_t *NewDialogNode(void); + void AddDialogParms( DialogNode_t *dialog_node, Event *ev ); + void PlayDialog( Sentient *user, float volume = -1.0, float min_dist = -1.0, + const char *dialog_name = NULL, const char *state_name = NULL ); + void FreeDialogList( void ); + void DialogDone( Event *ev ); + void PlayDialog( Event *ev ); + void StopDialog( Event *ev ); + void HeadTwitch( Event *ev ); + void HeadTwitchEveryFrame( Event *ev ); + float GetDialogRemainingTime( void ); + void SetMouthAngle( Event *ev ); + + // Mode functions + + qboolean ModeAllowed( int new_mode ); + void StartMode( int new_mode ); + void EndMode( void ); + void SaveMode( void ); + void RestoreMode( void ); + + // Finishing functions + + qboolean CanBeFinished( void ); + qboolean CanBeFinishedBy( int meansofdeath ); + void SetCanBeFinishedBy( Event *ev ); + void Finish( int meansofdeath ); + void StartLimbo( void ); + qboolean InLimbo( void ); + + // General functions + + void AlwaysGiveWater( Event *ev ); + void IgnorePainFromActors( Event *ev ); + void UpdateBossHealth( Event *ev ); + void SetMaxBossHealth( Event *ev ); + void SetWaterLevel( Event *ev ); + void IncrementNumSpawns( Event *ev ); + void DecrementNumSpawns( Event *ev ); + void TouchTriggers( Event *ev ); + void IgnoreWater( Event *ev ); + void SetNotAllowedToKill( Event *ev ); + void IgnorePlacementWarning( Event *ev ); + void SetTargetable( Event *ev ); + qboolean CanTarget( void ); + void AddSpawnItem( Event *ev ); + void SetSpawnChance( Event *ev ); + void ClearSpawnItems( Event *ev ); + void SpawnItems( void ); + void SpawnItem( str spawn_item_name ); + qboolean CanJump( void ); + void SetUseGravity( Event *ev ); + void SetAllowFall( Event *ev ); + void SetUseMovement( Event *ev ); + void SetHaveThing( Event *ev ); + void SetActorFlag( int flag, qboolean flag_value ); + qboolean GetActorFlag( int flag ); + void SetBounceOff( Event *ev ); + void BounceOffEvent( Event *ev ); + void SetBounceOffEffect( Event *ev ); + void NotifyOthersAtDeath( Event *ev ); + void NotifyOthersOfDeath( void ); + void GotoNextStage( Event *ev ); + void GotoPrevStage( Event *ev ); + void GotoStage( Event *ev ); + void Pickup( Event *ev ); + void Throw( Event *ev ); + void SetWatchOffset( Event *ev ); + void SetMaxInactiveTime( Event *ev ); + void SetTurnSpeed( Event *ev ); + void SetHealth( Event *ev ); + void AddHealth( Event *ev ); + virtual void setSize( Vector min, Vector max ); + void SetFov( Event *ev ); + void SetVisionDistance( Event *ev ); + void NoChatterEvent( Event *ev ); + virtual void Chatter( const char *sound, float chance = 10, float volume = 1.0f, int channel = CHAN_VOICE ); + void ActivateEvent( Event *ev ); + void UseEvent( Event *ev ); + void Think( void ); + void Active( Event *ev ); + bool IsEntityAlive( Entity *ent ); + void Name( Event *ev ); + void SetupTriggerField( Event *ev ); + void TriggerTouched( Event *ev ); + qboolean GetClosestTag( str tag_name, int number_of_tags, Vector target, Vector *orig ); + void AddStateFlag( unsigned int flag ); + void ClearStateFlags( void ); + void OnlyShootable( Event *ev ); + void SpawnActorAtTag( Event *ev ); + void SpawnActorAtLocation( Event *ev ); + void SpawnActor( str model_name, Vector orig, Vector ang, int how_many, qboolean attack, float width, float height ); + void TryTalkToPlayer( void ); + void AllowTalk( Event *ev ); + void AllowHangBack( Event *ev ); + void SolidMask( Event *ev ); + void IgnoreMonsterClip( Event *ev ); + void NotSolidMask( Event *ev ); + void NoMask( Event *ev ); + void SetMask( Event *ev ); + + qboolean CheckBottom( void ); + + void ChangeType( Event *ev ); + + void GetStateAnims( Container *c ); + + void Touched( Event *ev ); + + // State machine conditions + qboolean returntrue( Conditional &condition ); + qboolean checkanimname( Conditional &condition ); + qboolean checkinactive( Conditional &condition ); + qboolean checkanimdone( Conditional &condition ); + qboolean checkdead( Conditional &condition ); + qboolean checkhaveenemy( Conditional &condition ); + qboolean checkenemydead( Conditional &condition ); + qboolean checkenemynoclip( Conditional &condition ); + qboolean checkcanseeenemy( Conditional &condition ); + qboolean checkcanshootenemy( Conditional &condition ); + qboolean checkenemyinfov( Conditional &condition ); + qboolean checkenemyonground( Conditional &condition ); + qboolean checkenemyrelativeyaw( Conditional &condition ); + qboolean checkcanjumptoenemy( Conditional &condition ); + qboolean checkcanflytoenemy( Conditional &condition ); + qboolean checkinpain( Conditional &condition ); + qboolean checksmallpain( Conditional &condition ); + qboolean checkpainyaw( Conditional &condition ); + qboolean checkpainpitch( Conditional &condition ); + qboolean checkstunned( Conditional &condition ); + qboolean checkfinished( Conditional &condition ); + qboolean checkmeleehit( Conditional &condition ); + qboolean checkblockedhit( Conditional &condition ); + qboolean checkblocked( Conditional &condition ); + qboolean checkonfire( Conditional &condition ); + qboolean checkotherdied( Conditional &condition ); + qboolean checkstuck( Conditional &condition ); + qboolean checknopath( Conditional &condition ); + qboolean checkbehaviordone( Conditional &condition ); + qboolean checktimedone( Conditional &condition ); + qboolean checkdone( Conditional &condition ); + qboolean checkenemyrange( Conditional &condition ); + qboolean checkplayerrange( Conditional &condition ); + qboolean checkmovingactorrange( Conditional &condition ); + qboolean checkchance( Conditional &condition ); + qboolean checkstatetime( Conditional &condition ); + qboolean checktimesdone( Conditional &condition ); + qboolean checkmeansofdeath( Conditional &condition ); + qboolean checknoiseheard( Conditional &condition ); + qboolean checkpartstate( Conditional &condition ); + qboolean checkpartflag( Conditional &condition ); + qboolean checkpartdead( Conditional &condition ); + qboolean checknumspawns( Conditional &condition ); + qboolean checkcommand( Conditional &condition ); + qboolean checktouched( Conditional &condition ); + qboolean checkactivated( Conditional &condition ); + qboolean checkused( Conditional &condition ); + qboolean checktwitch( Conditional &condition ); + qboolean checkhealth( Conditional &condition ); + qboolean checkonground( Conditional &condition ); + qboolean checkinwater( Conditional &condition ); + qboolean checkincomingmeleeattack( Conditional &condition ); + qboolean checkincomingprojectile( Conditional &condition ); + qboolean checkenemystunned( Conditional &condition ); + qboolean checkenemyinpath( Conditional &condition ); + qboolean checkstage( Conditional &condition ); + qboolean checkheld( Conditional &condition ); + qboolean checkenemymelee( Conditional &condition ); + qboolean checkenemyranged( Conditional &condition ); + qboolean checkenemyshield( Conditional &condition ); + qboolean checkhasthing( Conditional &condition ); + qboolean checkallowhangback( Conditional &condition ); + qboolean checkname( Conditional &condition ); + + virtual void Archive( Archiver &arc ); + }; + +#define SAVE_FLAG_NEW_ANIM (1<<0) +#define SAVE_FLAG_FORWARD_SPEED (1<<1) +#define SAVE_FLAG_BEHAVIOR (1<<2) +#define SAVE_FLAG_PATH (1<<3) +#define SAVE_FLAG_NOISE (1<<4) +#define SAVE_FLAG_SCRIPT_THREAD (1<<5) +#define SAVE_FLAG_ACTOR_THREAD (1<<6) +#define SAVE_FLAG_KILL_THREAD (1<<7) +#define SAVE_FLAG_STATE (1<<8) +#define SAVE_FLAG_IDLE_THREAD (1<<7) +#define SAVE_FLAG_PARTS (1<<10) +#define SAVE_FLAG_TRIGGER (1<<11) +#define SAVE_FLAG_STATE_FLAGS (1<<12) +#define SAVE_FLAG_COMMAND (1<<13) +#define SAVE_FLAG_STAGE (1<<14) +#define SAVE_FLAG_NUM_OF_SPAWNS (1<<15) +#define SAVE_FLAG_SPAWN_PARENT (1<<16) +#define SAVE_FLAG_DIALOG (1<<17) +#define SAVE_FLAG_SAVED_STUFF (1<<18) +#define SAVE_FLAG_LAST_ANIM_EVENT (1<<19) +#define SAVE_FLAG_PICKUP_ENT (1<<20) +#define SAVE_FLAG_PAIN (1<<21) +#define SAVE_FLAG_SPAWN_ITEMS (1<<22) + +inline void Actor::Archive + ( + Archiver &arc + ) + { + //unsigned int save_flags; + str temp_state_name; + qboolean temp_bool; + + Sentient::Archive( arc ); + + arc.ArchiveString( &newanim ); + arc.ArchiveEventPointer( &newanimevent ); + arc.ArchiveInteger( &newanimnum ); + + arc.ArchiveInteger( (int *)&lastmove ); + arc.ArchiveFloat( &forwardspeed ); + + arc.ArchiveInteger( (int *)&actortype ); + + arc.ArchiveString( &animname ); + + if ( arc.Saving() ) + { + if ( behavior ) + { + temp_bool = true; + arc.ArchiveBoolean( &temp_bool ); + arc.ArchiveObject( behavior ); + } + else + { + temp_bool = false; + arc.ArchiveBoolean( &temp_bool ); + } + } + else + { + arc.ArchiveBoolean( &temp_bool ); + + if ( temp_bool ) + { + behavior = ( Behavior * )arc.ReadObject(); + currentBehavior = behavior->getClassname(); + } + else + { + behavior = NULL; + currentBehavior = ""; + } + } + + arc.ArchiveSafePointer( &path ); + + arc.ArchiveSafePointer( ¤tEnemy ); + + arc.ArchiveUnsigned( &actor_flags1 ); + arc.ArchiveUnsigned( &actor_flags2 ); + + arc.ArchiveVector ( &noise_position ); + arc.ArchiveFloat( &noise_time ); + + arc.ArchiveFloat( &fov ); + arc.ArchiveFloat( &fovdot ); + arc.ArchiveFloat( &vision_distance ); + + arc.ArchiveVector ( &startpos ); + + arc.ArchiveVector ( &move ); + arc.ArchiveVector ( &movedir ); + arc.ArchiveFloat ( &movespeed ); + arc.ArchiveVector ( &movevelocity ); + arc.ArchiveFloat ( &totallen ); + arc.ArchiveFloat ( &turnspeed ); + arc.ArchiveVector ( &animdir ); + + arc.ArchiveFloat ( &chattime ); + arc.ArchiveFloat ( &nextsoundtime ); + + arc.ArchiveSafePointer( &scriptthread ); + arc.ArchiveSafePointer( &actorthread ); + + arc.ArchiveFloat( &pain_threshold ); + + arc.ArchiveFloat( &next_drown_time ); + arc.ArchiveFloat( &air_finished ); + + arc.ArchiveString( &kill_thread ); + arc.ArchiveVector( &eyeoffset ); + arc.ArchiveFloat( &last_jump_time ); + + if ( arc.Saving() ) + { + + arc.ArchiveString( &statemap_name ); + + if ( currentState ) + temp_state_name = currentState->getName(); + + arc.ArchiveString( &temp_state_name ); + } + else + { + arc.ArchiveString( &statemap_name ); + + if ( statemap_name.length() ) + { + Event *event; + + event = new Event( EV_Actor_Statemap ); + event->AddString( statemap_name.c_str() ); + event->AddString( "" ); + event->AddInteger( 1 ); + ProcessEvent( event ); + } + + arc.ArchiveString( &temp_state_name ); + + if ( statemap ) + currentState = statemap->FindState( temp_state_name.c_str() ); + } + + arc.ArchiveFloat( &state_time ); + arc.ArchiveInteger( ×_done ); + arc.ArchiveFloat( &state_done_time ); + arc.ArchiveInteger( &stimuli ); + arc.ArchiveInteger( &permanent_stimuli ); + arc.ArchiveString( &idle_thread ); + arc.ArchiveFloat( &last_enemy_sight_time ); + arc.ArchiveFloat( &next_enemy_try_sight_time ); + arc.ArchiveFloat( &next_try_sleep_time ); + arc.ArchiveFloat( &last_time_active ); + + arc.ArchiveFloat( &max_inactive_time ); + + arc.ArchiveString( &name ); + arc.ArchiveString( &part_name ); + + { + part_t part; + int current_part; + int number_of_parts; + part_t *part_ptr; + + if ( arc.Saving() ) + { + number_of_parts = parts.NumObjects(); + } + else + { + parts.ClearObjectList(); + } + + arc.ArchiveInteger( &number_of_parts ); + + if ( arc.Loading() ) + parts.Resize( number_of_parts ); + + for( current_part = 1; current_part <= number_of_parts ; current_part++ ) + { + if ( arc.Saving() ) + { + part = parts.ObjectAt( current_part ); + part_ptr = ∂ + } + else + { + parts.AddObject( part ); + part_ptr = parts.AddressOfObjectAt( current_part ); + } + + arc.ArchiveSafePointer( &part_ptr->ent ); + arc.ArchiveUnsigned( &part_ptr->state_flags ); + } + } + + arc.ArchiveSafePointer( &trigger ); + + arc.ArchiveString( &enemytype ); + + arc.ArchiveUnsigned( &state_flags ); + arc.ArchiveString( &command ); + + arc.ArchiveSafePointer( &incoming_proj ); + arc.ArchiveFloat( &incoming_time ); + + arc.ArchiveFloat( &actorrange_time ); + arc.ArchiveFloat( &last_height ); + arc.ArchiveSafePointer( &last_ent ); + + arc.ArchiveFloat( &canseeenemy_time ); + + arc.ArchiveInteger( &stage ); + + arc.ArchiveInteger( &num_of_spawns ); + + arc.ArchiveSafePointer( &spawnparent ); + +// DialogNode_t *dialog_list; + + // Save dialog stuff + + if ( arc.Saving() ) + { + DialogNode_t *dialog_node; + byte more; + str alias_name; + str parm; + int current_parm; + + dialog_node = dialog_list; + + while( dialog_node ) + { + more = true; + arc.ArchiveByte( &more ); + + alias_name = dialog_node->alias_name; + + arc.ArchiveString( &alias_name ); + arc.ArchiveInteger( &dialog_node->random_flag ); + arc.ArchiveFloat( &dialog_node->random_percent ); + arc.ArchiveInteger( &dialog_node->number_of_parms ); + + for( current_parm = 0 ; current_parm < dialog_node->number_of_parms ; current_parm++ ) + { + arc.ArchiveByte( &dialog_node->parms[ current_parm ].type ); + + parm = dialog_node->parms[ current_parm ].parm; + + arc.ArchiveString( &parm ); + } + + dialog_node = dialog_node->next; + } + + more = false; + arc.ArchiveByte( &more ); + } + else + { + byte more; + DialogNode_t *new_dialog_node; + DialogNode_t *current_dialog_node = NULL; + str alias_name; + str parm; + int current_parm; + + arc.ArchiveByte( &more ); + + while( more ) + { + new_dialog_node = NewDialogNode(); + + if ( current_dialog_node ) + current_dialog_node->next = new_dialog_node; + else + dialog_list = new_dialog_node; + + current_dialog_node = new_dialog_node; + new_dialog_node->next = NULL; + + arc.ArchiveString( &alias_name ); + strcpy( new_dialog_node->alias_name, alias_name.c_str() ); + + arc.ArchiveInteger( &new_dialog_node->random_flag ); + arc.ArchiveFloat( &new_dialog_node->random_percent ); + arc.ArchiveInteger( &new_dialog_node->number_of_parms ); + + for( current_parm = 0 ; current_parm < new_dialog_node->number_of_parms ; current_parm++ ) + { + arc.ArchiveByte( &new_dialog_node->parms[ current_parm ].type ); + + arc.ArchiveString( &parm ); + strcpy( new_dialog_node->parms[ current_parm ].parm, parm.c_str() ); + } + + arc.ArchiveByte( &more ); + } + } + + arc.ArchiveFloat( &dialog_done_time ); + arc.ArchiveString( &dialog_state_name ); + arc.ArchiveString( &dialog_old_state_name ); + + arc.ArchiveVector( &watch_offset ); + + arc.ArchiveInteger( &mode ); + arc.ArchiveString( &idle_state_name ); + arc.ArchiveFloat( &next_player_near ); + + arc.ArchiveInteger( &saved_mode ); + + if ( arc.Saving() ) + { + if ( saved_behavior ) + { + temp_bool = true; + arc.ArchiveBoolean( &temp_bool ); + arc.ArchiveObject( saved_behavior ); + } + else + { + temp_bool = false; + arc.ArchiveBoolean( &temp_bool ); + } + } + else + { + arc.ArchiveBoolean( &temp_bool ); + + if ( temp_bool ) + saved_behavior = ( Behavior * )arc.ReadObject(); + else + saved_behavior = NULL; + } + + arc.ArchiveSafePointer( &saved_scriptthread ); + arc.ArchiveSafePointer( &saved_actorthread ); + arc.ArchiveString( &saved_anim_name ); + arc.ArchiveString( &saved_state_name ); + arc.ArchiveString( &saved_anim_event_name ); + + arc.ArchiveString( &last_anim_event_name ); + + arc.ArchiveSafePointer( &pickup_ent ); + + arc.ArchiveInteger( &pain_type ); + arc.ArchiveVector( &pain_angles ); + arc.ArchiveInteger( &bullet_hits ); + + arc.ArchiveFloat( &stunned_end_time ); + + spawn_items.Archive( arc ); + + arc.ArchiveFloat( &spawn_chance ); + + arc.ArchiveString( &bounce_off_effect ); + + arc.ArchiveVector( &last_attack_pos ); + arc.ArchiveVector( &last_attack_enemy_pos ); + arc.ArchiveSafePointer( &last_attack_entity_hit ); + arc.ArchiveVector( &last_attack_entity_hit_pos ); + + arc.ArchiveVector( &last_known_enemy_pos ); + + can_be_finsihed_by_mods.Archive( arc ); + + arc.ArchiveFloat( &feet_width ); + + arc.ArchiveVector( &last_origin ); + + arc.ArchiveFloat( &next_find_enemy_time ); + + arc.ArchiveFloat( &minimum_melee_height ); + arc.ArchiveFloat( &damage_angles ); + + arc.ArchiveFloat( &real_head_pitch ); + + arc.ArchiveFloat( &next_pain_sound_time ); + + arc.ArchiveFloat( &last_ground_z ); + + arc.ArchiveFloat( &water_level ); + + arc.ArchiveFloat( &max_boss_health ); + + if ( flags & FL_THINK ) + Wakeup(); + else + Sleep(); + + /* if ( arc.Saving() ) + { + // Determine the save flags + save_flags = 0; + + if ( newanim.length() ) + save_flags |= SAVE_FLAG_NEW_ANIM; + + if ( forwardspeed ) + save_flags |= SAVE_FLAG_FORWARD_SPEED; + + if ( behavior != NULL ) + save_flags |= SAVE_FLAG_BEHAVIOR; + + if ( path != NULL ) + save_flags |= SAVE_FLAG_PATH; + + if ( GetActorFlag( ACTOR_FLAG_NOISE_HEARD ) ) + save_flags |= SAVE_FLAG_NOISE; + + if ( scriptthread ) + save_flags |= SAVE_FLAG_SCRIPT_THREAD; + + if ( actorthread ) + save_flags |= SAVE_FLAG_ACTOR_THREAD; + + if ( kill_thread ) + save_flags |= SAVE_FLAG_KILL_THREAD; + + if ( currentState ) + save_flags |= SAVE_FLAG_STATE; + + if ( idle_thread ) + save_flags |= SAVE_FLAG_IDLE_THREAD; + + if ( parts.NumObjects() ) + save_flags |= SAVE_FLAG_PARTS; + + if ( trigger ) + save_flags |= SAVE_FLAG_TRIGGER; + + if ( state_flags ) + save_flags |= SAVE_FLAG_STATE_FLAGS; + + if ( command.length() ) + save_flags |= SAVE_FLAG_COMMAND; + + if ( stage ) + save_flags |= SAVE_FLAG_STAGE; + + if ( num_of_spawns ) + save_flags |= SAVE_FLAG_NUM_OF_SPAWNS; + + if ( spawnparent ) + save_flags |= SAVE_FLAG_SPAWN_PARENT; + + if ( GetActorFlag( ACTOR_FLAG_DIALOG_PLAYING ) ) + save_flags |= SAVE_FLAG_DIALOG; + + if ( saved_mode != ACTOR_MODE_NONE ) + save_flags |= SAVE_FLAG_SAVED_STUFF; + + if ( last_anim_event != NULL ) + save_flags |= SAVE_FLAG_LAST_ANIM_EVENT; + + if ( pickup_ent ) + save_flags |= SAVE_FLAG_PICKUP_ENT; + + if ( ( state_flags & STATE_FLAG_SMALL_PAIN ) || ( state_flags & STATE_FLAG_IN_PAIN ) ) + save_flags |= SAVE_FLAG_PAIN; + + if ( spawn_items.NumObjects() ) + save_flags |= SAVE_FLAG_SPAWN_ITEMS; + } + + // Save the save flags + + arc.ArchiveUnsigned( &save_flags ); + + // Add needed fields + + if ( save_flags & SAVE_FLAG_NEW_ANIM ) + { + arc.ArchiveString( &newanim ); + arc.ArchiveEventPointer( &newanimevent ); + arc.ArchiveInteger( &newanimnum ); + } + + if ( save_flags & SAVE_FLAG_FORWARD_SPEED ) + arc.ArchiveFloat( &forwardspeed ); + + arc.ArchiveString( &animname ); + + if ( save_flags & SAVE_FLAG_BEHAVIOR ) + { + if ( arc.Saving() ) + { + arc.ArchiveObject( behavior ); + } + else + { + behavior = ( Behavior * )arc.ReadObject(); + currentBehavior = behavior->getClassname(); + } + } + + if ( save_flags & SAVE_FLAG_PATH ) + arc.ArchiveSafePointer( &path ); + + arc.ArchiveSafePointer( ¤tEnemy ); + + arc.ArchiveUnsigned( &actor_flags1 ); + arc.ArchiveUnsigned( &actor_flags2 ); + + if ( save_flags & SAVE_FLAG_NOISE ) + { + arc.ArchiveVector( &noise_position ); + arc.ArchiveFloat( &noise_time ); + } + + arc.ArchiveFloat( &turnspeed ); + + if ( save_flags & SAVE_FLAG_SCRIPT_THREAD ) + arc.ArchiveSafePointer( &scriptthread ); + + if ( save_flags & SAVE_FLAG_ACTOR_THREAD ) + arc.ArchiveSafePointer( &actorthread ); + + if ( save_flags & SAVE_FLAG_KILL_THREAD ) + arc.ArchiveString( &kill_thread ); + + if ( save_flags & SAVE_FLAG_STATE ) + { + str temp_name; + + if ( arc.Saving() ) + { + temp_name = currentState->getName(); + } + arc.ArchiveString( &temp_name ); + if ( arc.Loading() ) + { + SetState( temp_name ); + } + } + + arc.ArchiveInteger( &stimuli ); + + if ( save_flags & SAVE_FLAG_IDLE_THREAD ) + arc.ArchiveString( &idle_thread ); + + if ( arc.Loading() ) + { + last_enemy_sight_time = level.time; + last_time_active = level.time; + } + + arc.ArchiveFloat( &max_inactive_time ); + + if ( save_flags & SAVE_FLAG_PARTS ) + { + part_t part; + int current_part; + int number_of_parts; + + if ( arc.Saving() ) + { + number_of_parts = parts.NumObjects(); + } + else + { + parts.ClearObjectList(); + } + + arc.ArchiveInteger( &number_of_parts ); + + for( current_part = 1; current_part <= number_of_parts ; current_part++ ) + { + if ( arc.Saving() ) + { + part = parts.ObjectAt( current_part ); + } + arc.ArchiveSafePointer( &part.ent ); + arc.ArchiveUnsigned( &part.state_flags ); + if ( arc.Loading() ) + { + parts.AddObject( part ); + } + } + } + + if ( save_flags & SAVE_FLAG_TRIGGER ) + arc.ArchiveSafePointer( &trigger ); + + if ( save_flags & SAVE_FLAG_STATE_FLAGS ) + arc.ArchiveUnsigned( &state_flags ); + + if ( save_flags & SAVE_FLAG_COMMAND ) + arc.ArchiveString( &command ); + + if ( save_flags & SAVE_FLAG_STAGE ) + { + arc.ArchiveInteger( &stage ); + } + + if ( save_flags & SAVE_FLAG_NUM_OF_SPAWNS ) + arc.ArchiveInteger( &num_of_spawns ); + + if ( save_flags & SAVE_FLAG_SPAWN_PARENT ) + arc.ArchiveSafePointer( &spawnparent ); + + if ( save_flags & SAVE_FLAG_DIALOG ) + { + arc.ArchiveFloat( &dialog_done_time ); + arc.ArchiveString( &dialog_state_name ); + arc.ArchiveString( &dialog_old_state_name ); + } + + arc.ArchiveInteger( &mode ); + + if ( save_flags & SAVE_FLAG_SAVED_STUFF ) + { + bool tempBool; + + arc.ArchiveInteger( &saved_mode ); + + tempBool = ( saved_behavior != NULL ); + arc.ArchiveBool( &tempBool ); + if ( tempBool ) + { + if ( arc.Saving() ) + { + arc.ArchiveObject( saved_behavior ); + } + else + { + Behavior * behavior; + + behavior = ( Behavior * )arc.ReadObject(); + saved_behavior = behavior; + } + } + + arc.ArchiveSafePointer( &saved_scriptthread ); + arc.ArchiveSafePointer( &saved_actorthread ); + + arc.ArchiveString( &saved_anim_name ); + arc.ArchiveString( &saved_state_name ); + + arc.ArchiveEventPointer( &saved_anim_event ); + } + + if ( arc.Loading() ) + { + stunned_end_time = level.time; + } + + if ( save_flags & SAVE_FLAG_LAST_ANIM_EVENT ) + { + arc.ArchiveEventPointer( &last_anim_event ); + } + + if ( save_flags & SAVE_FLAG_PICKUP_ENT ) + arc.ArchiveSafePointer( &pickup_ent ); + + if ( save_flags & SAVE_FLAG_PAIN ) + { + arc.ArchiveInteger( &pain_type ); + arc.ArchiveVector( &pain_angles ); + } + + if ( save_flags & SAVE_FLAG_SPAWN_ITEMS ) + { + spawn_items.Archive( arc ); + } + + if ( arc.Loading() ) + { + last_origin = origin + "1 1 1"; + } */ + } + +// Set destination to node with duck or cover set. Class will find a path to that node, or a closer one. +class FindCoverMovement : public StandardMovement + { + public: + Actor *self; + + inline qboolean validpath + ( + PathNode *node, + int i + ) + + { + pathway_t *path; + PathNode *n; + + path = &node->Child[ i ]; + + if ( !StandardMovement::validpath( node, i ) ) + { + return false; + } + + n = AI_GetNode( path->node ); + if ( !n || self->CloseToEnemy( n->origin, 128 ) ) + { + return false; + } + + return true; + } + + inline qboolean done + ( + PathNode *node, + PathNode *end + ) + + { + if ( node == end ) + { + return true; + } + + //if ( node->reject ) + if ( node->reject || !( node->nodeflags & ( AI_DUCK | AI_COVER ) ) ) + { + return false; + } + + if ( self ) + { + node->reject = self->CanSeeEnemyFrom( node->origin ); + return !node->reject; + } + + return false; + } + }; + +// Set destination to node with flee set. Class will find a path to that node, or a closer one. +class FindFleeMovement : public StandardMovement + { + public: + Actor *self; + + inline qboolean validpath + ( + PathNode *node, + int i + ) + + { + pathway_t *path; + PathNode *n; + + path = &node->Child[ i ]; + + if ( !StandardMovement::validpath( node, i ) ) + { + return false; + } + + n = AI_GetNode( path->node ); + if ( !n || self->CloseToEnemy( n->origin, 128 ) ) + { + return false; + } + + return true; + } + + inline qboolean done + ( + PathNode *node, + PathNode *end + ) + + { + if ( node == end ) + { + return true; + } + + //if ( node->reject ) + if ( node->reject || !( node->nodeflags & AI_FLEE ) ) + { + return false; + } + + if ( self ) + { + node->reject = self->CanSeeEnemyFrom( node->origin ); + return !node->reject; + } + + return false; + } + }; + +class FindEnemyMovement : public StandardMovement + { + public: + Actor *self; + + inline qboolean done + ( + PathNode *node, + PathNode *end + ) + + { + if ( node == end ) + { + return true; + } + + if ( node->reject ) + { + return false; + } + + if ( self ) + { + if ( self->currentEnemy ) + { + node->reject = !self->CanShootFrom( node->origin, self->currentEnemy, false ); + } + else + { + node->reject = false; + } + + return !node->reject; + } + + return false; + } + }; + +typedef PathFinder FindCoverPath; +typedef PathFinder FindFleePath; +typedef PathFinder FindEnemyPath; + +void AI_TargetPlayer( void ); + +class SpinningPlant : public Actor + { + public: + Mover *spinner_model; + Mover *spinner_clip; + + CLASS_PROTOTYPE( SpinningPlant ); + + SpinningPlant(); + ~SpinningPlant(); + + void GetClip( Event *ev ); + }; + +#endif /* actor.h */ \ No newline at end of file diff --git a/source/source/fgame/ammo.cpp b/source/source/fgame/ammo.cpp new file mode 100644 index 0000000..7ed83f8 --- /dev/null +++ b/source/source/fgame/ammo.cpp @@ -0,0 +1,218 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/ammo.cpp $ +// $Revision:: 11 $ +// $Author:: Markd $ +// $Date:: 7/01/00 4:11p $ +// +// Copyright (C) 1997 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source is may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/ammo.cpp $ +// +// 11 7/01/00 4:11p Markd +// added pickup_thread to ammo +// +// 10 6/23/00 8:41p Markd +// made a lot of changes to different constructors for saved game support +// +// 9 6/14/00 2:17p Markd +// fixed compiler warnings for Intel Compiler +// +// 8 5/22/00 4:41p Steven +// Fixed ammo ItemPickup (had different number of parms from item one). +// +// 7 4/05/00 7:13p Aldie +// Lots of inventory functionality changes. +// +// 6 3/02/00 4:43p Aldie +// Added some ammo functionality for the HUD +// +// 5 1/26/00 3:33p Aldie +// Change Amount to getAmount. Added some 'listinventory' command. Added give +// all cheat to execute the script in global/giveall.txt +// +// 4 12/03/99 7:02p Aldie +// More ammo joy +// +// 3 11/29/99 6:32p Aldie +// Lots of changes for ammo system +// +// 2 11/22/99 6:46p Aldie +// Started working on ammo changes - will finish after Thanksgiving break +// +// 1 9/10/99 10:53a Jimdose +// +// 1 9/08/99 3:15p Aldie +// +// +// DESCRIPTION: +// Base class for all ammunition for entities derived from the Weapon class. +// +// AmmoEntity is the Class which represents ammo that the player "sees" and " +// picks up" in the game +// +// Ammo is the Class which is used to keep track of how much ammo a player has +// in his inventory + +#include "ammo.h" +#include "player.h" + +CLASS_DECLARATION( Item, AmmoEntity, NULL ) + { + { NULL, NULL } + }; + +AmmoEntity::AmmoEntity + ( + ) + + { + if ( LoadingSavegame ) + { + // all data will be setup by the archive function + return; + } + setName( "UnknownAmmo" ); + amount = 0; + } + +Item *AmmoEntity::ItemPickup + ( + Entity *other, + qboolean add_to_inventory + ) + + { + Sentient *player; + str realname; + + if ( !other->isSubclassOf( Player ) ) + return NULL; + + player = ( Sentient * )other; + + // Play pickup sound + realname = GetRandomAlias( "snd_pickup" ); + if ( realname.length() > 1 ) + player->Sound( realname, CHAN_ITEM ); + + // Cancel some events + CancelEventsOfType( EV_Item_DropToFloor ); + CancelEventsOfType( EV_Item_Respawn ); + CancelEventsOfType( EV_FadeOut ); + + // Hide the model + setSolidType( SOLID_NOT ); + hideModel(); + + // Respawn? + if ( !Respawnable() ) + PostEvent( EV_Remove, FRAMETIME ); + else + PostEvent( EV_Item_Respawn, RespawnTime() ); + + // fire off any pickup_thread's + if ( pickup_thread.length() ) + { + ExecuteThread( pickup_thread ); + } + + // Give the ammo to the player + player->GiveAmmo( item_name, amount ); + return NULL; // This doesn't create any items + } + + +// This is the Class that is used to keep track of ammo in the player's inventory. +// It is not an entit, just a name and an amount. + +CLASS_DECLARATION( Class, Ammo, NULL ) + { + {NULL, NULL} + }; + +Ammo::Ammo + ( + ) + + { + if ( LoadingSavegame ) + { + // all data will be setup by the archive function + return; + } + setName( "UnknownAmmo" ); + setAmount( 0 ); + setMaxAmount( 100 ); + } + +void Ammo::setAmount + ( + int a + ) + + { + amount = a; + + if ( ( maxamount > 0 ) && ( amount > maxamount ) ) + amount = maxamount; + } + +int Ammo::getAmount + ( + void + ) + + { + return amount; + } + +void Ammo::setMaxAmount + ( + int a + ) + + { + maxamount = a; + } + +int Ammo::getMaxAmount + ( + void + ) + + { + return maxamount; + } + +void Ammo::setName + ( + str n + ) + + { + name = n; + name_index = gi.itemindex( name ); + } + +str Ammo::getName + ( + void + ) + + { + return name; + } + +int Ammo::getIndex + ( + void + ) + + { + return name_index; + } diff --git a/source/source/fgame/ammo.h b/source/source/fgame/ammo.h new file mode 100644 index 0000000..ea8d22c --- /dev/null +++ b/source/source/fgame/ammo.h @@ -0,0 +1,115 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/ammo.h $ +// $Revision:: 12 $ +// $Author:: Markd $ +// $Date:: 7/14/00 9:46a $ +// +// Copyright (C) 1997 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source is may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/ammo.h $ +// +// 12 7/14/00 9:46a Markd +// added comment about member variable not being in archive +// +// 11 6/14/00 2:17p Markd +// fixed compiler warnings for Intel Compiler +// +// 10 5/30/00 7:06p Markd +// saved games 4th pass +// +// 9 5/25/00 7:52p Markd +// 2nd pass save game stuff +// +// 8 5/24/00 3:13p Markd +// first phase of save/load games +// +// 7 5/22/00 4:40p Steven +// Fixed ammo ItemPickup (had different number of parms from item one). +// +// 6 5/20/00 5:15p Markd +// Added ammo archive member functions +// +// 5 3/02/00 4:43p Aldie +// Added some ammo functionality for the HUD +// +// 4 12/03/99 7:02p Aldie +// More ammo joy +// +// 3 11/29/99 6:32p Aldie +// Lots of changes for ammo system +// +// 2 11/22/99 6:46p Aldie +// Started working on ammo changes - will finish after Thanksgiving break +// +// 1 9/10/99 10:53a Jimdose +// +// 1 9/08/99 3:15p Aldie +// +// DESCRIPTION: +// Base class for all ammunition for entities derived from the Weapon class. +// + +#ifndef __AMMO_H__ +#define __AMMO_H__ + +#include "g_local.h" +#include "item.h" + +class AmmoEntity : public Item + { + public: + CLASS_PROTOTYPE( AmmoEntity ); + + AmmoEntity(); + virtual Item *ItemPickup( Entity *other, qboolean add_to_inventory ); + }; + +class Ammo : public Class + { + int amount; + int maxamount; + str name; + int name_index; + + public: + CLASS_PROTOTYPE( Ammo ); + + Ammo(); + Ammo(str name, int amount, int name_index ); + + void setAmount( int a ); + int getAmount( void ); + void setMaxAmount( int a ); + int getMaxAmount( void ); + void setName( str name); + str getName( void ); + int getIndex( void ); + virtual void Archive( Archiver &arc ); + }; + +inline void Ammo::Archive + ( + Archiver &arc + ) + + { + Class::Archive( arc ); + + arc.ArchiveInteger( &amount ); + arc.ArchiveInteger( &maxamount ); + arc.ArchiveString( &name ); + // + // name_index not archived, because it is auto-generated by gi.itemindex + // + if ( arc.Loading() ) + { + setName( name ); + } + } + +#endif /* ammo.h */ diff --git a/source/source/fgame/animate.cpp b/source/source/fgame/animate.cpp new file mode 100644 index 0000000..f54db01 --- /dev/null +++ b/source/source/fgame/animate.cpp @@ -0,0 +1,1131 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/animate.cpp $ +// $Revision:: 38 $ +// $Author:: Markd $ +// $Date:: 7/22/00 7:32p $ +// +// Copyright (C) 1998 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source is may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/animate.cpp $ +// +// 38 7/22/00 7:32p Markd +// bullet proofed RandomAnimate code +// +// 37 6/26/00 5:50p Markd +// re-did some renderfx commands, fixed anti-sb juice stuff +// +// 36 6/23/00 9:14p Markd +// don't go into NewAnim if we are currently loading a saved game +// +// 35 6/22/00 5:32p Steven +// Made it so server commands don't get run if RF_DONT_PROCESS_COMMANDS is set. +// +// 34 6/21/00 6:02p Markd +// allowed lower framerate animations to still post animations properly +// +// 33 6/05/00 3:11p Markd +// fixed HasCommands calls in server +// +// 32 5/02/00 10:59a Aldie +// Fix for initializations +// +// 31 4/14/00 11:31a Aldie +// Fixed cut and paste error +// +// 30 4/13/00 7:04p Aldie +// Fixed bug for animation events where the anim was greater than 255. Added +// animframe and animnumber to Event. +// +// 29 4/11/00 5:30p Markd +// fixed one frame animation bug +// +// 28 4/01/00 3:46p Markd +// Added single frame animation optimization +// +// 27 3/27/00 6:24p Markd +// reworked NewAnim function +// +// 26 3/21/00 2:30p Aldie +// Fixed a statck overflow with ClearTorsoAnim and ClearLegsAnim +// +// 25 3/20/00 5:00p Aldie +// Fixes for entry and exit commands +// +// 24 3/15/00 4:09p Aldie +// Fixed a bug with using weapons, and added some ability to force a state in +// the player +// +// 23 2/23/00 11:44a Markd +// fixed bug with 1 frame animations +// +// 22 2/22/00 6:20p Markd +// modified the way that the animation system works so that the animdone event +// is actually played 1 frame before the end of the animation +// +// 21 2/16/00 6:54p Markd +// reordered deltas and time based events +// +// 20 2/14/00 5:43p Jimdose +// legs anims are now only mixed in if ANIM_BLEND is set +// +// 19 2/09/00 6:02p Markd +// added entry and exit support to server side +// +// 18 1/27/00 9:05a Markd +// fixed enttiy type over writing +// +// 17 1/26/00 12:03p Markd +// added back old lighting code for certain objects in the game +// +// 16 1/22/00 12:42p Jimdose +// got rid of calls to vec3() +// +// 15 1/19/00 8:50p Jimdose +// added Anim_AbsolueDelta +// +// 14 1/12/00 11:27a Markd +// made entities which don't explicitly animate, not animate +// +// 13 1/06/00 11:08p Jimdose +// cleaning up unused code +// +// 12 12/10/99 12:30p Jimdose +// calling NewAnim multiple times per frame no longer toggles the togglebit +// more than once (which used to sometimes cause the animation not to change) +// +// 11 12/09/99 7:37p Jimdose +// changed magic number to MDL_ANIM_DELTA_DRIVEN +// +// 10 12/01/99 4:56p Markd +// fixed some reference versus pointer issues with RandomAnimate and NewAnim +// +// 9 12/01/99 3:17p Aldie +// fix for animation bug +// +// 8 11/11/99 5:25p Jimdose +// added separate torso animation +// +// 7 11/11/99 3:54p Jimdose +// readded separate torso animations +// +// 6 10/19/99 7:52p Markd +// Removed three part model system +// +// 5 10/08/99 2:12p Markd +// Made Animate entities of type MODELANIM +// +// 4 10/06/99 7:25p Markd +// removed TIMESTAMP, time and fixed make_static bug +// +// 3 9/27/99 6:18p Markd +// Added event documentation +// +// 2 9/16/99 11:18a Markd +// Continuing merge of code, not functional yet but closer +// +// 1 9/10/99 10:53a Jimdose +// +// 1 9/08/99 3:15p Aldie +// +// 22 9/01/99 9:08p Markd +// added animate once support +// +// 21 8/27/99 5:00p Markd +// cleaned up animate code so that deltas were only posted as needed +// +// 20 8/27/99 4:35p Jimdose +// changed NewAnim to post the anim done event after the frame events instead +// of before. +// +// 19 8/19/99 6:59p Markd +// removed the old tiki_cmd structure, now tiki_cmd_t is passed into the tiki +// functions +// +// 18 8/19/99 6:40p Steven +// Added a stop anim event. +// +// 17 8/09/99 5:07p Aldie +// More changes to accomodate weapons system +// +// 16 8/05/99 9:14a Steven +// Added a stop animating at end so that it wouldn't skip to beginning of +// animation again. +// +// 15 7/14/99 4:41p Markd +// Changed at which times events are posted +// +// DESCRIPTION: Animate Class +// + +#include "g_local.h" +#include "animate.h" +#include "player.h" +#include "../qcommon/qfiles.h" + +// Leg Animation events +Event EV_Anim + ( + "anim", + 0, + "s", + "animName", + "set the legs animation to animName." + ); + +Event EV_SetFrame + ( + "setframe", + 0, + "iS", + "frameNumber animName", + "Set the frame on the legs, if anim is not specified, current is assumed." + ); +Event EV_AnimDone + ( + "animdone", + 0, + NULL, + NULL, + "Legs animation has finished, not for script use." + ); +Event EV_FrameDelta + ( + "setmovedelta", + 0, + "vf", + "moveDelta moveTime", + "movement from animation, not for script use." + ); +Event EV_StopAnimating + ( + "stopanimating", + 0, + NULL, + NULL, + "stop the legs from animating. Animation will end at the end of current cycle." + ); + +// Torso Animation events +Event EV_Torso_Anim + ( + "torso_anim", + 0, + "s", + "animName", + "set the torso animation to animName." + ); +Event EV_Torso_SetFrame + ( + "torso_setframe", + 0, + "iS", + "frameNumber animName", + "Set the frame on the torso, if anim is not specified, current is assumed." + ); +Event EV_Torso_AnimDone + ( + "torso_animdone", + 0, + NULL, + NULL, + "Torso animation has finished, not for script use." + ); +Event EV_Torso_StopAnimating + ( + "torso_stopanimating", + 0, + NULL, + NULL, + "stop the torso from animating. Animation will end at the end of current cycle." + ); + +Event EV_NewAnim + ( + "animate_newanim", + 0, + "ii", + "animNum bodyPart", + "Start a new animation, not for script use." + ); + +CLASS_DECLARATION( Entity, Animate, "animate" ) + { + { &EV_Anim, Legs_AnimEvent }, + { &EV_SetFrame, Legs_SetFrameEvent }, + { &EV_AnimDone, Legs_AnimDoneEvent }, + { &EV_StopAnimating, Legs_StopAnimating }, + { &EV_FrameDelta, FrameDeltaEvent }, + { &EV_NewAnim, NewAnimEvent }, + + { &EV_Torso_Anim, Torso_AnimEvent }, + { &EV_Torso_SetFrame, Torso_SetFrameEvent }, + { &EV_Torso_AnimDone, Torso_AnimDoneEvent }, + { &EV_Torso_StopAnimating,Torso_StopAnimating }, + + { NULL, NULL } + }; + +Animate::Animate() + { + // Animation variables + frame_delta = "0 0 0"; + animDoneEvent = NULL; + torso_animDoneEvent = NULL; + + legs_animtime = 0; + torso_animtime = 0; + + legs_starttime = 0; + torso_starttime = 0; + + legs_numframes = 0; + torso_numframes = 0; + + edict->s.anim |= (ANIM_SERVER_EXITCOMMANDS_PROCESSED); + edict->s.torso_anim |= (ANIM_SERVER_EXITCOMMANDS_PROCESSED); + } + +void Animate::NewAnim + ( + int animnum, + bodypart_t part + ) + + { + float totaltime; + int *anim; + int flags; + int i; + float time; + tiki_cmd_t cmds; + Event *ev; + float *starttime; + float *animtime; + float *frametime; + int *numframes; + int last_anim,last_anim_flags; + qboolean dodelta; // should we even post movement delta stuff? + qboolean has_commands; // does this animation have any frame commands + + // + // this is an animating model, we set this here so that non-animating models + // don't have to go through the animating code path + // + if ( edict->s.eType == ET_GENERAL ) + { + edict->s.eType = ET_MODELANIM; + } + + if ( LoadingSavegame ) + { + // if we are loading a game, we don't need to start animating, that will be automatic + // all these events would mess everything up anyway + return; + } + + // initially don't post move delta stuff + dodelta = qfalse; + + switch( part ) + { + case legs: + anim = &edict->s.anim; + edict->s.frame &= ~FRAME_EXPLICIT; + flags = EVENT_LEGS_ANIM; + animtime = &legs_animtime; + starttime = &legs_starttime; + frametime = &legs_frametime; + numframes = &legs_numframes; + break; + case torso: + anim = &edict->s.torso_anim; + edict->s.torso_frame &= ~FRAME_EXPLICIT; + flags = EVENT_TORSO_ANIM; + animtime = &torso_animtime; + starttime = &torso_starttime; + frametime = &torso_frametime; + numframes = &torso_numframes; + break; + default: + warning( "NewAnim", "Unknown body part %d", part ); + return; + break; + } + + last_anim = *anim & ANIM_MASK; + last_anim_flags = *anim; + + // + // if the animations were different we need to process the entry and exit events + // + if ( ( last_anim != animnum ) && !( last_anim_flags & ANIM_SERVER_EXITCOMMANDS_PROCESSED ) ) + { + // exit the previous animation + if ( gi.Frame_Commands( edict->s.modelindex, last_anim, TIKI_FRAME_CMD_EXIT, &cmds ) ) + { + int ii, j; + + for( ii = 0; ii < cmds.num_cmds; ii++ ) + { + ev = new Event( cmds.cmds[ ii ].args[ 0 ] ); + + ev->SetSource( EV_FROM_ANIMATION ); + ev->SetAnimationNumber( last_anim ); + ev->SetAnimationFrame( 0 ); + + for( j = 1; j < cmds.cmds[ ii ].num_args; j++ ) + { + ev->AddToken( cmds.cmds[ ii ].args[ j ] ); + } + ProcessEvent( ev ); + } + } + } + + if ( ( animnum >= 0 ) && ( animnum < gi.NumAnims( edict->s.modelindex ) ) ) + { + if ( *starttime == level.time ) + { + // don't toggle the togglebit if we've already had an animation set this frame + *anim = ( *anim & ANIM_TOGGLEBIT ) | animnum | ANIM_BLEND; + } + else + { + *anim = ( ( *anim & ANIM_TOGGLEBIT ) ^ ANIM_TOGGLEBIT ) | animnum | ANIM_BLEND; + } + } + else + { + // bad value + return; + } + + // get rid of old anim events + CancelFlaggedEvents( flags ); + + // get total time of animation + totaltime = gi.Anim_Time( edict->s.modelindex, animnum ); + + // set the total time for the animation + *animtime = totaltime; + + // set the start time of the animation + *starttime = level.time; + + // set the number of frames for the animation + *numframes = gi.Anim_NumFrames( edict->s.modelindex, animnum ); + + // set the time for each animation frame + *frametime = gi.Frame_Time( edict->s.modelindex, animnum, 0 ); + + has_commands = gi.Anim_HasCommands( edict->s.modelindex, animnum ); + + if ( edict->s.eFlags & EF_DONT_PROCESS_COMMANDS ) + has_commands = false; + + if ( ( last_anim != animnum ) && ( has_commands ) ) + { + // enter this animation + if ( gi.Frame_Commands( edict->s.modelindex, animnum, TIKI_FRAME_CMD_ENTRY, &cmds ) ) + { + int ii, j; + + for( ii = 0; ii < cmds.num_cmds; ii++ ) + { + ev = new Event( cmds.cmds[ ii ].args[ 0 ] ); + + ev->SetSource( EV_FROM_ANIMATION ); + ev->SetAnimationNumber( animnum ); + ev->SetAnimationFrame( 0 ); + + for( j = 1; j < cmds.cmds[ ii ].num_args; j++ ) + { + ev->AddToken( cmds.cmds[ ii ].args[ j ] ); + } + ProcessEvent( ev ); + } + } + } + + + // if it is the legs, find out if there is a delta and if it is a delta_driven animation + if ( part == legs ) + { + float length; + Vector totaldelta; + + gi.Anim_AbsoluteDelta( edict->s.modelindex, animnum, totaldelta ); + length = totaldelta.length(); + if ( length > MINIMUM_DELTA_MOVEMENT ) + { + int flags; + + flags = gi.Anim_Flags( edict->s.modelindex, animnum ); + if ( !( flags & MDL_ANIM_DELTA_DRIVEN ) ) + { + length /= *numframes; + if ( length > MINIMUM_DELTA_MOVEMENT_PER_FRAME ) + { + dodelta = qtrue; + } + } + } + } + + if ( has_commands || dodelta ) + { + time = 0; + + for( i = 0; i < *numframes; i++ ) + { + if ( has_commands ) + { + // we want normal frame commands to occur right on the frame + if ( gi.Frame_Commands( edict->s.modelindex, animnum, i, &cmds ) ) + { + int ii, j; + + for( ii = 0; ii < cmds.num_cmds; ii++ ) + { + ev = new Event( cmds.cmds[ ii ].args[ 0 ] ); + + ev->SetSource( EV_FROM_ANIMATION ); + ev->SetAnimationNumber( animnum ); + ev->SetAnimationFrame( i ); + + for( j = 1; j < cmds.cmds[ ii ].num_args; j++ ) + { + ev->AddToken( cmds.cmds[ ii ].args[ j ] ); + } + PostEvent( ev, time, flags ); + } + } + } + // add to time + time += *frametime; + + // we want deltas to occur at the end of the frame + // only add deltas on the legs + if ( dodelta ) + { + Vector delta; + + // get the current frame delta + gi.Frame_Delta( edict->s.modelindex, animnum, i, delta ); + + if ( *frametime > FRAMETIME ) + { + float time_offset; + + VectorScale( delta, ( FRAMETIME / *frametime ), delta ); + + for ( time_offset = 0; time_offset < *frametime; time_offset += FRAMETIME ) + { + ev = new Event( EV_FrameDelta ); + ev->AddVector( delta ); + ev->AddFloat( *frametime ); + PostEvent( ev, time + time_offset, flags ); + } + } + else + { + ev = new Event( EV_FrameDelta ); + ev->AddVector( delta ); + ev->AddFloat( *frametime ); + PostEvent( ev, time, flags ); + } + } + + } + } + + // + // if we have a 1 frame animation, which has no commands, + // we aren't a subclass of Sentient and our animation time is the same as frametime + // there is no reason for us to constantly animate, since nothing will change + // lets get the hell out of dodge! + if ( + ( *numframes == 1 ) && + !isSubclassOf( Player ) && + !has_commands && + ( *frametime == FRAMETIME ) + ) + { + switch( part ) + { + case legs: + if ( animDoneEvent ) + { + PostEvent( *animDoneEvent, 0 ); + } + break; + case torso: + if ( torso_animDoneEvent ) + { + PostEvent( *torso_animDoneEvent, 0 ); + } + break; + default: + break; + } + return; + } + + switch( part ) + { + case legs: + if ( totaltime > *frametime ) + PostEvent( EV_AnimDone, totaltime - *frametime, flags ); + else + PostEvent( EV_AnimDone, totaltime, flags ); + break; + case torso: + if ( totaltime > *frametime ) + PostEvent( EV_Torso_AnimDone, totaltime - *frametime, flags ); + else + PostEvent( EV_Torso_AnimDone, totaltime, flags ); + break; + default: + warning( "NewAnim", "Unknown body part %d", part ); + return; + break; + } + } + +void Animate::NewAnim + ( + int animnum, + Event &newevent, + bodypart_t part + ) + { + SetAnimDoneEvent( newevent, part ); + NewAnim( animnum, part ); + } + +void Animate::NewAnim + ( + int animnum, + Event *newevent, + bodypart_t part + ) + { + SetAnimDoneEvent( newevent, part ); + NewAnim( animnum, part ); + } + +void Animate::FrameDeltaEvent + ( + Event *ev + ) + + { + frame_delta = ev->GetVector( 1 ); + move_time = ev->GetFloat( 2 ); + total_delta += frame_delta * edict->s.scale; + } + +void Animate::EndAnim + ( + bodypart_t part + ) + + { + Event * ev; + + switch( part ) + { + case legs: + if ( animDoneEvent ) + { + PostEvent( *animDoneEvent, 0 ); + } + ev = new Event( EV_NewAnim ); + ev->AddInteger( edict->s.anim ); + ev->AddInteger( part ); + if ( legs_animtime > legs_frametime ) + PostEvent( ev, legs_frametime, EVENT_LEGS_ANIM ); + else + PostEvent( ev, 0, EVENT_LEGS_ANIM ); + break; + case torso: + if ( torso_animDoneEvent ) + { + PostEvent( *torso_animDoneEvent, 0 ); + } + ev = new Event( EV_NewAnim ); + ev->AddInteger( edict->s.torso_anim ); + ev->AddInteger( part ); + if ( torso_animtime > torso_frametime ) + PostEvent( ev, torso_frametime, EVENT_TORSO_ANIM ); + else + PostEvent( ev, 0, EVENT_TORSO_ANIM ); + break; + default: + warning( "EndAnim", "Unknown body part %d", part ); + return; + break; + } + } + +void Animate::SetAnimDoneEvent + ( + Event *event, + bodypart_t part + ) + { + Event **doneevent; + + switch( part ) + { + case legs: + doneevent = &animDoneEvent; + break; + case torso: + doneevent = &torso_animDoneEvent; + break; + default: + warning( "SetAnimDoneEvent", "Unknown body part %d", part ); + return; + break; + } + if ( *doneevent ) + { + delete *doneevent; + } + + *doneevent = event; + } + +void Animate::SetAnimDoneEvent + ( + Event &event, + bodypart_t part + ) + { + SetAnimDoneEvent( new Event( event ), part ); + } + +void Animate::RandomAnimate + ( + const char *animname, + Event *endevent, + bodypart_t part + ) + + { + Event *event_to_post; + int num; + int flags; + qboolean allparts; + + assert( animname ); + if ( !animname ) + { + return; + } + + allparts = false; + if ( part == all ) + { + allparts = true; + } + + do { + if ( allparts ) + { + switch( part ) + { + case all: + part = legs; + break; + case legs: + part = torso; + break; + case torso: + return; + break; + } + } + switch( part ) + { + case legs: + flags = EVENT_LEGS_ANIM; + break; + case torso: + flags = EVENT_TORSO_ANIM; + break; + default: + warning( "RandomAnimate", "Unknown body part %d", part ); + return; + break; + } + num = gi.Anim_Random( edict->s.modelindex, animname ); + + currentAnim = animname; + + // + // this is here to ensure that multiple distinct events are posted for each body part + // + if ( allparts && ( part != legs ) ) + { + if ( endevent ) + { + event_to_post = new Event( endevent ); + } + else + { + event_to_post = NULL; + } + } + else + { + event_to_post = endevent; + } + + // + // see if we even have a valid animation at all + // + if ( num == -1 ) + { + if ( event_to_post ) + { + PostEvent( event_to_post, FRAMETIME, flags ); + } + } + else + { + SetAnimDoneEvent( event_to_post, part ); + NewAnim( num, part ); + } + } while( allparts ); + } + +void Animate::SetFrame + ( + int framenum, + bodypart_t part, + int anim + ) + + { + int flags; + int numframes; + int *panim; + int *frame; + + switch( part ) + { + case legs: + frame = &edict->s.frame; + flags = EVENT_LEGS_ANIM; + numframes = legs_numframes; + panim = &edict->s.anim; + break; + case torso: + frame = &edict->s.torso_frame; + flags = EVENT_TORSO_ANIM; + numframes = torso_numframes; + panim = &edict->s.torso_anim; + break; + default: + warning( "SetFrame", "Unknown body part %d", part ); + return; + break; + } + + if ( anim >= 0 ) + { + numframes = gi.Anim_NumFrames( edict->s.modelindex, anim ); + } + + if ( framenum < 0 || framenum >= numframes ) + { + warning( "SetFrame","Frame is out of range" ); + return; + } + + // get rid of old anim events so we don't animate + CancelFlaggedEvents( flags ); + + *frame = framenum | FRAME_EXPLICIT; + + // if we have a frame override, make sure to set the animation as well + if ( anim >= 0 ) + { + *panim = anim | ANIM_BLEND; + } + } + +qboolean Animate::HasAnim + ( + const char *animname + ) + { + int num; + + num = gi.Anim_Random( edict->s.modelindex, animname ); + return ( num >= 0 ); + } + +void Animate::NewAnimEvent + ( + Event *ev + ) + + { + NewAnim( ev->GetInteger( 1 ) & ANIM_MASK, (bodypart_t) ev->GetInteger( 2 ) ); + } + +void Animate::StopAnimating + ( + bodypart_t part + ) + { + int frame; + int anim; + + if ( part == all ) + { + // legs + frame = CurrentFrame( legs ); + anim = CurrentAnim( legs ); + SetFrame( frame, legs, anim ); + // torso + frame = CurrentFrame( torso ); + anim = CurrentAnim( torso ); + SetFrame( frame, torso, anim ); + } + else + { + frame = CurrentFrame( part ); + anim = CurrentAnim( part ); + SetFrame( frame, part, anim ); + } + } + +void Animate::StopAnimatingAtEnd + ( + bodypart_t part + ) + { + int anim; + + if ( part == all ) + { + StopAnimatingAtEnd( legs ); + StopAnimatingAtEnd( torso ); + } + else if ( part == legs ) + { + anim = CurrentAnim( part ); + SetFrame( legs_numframes - 1, part, anim ); + } + else if ( part == torso ) + { + anim = CurrentAnim( part ); + SetFrame( legs_numframes - 1, part, anim ); + } + } + + +//////////////////////////// +// +// BODY PART SPECIFIC EVENTS +// +//////////////////////////// + +// Legs + +void Animate::Legs_AnimDoneEvent + ( + Event *ev + ) + + { + EndAnim( legs ); + } + + +void Animate::Legs_AnimEvent + ( + Event *ev + ) + + { + RandomAnimate( ev->GetString( 1 ), NULL, legs ); + } + +void Animate::Legs_SetFrameEvent + ( + Event *ev + ) + + { + int framenum; + int animnum; + + framenum = ev->GetInteger( 1 ); + if ( ev->NumArgs() > 1 ) + { + animnum = gi.Anim_NumForName( edict->s.modelindex, ev->GetString( 2 ) ); + } + else + { + animnum = -1; + } + + SetFrame( framenum, legs, animnum ); + } + +// HACK HACK HACK +void Animate::Legs_StopAnimating + ( + Event *ev + ) + + { + CancelFlaggedEvents( EVENT_LEGS_ANIM ); + } + +// Torso + +void Animate::Torso_AnimDoneEvent + ( + Event *ev + ) + + { + EndAnim( torso ); + } + +void Animate::Torso_AnimEvent + ( + Event *ev + ) + + { + RandomAnimate( ev->GetString( 1 ), NULL, torso ); + } + +void Animate::Torso_SetFrameEvent + ( + Event *ev + ) + + { + int framenum; + int animnum; + + framenum = ev->GetInteger( 1 ); + if ( ev->NumArgs() > 1 ) + { + animnum = gi.Anim_NumForName( edict->s.modelindex, ev->GetString( 2 ) ); + } + else + { + animnum = -1; + } + + SetFrame( framenum, torso, animnum ); + } + +// HACK HACK HACK +void Animate::Torso_StopAnimating + ( + Event *ev + ) + + { + CancelFlaggedEvents( EVENT_TORSO_ANIM ); + } + +void Animate::ClearTorsoAnim + ( + void + ) + + { + tiki_cmd_t cmds; + int last_anim; + static qboolean clearing=qfalse; + + last_anim = edict->s.torso_anim & ANIM_MASK; + + if ( ( edict->s.torso_anim & ANIM_BLEND ) && !( edict->s.torso_anim & ANIM_SERVER_EXITCOMMANDS_PROCESSED ) && !clearing ) + { + if ( gi.Frame_Commands( edict->s.modelindex, last_anim, TIKI_FRAME_CMD_EXIT, &cmds ) ) + { + int ii, j; + + clearing = qtrue; + for( ii = 0; ii < cmds.num_cmds; ii++ ) + { + Event *ev = new Event( cmds.cmds[ ii ].args[ 0 ] ); + + ev->SetSource( EV_FROM_ANIMATION ); + ev->SetAnimationNumber( last_anim ); + ev->SetAnimationFrame( 0 ); + + for( j = 1; j < cmds.cmds[ ii ].num_args; j++ ) + { + ev->AddToken( cmds.cmds[ ii ].args[ j ] ); + } + ProcessEvent( ev ); + } + clearing = qfalse; + } + edict->s.torso_anim |= ANIM_SERVER_EXITCOMMANDS_PROCESSED; + } + + CancelFlaggedEvents( EVENT_TORSO_ANIM ); + edict->s.torso_anim &= ~ANIM_BLEND; + } + +void Animate::ClearLegsAnim + ( + void + ) + + { + tiki_cmd_t cmds; + int last_anim; + static qboolean clearing=qfalse; + + if ( edict->s.anim & ANIM_SERVER_EXITCOMMANDS_PROCESSED ) + { + last_anim = edict->s.anim & ANIM_MASK; + + if ( gi.Frame_Commands( edict->s.modelindex, last_anim, TIKI_FRAME_CMD_EXIT, &cmds ) ) + { + int ii, j; + + clearing = qtrue; + for( ii = 0; ii < cmds.num_cmds; ii++ ) + { + Event *ev = new Event( cmds.cmds[ ii ].args[ 0 ] ); + + ev->SetSource( EV_FROM_ANIMATION ); + ev->SetAnimationNumber( last_anim ); + ev->SetAnimationFrame( 0 ); + + for( j = 1; j < cmds.cmds[ ii ].num_args; j++ ) + { + ev->AddToken( cmds.cmds[ ii ].args[ j ] ); + } + ProcessEvent( ev ); + } + clearing = qfalse; + } + edict->s.anim |= ANIM_SERVER_EXITCOMMANDS_PROCESSED; + } + + CancelFlaggedEvents( EVENT_LEGS_ANIM ); + + edict->s.anim &= ~ANIM_BLEND; + } diff --git a/source/source/fgame/animate.h b/source/source/fgame/animate.h new file mode 100644 index 0000000..02ab22f --- /dev/null +++ b/source/source/fgame/animate.h @@ -0,0 +1,386 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/animate.h $ +// $Revision:: 19 $ +// $Author:: Markd $ +// $Date:: 6/05/00 3:11p $ +// +// Copyright (C) 1997 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source is may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/animate.h $ +// +// 19 6/05/00 3:11p Markd +// fixed HasCommands calls in server +// +// 18 5/30/00 7:06p Markd +// saved games 4th pass +// +// 17 5/25/00 7:52p Markd +// 2nd pass save game stuff +// +// 16 5/24/00 3:13p Markd +// first phase of save/load games +// +// 15 3/16/00 10:50a Markd +// Fixed some bad syntax in headers that exhibited itself in non-visualc +// compilers +// +// 14 3/15/00 4:09p Aldie +// Fixed a bug with using weapons, and added some ability to force a state in +// the player +// +// 13 2/22/00 6:20p Markd +// modified the way that the animation system works so that the animdone event +// is actually played 1 frame before the end of the animation +// +// 12 2/14/00 5:37p Jimdose +// added ClearLegsAnim +// +// 11 1/25/00 7:02p Markd +// Fixed viewthing frame reporting +// +// 10 1/14/00 4:23p Steven +// Added an AnimatePtr type; +// +// 9 1/06/00 11:08p Jimdose +// cleaning up unused code +// +// 8 12/01/99 4:56p Markd +// fixed some reference versus pointer issues with RandomAnimate and NewAnim +// +// 7 11/18/99 6:26p Steven +// Fixed some tag stuff because CurrentAnim and CurrentFrame had different +// paramters in Entity and Animate which made the virtual stuff not work +// properly. +// +// 6 11/11/99 5:25p Jimdose +// added separate torso animation +// +// 5 11/11/99 3:54p Jimdose +// readded separate torso animations +// +// 4 10/19/99 7:52p Markd +// Removed three part model system +// +// 3 10/01/99 4:51p Markd +// Made Warning level 4 work on all projects +// +// 2 9/27/99 6:18p Markd +// Added event documentation +// +// 1 9/10/99 10:53a Jimdose +// +// 1 9/08/99 3:15p Aldie +// +// 18 9/01/99 9:08p Markd +// added animate once support +// +// 17 8/19/99 6:41p Steven +// Added a stop anim event. +// +// 16 8/05/99 9:16a Steven +// Added a stop animating at end so that it wouldn't skip to beginning of +// animation again. +// +// 15 7/15/99 4:15p Markd +// added time output to viewthing +// +// 14 6/23/99 3:57p Markd +// Added viewthing support +// +// DESCRIPTION: +// Animate class +// + +#ifndef __ANIMATE_H__ +#define __ANIMATE_H__ + +#include "g_local.h" +#include "entity.h" + +extern Event EV_SetFrame; +extern Event EV_StopAnimating; +extern Event EV_Torso_StopAnimating; + +#define MINIMUM_DELTA_MOVEMENT 8 +#define MINIMUM_DELTA_MOVEMENT_PER_FRAME ( MINIMUM_DELTA_MOVEMENT / 20.0f ) + +class Animate; + +typedef SafePtr AnimatePtr; + +class Animate : public Entity + { + private: + Event *animDoneEvent; + Event *torso_animDoneEvent; + + float legs_animtime; + float torso_animtime; + + float legs_starttime; + float torso_starttime; + + float legs_frametime; + float torso_frametime; + + int legs_numframes; + int torso_numframes; + + str currentAnim; + + void FrameDeltaEvent( Event *ev ); + void EndAnim( bodypart_t part ); + void Legs_AnimDoneEvent( Event *ev ); + void Legs_AnimEvent( Event *ev ); + void Legs_SetFrameEvent( Event *ev ); + void Legs_StopAnimating( Event *ev ); + void Torso_AnimDoneEvent( Event *ev ); + void Torso_AnimEvent( Event *ev ); + void Torso_SetFrameEvent( Event *ev ); + void Torso_StopAnimating( Event *ev ); + void NewAnimEvent( Event *ev ); + public: + + // Animation variables + Vector frame_delta; // current movement from this frame + CLASS_PROTOTYPE( Animate ); + Animate(); + + void RandomAnimate( const char *animname, Event *endevent = NULL, bodypart_t part = legs ); + void RandomAnimate( const char *animname, Event &endevent, bodypart_t part = legs ); + void NewAnim( int animnum, bodypart_t part = legs ); + void NewAnim( int animnum, Event *endevent, bodypart_t part = legs ); + void NewAnim( int animnum, Event &endevent, bodypart_t part = legs ); + void SetFrame( int framenum, bodypart_t part = legs, int anim = -1 ); + qboolean HasAnim( const char *animname ); + Event *AnimDoneEvent( bodypart_t part = legs ); + void SetAnimDoneEvent( Event &event, bodypart_t part = legs ); + void SetAnimDoneEvent( Event *event, bodypart_t part = legs ); + int NumFrames( bodypart_t part = legs ); + int NumAnims( void ); + const char *AnimName( bodypart_t part = legs ); + float AnimTime( bodypart_t part = legs ); + + void ClearLegsAnim( void ); + void ClearTorsoAnim( void ); + + virtual void StopAnimating( bodypart_t part = legs ); + virtual void StopAnimatingAtEnd( bodypart_t part = legs ); + + virtual int CurrentAnim( bodypart_t part = legs ); + virtual int CurrentFrame( bodypart_t part = legs ); + + virtual void Archive( Archiver &arc ); + }; + +inline void Animate::RandomAnimate + ( + const char *animname, + Event &endevent, + bodypart_t part + ) + { + Event *ev; + + ev = new Event( endevent ); + RandomAnimate( animname, ev, part ); + } + +inline int Animate::CurrentAnim + ( + bodypart_t part + ) + { + switch( part ) + { + case legs: + return edict->s.anim & ANIM_MASK; + break; + case torso: + return edict->s.torso_anim & ANIM_MASK; + break; + default: + warning( "CurrentAnim", "Unknown body part %d", part ); + return -1; + break; + } + } + +inline int Animate::CurrentFrame + ( + bodypart_t part + ) + { + int frame; + + switch( part ) + { + case legs: + if ( edict->s.frame & FRAME_EXPLICIT ) + { + frame = edict->s.frame & FRAME_MASK; + } + else + { + if ( legs_numframes ) + { + frame = ( int )( ( float )( ( level.time - legs_starttime ) * legs_numframes ) / legs_animtime + 0.5f ); + while ( frame >= legs_numframes ) + frame -= legs_numframes; + } + else + { + frame = 0; + } + } + break; + case torso: + if ( edict->s.torso_frame & FRAME_EXPLICIT ) + { + frame = edict->s.torso_frame & FRAME_MASK; + } + else + { + if ( torso_numframes ) + { + frame = ( int )( ( float )( ( level.time - torso_starttime ) * torso_numframes ) / torso_animtime + 0.5f ); + while ( frame >= torso_numframes ) + frame -= torso_numframes; + } + else + { + frame = 0; + } + } + break; + default: + warning( "CurrentFrame", "Unknown body part %d", part ); + frame = 0; + break; + } + return frame; + } + +inline int Animate::NumFrames + ( + bodypart_t part + ) + { + switch( part ) + { + case legs: + return legs_numframes; + break; + case torso: + return torso_numframes; + break; + default: + warning( "NumFrames", "Unknown body part %d", part ); + return 0; + break; + } + } + +inline float Animate::AnimTime + ( + bodypart_t part + ) + { + switch( part ) + { + case legs: + return legs_animtime; + break; + case torso: + return torso_animtime; + break; + default: + warning( "AnimTime", "Unknown body part %d", part ); + return 0; + break; + } + } + +inline int Animate::NumAnims + ( + void + ) + + { + return gi.NumAnims( edict->s.modelindex ); + } + +inline const char *Animate::AnimName + ( + bodypart_t part + ) + { + switch( part ) + { + case legs: + return gi.Anim_NameForNum( edict->s.modelindex, CurrentAnim( part ) ); + break; + case torso: + return gi.Anim_NameForNum( edict->s.modelindex, CurrentAnim( part ) ); + break; + default: + warning( "AnimName", "Unknown body part %d", part ); + return NULL; + break; + } + } + +inline Event * Animate::AnimDoneEvent + ( + bodypart_t part + ) + { + switch( part ) + { + case legs: + if ( animDoneEvent ) + return new Event( animDoneEvent ); + else + return NULL; + break; + case torso: + if ( torso_animDoneEvent ) + return new Event( torso_animDoneEvent ); + else + return NULL; + break; + default: + warning( "AnimDoneEvent", "Unknown body part %d", part ); + return NULL; + break; + } + } + +inline void Animate::Archive + ( + Archiver &arc + ) + + { + Entity::Archive( arc ); + + arc.ArchiveVector( &frame_delta ); + arc.ArchiveEventPointer( &animDoneEvent ); + arc.ArchiveEventPointer( &torso_animDoneEvent ); + arc.ArchiveFloat( &legs_animtime ); + arc.ArchiveFloat( &torso_animtime ); + arc.ArchiveFloat( &legs_starttime ); + arc.ArchiveFloat( &torso_starttime ); + arc.ArchiveInteger( &legs_numframes ); + arc.ArchiveInteger( &torso_numframes ); + arc.ArchiveFloat( &legs_frametime ); + arc.ArchiveFloat( &torso_frametime ); + arc.ArchiveString( ¤tAnim ); + } + +#endif /* animate.h */ diff --git a/source/source/fgame/archive.cpp b/source/source/fgame/archive.cpp new file mode 100644 index 0000000..10eb3d0 --- /dev/null +++ b/source/source/fgame/archive.cpp @@ -0,0 +1,1214 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/archive.cpp $ +// $Revision:: 20 $ +// $Author:: Markd $ +// $Date:: 6/23/00 8:41p $ +// +// Copyright (C) 1997 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source is may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/archive.cpp $ +// +// 20 6/23/00 8:41p Markd +// made a lot of changes to different constructors for saved game support +// +// 19 6/13/00 5:09p Markd +// changed archive version number +// +// 18 6/13/00 5:07p Markd +// turned off types on archives to trim down sizes +// +// 17 6/06/00 5:58p Markd +// fixed warning message on archive load +// +// 16 6/05/00 3:41p Markd +// Made Archvie load quiet +// +// 15 6/02/00 4:24p Markd +// cleaned up archive functions +// +// 14 5/31/00 2:58p Markd +// saved game fun +// +// 13 5/31/00 10:19a Markd +// 4th pass saved games +// +// 12 5/30/00 7:06p Markd +// saved games 4th pass +// +// 11 5/27/00 8:06p Markd +// Saved games 3rd pass +// +// 10 5/27/00 2:56p Markd +// Save games 2nd pass +// +// 9 5/26/00 7:44p Markd +// 2nd phase save games +// +// 8 5/25/00 4:28p Markd +// fixed up archive functions +// +// 7 5/24/00 3:14p Markd +// first phase of save/load games +// +// 6 2/04/00 1:29p Markd +// Added checksum to ai path nodes. It auto saves on exit now and will +// automatically re-build nodes as needed +// +// 5 1/10/00 5:27p Markd +// Replaced TAG calls with normal malloc and free calls +// +// 4 12/17/99 6:35p Jimdose +// changed spawnarg code +// added Level class for spawning and map control +// got rid of unused or superflous variables +// changed setjmp/longjmp calls to try/throw/catch exception handling +// +// 3 12/13/99 10:46a Markd +// incremental merge fix +// +// 2 10/01/99 4:51p Markd +// Made Warning level 4 work on all projects +// +// 1 9/10/99 10:53a Jimdose +// +// 1 9/08/99 3:15p Aldie +// +// 7 8/17/99 5:08p Markd +// Changed all FS_ReadFile's to FS_ReadFileEx's in game code +// +// 6 7/29/99 5:33p Markd +// Fixed weird compiler bug +// +// DESCRIPTION: +// Class for archiving objects +// +#include "g_local.h" +#include "archive.h" + +enum + { + ARC_NULL, ARC_Vector, ARC_Vec3, ARC_Vec4, ARC_Integer, ARC_Unsigned, ARC_Byte, ARC_Char, ARC_Short, ARC_UnsignedShort, + ARC_Float, ARC_Double, ARC_Boolean, ARC_String, ARC_Raw, ARC_Object, ARC_ObjectPointer, + ARC_SafePointer, ARC_Event, ARC_EventPointer, ARC_Quat, ARC_Entity, ARC_Bool, + ARC_NUMTYPES + }; + +static const char *typenames[] = + { + "NULL", "vector", "vec3", "vec4", "int", "unsigned", "byte", "char", "short", "unsigned short", + "float", "double", "qboolean", "string", "raw data", "object", "objectpointer", + "safepointer", "event", "eventpointer", "quaternion", "entity", "bool" + }; + +#define ArchiveHeader ( *( int * )"FAKK" ) +#define ArchiveVersion 4 // This must be changed any time the format changes! +#define ArchiveInfo "FAKK Archive Version 4" // This must be changed any time the format changes! + +CLASS_DECLARATION( Class, FileRead, NULL ) + { + { NULL, NULL } + }; + +FileRead::FileRead() + { + length = 0; + buffer = NULL; + pos = 0; + } + +FileRead::~FileRead() + { + Close(); + } + +void FileRead::Close + ( + void + ) + + { + if ( buffer ) + { + gi.Free( ( void * )buffer ); + buffer = NULL; + } + + filename = ""; + length = 0; + pos = 0; + } + +const char *FileRead::Filename + ( + void + ) + + { + return filename.c_str(); + } + +size_t FileRead::Length + ( + void + ) + + { + return length; + } + +size_t FileRead::Pos + ( + void + ) + + { + return pos - buffer; + } + +qboolean FileRead::Seek + ( + size_t newpos + ) + + { + if ( !buffer ) + { + return false; + } + + if ( newpos > length ) + { + return false; + } + + pos = buffer + newpos; + + return true; + } + +qboolean FileRead::Open + ( + const char *name + ) + + { + byte *tempbuf; + assert( name ); + + assert( !buffer ); + Close(); + + if ( !name ) + { + return false; + } + + length = gi.FS_ReadFile( name, ( void ** )&tempbuf, qtrue ); + if ( length == ( size_t )( -1 ) ) + { + return false; + } + // create our own space + buffer = ( byte * )gi.Malloc( length ); + // copy the file over to our space + memcpy( buffer, tempbuf, length ); + // free the file + gi.FS_FreeFile( tempbuf ); + + filename = name; + pos = buffer; + + return true; + } + +qboolean FileRead::Read + ( + void *dest, + size_t size + ) + + { + assert( dest ); + assert( buffer ); + assert( pos ); + + if ( !dest ) + { + return false; + } + + if ( size <= 0 ) + { + return false; + } + + if ( ( pos + size ) > ( buffer + length ) ) + { + return false; + } + + memcpy( dest, pos, size ); + pos += size; + + return true; + } + +CLASS_DECLARATION( Class, Archiver, NULL ) + { + { NULL, NULL } + }; + +Archiver::Archiver() + { + file = 0; + fileerror = false; + harderror = true; + assert( ( sizeof( typenames ) / sizeof( typenames[ 0 ] ) ) == ARC_NUMTYPES ); + } + +Archiver::~Archiver() + { + if ( file ) + { + Close(); + } + + readfile.Close(); + } + +void Archiver::FileError + ( + const char *fmt, + ... + ) + + { + va_list argptr; + char text[ 1024 ]; + + va_start( argptr, fmt ); + vsprintf( text, fmt, argptr ); + va_end( argptr ); + + fileerror = true; + Close(); + if ( archivemode == ARCHIVE_READ ) + { + if ( harderror ) + { + gi.Error( ERR_DROP, "Error while loading %s : %s\n", filename.c_str(), text ); + } + else + { + gi.Printf( "Error while loading %s : %s\n", filename.c_str(), text ); + } + } + else + { + if ( harderror ) + { + gi.Error( ERR_DROP, "Error while writing to %s : %s\n", filename.c_str(), text ); + } + else + { + gi.Printf( "Error while writing to %s : %s\n", filename.c_str(), text ); + } + } + } + +void Archiver::Close + ( + void + ) + + { + if ( file ) + { + if ( archivemode == ARCHIVE_WRITE ) + { + int numobjects; + + // write out the number of classpointers + gi.FS_FSeek( file, numclassespos, FS_SEEK_SET ); + numclassespos = gi.FS_FTell( file ); + numobjects = classpointerList.NumObjects(); + ArchiveInteger( &numobjects ); + } + + gi.FS_FCloseFile( file ); + file = NULL; + } + + readfile.Close(); + + if ( archivemode == ARCHIVE_READ ) + { + int i, num; + Class * classptr; + pointer_fixup_t *fixup; + + num = fixupList.NumObjects(); + for( i = 1; i <= num; i++ ) + { + fixup = fixupList.ObjectAt( i ); + classptr = classpointerList.ObjectAt( fixup->index ); + if ( fixup->type == pointer_fixup_normal ) + { + Class ** fixupptr; + fixupptr = ( Class ** )fixup->ptr; + *fixupptr = classptr; + } + else if ( fixup->type == pointer_fixup_safe ) + { + SafePtrBase * fixupptr; + fixupptr = ( SafePtrBase * )fixup->ptr; + fixupptr->InitSafePtr( classptr ); + } + delete fixup; + } + fixupList.FreeObjectList(); + classpointerList.FreeObjectList(); + } + } + +/**************************************************************************************** + + File Read/Write functions + +*****************************************************************************************/ + +qboolean Archiver::Read + ( + const char *name, + qboolean harderror + ) + + { + unsigned header; + unsigned version; + str info; + int num; + int i; + Class *null; + + this->harderror = harderror; + + assert( name ); + if ( !name ) + { + FileError( "NULL pointer for filename in Archiver::Read.\n" ); + return false; + } + + fileerror = false; + + archivemode = ARCHIVE_READ; + + filename = name; + + if ( !readfile.Open( filename.c_str() ) ) + { + if ( harderror ) + { + FileError( "Couldn't open file." ); + } + return false; + } + + ArchiveUnsigned( &header ); + if ( header != ArchiveHeader ) + { + readfile.Close(); + FileError( "Not a valid Fakk2 archive." ); + return false; + } + + ArchiveUnsigned( &version ); + if ( version > ArchiveVersion ) + { + readfile.Close(); + FileError( "Archive is from version %.2f. Check http://www.ritual.com for an update.", version ); + return false; + } + + if ( version < ArchiveVersion ) + { + readfile.Close(); + FileError( "Archive is out of date." ); + return false; + } + + ArchiveString( &info ); + gi.DPrintf( "%s\n", info.c_str() ); + + // setup out class pointers + ArchiveInteger( &num ); + classpointerList.Resize( num ); + null = NULL; + for( i = 1; i <= num; i++ ) + { + classpointerList.AddObject( null ); + } + + return true; + } + +qboolean Archiver::Create + ( + const char *name, + qboolean harderror + ) + + { + unsigned header; + unsigned version; + str info; + int numZero = 0; + + this->harderror = harderror; + + assert( name ); + if ( !name ) + { + FileError( "NULL pointer for filename in Archiver::Create.\n" ); + return false; + } + + fileerror = false; + + archivemode = ARCHIVE_WRITE; + + filename = name; + + file = gi.FS_FOpenFileWrite( filename.c_str() ); + if ( !file ) + { + FileError( "Couldn't open file." ); + return false; + } + + header = ArchiveHeader; + ArchiveUnsigned( &header ); + version = ArchiveVersion; + ArchiveUnsigned( &version ); + info = ArchiveInfo; + ArchiveString( &info ); + + numclassespos = gi.FS_FTell( file ); + ArchiveInteger( &numZero ); + + return true; + } + + +inline void Archiver::CheckRead + ( + void + ) + + { + assert( archivemode == ARCHIVE_READ ); + if ( !fileerror && ( archivemode != ARCHIVE_READ ) ) + { + FileError( "File read during a write operation." ); + } + } + +inline void Archiver::CheckWrite + ( + void + ) + + { + assert( archivemode == ARCHIVE_WRITE ); + if ( !fileerror && ( archivemode != ARCHIVE_WRITE ) ) + { + FileError( "File write during a read operation." ); + } + } + +inline size_t Archiver::ReadSize + ( + void + ) + + { + size_t s; + + s = 0; + if ( !fileerror ) + { + readfile.Read( &s, sizeof( s ) ); + } + + return s; + } + +inline void Archiver::CheckSize + ( + int type, + size_t size + ) + + { + size_t s; + + if ( !fileerror ) + { + s = ReadSize(); + + if ( size != s ) + { + FileError( "Invalid data size of %d on %s.", s, typenames[ type ] ); + } + } + } + +inline void Archiver::WriteSize + ( + size_t size + ) + + { + gi.FS_Write( &size, sizeof( size ), file ); + } + +inline int Archiver::ReadType + ( + void + ) + + { + int t; + + if ( !fileerror ) + { + readfile.Read( &t, sizeof( t ) ); + + return t; + } + + return ARC_NULL; + } + +inline void Archiver::WriteType + ( + int type + ) + + { + gi.FS_Write( &type, sizeof( type ), file ); + } + + +inline void Archiver::CheckType + ( + int type + ) + + { + int t; + + assert( ( type >= 0 ) && ( type < ARC_NUMTYPES ) ); + + if ( !fileerror ) + { + t = ReadType(); + if ( t != type ) + { + FileError( "Expecting %s", typenames[ type ] ); + } + } + } + +/**************************************************************************************** + + File Archive functions + +*****************************************************************************************/ + +//#define ARCHIVE_USE_TYPES 1 + +inline void Archiver::ArchiveData + ( + int type, + void *data, + size_t size + ) + { + if ( archivemode == ARCHIVE_READ ) + { +#ifndef NDEBUG + CheckRead(); +#endif +#ifdef ARCHIVE_USE_TYPES + CheckType( type ); +#endif + + if ( !fileerror && size ) + { + readfile.Read( data, size ); + } + } + else + { +#ifndef NDEBUG + CheckWrite(); +#endif +#ifdef ARCHIVE_USE_TYPES + WriteType( type ); +#endif + + if ( !fileerror && size ) + { + gi.FS_Write( data, size, file ); + } + } + } + + +#define ARCHIVE( func, type ) \ +void Archiver::Archive##func \ + ( \ + type * v \ + ) \ + \ + { \ + ArchiveData( ARC_##func, v, sizeof( type ) ); \ + } + + ARCHIVE( Vector, Vector ); + ARCHIVE( Integer, int ); + ARCHIVE( Unsigned, unsigned ); + ARCHIVE( Byte, byte ); + ARCHIVE( Char, char ); + ARCHIVE( Short, short ); + ARCHIVE( UnsignedShort, unsigned short ); + ARCHIVE( Float, float ); + ARCHIVE( Double, double ); + ARCHIVE( Boolean, qboolean ); + ARCHIVE( Quat, Quat ); + ARCHIVE( Bool, bool ); + +void Archiver::ArchiveVec3( vec3_t vec ) + { + ArchiveData( ARC_Vec3, vec, sizeof( vec3_t ) ); + } + +void Archiver::ArchiveVec4( vec4_t vec ) + { + ArchiveData( ARC_Vec4, vec, sizeof( vec4_t ) ); + } + +void Archiver::ArchiveObjectPointer + ( + Class ** ptr + ) + + { + int index = 0; + + if ( archivemode == ARCHIVE_READ ) + { + pointer_fixup_t *fixup; + ArchiveData( ARC_ObjectPointer, &index, sizeof( index ) ); + + // Check for a NULL pointer + assert( ptr ); + if ( !ptr ) + { + FileError( "NULL pointer in ArchiveObjectPointer." ); + } + + // + // see if the variable was NULL + // + if ( index == ARCHIVE_NULL_POINTER ) + { + *ptr = NULL; + } + else + { + // init the pointer with NULL until we can fix it + *ptr = NULL; + + fixup = new pointer_fixup_t; + fixup->ptr = ( void ** )ptr; + fixup->index = index; + fixup->type = pointer_fixup_normal; + fixupList.AddObject( fixup ); + } + } + else + { + if ( *ptr ) + { + index = classpointerList.AddUniqueObject( *ptr ); + } + else + { + index = ARCHIVE_NULL_POINTER; + } + ArchiveData( ARC_ObjectPointer, &index, sizeof( index ) ); + } + } + +void Archiver::ArchiveSafePointer + ( + SafePtrBase * ptr + ) + + { + int index = 0; + + if ( archivemode == ARCHIVE_READ ) + { + pointer_fixup_t *fixup; + + ArchiveData( ARC_SafePointer, &index, sizeof( &index ) ); + + // Check for a NULL pointer + assert( ptr ); + if ( !ptr ) + { + FileError( "NULL pointer in ReadSafePointer." ); + } + + // + // see if the variable was NULL + // + if ( index == ARCHIVE_NULL_POINTER ) + { + ptr->InitSafePtr( NULL ); + } + else + { + // init the pointer with NULL until we can fix it + ptr->InitSafePtr( NULL ); + + // Add new fixup + fixup = new pointer_fixup_t; + fixup->ptr = ( void ** )ptr; + fixup->index = index; + fixup->type = pointer_fixup_safe; + fixupList.AddObject( fixup ); + } + } + else + { + if ( ptr->Pointer() ) + { + Class * obj; + + obj = ptr->Pointer(); + index = classpointerList.AddUniqueObject( obj ); + } + else + { + index = ARCHIVE_NULL_POINTER; + } + ArchiveData( ARC_SafePointer, &index, sizeof( index ) ); + } + } + +void Archiver::ArchiveEvent + ( + Event * ev + ) + + { + if ( archivemode == ARCHIVE_READ ) + { +#ifndef NDEBUG + CheckRead(); +#endif +#ifdef ARCHIVE_USE_TYPES + CheckType( ARC_Event ); +#endif + + if ( !fileerror ) + { + ev->Archive( *this ); + } + } + else + { +#ifndef NDEBUG + CheckWrite(); +#endif +#ifdef ARCHIVE_USE_TYPES + WriteType( ARC_Event ); +#endif + + //FIXME!!!! Make this handle null events + if ( ev == NULL ) + { + NullEvent.Archive( *this ); + } + else + { + ev->Archive( *this ); + } + } + } + +void Archiver::ArchiveEventPointer + ( + Event ** ev + ) + + { + int index; + + if ( archivemode == ARCHIVE_READ ) + { +#ifndef NDEBUG + CheckRead(); +#endif +#ifdef ARCHIVE_USE_TYPES + CheckType( ARC_EventPointer ); +#endif + ArchiveInteger( &index ); + + if ( !fileerror ) + { + if ( index == ARCHIVE_POINTER_VALID ) + { + *ev = new Event; + (*ev)->Archive( *this ); + } + else + { + (*ev) = NULL; + } + } + } + else + { +#ifndef NDEBUG + CheckWrite(); +#endif + if ( *ev ) + { + index = ARCHIVE_POINTER_VALID; + } + else + { + index = ARCHIVE_NULL_POINTER; + } + +#ifdef ARCHIVE_USE_TYPES + WriteType( ARC_EventPointer ); +#endif + + ArchiveInteger( &index ); + if ( *ev ) + { + (*ev)->Archive( *this ); + } + } + } + +void Archiver::ArchiveRaw + ( + void *data, + size_t size + ) + + { + ArchiveData( ARC_Raw, data, size ); + } + +void Archiver::ArchiveString + ( + str * string + ) + + { + if ( archivemode == ARCHIVE_READ ) + { + size_t s; + char *data; + +#ifndef NDEBUG + CheckRead(); +#endif +#ifdef ARCHIVE_USE_TYPES + CheckType( ARC_String ); +#endif + + if ( !fileerror ) + { + s = ReadSize(); + if ( !fileerror ) + { + data = new char[ s + 1 ]; + if ( data ) + { + if ( s ) + { + readfile.Read( data, s ); + } + data[ s ] = 0; + + *string = data; + + delete [] data; + } + } + } + } + else + { +#ifndef NDEBUG + CheckWrite(); +#endif +#ifdef ARCHIVE_USE_TYPES + WriteType( ARC_String ); +#endif + WriteSize( string->length() ); + gi.FS_Write( string->m_data->data, string->length(), file ); + } + } + +Class * Archiver::ReadObject + ( + void + ) + + { + ClassDef *cls; + Class *obj; + str classname; + long objstart; + long endpos; + int index; + size_t size; + qboolean isent; + int type; + + CheckRead(); + + type = ReadType(); + if ( ( type != ARC_Object ) && ( type != ARC_Entity ) ) + { + FileError( "Expecting %s or %s", typenames[ ARC_Object ], typenames[ ARC_Entity ] ); + } + + size = ReadSize(); + ArchiveString( &classname ); + + cls = getClass( classname.c_str() ); + if ( !cls ) + { + FileError( "Invalid class %s.", classname.c_str() ); + } + + isent = checkInheritance( &Entity::ClassInfo, cls ); + if ( type == ARC_Entity ) + { + if ( !isent ) + { + FileError( "Non-Entity class object '%s' saved as an Entity based object.", classname.c_str() ); + } + + ArchiveInteger( &level.spawn_entnum ); + // + // make sure to setup spawnflags properly + // + ArchiveInteger( &level.spawnflags ); + } + else if ( isent ) + { + FileError( "Entity class object '%s' saved as non-Entity based object.", classname.c_str() ); + } + + ArchiveInteger( &index ); + objstart = readfile.Pos(); + + + obj = ( Class * )cls->newInstance(); + if ( !obj ) + { + FileError( "Failed to on new instance of class %s.", classname.c_str() ); + } + else + { + obj->Archive( *this ); + } + + if ( !fileerror ) + { + endpos = readfile.Pos(); + if ( ( endpos - objstart ) > size ) + { + FileError( "Object read past end of object's data" ); + } + else if ( ( endpos - objstart ) < size ) + { + FileError( "Object didn't read entire data from file" ); + } + } + + // + // register this pointer with our list + // + classpointerList.AddObjectAt( index, obj ); + + return obj; + } + +void Archiver::ArchiveObject + ( + Class *obj + ) + + { + str classname; + int index; + size_t size; + qboolean isent; + + if ( archivemode == ARCHIVE_READ ) + { + ClassDef *cls; + long objstart; + long endpos; + int type; + + CheckRead(); + type = ReadType(); + if ( ( type != ARC_Object ) && ( type != ARC_Entity ) ) + { + FileError( "Expecting %s or %s", typenames[ ARC_Object ], typenames[ ARC_Entity ] ); + } + + size = ReadSize(); + ArchiveString( &classname ); + + cls = getClass( classname.c_str() ); + if ( !cls ) + { + FileError( "Invalid class %s.", classname.c_str() ); + } + + if ( obj->classinfo() != cls ) + { + FileError( "Archive has a '%s' object, but was expecting a '%s' object.", classname.c_str(), obj->getClassname() ); + } + + isent = obj->isSubclassOf( Entity ); + if ( type == ARC_Entity ) + { + int entnum; + if ( !isent ) + { + FileError( "Non-Entity class object '%s' saved as an Entity based object.", classname.c_str() ); + } + + ArchiveInteger( &entnum ); + ( ( Entity * )obj )->SetEntNum( entnum ); + // + // make sure to setup spawnflags properly + // + ArchiveInteger( &level.spawnflags ); + } + else if ( isent ) + { + FileError( "Entity class object '%s' saved as non-Entity based object.", classname.c_str() ); + } + + ArchiveInteger( &index ); + objstart = readfile.Pos(); + + obj->Archive( *this ); + + if ( !fileerror ) + { + endpos = readfile.Pos(); + if ( ( endpos - objstart ) > size ) + { + FileError( "Object read past end of object's data" ); + } + else if ( ( endpos - objstart ) < size ) + { + FileError( "Object didn't read entire data from file" ); + } + } + + // + // register this pointer with our list + // + classpointerList.AddObjectAt( index, obj ); + } + else + { + long sizepos; + long objstart = 0; + long endpos; + + assert( obj ); + if ( !obj ) + { + FileError( "NULL object in WriteObject" ); + } + + isent = obj->isSubclassOf( Entity ); + + CheckWrite(); + if ( isent ) + { + WriteType( ARC_Entity ); + } + else + { + WriteType( ARC_Object ); + } + + sizepos = gi.FS_FTell( file ); + size = 0; + WriteSize( size ); + + classname = obj->getClassname(); + ArchiveString( &classname ); + + if ( isent ) + { + // Write out the entity number + ArchiveInteger( &( ( Entity * )obj )->entnum ); + // + // make sure to setup spawnflags properly + // + ArchiveInteger( &( ( Entity * )obj )->spawnflags ); + } + + // write out pointer index for this class pointer + index = classpointerList.AddUniqueObject( obj ); + ArchiveInteger( &index ); + + if ( !fileerror ) + { + objstart = gi.FS_FTell( file ); + obj->Archive( *this ); + } + + if ( !fileerror ) + { + endpos = gi.FS_FTell( file ); + size = endpos - objstart; + gi.FS_FSeek( file, sizepos, FS_SEEK_SET ); + WriteSize( size ); + + if ( !fileerror ) + { + gi.FS_FSeek( file, endpos, FS_SEEK_SET ); + } + } + } + } + diff --git a/source/source/fgame/archive.h b/source/source/fgame/archive.h new file mode 100644 index 0000000..5091ed4 --- /dev/null +++ b/source/source/fgame/archive.h @@ -0,0 +1,315 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/archive.h $ +// $Revision:: 7 $ +// $Author:: Markd $ +// $Date:: 5/31/00 10:19a $ +// +// Copyright (C) 1997 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source is may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/archive.h $ +// +// 7 5/31/00 10:19a Markd +// 4th pass saved games +// +// 6 5/30/00 7:06p Markd +// saved games 4th pass +// +// 5 5/27/00 8:06p Markd +// Saved games 3rd pass +// +// 4 5/27/00 2:56p Markd +// Save games 2nd pass +// +// 3 5/26/00 7:44p Markd +// 2nd phase save games +// +// 2 5/25/00 4:28p Markd +// fixed up archive functions +// +// 1 9/10/99 10:53a Jimdose +// +// 1 9/08/99 3:15p Aldie +// +// 5 7/29/99 5:33p Markd +// Fixed weird compiler bug +// +// DESCRIPTION: +// Class for archiving objects +// + +#ifndef __ARCHIVE_H__ +#define __ARCHIVE_H__ + +#include "g_local.h" +#include "class.h" +#include "str.h" + +#define ARCHIVE_NULL_POINTER ( -654321 ) +#define ARCHIVE_POINTER_VALID ( 0 ) +#define ARCHIVE_POINTER_NULL ( ARCHIVE_NULL_POINTER ) +#define ARCHIVE_POINTER_SELF_REFERENTIAL ( -123456 ) + +#define ARCHIVE_WRITE 0 +#define ARCHIVE_READ 1 + +enum + { + pointer_fixup_normal, + pointer_fixup_safe + }; + +typedef struct + { + void **ptr; + int index; + int type; + } pointer_fixup_t; + +class FileRead : public Class + { + protected: + str filename; + size_t length; + byte *buffer; + byte *pos; + + public: + CLASS_PROTOTYPE( FileRead ); + + FileRead(); + ~FileRead(); + void Close( void ); + const char *Filename( void ); + size_t Length( void ); + size_t Pos( void ); + qboolean Seek( size_t newpos ); + qboolean Open( const char *name ); + qboolean Read( void *dest, size_t size ); + }; + +class Archiver : public Class + { + private: + Container classpointerList; + Container fixupList; + + protected: + str filename; + qboolean fileerror; + fileHandle_t file; + FileRead readfile; + int archivemode; + int numclassespos; + qboolean harderror; + + void CheckRead( void ); + void CheckType( int type ); + int ReadType( void ); + size_t ReadSize( void ); + void CheckSize( int type, size_t size ); + void ArchiveData( int type, void *data, size_t size ); + + void CheckWrite( void ); + void WriteType( int type ); + void WriteSize( size_t size ); + + public: + CLASS_PROTOTYPE( Archiver ); + + Archiver(); + ~Archiver(); + void FileError( const char *fmt, ... ); + void Close( void ); + + qboolean Read( str &name, qboolean harderror = true ); + qboolean Read( const char *name, qboolean harderror = true ); + Class *ReadObject( void ); + + qboolean Create( str &name, qboolean harderror = true ); + qboolean Create( const char *name, qboolean harderror = true ); + + qboolean Loading( void ); + qboolean Saving( void ); + qboolean NoErrors( void ); + + void ArchiveVector( Vector * vec ); + void ArchiveQuat( Quat * quat ); + void ArchiveInteger( int * num ); + void ArchiveUnsigned( unsigned * unum); + void ArchiveByte( byte * num ); + void ArchiveChar( char * ch ); + void ArchiveShort( short * num ); + void ArchiveUnsignedShort( unsigned short * num ); + void ArchiveFloat( float * num ); + void ArchiveDouble( double * num ); + void ArchiveBoolean( qboolean * boolean ); + void ArchiveString( str * string ); + void ArchiveObjectPointer( Class ** ptr ); + void ArchiveSafePointer( SafePtrBase * ptr ); + void ArchiveEvent( Event * ev ); + void ArchiveEventPointer( Event ** ev ); + void ArchiveBool( bool * boolean ); + void ArchiveVec3( vec3_t vec ); + void ArchiveVec4( vec4_t vec ); + + void ArchiveRaw( void *data, size_t size ); + void ArchiveObject( Class *obj ); + + }; + +inline qboolean Archiver::Read + ( + str &name, + qboolean harderror + ) + + { + return Read( name.c_str(), harderror ); + } + +inline qboolean Archiver::Create + ( + str &name, + qboolean harderror + ) + + { + return Create( name.c_str(), harderror ); + } + +inline qboolean Archiver::Loading + ( + void + ) + { + return ( archivemode == ARCHIVE_READ ); + } + +inline qboolean Archiver::Saving + ( + void + ) + { + return ( archivemode == ARCHIVE_WRITE ); + } + +inline qboolean Archiver::NoErrors + ( + void + ) + { + return ( !fileerror ); + } + +inline void Container::Archive + ( + Archiver &arc + ) + { + int i, num; + + if ( arc.Loading() ) + { + ClearObjectList(); + arc.ArchiveInteger( &num ); + Resize( num ); + } + else + { + num = numobjects; + arc.ArchiveInteger( &num ); + } + for( i = 1; i <= num; i++ ) + { + arc.ArchiveString( AddressOfObjectAt( i ) ); + } + } + +inline void Container::Archive + ( + Archiver &arc + ) + { + int i, num; + + if ( arc.Loading() ) + { + ClearObjectList(); + arc.ArchiveInteger( &num ); + Resize( num ); + } + else + { + num = numobjects; + arc.ArchiveInteger( &num ); + } + for( i = 1; i <= num; i++ ) + { + arc.ArchiveVector( AddressOfObjectAt( i ) ); + } + } + +inline void Container::Archive + ( + Archiver &arc + ) + { + int i, num; + + if ( arc.Loading() ) + { + ClearObjectList(); + arc.ArchiveInteger( &num ); + Resize( num ); + } + else + { + num = numobjects; + arc.ArchiveInteger( &num ); + } + for( i = 1; i <= num; i++ ) + { + arc.ArchiveInteger( AddressOfObjectAt( i ) ); + } + } + +inline void Container::Archive + ( + Archiver &arc + ) + { + int i, num; + + if ( arc.Loading() ) + { + ClearObjectList(); + arc.ArchiveInteger( &num ); + Resize( num ); + } + else + { + num = numobjects; + arc.ArchiveInteger( &num ); + } + for( i = 1; i <= num; i++ ) + { + arc.ArchiveFloat( AddressOfObjectAt( i ) ); + } + } + +#define ArchiveEnum( thing, type ) \ + { \ + int tempInt; \ + \ + tempInt = ( int )( thing ); \ + arc.ArchiveInteger( &tempInt ); \ + ( thing ) = ( type )tempInt; \ + } + + +#endif /* archive.h */ diff --git a/source/source/fgame/armor.cpp b/source/source/fgame/armor.cpp new file mode 100644 index 0000000..0979310 --- /dev/null +++ b/source/source/fgame/armor.cpp @@ -0,0 +1,114 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/armor.cpp $ +// $Revision:: 5 $ +// $Author:: Markd $ +// $Date:: 6/23/00 8:41p $ +// +// Copyright (C) 1997 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source is may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/armor.cpp $ +// +// 5 6/23/00 8:41p Markd +// made a lot of changes to different constructors for saved game support +// +// 4 6/01/00 3:18p Markd +// rewrote giveItem and item management in sentient +// +// 3 1/26/00 3:33p Aldie +// Change Amount to getAmount. Added some 'listinventory' command. Added give +// all cheat to execute the script in global/giveall.txt +// +// 2 1/06/00 11:08p Jimdose +// cleaning up unused code +// +// 1 9/10/99 10:53a Jimdose +// +// 1 9/08/99 3:15p Aldie +// +// +// DESCRIPTION: +// Standard armor that prevents a percentage of damage per hit. +// + +#include "g_local.h" +#include "armor.h" + +CLASS_DECLARATION( Item, Armor, NULL ) + { + { NULL, NULL } + }; + +Armor::Armor() + { + if ( LoadingSavegame ) + { + // no need to proceed if loading a game + return; + } + + if ( DM_FLAG( DF_NO_ARMOR ) ) + { + PostEvent( EV_Remove, EV_REMOVE ); + return; + } + + setAmount( 0 ); + } + +void Armor::Setup + ( + const char *model, + int amount + ) + + { + assert( model ); + setModel( model ); + setAmount( amount ); + } + +void Armor::Add + ( + int num + ) + + { + // Armor never adds, it only replaces + amount = num; + if ( amount >= MaxAmount() ) + { + amount = MaxAmount(); + } + } + +qboolean Armor::Pickupable + ( + Entity *other + ) + + { + if ( !other->isSubclassOf( Sentient ) ) + { + return false; + } + else + { + Sentient * sent; + Item * item; + + sent = ( Sentient * )other; + item = sent->FindItem( getName() ); + + // If our armor is > than our current armor or armor has no value, then leave it alone. + if ( item && ( ( item->getAmount() >= this->getAmount() ) || !this->getAmount() ) ) + { + return false; + } + } + return true; + } diff --git a/source/source/fgame/armor.h b/source/source/fgame/armor.h new file mode 100644 index 0000000..229d91c --- /dev/null +++ b/source/source/fgame/armor.h @@ -0,0 +1,46 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/armor.h $ +// $Revision:: 2 $ +// $Author:: Jimdose $ +// $Date:: 1/06/00 11:08p $ +// +// Copyright (C) 1997 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source is may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/armor.h $ +// +// 2 1/06/00 11:08p Jimdose +// cleaning up unused code +// +// 1 9/10/99 10:53a Jimdose +// +// 1 9/08/99 3:15p Aldie +// +// DESCRIPTION: +// Standard armor that prevents a percentage of damage per hit. +// + +#ifndef __ARMOR_H__ +#define __ARMOR_H__ + +#include "item.h" + +class Armor : public Item + { + protected: + virtual void Setup( const char *model, int amount ); + virtual void Add( int amount ); + + public: + CLASS_PROTOTYPE( Armor ); + + Armor(); + + virtual qboolean Pickupable( Entity *other ); + }; + +#endif /* armor.h */ diff --git a/source/source/fgame/b_files.cpp b/source/source/fgame/b_files.cpp new file mode 100644 index 0000000..fe51ab2 --- /dev/null +++ b/source/source/fgame/b_files.cpp @@ -0,0 +1,487 @@ +// +// b_files.c +// + + +#include "b_local.h" + +#if 0 +// +// parse support routines +// + +static qboolean Nav_ParseLiteral( char **data, const char *string ) { + char *token; + + token = COM_ParseExt( data, qtrue ); + if ( token[0] == 0 ) { + gi.Printf( ERROR "unexpected EOF\n" ); + return qtrue; + } + + if ( Q_stricmp( token, string ) ) { + gi.Printf( ERROR "required string '%s' missing\n", string ); + return qtrue; + } + + return qfalse; +} + + +static qboolean Nav_ParseString( char **data, char **s ) { + *s = COM_ParseExt( data, qfalse ); + if ( s[0] == 0 ) { + gi.Printf( ERROR "unexpected EOF\n" ); + return qtrue; + } + return qfalse; +} + + +static qboolean Nav_ParseInt( char **data, int *i ) { + char *token; + + token = COM_ParseExt( data, qfalse ); + if ( token[0] == 0 ) { + gi.Printf( ERROR "unexpected EOF\n" ); + return qtrue; + } + + *i = atoi( token ); + return qfalse; +} + + +// +// bot parameters file : scripts/bots.cfg +// + +char botParms[0x10000]; + + +static int MethodNameToNumber( const char *name ) { + if ( !Q_stricmp( name, "EXPONENTIAL" ) ) { + return METHOD_EXPONENTIAL; + } + if ( !Q_stricmp( name, "LINEAR" ) ) { + return METHOD_LINEAR; + } + if ( !Q_stricmp( name, "LOGRITHMIC" ) ) { + return METHOD_LOGRITHMIC; + } + if ( !Q_stricmp( name, "ALWAYS" ) ) { + return METHOD_ALWAYS; + } + if ( !Q_stricmp( name, "NEVER" ) ) { + return METHOD_NEVER; + } + + return -1; +} + + +static int ItemNameToNumber( const char *name, int itemType ) { + int n; + + for ( n = 0; n < bg_numItems; n++ ) { + if ( bg_itemlist[n].type != itemType ) { + continue; + } + if ( Q_stricmp( bg_itemlist[n].classname, name ) == 0 ) { + return bg_itemlist[n].tag; + } + } + + return -1; +} + + +void Bot_ParseParms( const char *botName, gentity_t *bot, char *userinfo ) { + char *token; + char *value; + char *p; + int n; + int count; + + if ( !botName || !botName[0]) { + botName = "Player"; + } + + strcpy( userinfo, "\\name\\" ); + strcat( userinfo, botName ); + + // fill in defaults + bot->bot->reactions = 3; + bot->bot->aim = 3; + bot->bot->move = 3; + bot->bot->aggression = 3; + bot->bot->intelligence = 3; + bot->bot->hfov = 90 / 2; + bot->bot->vfov = 68 / 2; + bot->bot->healthMethod = METHOD_LOGRITHMIC; + bot->bot->armorMethod = METHOD_LINEAR; + bot->bot->ammoMethod = METHOD_EXPONENTIAL; + bot->bot->allWeaponOrder[0] = WP_BFG; + bot->bot->allWeaponOrder[1] = WP_ROCKET_LAUNCHER; + bot->bot->allWeaponOrder[2] = WP_RAILGUN; + bot->bot->allWeaponOrder[3] = WP_PLASMAGUN; + bot->bot->allWeaponOrder[4] = WP_GRENADE_LAUNCHER; + bot->bot->allWeaponOrder[5] = WP_SHOTGUN; + bot->bot->allWeaponOrder[6] = WP_MACHINEGUN; + bot->bot->allWeaponOrder[7] = WP_NONE; + + p = botParms; + COM_BeginParseSession(); + + // look for the right bot + while ( p ) { + token = COM_ParseExt( &p, qtrue ); + if ( token[0] == 0 ) + return; + + if ( !Q_stricmp( token, botName ) ) { + break; + } + + SkipBracedSection( &p ); + } + if ( !p ) { + return; + } + + if ( Nav_ParseLiteral( &p, "{" ) ) { + return; + } + + // parse the bot info block + while ( 1 ) { + token = COM_ParseExt( &p, qtrue ); + if ( !token[0] ) { + gi.Printf( "ERROR: unexpected EOF while parsing '%s'\n", botName ); + return; + } + + if ( !Q_stricmp( token, "}" ) ) { + break; + } + + // model + if ( !Q_stricmp( token, "model" ) ) { + if ( Nav_ParseString( &p, &value ) ) { + continue; + } + strcat ( userinfo, "\\model\\" ); + strcat ( userinfo, value ); + continue; + } + + // reactions + if ( !Q_stricmp( token, "reactions" ) ) { + if ( Nav_ParseInt( &p, &n ) ) { + SkipRestOfLine( &p ); + continue; + } + if ( n < 1 || n > 5 ) { + gi.Printf( WARNING "bad %s in bot '%s'\n", token, botName ); + continue; + } + bot->bot->reactions = n; + continue; + } + + // aim + if ( !Q_stricmp( token, "aim" ) ) { + if ( Nav_ParseInt( &p, &n ) ) { + SkipRestOfLine( &p ); + continue; + } + if ( n < 1 || n > 5 ) { + gi.Printf( WARNING "bad %s in bot '%s'\n", token, botName ); + continue; + } + bot->bot->aim = n; + continue; + } + + // move + if ( !Q_stricmp( token, "move" ) ) { + if ( Nav_ParseInt( &p, &n ) ) { + SkipRestOfLine( &p ); + continue; + } + if ( n < 1 || n > 5 ) { + gi.Printf( WARNING "bad %s in bot '%s'\n", token, botName ); + continue; + } + bot->bot->move = n; + continue; + } + + // aggression + if ( !Q_stricmp( token, "aggression" ) ) { + if ( Nav_ParseInt( &p, &n ) ) { + SkipRestOfLine( &p ); + continue; + } + if ( n < 1 || n > 5 ) { + gi.Printf( WARNING "bad %s in bot '%s'\n", token, botName ); + continue; + } + bot->bot->aggression = n; + continue; + } + + // intelligence + if ( !Q_stricmp( token, "intelligence" ) ) { + if ( Nav_ParseInt( &p, &n ) ) { + SkipRestOfLine( &p ); + continue; + } + if ( n < 1 || n > 5 ) { + gi.Printf( WARNING "bad %s in bot '%s'\n", token, botName ); + continue; + } + bot->bot->intelligence = n; + continue; + } + + // hfov + if ( !Q_stricmp( token, "hfov" ) ) { + if ( Nav_ParseInt( &p, &n ) ) { + SkipRestOfLine( &p ); + continue; + } + if ( n < 30 || n > 180 ) { + gi.Printf( WARNING "bad %s in bot '%s'\n", token, botName ); + continue; + } + bot->bot->hfov = n / 2; + continue; + } + + // vfov + if ( !Q_stricmp( token, "vfov" ) ) { + if ( Nav_ParseInt( &p, &n ) ) { + SkipRestOfLine( &p ); + continue; + } + if ( n < 30 || n > 180 ) { + gi.Printf( WARNING "bad %s in bot '%s'\n", token, botName ); + continue; + } + bot->bot->vfov = n / 2; + continue; + } + + // healthMethod + if ( !Q_stricmp( token, "healthMethod" ) ) { + if ( Nav_ParseString( &p, &value ) ) { + continue; + } + n = MethodNameToNumber( value ); + if ( n == -1 ) { + gi.Printf( "WARNING: bad %s in bot '%s'\n", token, botName ); + continue; + } + bot->bot->healthMethod = n; + continue; + } + + // armorMethod + if ( !Q_stricmp( token, "armorMethod" ) ) { + if ( Nav_ParseString( &p, &value ) ) { + continue; + } + n = MethodNameToNumber( value ); + if ( n == -1 ) { + gi.Printf( "WARNING: bad %s in bot '%s'\n", token, botName ); + continue; + } + bot->bot->armorMethod = n; + continue; + } + + // ammoMethod + if ( !Q_stricmp( token, "ammoMethod" ) ) { + if ( Nav_ParseString( &p, &value ) ) { + continue; + } + n = MethodNameToNumber( value ); + if ( n == -1 ) { + gi.Printf( "WARNING: bad %s in bot '%s'\n", token, botName ); + continue; + } + bot->bot->ammoMethod = n; + continue; + } + + // weapons + if ( !Q_stricmp( token, "weapons" ) ) { + for ( count = 0; count < MAX_WEAPONS; count++ ) { + if ( Nav_ParseString( &p, &value ) ) { + break; + } + if ( *value == 0 ) { + break; + } + n = ItemNameToNumber( value, IT_WEAPON ); + if ( n == -1 ) { + gi.Printf( "WARNING: bad %s in bot '%s'\n", token, botName ); + continue; + } + bot->bot->allWeaponOrder[count] = n; + } + if ( count < MAX_WEAPONS ) { + bot->bot->allWeaponOrder[count] = WP_NONE; + } + continue; + } + + // snd + if ( !Q_stricmp( token, "snd" ) ) { + if ( Nav_ParseString( &p, &value ) ) { + continue; + } + strcat( userinfo, "\\snd\\" ); + strcat( userinfo, value ); + continue; + } + + gi.Printf( "WARNING: unknown keyword '%s' while parsing '%s'\n", token, botName ); + SkipRestOfLine( &p ); + } +} + + +void Bot_LoadParms( void ) { + int len; + char filename[MAX_QPATH]; + char *buffer; + + sprintf( filename, "scripts/bots.cfg" ); + gi.Printf( "Parsing %s\n", filename ); + len = gi.FS_ReadFile( filename, &buffer, qtrue ); + if ( len == -1 ) { + gi.Printf( "file not found\n" ); + } + + if ( len >= sizeof( botParms ) ) { + gi.Error( ERR_DROP, "scripts/bots.cfg is too large" ); + } + strncpy( botParms, buffer, sizeof( botParms ) - 1 ); + gi.FS_FreeFile( buffer ); +} +#endif + + +// +// navigation data : maps/*.nav +// + +void Nav_LoadRoutes( void ) { + int len; + navheader_t *header; + int value; + int n; + str filename; + + Swap_Init(); + + surfaceCount = 0; + surface = NULL; + neighborCount = 0; + neighbor = NULL; + + // load the file + filename = "maps/"; + filename += level.mapname + ".nav"; + + gi.Printf( "Loading %s\n", filename.c_str() ); + len = gi.FS_ReadFile( filename.c_str(), ( void ** )&navFileData, qtrue ); + if ( len == -1 ) { + gi.Printf( WARNING "no navigation data\n" ); + return; + } + if ( len < sizeof( navheader_t ) ) { + gi.Printf( ERROR "no nav file header\n" ); + goto cleanup; + } + + // process the header + header = (navheader_t *)navFileData; + header->id = LittleLong( header->id ); + header->version = LittleLong( header->version ); + header->surfaceCount = LittleLong( header->surfaceCount ); + header->neighborCount = LittleLong( header->neighborCount ); + + // validate the header fields + if ( header->id != NAVFILE_ID ) { + gi.Printf( ERROR "incorrect nav file id\n" ); + goto cleanup; + } + if ( header->version != NAVFILE_VERSION ) { + gi.Printf( ERROR "incorrect nav file version (%i, should be %i)\n", header->version, NAVFILE_VERSION ); + goto cleanup; + } + + value = /* header */ sizeof( navheader_t ) + + /* surfaces */ header->surfaceCount * sizeof( nsurface_t ) + + /* neighbors */ header->neighborCount * sizeof( nneighbor_t ) + + /* routes */ header->surfaceCount * header->surfaceCount * sizeof( byte ); + + if ( value != len ) { + gi.Printf( ERROR "incorrect nav file length (%i, should be %i)\n", len, value ); + goto cleanup; + } + + surfaceCount = header->surfaceCount; + neighborCount = header->neighborCount; + + // process surfaces + surface = (nsurface_t *)(navFileData + sizeof( navheader_t ) ); + for ( n = 0; n < surfaceCount; n++ ) { + surface[n].origin[0] = LittleFloat( surface[n].origin[0] ); + surface[n].origin[1] = LittleFloat( surface[n].origin[1] ); + surface[n].origin[2] = LittleFloat( surface[n].origin[2] ); + + surface[n].absmin[0] = LittleFloat( surface[n].absmin[0] ); + surface[n].absmin[1] = LittleFloat( surface[n].absmin[1] ); + + surface[n].absmax[0] = LittleFloat( surface[n].absmax[0] ); + surface[n].absmax[1] = LittleFloat( surface[n].absmax[1] ); + + surface[n].flags = LittleLong( surface[n].flags ); + surface[n].neighborCount = LittleLong( surface[n].neighborCount ); + surface[n].neighborIndex = LittleLong( surface[n].neighborIndex ); + surface[n].parm = LittleLong( surface[n].parm ); + } + + // process neighbors + neighbor = (nneighbor_t *)((byte *)surface + surfaceCount * sizeof( nsurface_t )); + for ( n = 0; n < neighborCount; n++ ) { + neighbor[n].origin[0] = LittleFloat( neighbor[n].origin[0] ); + neighbor[n].origin[1] = LittleFloat( neighbor[n].origin[1] ); + neighbor[n].origin[2] = LittleFloat( neighbor[n].origin[2] ); + + neighbor[n].absmin[0] = LittleFloat( neighbor[n].absmin[0] ); + neighbor[n].absmin[1] = LittleFloat( neighbor[n].absmin[1] ); + + neighbor[n].absmax[0] = LittleFloat( neighbor[n].absmax[0] ); + neighbor[n].absmax[1] = LittleFloat( neighbor[n].absmax[1] ); + + neighbor[n].surfaceNum = LittleLong( neighbor[n].surfaceNum ); + neighbor[n].flags = LittleLong( neighbor[n].flags ); + neighbor[n].cost = LittleLong( neighbor[n].cost ); + neighbor[n].filler = LittleLong( neighbor[n].filler ); + } + + // process routes + route = (byte *)neighbor + neighborCount * sizeof( nneighbor_t ); + + gi.Printf( "...loaded %i surfaces and %i neighbors\n", surfaceCount, neighborCount ); + return; + +cleanup: + gi.FS_FreeFile ( navFileData ); + navFileData = NULL; +} diff --git a/source/source/fgame/b_local.h b/source/source/fgame/b_local.h new file mode 100644 index 0000000..ac094e5 --- /dev/null +++ b/source/source/fgame/b_local.h @@ -0,0 +1,167 @@ +#ifndef __B_LOCAL_H__ +#define __B_LOCAL_H__ + +#include "g_local.h" + +// +// This section should be moved to QFILES.H +// + +#define NAVFILE_ID (('I')+('N'<<8)+('A'<<16)+('V'<<24)) +#define NAVFILE_VERSION 2 + +typedef struct { + unsigned id; + unsigned version; + unsigned surfaceCount; + unsigned neighborCount; +} navheader_t; + + +#define MAX_SURFACES 4096 + +#define SF_PUSH 0x00000001 +#define SF_WATERLEVEL1 0x00000002 +#define SF_WATERLEVEL2 0x00000004 +#define SF_WATER_NOAIR 0x00000008 +#define SF_DUCK 0x00000010 +#define SF_PAIN 0x00000020 +#define SF_TELEPORTER 0x00000040 +#define SF_PLATHIGH 0x00000080 +#define SF_PLATLOW 0x00000100 + +typedef struct { + vec3_t origin; + vec2_t absmin; + vec2_t absmax; + int parm; + unsigned flags; + unsigned neighborCount; + unsigned neighborIndex; +} nsurface_t; + + +#define MAX_NEIGHBORS 16384 + +#define NF_JUMP 0x00000001 +#define NF_DUCK 0x00000002 +#define NF_PLAT 0x00000004 +#define NF_FALL1 0x00000008 +#define NF_FALL2 0x00000010 + +typedef struct { + vec3_t origin; + vec2_t absmin; // region within this surface that is the portal to the other surface + vec2_t absmax; + int surfaceNum; + unsigned flags; // jump, prerequisite button, will take falling damage, etc... + float cost; + unsigned filler; // to be used as a "string index" into an array of targetnames for buttons, etc +} nneighbor_t; + +#define WARNING "\033" "3" "WARNING: " +#define ERROR "\033" "1" "ERROR: " + + +// file buffers + +extern char botParms[0x10000]; +extern char *navFileData; + + +// +// Navigation susbsystem +// + +#define NAVF_DUCK 0x00000001 +#define NAVF_JUMP 0x00000002 +#define NAVF_HOLD 0x00000004 +#define NAVF_SLOW 0x00000008 + +#define METHOD_EXPONENTIAL 1 +#define METHOD_LINEAR 2 +#define METHOD_LOGRITHMIC 3 +#define METHOD_ALWAYS 4 +#define METHOD_NEVER 5 + +// combat maneuvers +#define CM_NONE 0 + +#define CM_CLOSE_DISTANCE 1 +#define CM_OPEN_DISTANCE 2 +#define CM_HOLD_DISTANCE 3 + +#define CM_GET_ITEM 4 +#define CM_RUN_AWAY 5 + +#define CM_CIRCLE 6 +#define CM_DUCK 7 + +typedef enum {SPOT_ORIGIN, SPOT_HEAD, SPOT_WEAPON, SPOT_LEGS, SPOT_GROUND} spot_t; + +#define BOT_TIME_TO_LOSE_SIGHT 2000 + +#define SF_FROMMAPFILE 0x80000000 + +#define DEBUG_LEVEL_DETAIL 4 +#define DEBUG_LEVEL_INFO 3 +#define DEBUG_LEVEL_WARNING 2 +#define DEBUG_LEVEL_ERROR 1 +#define DEBUG_LEVEL_NONE 0 + + +// +// b_main.c +// +void Debug_Printf( cvar_t *cv, int level, char *fmt, ... ); +void Debug_BotPrintf( gentity_t *bot, cvar_t *cv, int debugLevel, char *fmt, ... ); + + +// +// b_ai.c +// +extern cvar_t *debugBotAI; +extern cvar_t *debugBotFreeze; + +void Bot_InitAI( void ); +void Bot_Pain( gentity_t *bot, gentity_t *other, int damage ); +void Bot_Touch( gentity_t *bot, gentity_t *other, trace_t *trace ); +void BotSpawn( gentity_t *bot ); +void Bot_Fetch_f( void ); + +// +// b_nav.c +// +extern char *navFileData; +extern int surfaceCount; +extern nsurface_t *surface; +extern int neighborCount; +extern nneighbor_t *neighbor; +extern byte *route; + + +void Nav_InitPreSpawn( void ); +void Nav_InitPostSpawn( void ); +void Nav_Shutdown( void ); +void Nav_ShowPath( gentity_t *bot ); +int Nav_GroundSurfaceNumber( gentity_t *ent ); +int Nav_ItemSurfaceNumber( gentity_t *ent ); +int Nav_EntitySurfaceNumber( gentity_t *ent ); +int Nav_MoveToGoal( gentity_t *bot, vec3_t dir, int *flags ); + +// +// b_items.c +// +void Nav_InitRoamList( void ); +qboolean WeaponIsOnLevel( int weapon ); +gentity_t *Nav_ChooseRoamGoal( void ); + +// +// b_files.c +// +void Bot_ParseParms( const char *botName, gentity_t *bot, char *userinfo ); +void Bot_LoadParms( void ); +void Nav_LoadRoutes( void ); +void Nav_SaveRoutes( void ); + +#endif diff --git a/source/source/fgame/b_nav.cpp b/source/source/fgame/b_nav.cpp new file mode 100644 index 0000000..1abbb49 --- /dev/null +++ b/source/source/fgame/b_nav.cpp @@ -0,0 +1,632 @@ + +// +// b_nav.c +// + +//FIXME make botInfo, etc visible here too and get rid of all the mutliple dereferences like bot->bot-> + +#include "b_local.h" + + +#define NAVF_EDGEZONE 0x00000001 + +#define INFINITE 1000000 + +#define BOTAI_PUSHED (1<<0) + +cvar_t *nav_showsectors; + +char *navFileData; + +int surfaceCount; +nsurface_t *surface; +int neighborCount; +nneighbor_t *neighbor; +byte *route; + +//#if 0 + +static int spawnpadModelIndex; + + +int Nav_SurfaceUnderPlayer( gentity_t *player ) { + vec3_t start; + vec3_t end; + vec3_t p; + trace_t tr; + float bestDist; + int bestSurf; + vec3_t v; + int n; + float dist; + + VectorCopy( player->s.origin, start ); + VectorCopy( player->s.origin, end ); + end[2] -= 4096; + + gi.trace ( &tr, start, player->mins, player->maxs, end, player->s.number, MASK_DEADSOLID, true ); + +// p[0] = ((int)tr.endpos[0] + 8) & (~16); +// p[1] = ((int)tr.endpos[1] + 8) & (~16); + p[0] = tr.endpos[0]; + p[1] = tr.endpos[1]; + p[2] = floor(tr.endpos[2]+player->mins[2]); + + bestDist = INFINITE; + bestSurf = -1; + + for ( n = 0; n < surfaceCount; n++ ) { + if ( Q_fabs( surface[n].origin[2] - p[2] ) > 24 ) { + continue; + } + + VectorSubtract( p, surface[n].origin, v ); + dist = VectorLength( v ); + if ( dist < bestDist ) { + bestDist = dist; + bestSurf = n; + } + + if ( surface[n].origin[2] != p[2] ) { + continue; + } + if ( surface[n].absmin[0] > p[0] ) { + continue; + } + if ( surface[n].absmax[0] < p[0] ) { + continue; + } + if ( surface[n].absmin[1] > p[1] ) { + continue; + } + if ( surface[n].absmax[1] < p[1] ) { + continue; + } + return n; + } + +// gi.Printf( "guess for %s at %s\n", ent->classname, vtos( p ) ); + return bestSurf; +} + + +/* +============= +Nav_GroundSurfaceNumber + +Returns the surface number for where an entity is currently located. +If the entity is not on the ground, it returns -1. + +FIXME we can make this more efficient + right now surfaces are in Z sorted order + we could make a Z index and binary search it to get to right z group fast +============= +*/ +int Nav_GroundSurfaceNumber( gentity_t *ent ) { + vec3_t p; + vec3_t v; + int n; + float dist; + float bestDist; + int bestSurf; + gentity_t *groundEntity; + + // if ent is not on the ground it is not on a surface + if ( ent->s.groundEntityNum == -1 ) { + return -1; + } + +// p[0] = ((int)ent->s.origin[0] + 8) & (~16); +// p[1] = ((int)ent->s.origin[1] + 8) & (~16); + p[0] = ent->s.origin[0]; + p[1] = ent->s.origin[1]; + p[2] = floor(ent->s.origin[2]+ent->mins[2]); + + // if ground is not the world we need to handle it differently. + if ( ent->s.groundEntityNum != ENTITYNUM_WORLD ) { + groundEntity = &g_entities[ent->s.groundEntityNum]; + + // check for sitting on a spawn pad + if ( !groundEntity->bmodel && groundEntity->s.modelindex == spawnpadModelIndex ) { + p[2] -= 8.0; + } + // check for plats + /* else if ( groundEntity->bmodel && Q_stricmp( groundEntity->classname, "func_plat" ) == 0 ) { + // if at the top the return PLATHIGH surface number, otherwise return PLATLOW surface number + if ( VectorCompare( groundEntity->currentOrigin, groundEntity->pos2 ) ) { + return surface[groundEntity->navSurfaceNum].parm; + } + return groundEntity->navSurfaceNum; + } */ + } + + bestDist = INFINITE; + bestSurf = -1; + + for ( n = 0; n < surfaceCount; n++ ) { + if ( Q_fabs( surface[n].origin[2] - p[2] ) > 24 ) { + continue; + } + + VectorSubtract( p, surface[n].origin, v ); + dist = VectorLength( v ); + if ( dist < bestDist ) { + bestDist = dist; + bestSurf = n; + } + + if ( surface[n].origin[2] != p[2] ) { + continue; + } + if ( surface[n].absmin[0] > p[0] ) { + continue; + } + if ( surface[n].absmax[0] < p[0] ) { + continue; + } + if ( surface[n].absmin[1] > p[1] ) { + continue; + } + if ( surface[n].absmax[1] < p[1] ) { + continue; + } + return n; + } + +// gi.Printf( "guess for %s at %s\n", ent->classname, vtos( p ) ); + return bestSurf; +} + + +/* +============= +Nav_ItemSurfaceNumber + +Returns the surface number for where an item entity is currently located. +If the entity is not on the ground, it returns -1. This is a specialized +copy of Nav_GroundSurfaceNumber for items that caches the result. +============= +*/ +int Nav_ItemSurfaceNumber( gentity_t *ent ) { + if ( !VectorCompare( ent->s.origin, ent->navOrigin ) && level.time > ent->navTime ) { + VectorCopy( ent->s.origin, ent->navOrigin ); + ent->navTime = level.time; + ent->navSurfaceNum = Nav_GroundSurfaceNumber( ent ); + } + return ent->navSurfaceNum; +} + + +/* +============= +Nav_EntitySurfaceNumber +============= +*/ +int Nav_EntitySurfaceNumber( gentity_t *ent ) { + if ( ent->s.eType == ET_ITEM ) { + return Nav_ItemSurfaceNumber( ent ); + } + + /*if ( ent->classname&& strcmp( ent->classname, "bot_goal" ) == 0 ) { + return Nav_SurfaceUnderPlayer( ent ); + }*/ + + return Nav_GroundSurfaceNumber( ent ); +} + + +/* +============= +PathEdge +============= +*/ + +static nneighbor_t *PathEdge( int sourceSurfNum, int destSurfNum ) { + int base; + int n; + + base = surface[sourceSurfNum].neighborIndex; + for ( n = 0; n < surface[sourceSurfNum].neighborCount; n++ ) { + if ( neighbor[base+n].surfaceNum == destSurfNum ) { + return &neighbor[base+n]; + } + } + return NULL; +} + +/* +============= +PointIsInEdgeRegion +============= +*/ + +static qboolean PointIsInEdgeRegion( vec3_t p, nneighbor_t *n ) { + if ( p[0] < n->absmin[0] ) { + return qfalse; + } + if ( p[0] > n->absmax[0] ) { + return qfalse; + } + if ( p[1] < n->absmin[1] ) { + return qfalse; + } + if ( p[1] > n->absmax[1] ) { + return qfalse; + } + return qtrue; +} + + + +/* +============= +Nav_MoveToGoal +============= +*/ + +int Nav_MoveToGoal( gentity_t *bot, vec3_t dir, int *flags ) { + int currentSurf; + int nextSurf; + int thirdSurf; + int goalSurf; + int routeIndex; + nneighbor_t *edge; + nneighbor_t *nextEdge; + //gentity_t *ent; + //float dist; + + *flags = 0; + VectorCopy( bot->navDir, dir ); + + currentSurf = bot->currentSurface; + + // if bot is airborne, just keep heading the same + if ( currentSurf == -1 ) { + if ( bot->aiFlags & BOTAI_PUSHED ) { + //gi.Printf( "bot was bounced\n" ); + *flags |= NAVF_HOLD; + } + //gi.Printf( "not on ground\n" ); + return 0; + } + if ( bot->pushedTime < level.time ) { + bot->aiFlags &= ~BOTAI_PUSHED; + } + + if ( !bot->goalEntity ) { +// gi.Printf( ERROR "Nav_MoveToGoal called with no goalEntity set\n" ); + return -1; + } + + goalSurf = Nav_EntitySurfaceNumber( bot->goalEntity ); + if ( goalSurf == -1 ) { + return -1; + } + + // if we've changed surfaces, the surface to surface navigation flags and timer need to be cleared + if ( currentSurf != bot->lastSurface ) { + bot->navFlags = 0; + bot->navTime = 0; + //gi.Printf( "surface changed from %i to %i\n", bot->bot->lastSurface, bot->bot->currentSurface ); + } + + if ( currentSurf == goalSurf ) { + //gi.Printf( "On target surface\n" ); + VectorSubtract( bot->goalEntity->s.origin, bot->s.origin, dir ); + //VectorCopy( dir, bot->bot->navDir ); + VectorCopy( dir, bot->navDir ); + return 0; + } + + routeIndex = route[currentSurf * surfaceCount + goalSurf]; + if ( routeIndex == 255 ) { + //gi.Printf( "Nav_MoveToGoal - no known route from %i to %i\n", currentSurf, goalSurf ); + return -1; + } + if ( routeIndex >= surface[currentSurf].neighborCount ) { + gi.Printf( ERROR "Nav_MoveToGoal - bad routeIndex\n" ); + return -1; + } + nextSurf = neighbor[surface[currentSurf].neighborIndex + routeIndex].surfaceNum; + + edge = PathEdge( currentSurf, nextSurf ); + if ( !edge ) { + gi.Printf( ERROR "Nav_MoveToGoal - %i does not have %i as a neighbor\n", currentSurf, nextSurf ); + VectorClear( dir ); + return -1; + } + + if ( ! ( bot->navFlags & NAVF_EDGEZONE ) ) { + if ( PointIsInEdgeRegion( bot->s.origin, edge ) ) { + //gi.Printf( "hit edge\n" ); + bot->navFlags |= NAVF_EDGEZONE; + bot->navTime = level.time; + } + } + + // if we are in the edge zone + if ( bot->navFlags & NAVF_EDGEZONE ) { + // if we're trying to get onto a plat, we must make sure it's there + /*if ( surface[nextSurf].flags & SF_PLATLOW ) { + ent = &g_entities[surface[surface[nextSurf].parm].parm]; //FIXME this works for now, but I don't like it + if ( VectorCompare( ent->currentOrigin, ent->pos1 ) == 0 ) { + *flags |= NAVF_HOLD; + //gi.Printf(" wait for plat2\n" ); + } + }*/ + + // if we're riding up on a plat, we don't need to move + if ( surface[nextSurf].flags & SF_PLATHIGH ) { + *flags |= NAVF_HOLD; + //gi.Printf(" hold on plat\n" ); + } + + // if the next surface contains the goalEntity, head towards it + if ( nextSurf == goalSurf ) { + //gi.Printf( "next surf has goal - targeting directly\n" ); + VectorSubtract( bot->goalEntity->s.origin, bot->s.origin, dir ); + //VectorCopy( dir, bot->bot->navDir ); + VectorCopy( dir, bot->navDir ); + } + // start heading towards the next edge + else { + routeIndex = route[nextSurf * surfaceCount + goalSurf]; + if ( routeIndex == 255 ) { + gi.Printf( ERROR "Nav_MoveToGoal - no known route from %i to %i\n", nextSurf, goalSurf ); + return -1; + } + if ( routeIndex >= surface[nextSurf].neighborCount ) { + gi.Printf( ERROR "Nav_MoveToGoal - bad routeIndex\n" ); + return -1; + } + thirdSurf = neighbor[surface[nextSurf].neighborIndex + routeIndex].surfaceNum; + nextEdge = PathEdge( nextSurf, thirdSurf ); + if ( !nextEdge ) { + gi.Printf( ERROR "Nav_MoveToGoal - %i does not have %i as a neighbor\n", nextSurf, thirdSurf ); + VectorClear( dir ); + return -1; + } + //gi.Printf( "targeting next edge\n" ); + if ( surface[nextSurf].flags & SF_PLATHIGH ) { + VectorSubtract( nextEdge->origin, surface[nextSurf].origin, dir ); + } + else { + VectorSubtract( nextEdge->origin, bot->s.origin, dir ); + } + //VectorCopy( dir, bot->bot->navDir ); + VectorCopy( dir, bot->navDir ); + } + + if ( edge->flags & NF_DUCK ) { + *flags |= NAVF_DUCK; + } + if ( edge->flags & NF_JUMP ) { + *flags |= NAVF_JUMP; + } + } + else { + VectorSubtract( edge->origin, bot->s.origin, dir ); + //VectorCopy( dir, bot->bot->navDir ); + VectorCopy( dir, bot->navDir ); + + /*if ( surface[nextSurf].flags & SF_PLATLOW ) { + ent = &g_entities[surface[surface[nextSurf].parm].parm]; //FIXME this works for now, but I don't like it + if ( VectorCompare( ent->currentOrigin, ent->pos1 ) == 0 ) { + dist = VectorLength( dir ); + if ( dist > 64 ) { + *flags |= NAVF_SLOW; + //gi.Printf(" slow for plat\n" ); + } + else { + *flags |= NAVF_HOLD; + //gi.Printf(" wait for plat\n" ); + } + } + }*/ + } + + return 0; +} + + +void Nav_ShowPath( gentity_t *bot ) { +#if 0 + gentity_t *tent; + int m, n; + + if ( !bot->bot->goalEntity ) { + return; + } + + tent = G_TempEntity( bot->s.origin, EV_DEBUG_LINE ); + VectorCopy( bot->bot->currentWaypoint->s.origin, tent->s.origin2 ); + + m = bot->bot->currentWaypoint->count; + for (;;) { + if ( m == bot->bot->finalWaypoint->count ) { + break; + } + n = route[m*maxwaypoints+bot->bot->finalWaypoint->count]; + if ( n == -1 ) { + break; + } + tent = G_TempEntity( rents[m]->s.origin, EV_DEBUG_LINE ); + VectorCopy( rents[n]->s.origin, tent->s.origin2 ); + m = n; + } + + if ( bot->bot->finalWaypoint != bot->bot->goalEntity ) { + tent = G_TempEntity( bot->bot->finalWaypoint->s.origin, EV_DEBUG_LINE ); + VectorCopy( bot->bot->goalEntity->s.origin, tent->s.origin2 ); + } +#endif + /* gentity_t *tent; + int m, n; + gentity_t *player; + int pSurf; + + player = &g_entities[1]; + pSurf = Nav_GroundSurfaceNumber( player ); + + tent = G_TempEntity( player->s.origin, EV_DEBUG_LINE ); + VectorCopy( surface[pSurf].origin, tent->s.origin2 ); */ +} +//#endif + + +/* +// Init and Shutdown +// +// +*/ + +static void Nav_Cleanup( void ) { + if ( navFileData ) { + gi.FS_FreeFile ( navFileData ); + navFileData = NULL; + } + surfaceCount = 0; + neighborCount = 0; +} + +void Nav_InitPreSpawn( void ) { + nav_showsectors = gi.cvar( "nav_showsectors", "0", 0 ); + Nav_Cleanup(); + Nav_LoadRoutes(); +} + +void Nav_InitPostSpawn( void ) { +#if 0 + int n; + nsurface_t *s; + gentity_t *ent; + + // FIXME resolve targetnames here (like button needed to open a door) + + // get the modelindex for the spawnpad model so we can use it for surface determination + spawnpadModelIndex = G_ModelIndex( "models/objects/dmspot.md3" ); + + // set the navSurface for plats + for ( n = 0; n < surfaceCount; n++ ) { + s = &surface[n]; + if ( s->flags & SF_PLATLOW ) { + ent = &g_entities[surface[s->parm].parm]; //FIXME this works for now, but I don't like it + ent->navSurfaceNum = n; + } + } +#endif +} + + +void Nav_Shutdown ( void ) { + Nav_Cleanup(); +} + +void Nav_Test_f( void ) { +#if 0 + gentity_t *player; + gentity_t *goal; + char *goalname; + int pSurf; + int gSurf; + int cSurf; + int n; + gentity_t *tent; + + player = &g_entities[0]; + pSurf = Nav_GroundSurfaceNumber( player ); + + goalname = gi.argv(2); + if ( !goalname[0] ) { + gi.Printf( "Player1 is at (%f, %f, %f) on surface %i\n", player->s.origin[0], player->s.origin[1], player->s.origin[2] + player->mins[2], pSurf ); + return; + } + + goal = NULL; + goal = G_Find( goal, FOFS( classname ), goalname ); + if ( !goal ) { + gi.Printf( "no %s on level\n", goalname ); + return; + } + gSurf = Nav_EntitySurfaceNumber( goal ); + + + cSurf = pSurf; + while ( cSurf != gSurf ) { + n = route[cSurf * surfaceCount + gSurf]; + if ( n == 255 ) { + //gi.Printf( "no known route from %i to %i\n", cSurf, gSurf ); + return; + } + if ( n >= surface[cSurf].neighborCount ) { + gi.Printf( ERROR "bad routeIndex\n" ); + return; + } + n = neighbor[surface[cSurf].neighborIndex + n].surfaceNum; + + if ( cSurf == pSurf ) { + tent = G_TempEntity( player->s.origin, EV_DEBUG_LINE ); + } + else { + tent = G_TempEntity( surface[cSurf].origin, EV_DEBUG_LINE ); + } + if ( n == gSurf ) { + VectorCopy( goal->s.origin, tent->s.origin2 ); + } + else { + VectorCopy( surface[n].origin, tent->s.origin2 ); + } + + cSurf = n; + } +#endif +} + +void Nav_Gen_f( void ); + +void Cmd_Nav_f( void ) +{ + char *cmd; + + cmd = gi.argv(1); + + if ( Q_stricmp ( cmd, "gen" ) == 0 ) { + Nav_Gen_f(); + Nav_InitPreSpawn(); + } + else if ( Q_stricmp ( cmd, "test" ) == 0 ) { + Nav_Test_f(); + } + else { + gi.Printf("Unknown nav command '%s'\n", cmd); + } +} + +void Nav_ShowStuff + ( + void + ) + + { + int i; + nsurface_t *surf; + + if ( !nav_showsectors->integer ) + { + return; + } + + G_Color4f( 1, 1, 0, 1 ); + for( i = 0; i < surfaceCount; i++ ) + { + surf = &surface[ i ]; + + G_BeginLine(); + G_Vertex( Vector( surf->absmin[ 0 ], surf->absmin[ 1 ], surf->origin[ 2 ] ) ); + G_Vertex( Vector( surf->absmin[ 0 ], surf->absmax[ 1 ], surf->origin[ 2 ] ) ); + G_Vertex( Vector( surf->absmax[ 0 ], surf->absmax[ 1 ], surf->origin[ 2 ] ) ); + G_Vertex( Vector( surf->absmax[ 0 ], surf->absmin[ 1 ], surf->origin[ 2 ] ) ); + G_Vertex( Vector( surf->absmin[ 0 ], surf->absmin[ 1 ], surf->origin[ 2 ] ) ); + G_EndLine(); + } + } diff --git a/source/source/fgame/b_navgen.cpp b/source/source/fgame/b_navgen.cpp new file mode 100644 index 0000000..250c593 --- /dev/null +++ b/source/source/fgame/b_navgen.cpp @@ -0,0 +1,3089 @@ +// +// b_navgen.c +// + +/* +Path costs - time is the cost basis + For normal paths: take dist(sSurf.origin->edge + pmoveEndSpot->tSurf.origin) and + divide by speed to get time. Adjust for duck/wade/swim. Add on time used for + the pmoves to get from edge to pmoveEndspot. + Teleporter: fixed cost of teleport delay (currently 160ms, should be a shared define) + Plats: take vertical distance and divide by plat speed to get move time; add on + any delays (this assumes plats are always at bottom waiting for us) + Trains: ??? +*/ + +/* +FIXME for Q3MAP + When done in game, plates are seen at their low position. Once this is in Q3MAP they will + be seen in their high position requiring a bit of rework of that code. I've noted most of it. +*/ + + +#include +#include "b_local.h" +#include "mover.h" + + +// these defines are placeholders for when this code moves into Q3MAP and is multithreaded +#define ThreadLock() +#define ThreadUnlock() + +#define INFINITE 1000000 + +// these defines MUST match those in bg_pmove!!! +#define MIN_WALK_NORMAL 0.7 +#define STEPSIZE 18 +#define DEFAULT_VIEWHEIGHT 26 +#define CROUCH_VIEWHEIGHT 12 + +#define DUCKSCALE 0.25 +#define SWIMSCALE 0.50 +#define WADESCALE 0.70 + +// these defines MUST match the values used in the game dll +#define DEFAULT_MINS_0 -48 +#define DEFAULT_MINS_1 -48 +#define DEFAULT_MINS_2 0 +#define DEFAULT_MAXS_0 48 +#define DEFAULT_MAXS_1 48 +#define DEFAULT_MAXS_2 76 +#define CROUCH_MAXS_2 49 + +// although this is a derived value, it needs to match the game +#define MAX_JUMPHEIGHT 32 + +// these are used to drive the pmove based reachability function +#define MAX_PMOVES 64 +#define PMOVE_MSEC 50 +#define PLAYER_SPEED 320 + +// defines for ranges and granularity of the spot testing +#define XY_MIN -4080 +#define XY_MAX 4080 +#define XY_STEP 16 +#define Z_MIN -4096 +#define Z_MAX 4064 +#define Z_STEP 1 + +#define MAX_SPOTS 65536 +#define MAX_SPOTINDEX (((XY_MAX - XY_MIN) / XY_STEP) + 2 ) + +typedef struct { + unsigned flags; + int surfaceNum; + vec3_t origin; + int parm; +} nspot_t; + +static nspot_t *spot; +static int spotCount; + +static int sortIndex[MAX_SPOTS]; +static int spotIndex[MAX_SPOTINDEX]; +static int spotIndexCount; + + +#if 0 //Q3MAP +nsurface_t *surface; +int surfaceCount; + + +nneighbor_t *neighbor; +int neighborCount; + +byte *route; +#endif + +/* +============= +VectorToString + +This is just a convenience function +for printing vectors +============= +*/ +char *vtos( const 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; +} + +// +// FindSpots +// + +static vec3_t mins; +static vec3_t duckMaxs; +static vec3_t standMaxs; + +//FIXME this should NOT be global +static gentity_t *test; + +static void FindSpotsInY( int num ) { + trace_t tr; + trace_t tr2; + vec3_t origin; + vec3_t point2; + vec3_t testpoint; + qboolean roof; + float viewheight; + int cont; + float sample1; + float sample2; + int waterlevel; + //int numEnts; + //gentity_t *ents[MAX_GENTITIES]; + gentity_t *ent; + qboolean n; + vec3_t absmin; + vec3_t absmax; + int spotNum; + float height; + //gentity_t *target; + //gentity_t *destTarget; + + origin[0] = XY_MIN + num * XY_STEP; + + for ( origin[1] = XY_MIN; origin[1] <= XY_MAX; origin[1] += XY_STEP ) { + origin[2] = Z_MAX; + tr.endpos[2] = Z_MAX + Z_STEP; + point2[0] = origin[0]; + point2[1] = origin[1]; + point2[2] = Z_MIN; + roof = qtrue; + height = Z_STEP; + +// gi.Printf( "begin %i %i\n", (int)origin[0], (int)origin[1] ); + while ( origin[2] > Z_MIN ) { + origin[2] = tr.endpos[2] - height; + height = Z_STEP; + + gi.trace( &tr, origin, mins, duckMaxs, point2, ENTITYNUM_NONE, MASK_DEADSOLID, true ); + + // did we fall out the bottom? yes = this xy finished + if ( tr.endpos[2] <= point2[2] ) { +// gi.Printf( " done - fell out\n" ); + break; + } + + // were we in solid the whole time? yes = this xy finished + if ( tr.allsolid ) { +// gi.Printf( " done - all solid\n" ); + break; + } + + // did we end up inside a solid? + gi.trace( &tr2, tr.endpos, mins, duckMaxs, tr.endpos, ENTITYNUM_NONE, MASK_DEADSOLID, true ); + if ( tr2.startsolid ) { +// gi.Printf( " in solid @ %f\n", tr.endpos[2] - 24.0 ); + continue; + } + + // did we land on the roof of the level? yes = move z down a step from point of contact + if ( roof ) { +// gi.Printf( " fell onto level @ %f\n", tr.endpos[2] - 24.0 ); + roof = qfalse; + continue; + } + + // is this too steep to stand on? yes = move z down a step from point of contact + if ( tr.plane.normal[2] < MIN_WALK_NORMAL ) { +// gi.Printf( " spot too steep @ %f\n", tr.endpos[2] - 24.0 ); + continue; + } + +// FIXME rule out any we want ignored here + // see if we are on a special entity + ent = &g_entities[tr.entityNum]; + if ( ent->s.number != ENTITYNUM_WORLD ) { + if ( ent->entity && ent->entity->isSubclassOf( Mover ) ) { + continue; + } +#if 0 + if ( Q_stricmp( ent->entname, "func_plat" ) == 0 ) { + //FIXME what do we need to do if we are + } +#endif + } + + // see if we are outside the world + VectorCopy( tr.endpos, test->s.origin ); + gi.linkentity( test ); + n = test->linked; + gi.unlinkentity( test ); + if ( n == qfalse ) { +// gi.Printf( " outside world c @ %s\n", vtos( tr.endpos ) ); + continue; + } + + if ( spotCount == MAX_SPOTS ) { + gi.Printf( "MAX_SPOTS exceeded\n" ); + //FIXME in Q3MAP this should be an exit() + return; + } + + // we found a valid standing location, add it to spot list + ThreadLock(); + spotNum = spotCount++; + ThreadUnlock(); + +// gi.Printf( " found spot @ %f %f %f\n", tr.endpos[0], tr.endpos[1], tr.endpos[2] - 24.0); +// VectorCopy( tr.endpos, spot[spotNum].origin ); + spot[spotNum].origin[0] = tr.endpos[0]; + spot[spotNum].origin[1] = tr.endpos[1]; + spot[spotNum].origin[2] = COORDINATE_TO_FLOAT * (int)(tr.endpos[2]*FLOAT_TO_COORDINATE); + spot[spotNum].flags = 0; + spot[spotNum].surfaceNum = -1; + + // see if we are on a special entity + ent = &g_entities[tr.entityNum]; + if ( ent->s.number != ENTITYNUM_WORLD ) { +#if 0 + if ( Q_stricmp( ent->entname, "func_plat" ) == 0 ) { + spot[spotNum].flags |= SF_PLATLOW; // Q3MAP: SF_PLATHIGH + height = Z_STEP; // Q3MAP: ent->pos2[2] - ent->pos1[2]; + spot[spotNum].parm = tr.entityNum; + } +// else if ( Q_stricmp( ent->entname, "func_train" ) == 0 ) { +// spot[spotNum].flags |= SF_TRAIN; +// } +#endif + } + + // check if we must be ducked + VectorAdd( tr.endpos, mins, absmin ); + gi.trace( &tr2, tr.endpos, mins, standMaxs, tr.endpos, ENTITYNUM_NONE, MASK_DEADSOLID, true ); + if ( tr2.allsolid ) { + spot[spotNum].flags |= SF_DUCK; + viewheight = CROUCH_VIEWHEIGHT; + VectorAdd( tr.endpos, duckMaxs, absmax ); + } + else { + viewheight = DEFAULT_VIEWHEIGHT; + VectorAdd( tr.endpos, standMaxs, absmax ); + } + + // check water depth and type (depends on duck state to set viewheight) + waterlevel = 0; + testpoint[0] = tr.endpos[0]; + testpoint[1] = tr.endpos[1]; + testpoint[2] = tr.endpos[2] + mins[2] + 1; + cont = gi.pointcontents( testpoint, 0 ); + + if ( cont & MASK_WATER ) { + sample2 = viewheight - mins[2]; + sample1 = sample2 / 2; + + if ( cont & (CONTENTS_LAVA | CONTENTS_SLIME) ) { + spot[spotNum].flags |= SF_PAIN; + } + + waterlevel = 1; + testpoint[2] = tr.endpos[2] + mins[2] + sample1; + cont = gi.pointcontents( testpoint, 0 ); + if (cont & MASK_WATER) { + waterlevel = 2; + testpoint[2] = tr.endpos[2] + mins[2] + sample2; + cont = gi.pointcontents( testpoint, 0 ); + if (cont & MASK_WATER) { + waterlevel = 3; + } + } + } + if ( waterlevel & 1) { + spot[spotNum].flags |= SF_WATERLEVEL1; + } + if ( waterlevel & 2) { + spot[spotNum].flags |= SF_WATERLEVEL2; + } + + // if water depth 3, see if there is air above us + if ( waterlevel == 3) { + if ( spot[spotNum].flags & SF_DUCK ) { + spot[spotNum].flags |= SF_WATER_NOAIR; + } + else { + gi.trace( &tr2, tr.endpos, mins, standMaxs, origin, ENTITYNUM_NONE, MASK_DEADSOLID, true ); + testpoint[0] = tr2.endpos[0]; + testpoint[1] = tr2.endpos[1]; + testpoint[2] = tr2.endpos[2] + DEFAULT_VIEWHEIGHT; + cont = gi.pointcontents( testpoint, 0 ); + if (cont & MASK_WATER) { + spot[spotNum].flags |= SF_WATER_NOAIR; + } + } + } +#if 0 + // check if this spot is in a trigger we care about + numEnts = gi.EntitiesInBox( absmin, absmax, ents, MAX_GENTITIES ); + for ( n = 0; n < numEnts; n++ ) { + ent = ents[n]; +// if ( Q_stricmp ( ent->entname, "misc_teleporter" ) == 0 ) { + if ( Q_stricmp ( ent->entname, "trigger_teleport" ) == 0 ) { + spot[spotNum].flags |= SF_TELEPORTER; + destTarget = NULL; + destTarget = G_Find( destTarget, FOFS( targetname ), ent->target ); + if ( !destTarget ) { + gi.Printf( "target_teleporter with no target\n" ); + spot[spotNum].parm = 0; + } + else { + spot[spotNum].parm = destTarget->s.number; + } + } + if ( !( ent->contents & CONTENTS_TRIGGER ) ) { + continue; + } + if ( Q_stricmp ( ent->entname, "trigger_hurt" ) == 0 ) { + spot[spotNum].flags |= SF_PAIN; + } + if ( Q_stricmp ( ent->entname, "trigger_push" ) == 0 ) { + spot[spotNum].flags |= SF_PUSH; + spot[spotNum].parm = ent->s.number; + } + if ( Q_stricmp ( ent->entname, "trigger_multiple" ) == 0 ) { + target = NULL; + while ( (target = G_Find( target, FOFS( targetname ), ent->target ) ) != NULL ) { + if ( target == ent ) { + continue; + } + if ( Q_stricmp ( target->entname, "target_teleporter" ) == 0 ) { + spot[spotNum].flags |= SF_TELEPORTER; + destTarget = NULL; + destTarget = G_Find( destTarget, FOFS( targetname ), target->target ); + if ( !destTarget ) { + gi.Printf( "target_teleporter with no target\n" ); + spot[spotNum].parm = 0; + } + else { + spot[spotNum].parm = destTarget->s.number; + } + } + if ( Q_stricmp ( target->entname, "target_push" ) == 0 ) { + spot[spotNum].flags |= SF_PUSH; + spot[spotNum].parm = target->s.number; + } + } + } + } +#endif + } + } +} + +static void FindSpots( void ) { + int n; + //gentity_t *ent; + //gentity_t *target; + //int spotNum; + + spot = ( nspot_t * )gi.TagMalloc ( MAX_SPOTS * sizeof(spot[0]), TAG_GAME ); + spotCount = 0; + + for ( n = 0; n < MAX_SPOTS; n++ ) { + spot[n].flags = 0; + } + + VectorSet( mins, DEFAULT_MINS_0, DEFAULT_MINS_1, DEFAULT_MINS_2 ); + VectorSet( standMaxs, DEFAULT_MAXS_0, DEFAULT_MAXS_1, DEFAULT_MAXS_2 ); + VectorSet( duckMaxs, DEFAULT_MAXS_0, DEFAULT_MAXS_1, CROUCH_MAXS_2 ); + + test = G_Spawn(); + test->s.eType = ET_GENERAL; + VectorCopy( mins, test->mins ); + VectorCopy( duckMaxs, test->maxs ); + + // RunThreadsOn( (XY_MAX - XY_MIN) / XY_STEP, qtrue, FindSpotsInY ); + for ( n = 0; n < ((XY_MAX - XY_MIN) / XY_STEP); n++ ) { + gi.DebugPrintf( "FindSpotsInY %d/%d\n", n, ((XY_MAX - XY_MIN) / XY_STEP) ); + FindSpotsInY( n ); + } + + G_FreeEdict( test ); + + +#if 0 + //FIXME add spots for trigger_teleport + for ( n = 0; n < globals.num_entities; n++ ) { + ent = &g_entities[n]; + if ( !ent->inuse ) { + continue; + } + if ( Q_stricmp ( ent->entname, "misc_teleporter" ) == 0 ) { + if ( Q_stricmp ( ent->entname, "trigger_teleport" ) == 0 ) { + target = NULL; + target = G_Find( target, FOFS( targetname ), ent->target ); + if ( !target ) { + continue; + } + spotNum = spotCount++; + spot[spotNum].origin[0] = ent->s.origin[0]; + spot[spotNum].origin[1] = ent->s.origin[1]; + spot[spotNum].origin[2] = COORDINATE_TO_FLOAT * (int)(ent->s.origin[2]*FLOAT_TO_COORDINATE); + spot[spotNum].flags = SF_TELEPORTER; + spot[spotNum].surfaceNum = -1; + spot[spotNum].parm = target - &g_entities[0]; + } + } + +#endif + gi.Printf( " %i spots\n", spotCount ); +} + + +// +// FindSurfaces +// + +#define MAX_SURFACES 4096 + +static int zstart; +static int zend; +//static int surfaceSizes[10]; + +static int CompareSpotsByZ( const void *a, const void *b ) { + nspot_t *s1 = &spot[*(int *)a]; + nspot_t *s2 = &spot[*(int *)b]; + + // z + if ( s1->origin[2] > s2->origin[2] ) { + return -1; + } + if ( s1->origin[2] < s2->origin[2] ) { + return 1; + } + + // x + if ( s1->origin[0] < s2->origin[0] ) { + return -1; + } + if ( s1->origin[0] > s2->origin[0] ) { + return 1; + } + + // y + if ( s1->origin[1] < s2->origin[1] ) { + return -1; + } + if ( s1->origin[1] > s2->origin[1] ) { + return 1; + } + + return 0; +} + +static void BuildSpotIndexByZ( void ) { + int n; + int i; + float z; + float cz; + + for ( n = 0; n < spotCount; n++ ) { + sortIndex[n] = n; + } + for ( n = 0; n < (((XY_MAX - XY_MIN) / XY_STEP) + 2); n++ ) { + spotIndex[n] = 0; + } + qsort( sortIndex, spotCount, sizeof(sortIndex[0]), CompareSpotsByZ ); + + i = 0; + cz = -8192; + for ( n = 0; n < spotCount; n++ ) { + z = spot[sortIndex[n]].origin[2]; + if ( z != cz ) { + spotIndex[i++] = n; + cz = z; + if ( i >= ( MAX_SPOTINDEX - 1 ) ) + { + gi.Printf( "MAX_SPOTINDEX exceeded\n" ); + //FIXME in Q3MAP this should be an exit() + break; + } + } + } + spotIndexCount = i; + spotIndex[i] = n; +} + +static int SpotIndex( vec3_t origin, int flags ) { + int n; + +// gi.Printf( " SpotIndex( %s )\n", vtos( origin ) ); + + for ( n = zstart; n < zend; n++ ) { + if ( spot[sortIndex[n]].origin[0] < origin[0] ) { + continue; + } + if ( spot[sortIndex[n]].origin[0] > origin[0] ) { + return -1; + } + if ( spot[sortIndex[n]].origin[1] < origin[1] ) { + continue; + } + if ( spot[sortIndex[n]].origin[1] > origin[1] ) { + return -1; + } + if ( spot[sortIndex[n]].surfaceNum != -1 ) { + return -1; + } + if ( spot[sortIndex[n]].flags != flags ) { + return -1; + } + return sortIndex[n]; + } + return -1; +} + +static void BuildSurface( int index ) { + int surfaceNum; + int plusx; + int minusx; + int plusy; + int minusy; + qboolean plusxLock; + qboolean minusxLock; + qboolean plusyLock; + qboolean minusyLock; + float xmin, xmax, x; + float ymin, ymax, y; + vec3_t test; + int n; + int count; + int tbm[256]; + int sCount; + nsurface_t *surf; + //int surfaceNum2; + //gentity_t *ent; + //float height; + + if ( surfaceCount == MAX_SURFACES ) { + gi.Printf( "MAX_SURFACES exceeded\n" ); + //FIXME in Q3MAP this should be an exit() + return; + } + + ThreadLock(); + surfaceNum = surfaceCount++; + ThreadUnlock(); + + spot[index].surfaceNum = surfaceNum; + + plusx = 0; + minusx = 0; + plusy = 0; + minusy = 0; + plusxLock = qfalse; + minusxLock = qfalse; + plusyLock = qfalse; + minusyLock = qfalse; + test[2] = spot[index].origin[2]; + sCount = 1; + + while ( !plusxLock || !minusxLock || !plusyLock || !minusyLock ) { + if ( !plusxLock ) { + plusx++; + count = 0; + test[0] = spot[index].origin[0] + plusx * XY_STEP; + ymin = spot[index].origin[1] - minusy * XY_STEP; + ymax = spot[index].origin[1] + plusy * XY_STEP; + for ( y = ymin; y <= ymax; y += XY_STEP ) { + test[1] = y; + n = SpotIndex( test, spot[index].flags ); + if ( n == -1 ) { + plusx--; + plusxLock = qtrue; + break; + } + tbm[count++] = n; + } + for ( n = 0; n < count; n ++ ) { + spot[tbm[n]].surfaceNum = surfaceNum; + } + sCount += count; + } + + if ( !minusxLock ) { + minusx++; + count = 0; + test[0] = spot[index].origin[0] - minusx * XY_STEP; + ymin = spot[index].origin[1] - minusy * XY_STEP; + ymax = spot[index].origin[1] + plusy * XY_STEP; + for ( y = ymin; y <= ymax; y += XY_STEP ) { + test[1] = y; + n = SpotIndex( test, spot[index].flags ); + if ( n == -1 ) { + minusx--; + minusxLock = qtrue; + break; + } + tbm[count++] = n; + } + for ( n = 0; n < count; n ++ ) { + spot[tbm[n]].surfaceNum = surfaceNum; + } + sCount += count; + } + + if ( !plusyLock ) { + plusy++; + count = 0; + test[1] = spot[index].origin[1] + plusy * XY_STEP; + xmin = spot[index].origin[0] - minusx * XY_STEP; + xmax = spot[index].origin[0] + plusx * XY_STEP; + for ( x = xmin; x <= xmax; x += XY_STEP ) { + test[0] = x; + n = SpotIndex( test, spot[index].flags ); + if ( n == -1 ) { + plusy--; + plusyLock = qtrue; + break; + } + tbm[count++] = n; + } + for ( n = 0; n < count; n ++ ) { + spot[tbm[n]].surfaceNum = surfaceNum; + } + sCount += count; + } + + if ( !minusyLock ) { + minusy++; + count = 0; + test[1] = spot[index].origin[1] - minusy * XY_STEP; + xmin = spot[index].origin[0] - minusx * XY_STEP; + xmax = spot[index].origin[0] + plusx * XY_STEP; + for ( x = xmin; x <= xmax; x += XY_STEP ) { + test[0] = x; + n = SpotIndex( test, spot[index].flags ); + if ( n == -1 ) { + minusy--; + minusyLock = qtrue; + break; + } + tbm[count++] = n; + } + for ( n = 0; n < count; n ++ ) { + spot[tbm[n]].surfaceNum = surfaceNum; + } + sCount += count; + } + } + +#if 0 + if ( sCount <= 1 ) { + surfaceSizes[0]++; + } + else if ( sCount <= 2 ) { + surfaceSizes[1]++; + } + else if ( sCount <= 4 ) { + surfaceSizes[2]++; + } + else if ( sCount <= 8 ) { + surfaceSizes[3]++; + } + else if ( sCount <= 16 ) { + surfaceSizes[4]++; + } + else if ( sCount <= 32 ) { + surfaceSizes[5]++; + } + else if ( sCount <= 64 ) { + surfaceSizes[6]++; + } + else if ( sCount <= 128 ) { + surfaceSizes[7]++; + } + else if ( sCount <= 256 ) { + surfaceSizes[8]++; + } + else { + surfaceSizes[9]++; + } +#endif + + surf = &surface[surfaceNum]; + surf->flags = spot[index].flags; + + surf->absmin[0] = spot[index].origin[0] - ( minusx * XY_STEP ); + surf->absmin[1] = spot[index].origin[1] - ( minusy * XY_STEP ); + + surf->absmax[0] = spot[index].origin[0] + ( plusx * XY_STEP ); + surf->absmax[1] = spot[index].origin[1] + ( plusy * XY_STEP ); + + surf->origin[0] = ( surf->absmin[0] + surf->absmax[0] ) * 0.5; + surf->origin[1] = ( surf->absmin[1] + surf->absmax[1] ) * 0.5; + surf->origin[2] = spot[index].origin[2]; + + gi.DebugPrintf( "Spot %d : origin %s\n", index, vtos( surf->origin ) ); + +// gi.Printf( "Surface from %s ", vtos( surf->absmin ) ); +// gi.Printf( "to %s", vtos( surf->absmax) ); +// gi.Printf( "at %s\n", vtos( surf->origin) ); +#if 0 + // if this is a plat high position, build to plat low surface + // Q#MAP: numerous changes in here + if ( spot[index].flags & SF_PLATLOW ) { //Q3MAP: SF_PLATHIGH + // grab another surface + ThreadLock(); + surfaceNum2 = surfaceCount++; + ThreadUnlock(); + + // make a copy of the other plat surface + memcpy( &surface[surfaceNum2], &surface[surfaceNum], sizeof( nsurface_t ) ); + +// // switch the flag from high to low +// surface[surfaceNum2].flags &= ~SF_PLATHIGH; +// surface[surfaceNum2].flags |= SF_PLATLOW; + // switch the flag from low to high + surface[surfaceNum2].flags &= ~SF_PLATLOW; + surface[surfaceNum2].flags |= SF_PLATHIGH; + + // adjust the z value + ent = &g_entities[spot[index].parm]; + height = ent->pos2[2] - ent->pos1[2]; +// surface[surfaceNum2].origin[2] -= height; + surface[surfaceNum2].origin[2] += height; + + // set low plat surface parm to high plat surface number +// surface[surfaceNum2].parm = surfaceNum; + surface[surfaceNum].parm = surfaceNum2; + +// // set high plat surface parm plat cost +// surface[surfaceNum].parm = (height / ent->speed) * 1000; +// surface[surfaceNum2].parm = (height / ent->speed) * 1000; + // set high plat surface parm to plat entity number +// surface[surfaceNum].parm = spot[index].parm; + surface[surfaceNum2].parm = spot[index].parm; + } +#endif + if ( spot[index].flags & SF_PUSH ) { + surf->parm = spot[index].parm; + } + + if ( spot[index].flags & SF_TELEPORTER ) { + surf->parm = spot[index].parm; + } +} + +static void FindSurfacesAtZ( int zIndex ) { + int n; + + zstart = spotIndex[zIndex]; + zend = spotIndex[zIndex + 1]; + + for ( n = zstart; n < zend; n++ ) { + if ( spot[sortIndex[n]].surfaceNum == -1 ) { + BuildSurface( sortIndex[n] ); + } + } +} + +static void FindSurfaces( void ) { + int n; + + surface = ( nsurface_t * )gi.TagMalloc ( MAX_SURFACES * sizeof(surface[0]), TAG_GAME ); + surfaceCount = 0; + +// memset( surfaceSizes, 0, sizeof( surfaceSizes ) ); + BuildSpotIndexByZ(); + +// RunThreadsOn( spotIndexCount, qtrue, FindSurfacesAtZ ); + for ( n = 0; n < spotIndexCount; n++ ) { + FindSurfacesAtZ( n ); + } + + gi.TagFree( spot ); + +#if 0 + gi.Printf( "%3i @ 1\n", surfaceSizes[0] ); + gi.Printf( "%3i @ 2\n", surfaceSizes[1] ); + gi.Printf( "%3i @ 3-4\n", surfaceSizes[2] ); + gi.Printf( "%3i @ 5-8\n", surfaceSizes[3] ); + gi.Printf( "%3i @ 9-16\n", surfaceSizes[4] ); + gi.Printf( "%3i @ 17-32\n", surfaceSizes[5] ); + gi.Printf( "%3i @ 33-64\n", surfaceSizes[6] ); + gi.Printf( "%3i @ 65-128\n", surfaceSizes[7] ); + gi.Printf( "%3i @ 129-256\n", surfaceSizes[8] ); + gi.Printf( "%3i @ 257+\n", surfaceSizes[9] ); +#endif + + gi.Printf( " %i surfaces\n", surfaceCount ); +} + +int FindSpot( vec3_t origin, int flags, float min_height ) +{ + int n; + + for ( n = 0; n < spotCount ; n++ ) + { + if ( spot[sortIndex[n]].origin[0] < origin[0] ) { + continue; + } + if ( spot[sortIndex[n]].origin[0] > origin[0] ) { + return -1; + } + if ( spot[sortIndex[n]].origin[1] < origin[1] ) { + continue; + } + if ( spot[sortIndex[n]].origin[1] > origin[1] ) { + return -1; + } + if ( spot[sortIndex[n]].origin[2] <= min_height ) { + continue; + } + if ( spot[sortIndex[n]].surfaceNum != -1 ) { + return -1; + } + if ( spot[sortIndex[n]].flags != flags ) { + return -1; + } + return sortIndex[n]; + } + return -1; +} + +int FindUsedSpot( vec3_t origin, float min_height ) +{ + int n; + + for ( n = 0; n < spotCount ; n++ ) + { + if ( spot[sortIndex[n]].origin[0] < origin[0] ) { + continue; + } + if ( spot[sortIndex[n]].origin[0] > origin[0] ) { + return -1; + } + if ( spot[sortIndex[n]].origin[1] < origin[1] ) { + continue; + } + if ( spot[sortIndex[n]].origin[1] > origin[1] ) { + return -1; + } + if ( spot[sortIndex[n]].origin[2] <= min_height ) { + continue; + } + return sortIndex[n]; + } + return -1; +} + +int FindSpotInSurface( vec3_t origin, int surfaceNum ) +{ + int index; + float current_height; + + + current_height = Z_MIN; + + while( 1 ) + { + index = FindUsedSpot( origin, current_height ); + + if (index == -1) + return -1; + + if (spot[index].surfaceNum == surfaceNum) + return index; + + current_height = spot[index].origin[2]; + } + + return -1; +} + +qboolean IsConvex( int surfaceNum, vec3_t check_point, int n ) +{ + float i, j; + float x1, y1; + float x2, y2; + float step; + int test_y; + float y_diff; + vec3_t test_point; + int test = 0; + + + if (check_point[0] < spot[n].origin[0]) + { + x1 = check_point[0]; + y1 = check_point[1]; + + x2 = spot[n].origin[0]; + y2 = spot[n].origin[1]; + } + else + { + x1 = spot[n].origin[0]; + y1 = spot[n].origin[1]; + + x2 = check_point[0]; + y2 = check_point[1]; + } + + if (x2 - x1 != 0) + step = (y2 - y1) / (x2 - x1) / XY_STEP; + else + step = 0; + + j = 0; + + for ( i = x1 ; i < x2 ; i += XY_STEP ) + { + // Test points here + + test_point[0] = i; + + test_y = j + .5; + + y_diff = j - test_y; + + if (0) //((y_diff < .05) && (y_diff > -.05)) + { + test_point[1] = y1 + ((int)j) * XY_STEP; + + if (FindSpotInSurface( test_point, surfaceNum ) == -1) + //return qfalse; + test++; + else + test = 0; + + } + else + { + + test_point[1] = y1 + ((int)j) * XY_STEP; + + if (FindSpotInSurface( test_point, surfaceNum ) == -1) + { + if (j > 0) + test_point[1] = y1 + ((int)(j + 1)) * XY_STEP; + else + test_point[1] = y1 + ((int)(j - 1)) * XY_STEP; + + if (FindSpotInSurface( test_point, surfaceNum ) == -1) + //return qfalse; + test++; + else + test = 0; + } + else + test = 0; + } + + if (test == 3) + return qfalse; + + j += step; + } + + return qtrue; +} + +qboolean CanAddPoint1( int surfaceNum, int n ) +{ + int i, j; + float z_diff; + int index; + vec3_t check_point; + float current_height; + int has_neighbor_point; + + + // Make sure can walk to nearest points in this surface + + has_neighbor_point = qfalse; + + for ( i = -1 ; i <= 1 ; i++ ) + { + check_point[0] = spot[n].origin[0] + i * XY_STEP; + + for ( j = -1 ; j <= 1 ; j++ ) + { + check_point[1] = spot[n].origin[1] + j * XY_STEP; + + if (! ((i == 0) && (j == 0)) ) + { + // Find point in same surface + + current_height = Z_MIN; + + while( 1 ) + { + index = FindUsedSpot( check_point, current_height ); + + if (index == -1) + break; + + if (spot[index].surfaceNum == surfaceNum) + { + has_neighbor_point = qtrue; + + z_diff = spot[index].origin[2] - spot[n].origin[2]; + if (z_diff < 0) + z_diff = -z_diff; + + if (z_diff > STEPSIZE) + return qfalse; + + break; + } + + current_height = spot[index].origin[2]; + } + } + } + } + + // Make sure it was next to at least one other point in this surface + + if (!has_neighbor_point) + return qfalse; + + return qtrue; +} + +qboolean CanAddPoint2( int surfaceNum, int n ) +{ + int i, j; + vec3_t check_point; + vec2_t absmin; + vec2_t absmax; + qboolean skip_top, skip_left, skip_right, skip_bottom; + + + // Setup ansolute mins and maxs correctly + + if (spot[n].origin[0] < surface[surfaceNum].absmin[0]) + { + absmin[0] = spot[n].origin[0]; + skip_left = qtrue; + } + else + { + absmin[0] = surface[surfaceNum].absmin[0]; + skip_left = qfalse; + } + + if (spot[n].origin[0] > surface[surfaceNum].absmax[0]) + { + absmax[0] = spot[n].origin[0]; + skip_right = qtrue; + } + else + { + absmax[0] = surface[surfaceNum].absmax[0]; + skip_right = qfalse; + } + + if (spot[n].origin[1] < surface[surfaceNum].absmin[1]) + { + absmin[1] = spot[n].origin[1]; + skip_top = qtrue; + } + else + { + absmin[1] = surface[surfaceNum].absmin[1]; + skip_top = qfalse; + } + + if (spot[n].origin[1] > surface[surfaceNum].absmax[1]) + { + absmax[1] = spot[n].origin[1]; + skip_bottom = qtrue; + } + else + { + absmax[1] = surface[surfaceNum].absmax[1]; + skip_bottom = qfalse; + } + + // Test top and bottom points for convexness + + for( i = absmin[0] ; i <= absmax[0] ; i += XY_STEP ) + { + check_point[0] = i; + + // Find top point in this column + + if (!skip_top) + { + for( j = absmin[1] ; j <= absmax[1] ; j += XY_STEP ) + { + check_point[1] = j; + + if (FindSpotInSurface( check_point, surfaceNum ) != -1) + { + // Test for convexness + + if (!IsConvex( surfaceNum, check_point, n )) + return qfalse; + + break; + } + } + } + + // Find bottom point in this column + + if (!skip_bottom) + { + for( j = absmax[1] ; j >= absmin[1] ; j -= XY_STEP ) + { + check_point[1] = j; + + if (FindSpotInSurface( check_point, surfaceNum ) != -1) + { + // Test for convexness + + if (!IsConvex( surfaceNum, check_point, n )) + return qfalse; + + break; + } + } + } + } + + // Test left and right points for convexness + + for( j = absmin[1] ; j <= absmax[1] ; j += XY_STEP ) + { + check_point[1] = j; + + // Find left point in this row + + if (!skip_left) + { + for( i = absmin[0] ; i <= absmax[0] ; i += XY_STEP ) + { + check_point[0] = i; + + if (FindSpotInSurface( check_point, surfaceNum ) != -1) + { + // Test for convexness + + if (!IsConvex( surfaceNum, check_point, n )) + return qfalse; + + break; + } + } + } + + // Find right point in this row + + if (!skip_right) + { + for( i = absmax[0] ; i >= absmin[0] ; i -= XY_STEP ) + { + check_point[0] = i; + + if (FindSpotInSurface( check_point, surfaceNum ) != -1) + { + // Test for convexness + + if (!IsConvex( surfaceNum, check_point, n )) + return qfalse; + + break; + } + } + } + } + + + /* for ( i = -1 ; i <= 1 ; i++ ) + { + check_point[0] = spot[n].origin[0] + i * XY_STEP; + + for ( j = -1 ; j <= 1 ; j++ ) + { + check_point[1] = spot[n].origin[1] + j * XY_STEP; + + if (! ((i == 0) && (j == 0)) ) + { + // Find point in same surface + + current_height = Z_MIN; + + while( 1 ) + { + index = FindUsedSpot( check_point, current_height ); + + if (index == -1) + break; + + if (spot[index].surfaceNum == surfaceNum) + break; + + current_height = spot[index].origin[2]; + } + + if (index == -1) + { + current_height = Z_MIN; + + while( 1 ) + { + index = FindUsedSpot( check_point, current_height ); + + if (index == -1) + break; + + if (spot[index].surfaceNum == surfaceNum) + break; + + current_height = spot[index].origin[2]; + } + + if (index != -1) + return qfalse; + } + } + } + } */ + + return qtrue; +} + +void AddPointToSurface( int surfaceNum, int n ) +{ + spot[n].surfaceNum = surfaceNum; + + if (spot[n].origin[0] < surface[surfaceNum].absmin[0]) + surface[surfaceNum].absmin[0] = spot[n].origin[0]; + + if (spot[n].origin[0] > surface[surfaceNum].absmax[0]) + surface[surfaceNum].absmax[0] = spot[n].origin[0]; + + if (spot[n].origin[1] < surface[surfaceNum].absmin[1]) + surface[surfaceNum].absmin[1] = spot[n].origin[1]; + + if (spot[n].origin[1] > surface[surfaceNum].absmax[1]) + surface[surfaceNum].absmax[1] = spot[n].origin[1]; +} + +static void BuildConvexSurface( int index ) +{ + int surfaceNum; + int plusx; + int minusx; + int plusy; + int minusy; + qboolean plusxLock; + qboolean minusxLock; + qboolean plusyLock; + qboolean minusyLock; + qboolean plusxhold, minusxhold, plusyhold, minusyhold; + qboolean plusxalreadyheld, minusxalreadyheld, plusyalreadyheld, minusyalreadyheld; + float xmin, xmax, x; + float ymin, ymax, y; + vec3_t test; + int n; + int count; + int tbm[256]; + int sCount; + nsurface_t *surf; + qboolean valid_direction; + float current_height; + int i; + + + + if ( surfaceCount == MAX_SURFACES ) + { + gi.Printf( "MAX_SURFACES exceeded\n" ); + return; + } + + //if (surfaceCount > 100) + // return; + + ThreadLock(); + surfaceNum = surfaceCount++; + ThreadUnlock(); + + spot[index].surfaceNum = surfaceNum; + + surface[surfaceNum].absmin[0] = spot[index].origin[0]; + surface[surfaceNum].absmax[0] = spot[index].origin[0]; + surface[surfaceNum].absmin[1] = spot[index].origin[1]; + surface[surfaceNum].absmax[1] = spot[index].origin[1]; + + plusx = 0; + minusx = 0; + plusy = 0; + minusy = 0; + + plusxLock = qfalse; + minusxLock = qfalse; + plusyLock = qfalse; + minusyLock = qfalse; + + plusxhold = qfalse; + minusxhold = qfalse; + plusyhold = qfalse; + minusyhold = qfalse; + + plusxalreadyheld = qfalse; + minusxalreadyheld = qfalse; + plusyalreadyheld = qfalse; + minusyalreadyheld = qfalse; + + test[2] = spot[index].origin[2]; + sCount = 1; + + while ( !plusxLock || !minusxLock || !plusyLock || !minusyLock ) + { + if ( ( plusxLock || plusxhold ) && ( minusxLock || minusxhold ) && ( plusyLock || plusyhold ) && ( minusyLock || minusyhold ) ) + { + // Remove all of the holds + + plusxhold = qfalse; + minusxhold = qfalse; + plusyhold = qfalse; + minusyhold = qfalse; + + plusxalreadyheld = qtrue; + minusxalreadyheld = qtrue; + plusyalreadyheld = qtrue; + minusyalreadyheld = qtrue; + } + + if ( !plusxLock && !plusxhold ) + { + plusx++; + count = 0; + test[0] = spot[index].origin[0] + plusx * XY_STEP; + ymin = spot[index].origin[1] - minusy * XY_STEP; + ymax = spot[index].origin[1] + plusy * XY_STEP; + valid_direction = qfalse; + + for ( y = ymin; y <= ymax; y += XY_STEP ) + { + // Find this spot + + test[1] = y; + current_height = Z_MIN; + n = FindSpot( test, spot[index].flags, current_height ); + + while( n != -1 ) + { + // See if this point can be added and the surface stay convex + + if ( CanAddPoint1( surfaceNum, n ) ) + { + // Add this point to this surface + + spot[n].surfaceNum = surfaceNum; + tbm[count] = n; + count++; + + break; + } + + // Get the next spot at this x, y + + current_height = spot[n].origin[2]; + n = FindSpot( test, spot[index].flags, current_height ); + } + } + + if ( plusxalreadyheld ) + { + for( i = 0 ; i < count ; i++ ) + { + if ( CanAddPoint2( surfaceNum, tbm[i] ) ) + { + AddPointToSurface( surfaceNum, tbm[i] ); + valid_direction = qtrue; + } + else + spot[tbm[i]].surfaceNum = -1; + } + } + else + { + valid_direction = qtrue; + + if (count == (ymax - ymin) / XY_STEP + 1) + { + for( i = 0 ; i < count ; i++ ) + AddPointToSurface( surfaceNum, tbm[i] ); + } + else + { + for( i = 0 ; i < count ; i++ ) + spot[tbm[i]].surfaceNum = -1; + plusxhold = qtrue; + plusx--; + } + } + + if ( !valid_direction ) + { + plusx--; + plusxLock = qtrue; + } + } + + if ( !minusxLock && !minusxhold ) + { + minusx++; + count = 0; + test[0] = spot[index].origin[0] - minusx * XY_STEP; + ymin = spot[index].origin[1] - minusy * XY_STEP; + ymax = spot[index].origin[1] + plusy * XY_STEP; + valid_direction = qfalse; + + for ( y = ymin; y <= ymax; y += XY_STEP ) + { + // Find this spot + + test[1] = y; + current_height = Z_MIN; + n = FindSpot( test, spot[index].flags, current_height ); + + while( n != -1 ) + { + // See if this point can be added and the surface stay convex + + if ( CanAddPoint1( surfaceNum, n ) ) + { + // Add this point to this surface + + spot[n].surfaceNum = surfaceNum; + tbm[count] = n; + count++; + + break; + } + + // Get the next spot at this x, y + + current_height = spot[n].origin[2]; + n = FindSpot( test, spot[index].flags, current_height ); + } + } + + if ( minusxalreadyheld ) + { + for( i = 0 ; i < count ; i++ ) + { + if ( CanAddPoint2( surfaceNum, tbm[i] ) ) + { + AddPointToSurface( surfaceNum, tbm[i] ); + valid_direction = qtrue; + } + else + spot[tbm[i]].surfaceNum = -1; + } + } + else + { + valid_direction = qtrue; + + if (count == (ymax - ymin) / XY_STEP + 1) + { + for( i = 0 ; i < count ; i++ ) + AddPointToSurface( surfaceNum, tbm[i] ); + } + else + { + for( i = 0 ; i < count ; i++ ) + spot[tbm[i]].surfaceNum = -1; + minusxhold = qtrue; + minusx--; + } + } + + if ( !valid_direction ) + { + minusx--; + minusxLock = qtrue; + } + } + + if ( !plusyLock && !plusyhold ) + { + plusy++; + count = 0; + test[1] = spot[index].origin[1] + plusy * XY_STEP; + xmin = spot[index].origin[0] - minusx * XY_STEP; + xmax = spot[index].origin[0] + plusx * XY_STEP; + valid_direction = qfalse; + + for ( x = xmin; x <= xmax; x += XY_STEP ) + { + // Find this spot + + test[0] = x; + current_height = Z_MIN; + n = FindSpot( test, spot[index].flags, current_height ); + + while( n != -1 ) + { + // See if this point can be added and the surface stay convex + + if ( CanAddPoint1( surfaceNum, n ) ) + { + // Add this point to this surface + + spot[n].surfaceNum = surfaceNum; + tbm[count] = n; + count++; + + break; + } + + // Get the next spot at this x, y + + current_height = spot[n].origin[2]; + n = FindSpot( test, spot[index].flags, current_height ); + } + } + + if ( plusyalreadyheld ) + { + for( i = 0 ; i < count ; i++ ) + { + if ( CanAddPoint2( surfaceNum, tbm[i] ) ) + { + AddPointToSurface( surfaceNum, tbm[i] ); + valid_direction = qtrue; + } + else + spot[tbm[i]].surfaceNum = -1; + } + } + else + { + valid_direction = qtrue; + + if (count == (xmax - xmin) / XY_STEP + 1) + { + for( i = 0 ; i < count ; i++ ) + AddPointToSurface( surfaceNum, tbm[i] ); + } + else + { + for( i = 0 ; i < count ; i++ ) + spot[tbm[i]].surfaceNum = -1; + plusyhold = qtrue; + plusy--; + } + } + + if ( !valid_direction ) + { + plusy--; + plusyLock = qtrue; + } + } + + if ( !minusyLock && !minusyhold ) + { + minusy++; + count = 0; + test[1] = spot[index].origin[1] - minusy * XY_STEP; + xmin = spot[index].origin[0] - minusx * XY_STEP; + xmax = spot[index].origin[0] + plusx * XY_STEP; + valid_direction = qfalse; + + for ( x = xmin; x <= xmax; x += XY_STEP ) + { + // Find this spot + + test[0] = x; + current_height = Z_MIN; + n = FindSpot( test, spot[index].flags, current_height ); + + while( n != -1 ) + { + // See if this point can be added and the surface stay convex + + if ( CanAddPoint1( surfaceNum, n ) ) + { + // Add this point to this surface + + spot[n].surfaceNum = surfaceNum; + tbm[count] = n; + count++; + + break; + } + + // Get the next spot at this x, y + + current_height = spot[n].origin[2]; + n = FindSpot( test, spot[index].flags, current_height ); + } + } + + if ( minusyalreadyheld ) + { + for( i = 0 ; i < count ; i++ ) + { + if ( CanAddPoint2( surfaceNum, tbm[i] ) ) + { + AddPointToSurface( surfaceNum, tbm[i] ); + valid_direction = qtrue; + } + else + spot[tbm[i]].surfaceNum = -1; + } + } + else + { + valid_direction = qtrue; + + if (count == (xmax - xmin) / XY_STEP + 1) + { + for( i = 0 ; i < count ; i++ ) + AddPointToSurface( surfaceNum, tbm[i] ); + } + else + { + for( i = 0 ; i < count ; i++ ) + spot[tbm[i]].surfaceNum = -1; + minusyhold = qtrue; + minusy--; + } + } + + if ( !valid_direction ) + { + minusy--; + minusyLock = qtrue; + } + } + } + + // Setup surface info + + surf = &surface[surfaceNum]; + surf->flags = spot[index].flags; + + surf->absmin[0] = spot[index].origin[0] - ( minusx * XY_STEP ); + surf->absmin[1] = spot[index].origin[1] - ( minusy * XY_STEP ); + + surf->absmax[0] = spot[index].origin[0] + ( plusx * XY_STEP ); + surf->absmax[1] = spot[index].origin[1] + ( plusy * XY_STEP ); + + surf->origin[0] = ( surf->absmin[0] + surf->absmax[0] ) * 0.5; + surf->origin[1] = ( surf->absmin[1] + surf->absmax[1] ) * 0.5; + surf->origin[2] = spot[index].origin[2]; + + gi.DebugPrintf( "surface #%d - Spot %d : origin %s\n", surfaceNum, index, vtos( surf->origin ) ); +} + +static int CompareSpots( const void *a, const void *b ) { + nspot_t *s1 = &spot[*(int *)a]; + nspot_t *s2 = &spot[*(int *)b]; + + // x + if ( s1->origin[0] < s2->origin[0] ) { + return -1; + } + if ( s1->origin[0] > s2->origin[0] ) { + return 1; + } + + // y + if ( s1->origin[1] < s2->origin[1] ) { + return -1; + } + if ( s1->origin[1] > s2->origin[1] ) { + return 1; + } + + // z + if ( s1->origin[2] > s2->origin[2] ) { + return -1; + } + if ( s1->origin[2] < s2->origin[2] ) { + return 1; + } + + return 0; +} + +static void SortSpots( void ) +{ + int n; + //int i; + //float z; + //float cz; + + for ( n = 0; n < spotCount; n++ ) + sortIndex[n] = n; + + for ( n = 0; n < (((XY_MAX - XY_MIN) / XY_STEP) + 2); n++ ) + spotIndex[n] = 0; + + qsort( sortIndex, spotCount, sizeof(sortIndex[0]), CompareSpots ); +} + +static void FindConvexSurfaces( void ) +{ + int n; + + surface = ( nsurface_t * )gi.TagMalloc ( MAX_SURFACES * sizeof(surface[0]), TAG_GAME ); + surfaceCount = 0; + + SortSpots(); + + for ( n = 0; n < spotCount; n++ ) + { + if ( spot[sortIndex[n]].surfaceNum == -1 ) + BuildConvexSurface( sortIndex[n] ); + } + + gi.TagFree( spot ); + + gi.Printf( " %i surfaces\n", surfaceCount ); +} + +// +// FindNeighbors +// + +// stats on point to edge reachability testing +typedef struct { + int count; + int accept; + int reject1; + int reject2; + int reject3; + int pmoveCount; +} reachStats_t; + +// stats on surface to surface testing +typedef struct { + int count; + int accept; + int reject; + int treject1; + int treject2; + int treject3; + int treject4; + int zeroNeighbors; +} surfaceStats_t; + +// per source surface info +// +// The reason for the local neighbors array and MAX_NEIGHBORS_PER_SURFACE is so FindSurfaceNeighbors +// can be run on many surfaces at once when multithreaded. + +#define MAX_NEIGHBORS_PER_SURFACE 256 + +typedef struct { + int number; + nsurface_t *surface; + int neighborCount; + nneighbor_t neighbor[MAX_NEIGHBORS_PER_SURFACE]; +} sourceSurfaceInfo_t; + +// per target surface info +typedef struct { + int number; + nsurface_t *surface; + qboolean edgeActive; + vec2_t edgeStart; + vec2_t edgeEnd; + int edgeFlags; + float cost; +} targetSurfaceInfo_t; + +// per thread neighbor testing info block +typedef struct { + reachStats_t rStats; + surfaceStats_t sStats; + sourceSurfaceInfo_t sSurf; + targetSurfaceInfo_t tSurf; +} surfaceThreadInfo_t; + +// global (per map) instances of stats; used to sum all the per thread stats +static reachStats_t reachStats; +static surfaceStats_t surfStats; + + +#define FLOAT_TO_VELOCITY 16.0 +#define VELOCITY_TO_FLOAT (1.0/FLOAT_TO_VELOCITY) + +static int SurfaceNumberAtPoint( vec3_t point ) { + vec3_t p; + int n; + + p[0] = point[0]; + p[1] = point[1]; + p[2] = floor( point[2] ); + + for ( n = 0; n < surfaceCount; n++ ) { + if ( floor( surface[n].origin[2] ) != p[2] ) { + continue; + } + if ( ( surface[n].absmin[0] - 16 ) > p[0] ) { + continue; + } + if ( ( surface[n].absmax[0] + 16 ) < p[0] ) { + continue; + } + if ( ( surface[n].absmin[1] - 16 ) > p[1] ) { + continue; + } + if ( ( surface[n].absmax[1] + 16 ) < p[1] ) { + continue; + } + return n; + } + + return -1; +} + + +static qboolean PointIsOnSurfaceNumber( vec3_t point, int n ) { + vec3_t p; + + p[0] = point[0]; + p[1] = point[1]; + p[2] = floor( point[2] ); + + if ( floor( surface[n].origin[2] ) != p[2] ) { + return qfalse; + } + if ( ( surface[n].absmin[0] - 16 ) > p[0] ) { + return qfalse; + } + if ( ( surface[n].absmax[0] + 16 ) < p[0] ) { + return qfalse; + } + if ( ( surface[n].absmin[1] - 16 ) > p[1] ) { + return qfalse; + } + if ( ( surface[n].absmax[1] + 16 ) < p[1] ) { + return qfalse; + } + return qtrue; +} + +static void ReachTrace(trace_t *result, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int passEntityNum, int contents, qboolean cylinder ) + { + trace_t tr; + + gi.trace ( &tr, start, mins, maxs, end, passEntityNum, contents, cylinder ); + + //FIXME this is FUGLY + while ( tr.entityNum && ( g_entities[tr.entityNum].s.eType == ET_MOVER ) ) + { + if ( Q_stricmp( g_entities[tr.entityNum].entname, "func_plat" ) == 0 ) + { + *result = tr; + return; + } + gi.trace ( &tr, tr.endpos, mins, maxs, end, tr.entityNum, contents, cylinder ); + if ( tr.fraction == 0.0 ) + { + *result = tr; + return; + } + } + *result = tr; + return; + } + +//FIXME try start running, start walking, and start motionless (special flags set if slower speed required) +static qboolean CanReach( surfaceThreadInfo_t *info, vec3_t start, vec3_t dir, int *flags ) { + pmove_t pm; + playerState_t ps; + int n; + int currentSurface; + vec3_t lastOrigin; + + info->rStats.count++; + + *flags = 0; + + VectorNormalize( dir ); + VectorCopy( start, lastOrigin ); + + memset( &pm, 0, sizeof( pm ) ); + memset( &ps, 0, sizeof( ps ) ); + pm.ps = &ps; + pm.cmd.msec = PMOVE_MSEC; + pm.cmd.buttons = 0; + pm.cmd.weapon = 0; + pm.cmd.angles[0] = 0; + pm.cmd.angles[1] = 0; + pm.cmd.angles[2] = 0; + pm.cmd.forwardmove = 127; + pm.cmd.rightmove = 0; + pm.cmd.upmove = 0; + pm.tracemask = MASK_DEADSOLID; + pm.noFootsteps = qtrue; + pm.trace = ReachTrace; + pm.pointcontents = gi.pointcontents; + + ps.pm_type = PM_NORMAL; + ps.gravity = sv_gravity->value; + ps.speed = PLAYER_SPEED; + VectorCopy( start, ps.origin ); +// VectorClear( ps.velocity ); + VectorScale( dir, ps.speed, ps.velocity ); + ps.delta_angles[0] = 0; + ps.delta_angles[1] = ANGLE2SHORT ( vectoyaw ( dir ) ); + ps.delta_angles[2] = 0; + ps.groundEntityNum = 0; + ps.clientNum = 0; // FIXME? was ent->s.number; + + // do we need to start ducked? + if ( info->sSurf.surface->flags & SF_DUCK ) { + ps.pm_flags |= PMF_DUCKED; + } + + // does the target surface require us to be ducked + if ( info->tSurf.surface->flags & SF_DUCK ) { + ps.pm_flags |= PMF_DUCKED; + pm.cmd.upmove = -127; + } + + // do we need to jump up? + if ( ( info->tSurf.surface->origin[2] - info->sSurf.surface->origin[2] ) > STEPSIZE ) { + // if we're ducked we can't jump so it is unreachable + if ( ps.pm_flags & PMF_DUCKED ) { + return qfalse; + } + pm.cmd.upmove = 127; + *flags |= NF_JUMP; + } + + // junk we need to fill in so PMove behaves correctly + for( n = 0; n < MAX_STATS; n++ ) { + ps.stats[n] = 0; + } + ps.stats[STAT_HEALTH] = 100; + for( n = 0; n < PW_NUM_POWERUPS; n++ ) { + ps.powerups[n] = 0; + } + + for ( n = 0; n < MAX_PMOVES; n++ ) { + + Pmove( &pm ); + info->rStats.pmoveCount++; + + if( VectorCompare( ps.origin, lastOrigin ) != 0 ) { + info->rStats.reject1++; + return qfalse; + } + VectorCopy( ps.origin, lastOrigin ); + + if ( ps.groundEntityNum == -1 ) { + continue; + } + + currentSurface = SurfaceNumberAtPoint( ps.origin ); + + // FIXME - this happens at the spot under a door + if ( currentSurface == -1 ) { + continue; + } + + if ( pm.pmoveEvent == EV_FALL_FAR ) { + *flags |= NF_FALL2; + } + else if ( pm.pmoveEvent == EV_FALL_MEDIUM ) { + *flags |= NF_FALL1; + } + + if ( PointIsOnSurfaceNumber( ps.origin, info->tSurf.number ) ) { + info->rStats.accept++; + return qtrue; + } + + if ( !PointIsOnSurfaceNumber( ps.origin, info->sSurf.number ) ) { + info->rStats.reject2++; + return qfalse; + } + } + + info->rStats.reject3++; + return qfalse; +} + + +static int FindDestination_Push( surfaceThreadInfo_t *info, gentity_t *pushEnt, int *flags ) { + return -1; +#if 0 + vec3_t dir; + pmove_t pm; + playerState_t ps; + int n; + int currentSurface; + qboolean leftGround; + vec3_t pushVel; + vec3_t absmin; + vec3_t absmax; + int numEnts; + gentity_t *ents[MAX_GENTITIES]; + + *flags = 0; + VectorCopy( pushEnt->movedir, dir ); + VectorCopy( dir, pushVel ); + VectorNormalize( dir ); + + memset( &pm, 0, sizeof( pm ) ); + memset( &ps, 0, sizeof( ps ) ); + pm.ps = &ps; + pm.cmd.msec = PMOVE_MSEC; + pm.cmd.buttons = 0; + pm.cmd.weapon = 0; + pm.cmd.angles[0] = 0; + pm.cmd.angles[1] = 0; + pm.cmd.angles[2] = 0; + pm.cmd.forwardmove = 0; + pm.cmd.rightmove = 0; + pm.cmd.upmove = 0; + pm.tracemask = MASK_DEADSOLID; + pm.noFootsteps = qtrue; + pm.trace = ReachTrace; + pm.pointcontents = gi.pointcontents; + + ps.pm_type = PM_NORMAL; + ps.gravity = g_gravity->value; + ps.speed = PLAYER_SPEED; + VectorCopy( info->sSurf.surface->origin, ps.origin ); + VectorCopy( pushVel, ps.velocity ); + ps.delta_angles[0] = 0; + ps.delta_angles[1] = ANGLE2SHORT ( vectoyaw ( dir ) ); + ps.delta_angles[2] = 0; + ps.groundEntityNum = 0; + ps.playernum = 1; + + // junk we need to fill in so PMove behaves correctly + for( n = 0; n < MAX_STATS; n++ ) { + ps.stats[n] = 0; + } + ps.stats[STAT_HEALTH] = 100; + for( n = 0; n < PW_NUM_POWERUPS; n++ ) { + ps.powerups[n] = 0; + } + + leftGround = qfalse; + for ( n = 0; n < MAX_PMOVES; n++ ) { + VectorAdd( ps.origin, mins, absmin ); + VectorAdd( ps.origin, standMaxs, absmax ); + numEnts = gi.EntitiesInBox( absmin, absmax, ents, MAX_GENTITIES ); + for ( n = 0; n < numEnts; n++ ) { + if ( ents[n] == pushEnt ) { + VectorCopy( pushVel, ps.velocity ); + } + } + + Pmove( &pm ); + if ( ps.groundEntityNum == -1 ) { + leftGround = qtrue; + continue; + } + + currentSurface = SurfaceNumberAtPoint( ps.origin ); + + if ( currentSurface == info->sSurf.number && !leftGround ) { + continue; + } + + if ( pm.pmoveEvent == EV_FALL_FAR ) { + *flags |= NF_FALL2; + } + else if ( pm.pmoveEvent == EV_FALL_MEDIUM ) { + *flags |= NF_FALL1; + } + + info->tSurf.cost = n * PMOVE_MSEC; + + return currentSurface; + } + + return -1; +#endif +} + + +// TeleportPlayer( activator, dest->s.origin, dest->s.angles ); +// AngleVectors( angles, player->client->ps.velocity, NULL, NULL ); +// VectorScale( player->client->ps.velocity, 400, player->client->ps.velocity ); + +static int FindDestination_Teleport( surfaceThreadInfo_t *info, gentity_t *destEnt, int *flags ) { + pmove_t pm; + playerState_t ps; + int n; + int currentSurface; + vec3_t lastOrigin; + vec3_t angles; + + *flags = 0; + + VectorCopy( destEnt->s.origin, lastOrigin ); + lastOrigin[2] += 1; + + AngleVectors( destEnt->s.angles, angles, NULL, NULL ); + + memset( &pm, 0, sizeof( pm ) ); + memset( &ps, 0, sizeof( ps ) ); + pm.ps = &ps; + pm.cmd.msec = PMOVE_MSEC; + pm.cmd.buttons = 0; + pm.cmd.weapon = 0; + pm.cmd.angles[0] = 0; + pm.cmd.angles[1] = 0; + pm.cmd.angles[2] = 0; + pm.cmd.forwardmove = 0; + pm.cmd.rightmove = 0; + pm.cmd.upmove = 0; + pm.tracemask = MASK_DEADSOLID; + pm.noFootsteps = qtrue; + pm.trace = ReachTrace; + pm.pointcontents = gi.pointcontents; + + ps.pm_type = PM_NORMAL; + ps.gravity = sv_gravity->value; + ps.speed = PLAYER_SPEED; + VectorCopy( lastOrigin, ps.origin ); + VectorScale( angles, 400, ps.velocity ); + ps.delta_angles[0] = 0; + ps.delta_angles[1] = ANGLE2SHORT ( angles[YAW] ); + ps.delta_angles[2] = 0; + ps.groundEntityNum = 0; + ps.clientNum = 0; + + // junk we need to fill in so PMove behaves correctly + for( n = 0; n < MAX_STATS; n++ ) { + ps.stats[n] = 0; + } + ps.stats[STAT_HEALTH] = 100; + for( n = 0; n < PW_NUM_POWERUPS; n++ ) { + ps.powerups[n] = 0; + } + + n = 0; + while ( 1 ) { + n++; + Pmove( &pm ); + info->rStats.pmoveCount++; + + if( VectorCompare( ps.origin, lastOrigin ) != 0 ) { + break; + } + VectorCopy( ps.origin, lastOrigin ); + + if ( ps.groundEntityNum == -1 ) { + continue; + } + + currentSurface = SurfaceNumberAtPoint( ps.origin ); + + if ( pm.pmoveEvent == EV_FALL_FAR ) { + *flags |= NF_FALL2; + } + else if ( pm.pmoveEvent == EV_FALL_MEDIUM ) { + *flags |= NF_FALL1; + } + + info->tSurf.cost = n * PMOVE_MSEC; + + return currentSurface; + } + + return -1; +} + + +static vec3_t testDir[] = { {0, 1, 0}, {-1, 0, 0}, {0, -1, 0}, {1, 0, 0}, {-0.5, 0.5, 0}, {0.5, 0.5, 0}, {-0.5, -0.5, 0}, {0.5, -0.5, 0} }; + +static void EdgeOpen( surfaceThreadInfo_t *info, vec3_t spot, int flags ) { + info->tSurf.edgeActive = qtrue; + info->tSurf.edgeStart[0] = spot[0]; + info->tSurf.edgeStart[1] = spot[1]; + info->tSurf.edgeEnd[0] = spot[0]; + info->tSurf.edgeEnd[1] = spot[1]; + info->tSurf.edgeFlags = flags; +} + +static void EdgeClose( surfaceThreadInfo_t *info ) { + nneighbor_t *n; + vec3_t vec; + float d; + + n = &info->sSurf.neighbor[info->sSurf.neighborCount]; + + n->surfaceNum = info->tSurf.number; + if ( info->tSurf.edgeStart[0] <= info->tSurf.edgeEnd[0] ) { + n->absmin[0] = info->tSurf.edgeStart[0]; + n->absmax[0] = info->tSurf.edgeEnd[0]; + } + else { + n->absmin[0] = info->tSurf.edgeEnd[0]; + n->absmax[0] = info->tSurf.edgeStart[0]; + } + if ( info->tSurf.edgeStart[1] <= info->tSurf.edgeEnd[1] ) { + n->absmin[1] = info->tSurf.edgeStart[1]; + n->absmax[1] = info->tSurf.edgeEnd[1]; + } + else { + n->absmin[1] = info->tSurf.edgeEnd[1]; + n->absmax[1] = info->tSurf.edgeStart[1]; + } + + n->origin[0] = (n->absmin[0] + n->absmax[0]) * 0.5; + n->origin[1] = (n->absmin[1] + n->absmax[1]) * 0.5; + n->origin[2] = info->sSurf.surface->origin[2]; + + n->flags = info->tSurf.edgeFlags; + + // calc path cost + + if ( info->tSurf.cost ) { + n->cost = info->tSurf.cost; + } + else { + // take dist from source origin to point + VectorSubtract( info->sSurf.surface->origin, n->origin, vec ); + d = VectorLength( vec ); + + // add any movement weights + if ( ( info->sSurf.surface->flags & (SF_WATERLEVEL1 | SF_WATERLEVEL2 ) ) == (SF_WATERLEVEL1 | SF_WATERLEVEL2 ) ) { + d /= SWIMSCALE; + } + else if ( info->sSurf.surface->flags & SF_DUCK ) { + d /= DUCKSCALE; + } + else if ( info->sSurf.surface->flags & (SF_WATERLEVEL1 | SF_WATERLEVEL2 ) ) { + d /= WADESCALE; + } + + // save that as first segment distance + n->cost = d; + + // take dist from point to target origin + VectorSubtract( info->tSurf.surface->origin, n->origin, vec ); + d = VectorLength( vec ); + + // add any movement weights + if ( ( info->tSurf.surface->flags & (SF_WATERLEVEL1 | SF_WATERLEVEL2 ) ) == (SF_WATERLEVEL1 | SF_WATERLEVEL2 ) ) { + d /= SWIMSCALE; + } + else if ( info->tSurf.surface->flags & SF_DUCK ) { + d /= DUCKSCALE; + } + else if ( info->tSurf.surface->flags & (SF_WATERLEVEL1 | SF_WATERLEVEL2 ) ) { + d /= WADESCALE; + } + + // add that to first distance + n->cost += d; + + // convert distance to time + n->cost = ( n->cost / (float)PLAYER_SPEED ) * 1000.0; + + // possibly add a jump cost + if ( n->flags & NF_JUMP ) { + n->cost += 250.0; //FIXME what is a good value to use here? track actual time used for transitional pmoves! + } + } + + if ( info->tSurf.surface->flags & SF_DUCK ) { + n->flags |= NF_DUCK; + } + +// gi.Printf( "s%i to s%i: edge %f,%f to %f,%f f=%i\n", info->sSurf.number, info->tSurf.number, edgeStart[0], edgeStart[1], edgeEnd[0], edgeEnd[1], *edgeFlags ); +// gi.Printf( "s%i to s%i\n", info->sSurf.number, info->tSurf.number ); + info->tSurf.edgeActive = qfalse; + + info->sSurf.neighborCount++; + if ( info->sSurf.neighborCount == MAX_NEIGHBORS_PER_SURFACE ) { + gi.Printf( "MAX_NEIGHBORS_PER_SURFACE exceeded\n" ); + } +} + +static void EdgeUpdate( surfaceThreadInfo_t *info, qboolean reachable, vec3_t spot, int flags ) { +// gi.Printf( "s1=%i s2=%i spot=%s result=%i f=%i\n", info->sSurf.number, info->tSurf.number, vtos( spot ), reachable, flags ); + if ( reachable ) { + if ( info->tSurf.edgeActive ) { + if ( flags == info->tSurf.edgeFlags ) { + // continue edge + info->tSurf.edgeEnd[0] = spot[0]; + info->tSurf.edgeEnd[1] = spot[1]; + } + else { + EdgeClose( info ); + EdgeOpen( info, spot, flags ); + } + } + else { + EdgeOpen( info, spot, flags ); + } + } + else { + if ( info->tSurf.edgeActive ) { + EdgeClose( info ); + } + } +} + + +static void TestReachSurface( surfaceThreadInfo_t *info ) { + int edgeCode; + float xStart, xEnd; + float yStart, yEnd; + float x, y, z; + vec3_t spot; + int flags; + qboolean reachable; + + // determine which edges of s1 are facing s2 + edgeCode = 0; + + if ( info->tSurf.surface->absmin[1] > info->sSurf.surface->absmax[1] ) { + edgeCode |= 1; + } + if ( info->tSurf.surface->absmax[0] < info->sSurf.surface->absmin[0] ) { + edgeCode |= 2; + } + if ( info->tSurf.surface->absmin[0] > info->sSurf.surface->absmax[0] ) { + edgeCode |= 4; + } + if ( info->tSurf.surface->absmax[1] < info->sSurf.surface->absmin[1] ) { + edgeCode |= 8; + } + + if ( info->tSurf.surface->absmax[1] > info->sSurf.surface->absmax[1] && info->tSurf.surface->absmin[0] <= info->sSurf.surface->absmax[0] && info->tSurf.surface->absmax[0] >= info->sSurf.surface->absmin[0] ) { + edgeCode |= 1; + } + if ( info->tSurf.surface->absmin[0] < info->sSurf.surface->absmin[0] && info->tSurf.surface->absmin[1] <= info->sSurf.surface->absmax[1] && info->tSurf.surface->absmax[1] >= info->sSurf.surface->absmin[1] ) { + edgeCode |= 2; + } + if ( info->tSurf.surface->absmax[0] > info->sSurf.surface->absmax[0] && info->tSurf.surface->absmin[1] <= info->sSurf.surface->absmax[1] && info->tSurf.surface->absmax[1] >= info->sSurf.surface->absmin[1] ) { + edgeCode |= 4; + } + if ( info->tSurf.surface->absmin[1] < info->sSurf.surface->absmin[1] && info->tSurf.surface->absmin[0] <= info->sSurf.surface->absmax[0] && info->tSurf.surface->absmax[0] >= info->sSurf.surface->absmin[0] ) { + edgeCode |= 8; + } + + if ( edgeCode == 0 ) { + gi.Printf( "bad edgeCode\n" ); + return; + } + + // get coordinates for corners + xStart = info->sSurf.surface->absmin[0]; + xEnd = info->sSurf.surface->absmax[0]; + yStart = info->sSurf.surface->absmin[1]; + yEnd = info->sSurf.surface->absmax[1]; + z = info->sSurf.surface->origin[2]; + + // run through the spots on the relevant edges + // for each spot, see if the target surface is reachable from there + info->tSurf.edgeActive = qfalse; + + if ( edgeCode & 1 ) { + for ( x = xStart; x <= xEnd; x += XY_STEP ) { + VectorSet( spot, x, yEnd, z ); + reachable = CanReach( info, spot, testDir[0], &flags ); + EdgeUpdate( info, reachable, spot, flags ); + } + } + if ( info->tSurf.edgeActive ) { + EdgeClose( info ); + } + + if ( edgeCode & 2 ) { + for ( y = yStart; y <= yEnd; y += XY_STEP ) { + VectorSet( spot, xStart, y, z ); + reachable = CanReach( info, spot, testDir[1], &flags ); + EdgeUpdate( info, reachable, spot, flags ); + } + } + if ( info->tSurf.edgeActive ) { + EdgeClose( info ); + } + + if ( edgeCode & 4 ) { + for ( y = yStart; y <= yEnd; y += XY_STEP ) { + VectorSet( spot, xEnd, y, z ); + reachable = CanReach( info, spot, testDir[3], &flags ); + EdgeUpdate( info, reachable, spot, flags ); + } + } + if ( info->tSurf.edgeActive ) { + EdgeClose( info ); + } + + if ( edgeCode & 8 ) { + for ( x = xStart; x <= xEnd; x += XY_STEP ) { + VectorSet( spot, x, yStart, z ); + reachable = CanReach( info, spot, testDir[2], &flags ); + EdgeUpdate( info, reachable, spot, flags ); + } + } + if ( info->tSurf.edgeActive ) { + EdgeClose( info ); + } + + // special checks for corners + if ( ( edgeCode & 3 ) == 3 ) { + VectorSet( spot, xStart, yEnd, z ); + reachable = CanReach( info, spot, testDir[4], &flags ); + EdgeUpdate( info, reachable, spot, flags ); + } + if ( info->tSurf.edgeActive ) { + EdgeClose( info ); + } + + if ( ( edgeCode & 5 ) == 5 ) { + VectorSet( spot, xEnd, yEnd, z ); + reachable = CanReach( info, spot, testDir[5], &flags ); + EdgeUpdate( info, reachable, spot, flags ); + } + if ( info->tSurf.edgeActive ) { + EdgeClose( info ); + } + + if ( ( edgeCode & 10 ) == 10 ) { + VectorSet( spot, xStart, yStart, z ); + reachable = CanReach( info, spot, testDir[6], &flags ); + EdgeUpdate( info, reachable, spot, flags ); + } + if ( info->tSurf.edgeActive ) { + EdgeClose( info ); + } + + if ( ( edgeCode & 12 ) == 12 ) { + VectorSet( spot, xEnd, yStart, z ); + reachable = CanReach( info, spot, testDir[7], &flags ); + EdgeUpdate( info, reachable, spot, flags ); + } + if ( info->tSurf.edgeActive ) { + EdgeClose( info ); + } +} + + +static void TestReachSurface_Push( surfaceThreadInfo_t *info, gentity_t *pushEnt ) { + int flags; + int destSurf; + + //Q3MAP we will need to calculate movedir the same way the game dll does + + destSurf = FindDestination_Push( info, pushEnt, &flags ); + if ( destSurf == -1 ) { + gi.Printf( "pusher at %s never hit ground?\n", vtos( info->sSurf.surface->origin ) ); + } + else if ( destSurf != info->sSurf.number ) { + info->tSurf.number = destSurf; + info->tSurf.surface = &surface[destSurf]; + info->tSurf.edgeActive = qfalse; + EdgeUpdate( info, qtrue, info->sSurf.surface->origin, flags ); + EdgeClose( info ); + gi.Printf( "pusher at %s ", vtos( info->sSurf.surface->origin ) ); + gi.Printf( "hits surface at %s ", vtos( info->tSurf.surface->origin ) ); + gi.Printf( "(%i,%i)-(%i,%i)\n", (int)info->tSurf.surface->absmin[0], (int)info->tSurf.surface->absmin[1], (int)info->tSurf.surface->absmax[0], (int)info->tSurf.surface->absmax[1] ); + } + else { + gi.Printf( WARNING "bad pusher at %s\n", vtos( info->sSurf.surface->origin ) ); + } +} + + +static void TestReachSurface_Teleport( surfaceThreadInfo_t *info, gentity_t *teleportEnt ) { + int flags; + int destSurf; + + destSurf = FindDestination_Teleport( info, teleportEnt, &flags ); + if ( destSurf != -1 ) { + info->tSurf.number = destSurf; + info->tSurf.surface = &surface[destSurf]; + info->tSurf.edgeActive = qfalse; + EdgeUpdate( info, qtrue, info->sSurf.surface->origin, flags ); + EdgeClose( info ); + } +} + + +static void CreatePlatNeighbor( surfaceThreadInfo_t *info ) { +#if 0 + nneighbor_t *n; + gentity_t *ent; + + n = &info->sSurf.neighbor[info->sSurf.neighborCount]; + ent = &g_entities[info->tSurf.surface->parm]; + + n->surfaceNum = info->tSurf.number; + + n->absmin[0] = info->sSurf.surface->absmin[0] + 8; + n->absmin[1] = info->sSurf.surface->absmin[1] + 8; + + n->absmax[0] = info->sSurf.surface->absmax[0] - 8; + n->absmax[1] = info->sSurf.surface->absmax[1] - 8; + + VectorCopy( info->sSurf.surface->origin, n->origin ); + n->flags = NF_PLAT; + n->cost = ( ( ent->pos2[2] - ent->pos1[2] ) / (float)PLAYER_SPEED ) * 1000.0; + info->sSurf.neighborCount++; +#endif +} + + +static void FindSurfaceNeighbors( int surfaceNum ) { + int n; + int oldCount; + surfaceThreadInfo_t info; + gentity_t *ent; + + memset( &info, 0, sizeof( info ) ); + info.sSurf.number = surfaceNum; + info.sSurf.surface = &surface[surfaceNum]; + info.sSurf.neighborCount = 0; + + //FIXME we must handle special surface cases here - push, teleport + // they don't need to check every other surface, where player will wind + // up is predetermined (roughly at least) + + // teleporter special case + if ( info.sSurf.surface->flags & SF_TELEPORTER ) { + ent = &g_entities[info.sSurf.surface->parm]; + TestReachSurface_Teleport( &info, ent ); + goto updateGlobals; + } + + // trigger_push special case + if ( info.sSurf.surface->flags & SF_PUSH ) { + ent = &g_entities[info.sSurf.surface->parm]; + TestReachSurface_Push( &info, ent ); + goto updateGlobals; + } +#if 0 + // Q3MAP: reverse this + // if this is a PLATHIGH surface, we need to temporarily relink the plat to the high position + if ( info.sSurf.surface->flags & SF_PLATHIGH ) { + ent = &g_entities[info.sSurf.surface->parm]; + VectorCopy( ent->pos2, ent->s.origin ); + VectorCopy( ent->pos2, ent->currentOrigin ); + gi.linkentity( ent ); + } +#endif + for ( n = 0; n < surfaceCount; n++ ) { + if ( n == info.sSurf.number ) { + info.sStats.treject1++; + continue; + } + + info.tSurf.number = n; + info.tSurf.surface = &surface[n]; + + // plat high surfaces are a special case as a target + // only the corresponding plat low should have them as a neighbor + if ( info.tSurf.surface->flags & SF_PLATHIGH ) { + if ( info.sSurf.surface->flags & SF_PLATLOW ) { + CreatePlatNeighbor( &info ); + info.sStats.accept++; + } + continue; + } + + // reject if surf is too high to be reached + if ( ( info.tSurf.surface->origin[2] - info.sSurf.surface->origin[2] ) > MAX_JUMPHEIGHT ) { + info.sStats.treject2++; + continue; + } + + // reject is surf XY range is a subset of our own (meaning it is underneath us and not directly reachable) + if ( ( info.tSurf.surface->absmin[0] >= info.sSurf.surface->absmin[0] ) && ( info.tSurf.surface->absmin[1] >= info.sSurf.surface->absmin[1] ) && + ( info.tSurf.surface->absmax[0] <= info.sSurf.surface->absmax[0] ) && ( info.tSurf.surface->absmax[1] <= info.sSurf.surface->absmax[1] ) ) { + info.sStats.treject3++; + continue; + } + + // reject if surf origin is not in PVS + if ( !gi.inPVSIgnorePortals( info.tSurf.surface->origin, info.sSurf.surface->origin ) ) { + info.sStats.treject4++; + continue; + } + + // see if it's a neighbor + info.sStats.count++; + oldCount = info.sSurf.neighborCount; + TestReachSurface( &info ); + if ( info.sSurf.neighborCount != oldCount ) { + info.sStats.accept++; + } + else { + info.sStats.reject++; + } + } + +#if 0 + // Q3MAP: reverse this + // if this is a PLATHIGH surface, we need to restore the plat to the low position + if ( info.sSurf.surface->flags & SF_PLATHIGH ) { + ent = &g_entities[info.sSurf.surface->parm]; + VectorCopy( ent->pos1, ent->s.origin ); + VectorCopy( ent->pos1, ent->currentOrigin ); + gi.linkentity( ent ); + } +#endif + if ( neighborCount + info.sSurf.neighborCount > MAX_NEIGHBORS ) { + gi.Printf( "MAX_NEIGHBORS exceeded\n" ); + return; + } + +updateGlobals: + // grab the critical section lock to do global variable updates + ThreadLock(); + + // reserve the block of neighbors we need + surface[info.sSurf.number].neighborIndex = neighborCount; + neighborCount += info.sSurf.neighborCount; + + // update global stats + surfStats.count += info.sStats.count; + surfStats.accept += info.sStats.accept; + surfStats.reject += info.sStats.reject; + surfStats.treject1 += info.sStats.treject1; + surfStats.treject2 += info.sStats.treject2; + surfStats.treject3 += info.sStats.treject3; + surfStats.treject4 += info.sStats.treject4; + if ( info.sSurf.neighborCount == 0 ) { + surfStats.zeroNeighbors++; + } + + reachStats.count += info.rStats.count; + reachStats.accept += info.rStats.accept; + reachStats.reject1 += info.rStats.reject1; + reachStats.reject2 += info.rStats.reject2; + reachStats.reject3 += info.rStats.reject3; + reachStats.pmoveCount += info.rStats.pmoveCount; + + // release the lock + ThreadUnlock(); + + // now we can fill in the block of neighbors from our cache + surface[info.sSurf.number].neighborCount = info.sSurf.neighborCount; + if ( info.sSurf.neighborCount ) { + memcpy( &neighbor[surface[info.sSurf.number].neighborIndex], info.sSurf.neighbor, info.sSurf.neighborCount * sizeof( info.sSurf.neighbor[0] ) ); + } + +} + + +static void FindNeighbors( void ) { + int n; + + neighbor = ( nneighbor_t * )gi.TagMalloc ( MAX_NEIGHBORS * sizeof(neighbor[0]), TAG_GAME ); + neighborCount = 0; + + memset( &reachStats, 0, sizeof( reachStats ) ); + memset( &surfStats, 0, sizeof( surfStats ) ); + +// RunThreadsOn( spotIndexCount, qtrue, FindSurfaceNeighbors ); +//#if 0 + for ( n = 0; n < surfaceCount; n++ ) { + gi.DebugPrintf( "FindSurfaceNeighbors %d/%d\n", n, surfaceCount ); + FindSurfaceNeighbors( n ); + } +//#endif + + gi.Printf( " %i neighbors (avg %.2f per surf)\n", neighborCount, (float)neighborCount/(float)surfaceCount ); + gi.Printf( " %i surfaces with 0 neighbors\n", surfStats.zeroNeighbors ); + + gi.Printf( " surface to surface testing stats:\n" ); + gi.Printf( " %i combinations\n", surfaceCount * surfaceCount ); + gi.Printf( " %i trivial rejects (%i %i %i %i)\n", surfStats.treject1 + surfStats.treject2 + surfStats.treject3 + surfStats.treject4, surfStats.treject1, surfStats.treject2, surfStats.treject3, surfStats.treject4 ); + gi.Printf( " %i full tests (%.2f avg per surf)\n", surfStats.count, (float)surfStats.count / (float)surfaceCount ); + gi.Printf( " %i accepted, %i rejected\n", surfStats.accept, surfStats.reject ); + + gi.Printf( " spot to surface testing stats:\n" ); + gi.Printf( " %i tests (%.2f avg per surf)\n", reachStats.count, (float)reachStats.count / (float)surfaceCount ); + gi.Printf( " %i accepted, %i rejected (%i %i %i)\n", reachStats.accept, reachStats.reject1 + reachStats.reject2 + reachStats.reject3, reachStats.reject1, reachStats.reject2, reachStats.reject3 ); + gi.Printf( " %.2f avg pmoves per test\n", (float)reachStats.pmoveCount / (float)reachStats.count ); +} + + +// +// InflateSurfaces +// + +static void InflateSurfaces( void ) { + int n; + + // inflate surfaces by 16 along both axis + // also drop the Z value by mins + for ( n = 0; n < surfaceCount; n++ ) { + surface[n].absmin[0] -= 0; + surface[n].absmin[1] -= 0; + surface[n].absmax[0] += 0; + surface[n].absmax[1] += 0; + surface[n].origin[2] = floor( surface[n].origin[2] + mins[2] ); + } + + // inflate neighbor edges by 16 along the fixed axis + for ( n = 0; n < neighborCount; n++ ) { + if ( neighbor[n].absmin[0] == neighbor[n].absmax[0] ) { + neighbor[n].absmin[0] -= 0; + neighbor[n].absmax[0] += 0; + } + if ( neighbor[n].absmin[1] == neighbor[n].absmax[1] ) { + neighbor[n].absmin[1] -= 0; + neighbor[n].absmax[1] += 0; + } + neighbor[n].origin[2] = floor( neighbor[n].origin[2] + mins[2] ); + } +} + + +// +// CalculateAllRoutes +// + +typedef enum { + nodestate_estimate, + nodestate_final +} nodeState_t; + +typedef struct { + float cost; + nodeState_t state; + int predecessor; +} nodeInfo_t; + +static nodeInfo_t *nodeInfo; + + +static int NeighborIndex( int sourceSurfNum, int destSurfNum ) { + int base; + int n; + + if ( destSurfNum == -1 ) { + return -1; + } + base = surface[sourceSurfNum].neighborIndex; + for ( n = 0; n < surface[sourceSurfNum].neighborCount; n++ ) { + if ( neighbor[base+n].surfaceNum == destSurfNum ) { + return n; + } + } + return -1; +} + + +static nneighbor_t *PathEdge( int sourceSurfNum, int destSurfNum ) { + int base; + int n; + + base = surface[sourceSurfNum].neighborIndex; + for ( n = 0; n < surface[sourceSurfNum].neighborCount; n++ ) { + if ( neighbor[base+n].surfaceNum == destSurfNum ) { + return &neighbor[base+n]; + } + } + return NULL; +} + + +/* +============= +SurfaceDistance + +Returns the cost of moving from sourceSurfNum to targetSurfNum, 0 if there +is no direct path. +============= +*/ + +static float SurfaceDistance( int sourceSurfNum, int destSurfNum ) { + nneighbor_t *n; + + n = PathEdge( sourceSurfNum, destSurfNum ); + if ( n ) { + return n->cost; + } + return 0; +} + + +/* +============= +CalculateRoutes + +Takes the surfaces and neighbors tablea and uses Dijkstra's algorithm to +determine the shortest route from one surface to another. +============= +*/ + +static void CalculateRoutes( int rootSurfaceNum ) { + int n; + int currentNode; + int testNode; + float bestCost; + int bestNode; + float d; + + // initialize the node info + for ( n = 0; n < surfaceCount; n++ ) { + nodeInfo[n].cost = INFINITE; + nodeInfo[n].state = nodestate_estimate; + nodeInfo[n].predecessor = -1; + } + + // prime thing to get the loop started + currentNode = rootSurfaceNum; + nodeInfo[rootSurfaceNum].cost= 0; + + // calculate the shortest path info + // we loop surfaceCount times; a new final node is determined each iteration + n = 0; + while ( currentNode != -1 ) { + + bestCost = INFINITE; + bestNode = -1; + + // test each node + for ( testNode = 0; testNode < surfaceCount; testNode++ ) { + // do not test it against itself + if ( testNode == currentNode ) { + continue; + } + + // leave final nodes alone + if ( nodeInfo[testNode].state == nodestate_final ) { + continue; + } + + if ( surface[testNode].neighborCount == 0 ) { + continue; + } + + // update adjacent nodes + d = SurfaceDistance( currentNode, testNode ); + if ( d != 0 ) { + // see if we can improve the current estimate at the test node + if ( nodeInfo[currentNode].cost + d < nodeInfo[testNode].cost ) + { + nodeInfo[testNode].predecessor = currentNode; + nodeInfo[testNode].cost = nodeInfo[currentNode].cost + d; + } + } + + // see if this is our new best estimate + if ( nodeInfo[testNode].cost < bestCost ) { + bestCost = nodeInfo[testNode].cost; + bestNode = testNode; + } + } + + // mark current node as final and best node as new current node + nodeInfo[currentNode].state = nodestate_final; + currentNode = bestNode; + n++; + } + + // now fill in the route info + for ( n = 0; n < surfaceCount; n++ ) { + if ( n == rootSurfaceNum ) { + route[rootSurfaceNum * surfaceCount + n] = 255; + continue; + } + testNode = n; + while ( ( testNode != -1 ) && ( nodeInfo[testNode].predecessor != rootSurfaceNum ) ) { + testNode = nodeInfo[testNode].predecessor; + } + if ( testNode == -1 ) { + route[rootSurfaceNum * surfaceCount + n] = 255; + continue; + } + route[rootSurfaceNum * surfaceCount + n] = NeighborIndex( rootSurfaceNum, testNode ); + } +} + + +static void CalculateAllRoutes( void ) { + int n; + + route = ( byte * )gi.TagMalloc ( surfaceCount * surfaceCount * sizeof( byte ), TAG_GAME ); + nodeInfo = ( nodeInfo_t * )gi.TagMalloc ( surfaceCount * sizeof( nodeInfo[0] ), TAG_GAME ); + + for ( n = 0; n < surfaceCount; n++ ) { + CalculateRoutes( n ); + } + + gi.TagFree( nodeInfo ); +} + + + +// +// WriteNavigationData +// + +static void WriteNavigationData( void ) { + FILE *f; + int n; + navheader_t outHeader; + nsurface_t outSurface; + nneighbor_t outNeighbor; + str filename; + str osFilename; + + Swap_Init(); + + filename = str( "maps/" ) + level.mapname.c_str() + ".nav"; + gi.Printf( "Writing %s.\n", filename.c_str() ); + osFilename = gi.FS_PrepFileWrite( filename.c_str() ); + f = fopen( osFilename.c_str(), "wb" ); + if ( !f ) + { + gi.Printf( "Open failed.\n" ); + return; + } + + // write version header + outHeader.id = LittleLong( NAVFILE_ID ); + outHeader.version = LittleLong( NAVFILE_VERSION ); + outHeader.surfaceCount = LittleLong( surfaceCount ); + outHeader.neighborCount = LittleLong( neighborCount ); + fwrite( &outHeader, sizeof( outHeader ), 1, f ); + + // write surfaces + for ( n = 0; n < surfaceCount; n++ ) { + outSurface.origin[0] = LittleFloat( surface[n].origin[0] ); + outSurface.origin[1] = LittleFloat( surface[n].origin[1] ); + outSurface.origin[2] = LittleFloat( surface[n].origin[2] ); + + outSurface.absmin[0] = LittleFloat( surface[n].absmin[0] ); + outSurface.absmin[1] = LittleFloat( surface[n].absmin[1] ); + + outSurface.absmax[0] = LittleFloat( surface[n].absmax[0] ); + outSurface.absmax[1] = LittleFloat( surface[n].absmax[1] ); + + outSurface.flags = LittleLong( surface[n].flags ); + outSurface.neighborCount = LittleLong( surface[n].neighborCount ); + outSurface.neighborIndex = LittleLong( surface[n].neighborIndex ); + outSurface.parm = LittleLong( surface[n].parm ); + + fwrite( &outSurface, sizeof( outSurface ), 1, f ); + + gi.Printf( "surface%02i f=%04x n=%i@%i z=%i ", n, surface[n].flags, surface[n].neighborCount, surface[n].neighborIndex, (int)surface[n].origin[2] ); + gi.Printf( "(%i,%i)-(%i,%i)\n", (int)surface[n].absmin[0], (int)surface[n].absmin[1], (int)surface[n].absmax[0], (int)surface[n].absmax[1] ); + } + + // write neighbors + for ( n = 0; n < neighborCount; n++ ) { + outNeighbor.origin[0] = LittleFloat( neighbor[n].origin[0] ); + outNeighbor.origin[1] = LittleFloat( neighbor[n].origin[1] ); + outNeighbor.origin[2] = LittleFloat( neighbor[n].origin[2] ); + + outNeighbor.absmin[0] = LittleFloat( neighbor[n].absmin[0] ); + outNeighbor.absmin[1] = LittleFloat( neighbor[n].absmin[1] ); + + outNeighbor.absmax[0] = LittleFloat( neighbor[n].absmax[0] ); + outNeighbor.absmax[1] = LittleFloat( neighbor[n].absmax[1] ); + + outNeighbor.surfaceNum = LittleLong( neighbor[n].surfaceNum ); + outNeighbor.flags = LittleLong( neighbor[n].flags ); + outNeighbor.cost = LittleLong( neighbor[n].cost ); + outNeighbor.filler = LittleLong( neighbor[n].filler ); + + fwrite( &outNeighbor, sizeof( outNeighbor ), 1, f ); + + gi.Printf( "neighbor%03i f=%04x surface=%02i cost=%f\n", n, neighbor[n].flags, neighbor[n].surfaceNum, neighbor[n].cost ); + } + + // write routes + fwrite( route, surfaceCount * surfaceCount * sizeof( byte ), 1, f ); + + fclose( f ); +} + + +// +// Nav_Gen_f +// + +void Nav_Gen_f( void ) { + int start; + int elapsed; + int i; + gentity_t *ent; + + for( i = 0; i < globals.num_entities; i++ ) + { + ent = &g_entities[i]; + if ( ent->entity && ent->entity->isSubclassOf( Mover ) ) + { + ent->entity->unlink(); + } + } + + // FindSpots + gi.Printf( "FindSpots\n" ); + start = gi.Milliseconds(); + FindSpots(); + elapsed = gi.Milliseconds() - start; + gi.Printf( " %.2f seconds elapsed\n", (float)elapsed / 1000.0 ); + + // FindSurfaces + gi.Printf( "FindSurfaces\n" ); + start = gi.Milliseconds(); + //FindSurfaces(); + FindConvexSurfaces(); + elapsed = gi.Milliseconds() - start; + gi.Printf( " %.2f seconds elapsed\n", (float)elapsed / 1000.0 ); + + // FindNeighbors + gi.Printf( "FindNeighbors\n" ); + start = gi.Milliseconds(); + FindNeighbors(); + elapsed = gi.Milliseconds() - start; + gi.Printf( " %.2f seconds elapsed\n", (float)elapsed / 1000.0 ); + + // InflateSurfaces + gi.Printf( "InflateSurfaces\n" ); + start = gi.Milliseconds(); + InflateSurfaces(); + elapsed = gi.Milliseconds() - start; + gi.Printf( " %.2f seconds elapsed\n", (float)elapsed / 1000.0 ); + + // CalculateAllRoutes + gi.Printf( "CalculateAllRoutes\n" ); + start = gi.Milliseconds(); + CalculateAllRoutes(); + elapsed = gi.Milliseconds() - start; + gi.Printf( " %.2f seconds elapsed\n", (float)elapsed / 1000.0 ); + + // WriteNavigationData + start = gi.Milliseconds(); + WriteNavigationData(); + elapsed = gi.Milliseconds() - start; + gi.Printf( " %.2f seconds elapsed\n", (float)elapsed / 1000.0 ); + + gi.TagFree( route ); + gi.TagFree( neighbor ); + gi.TagFree( surface ); + + for( i = 0; i < globals.num_entities; i++ ) + { + ent = &g_entities[i]; + if ( ent->entity && ent->entity->isSubclassOf( Mover ) ) + { + ent->entity->link(); + } + } +} diff --git a/source/source/fgame/beam.cpp b/source/source/fgame/beam.cpp new file mode 100644 index 0000000..f70cb08 --- /dev/null +++ b/source/source/fgame/beam.cpp @@ -0,0 +1,924 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/beam.cpp $ +// $Revision:: 39 $ +// $Author:: Markd $ +// $Date:: 6/23/00 8:41p $ +// +// Copyright (C) 1999 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/beam.cpp $ +// +// 39 6/23/00 8:41p Markd +// made a lot of changes to different constructors for saved game support +// +// 38 6/23/00 11:49a Markd +// fixed various imagindexes and saved games +// +// 37 5/30/00 2:47p Aldie +// Fix for beam parent +// +// 36 5/30/00 10:59a Aldie +// Added Circle of Protection Powerup +// +// 35 5/24/00 6:05p Markd +// Fixed bug where MAX_MAP_BOUNDS was being used instead of MAP_SIZE +// +// 34 5/01/00 4:19p Steven +// Added some caching stuff to beams. +// +// 33 3/30/00 6:23p Steven +// Fixed life not getting set properly. +// +// 32 3/28/00 5:00p Aldie +// Fix beam parameter +// +// 31 3/28/00 4:25p Aldie +// Some more beam changes for Pat +// +// 30 3/28/00 3:16p Aldie +// Fixed some beam problems for Pat +// +// 29 3/14/00 3:38p Aldie +// Added persist command +// +// 28 2/14/00 7:34p Aldie +// Fixed some beam rendering issues +// +// 27 2/03/00 7:01p Jimdose +// made all hardcoded map bounds use MAX_MAP_BOUNDS +// +// 26 1/31/00 4:35p Steven +// Fixed a bug in CreateBeam. +// +// 25 1/26/00 5:07p Aldie +// Fixed beamdamage +// +// 24 1/22/00 12:42p Jimdose +// got rid of calls to vec3() +// +// 23 1/21/00 8:01p Aldie +// Fixed a warning +// +// 22 1/21/00 5:38p Aldie +// Fix more beam bugs +// +// 21 1/21/00 2:10p Aldie +// Fixed beam endpoint tracking +// +// 20 1/20/00 5:26p Aldie +// Clarified some of the spawnargs +// +// 19 1/15/00 3:57p Markd +// Eliminated multiple "angle" events and replaced them with EV_SetAngle +// +// 18 1/14/00 5:06p Markd +// Removed surface num, tri_num and damage_multiplier from multiple functions +// and events +// +// 17 1/11/00 6:41p Markd +// Removed fulltrace code from the game +// +// 16 1/07/00 8:12p Jimdose +// cleaning up unused code +// +// 15 1/05/00 7:25p Jimdose +// made angle functions all use the same coordinate system +// AngleVectors now returns left instead of right +// no longer need to invert pitch +// +// 14 11/19/99 11:29a Steven +// Added ability to specify the end point of a beam. +// +// 13 10/25/99 6:45p Aldie +// Add noise spawnflag +// +// 12 10/25/99 3:46p Aldie +// Fixed beam spawnflag +// +// 11 10/25/99 3:21p Aldie +// Fixed activate and deactivate +// +// 10 10/22/99 4:28p Aldie +// added some defaults +// +// 9 10/22/99 12:17p Aldie +// fixed defaults +// +// 8 10/21/99 6:19p Markd +// removed torso and head members from entity_state +// +// 7 10/21/99 2:51p Aldie +// Added some more beam functions +// +// 6 10/19/99 4:30p Aldie +// Added wave effect +// +// 5 10/19/99 11:57a Aldie +// Added some more beam features +// +// 4 10/18/99 4:00p Aldie +// Fix for beam endpoints +// +// 3 10/18/99 3:58p Aldie +// Fix for beam endpoints +// +// 2 10/18/99 1:59p Aldie +// Lots of fixes for beams and stuff +// +// DESCRIPTION: +// + +#include "beam.h" +#include "../qcommon/qfiles.h" + +/*****************************************************************************/ +/*QUAKED func_beam (0 0.25 .5) (-8 -8 -8) (8 8 8) START_ON PERSIST WAVE NOISE + +This creates a beam effect from the origin to the target's origin. If no +target is specified, uses angles and projects beam out from there. + +"model" Specifies the model to use as the beam +"overlap" Specifies the amount of overlap each beam link should have. Use this to fill +in the cracks when using electric on beams. (Default is 0) +"minoffset" Minimum amount of electrical variation (Default is 0) +"maxoffset" Maximum amount of electrical variation (Default is 5) +"color" Vector specifiying the red,green, and blue components. (Default is "1 1 1") +"alpha" Alpha of the beam (Default is 1.0) +"damage" Amount of damage the beam inflicts if beam hits someone (Default is 0) +"angles" Sets the angle of the beam if no target is specified. +"life" Sets the life of the beam for use with the persist spawnflag. This is how long a beam will +be displayed. +"numsegments" Number of segments in a beam (Default is 4) +"delay" Delay between beam updates. (i.e. slows the effect of the beam down) +"shader" Set the shader of the beam +"scale" Set the width of the beam + +START_ON - Starts the beam on +PERSIST - Keeps the last few beams around and fades them out over the life of the beam +WAVE - Make the beam follow a sin wave pattern +NOISE - Use a more computationally expensive random effect, but the results are smoother + +If the model field is not set, then a renderer generated beam will be created +using the color, minoffset, maxoffset, scale, and subdivisions fields + +If the targetname is set, it will use the target specified as the endpoint of the beam + +/*****************************************************************************/ + +Event EV_FuncBeam_Activate + ( + "activate", + EV_DEFAULT, + NULL, + NULL, + "Activate the beam" + ); +Event EV_FuncBeam_Deactivate + ( + "deactivate", + EV_DEFAULT, + NULL, + NULL, + "Deactivate the beam" + ); +Event EV_FuncBeam_Diameter + ( + "diameter", + EV_DEFAULT, + "f", + "diameter", + "Set the diameter of the beam" + ); +Event EV_FuncBeam_Maxoffset + ( + "maxoffset", + EV_DEFAULT, + "f", + "max_offset", + "Set the maximum offset the beam can travel above, below, forward or back of it's endpoints" + ); +Event EV_FuncBeam_Minoffset + ( + "minoffset", + EV_DEFAULT, + "f", + "min_offset", + "Set the minimun offset the beam can travel above, below, forward or back of it's endpoints" + ); +Event EV_FuncBeam_Overlap + ( + "overlap", + EV_DEFAULT, + "f", + "beam_overlap", + "Set the amount of overlap the beams have when they are being strung together" + ); +Event EV_FuncBeam_Color + ( + "color", + EV_DEFAULT, + "v[0,1][0,1][0,1]", + "beam_color", + "Set the color of the beam" + ); +Event EV_FuncBeam_SetTarget + ( + "target", + EV_DEFAULT, + "s", + "beam_target", + "Set the target of the beam. The beam will be drawn from the origin\n" + "to the origin of the target entity" + ); +Event EV_FuncBeam_SetEndPoint + ( + "endpoint", + EV_DEFAULT, + "v", + "beam_end_point", + "Set the end point of the beam. The beam will be draw from the origin to\n" + "the end point." + ); +Event EV_FuncBeam_SetLife + ( + "life", + EV_DEFAULT, + "f", + "beam_life", + "Set the amount of time the beam stays on when activated" + ); +Event EV_FuncBeam_Shader + ( + "shader", + EV_DEFAULT, + "s", + "beam_shader", + "Set the shader that the beam will use" + ); +Event EV_FuncBeam_TileShader + ( + "tileshader", + EV_DEFAULT, + "s", + "beam_shader", + "Set the shader that the beam will use. This shader will be tiled." + ); +Event EV_FuncBeam_Segments + ( + "numsegments", + EV_DEFAULT, + "i", + "numsegments", + "Set the number of segments for the beam" + ); +Event EV_FuncBeam_Delay + ( + "delay", + EV_DEFAULT, + "f", + "delay", + "Set the amount of delay on the beam updater" + ); +Event EV_FuncBeam_NumSphereBeams + ( + "numspherebeams", + EV_DEFAULT, + "i", + "num", + "Set the number of beams that will be shot out in a sphere like formation" + ); +Event EV_FuncBeam_SphereRadius + ( + "radius", + EV_DEFAULT, + "f", + "radius", + "Set the starting radius of the beams if this is a beamsphere" + ); +Event EV_FuncBeam_ToggleDelay + ( + "toggledelay", + EV_DEFAULT, + "SF", + "[random] time", + "Causes a beam toggling effect. Sets the time between toggling. If random is specified, The time will be between 0 and time" + ); +Event EV_FuncBeam_FindEndpoint + ( + "findendpoint", + EV_DEFAULT, + NULL, + NULL, + "Find the endpoint of a beam" + ); +Event EV_FuncBeam_UpdateEndpoint + ( + "updateendpoint", + EV_DEFAULT, + NULL, + NULL, + "Update the endpoint of a beam" + ); +Event EV_FuncBeam_UpdateOrigin + ( + "updateorigin", + EV_DEFAULT, + NULL, + NULL, + "Update the origin of a beam" + ); +Event EV_FuncBeam_EndAlpha + ( + "endalpha", + EV_DEFAULT, + "f", + "alpha", + "Set the endpoint alpha value of the beam" + ); +Event EV_FuncBeam_Shoot + ( + "shoot", + EV_DEFAULT, + NULL, + NULL, + "Make the beam cause damage to entities that get in the way" + ); +Event EV_FuncBeam_ShootRadius + ( + "shootradius", + EV_DEFAULT, + "f", + "radius", + "Set the radius of the damage area between beam endpoints" + ); +Event EV_FuncBeam_Persist + ( + "persist", + EV_DEFAULT, + "b", + "bool", + "Set the persist property of the beam" + ); + +CLASS_DECLARATION( ScriptSlave, FuncBeam, "func_beam" ) + { + { &EV_Activate, Activate }, + { &EV_FuncBeam_Activate, Activate }, + { &EV_FuncBeam_Deactivate, Deactivate }, + { &EV_FuncBeam_Maxoffset, SetMaxoffset }, + { &EV_FuncBeam_Minoffset, SetMinoffset }, + { &EV_FuncBeam_Overlap, SetOverlap }, + { &EV_FuncBeam_Color, SetColor }, + { &EV_FuncBeam_SetTarget, SetTarget }, + { &EV_SetAngle, SetAngle }, + { &EV_FuncBeam_Segments, SetSegments }, + { &EV_SetAngles, SetAngles }, + { &EV_FuncBeam_SetEndPoint, SetEndPoint }, + { &EV_Model, SetModel }, + { &EV_Damage, SetDamage }, + { &EV_FuncBeam_SetLife, SetLife }, + { &EV_FuncBeam_Shader, SetBeamShader }, + { &EV_FuncBeam_TileShader, SetBeamTileShader }, + { &EV_FuncBeam_Delay, SetDelay }, + { &EV_FuncBeam_NumSphereBeams, SetNumSphereBeams }, + { &EV_FuncBeam_SphereRadius, SetSphereRadius }, + { &EV_FuncBeam_ToggleDelay, SetToggleDelay }, + { &EV_FuncBeam_ShootRadius, SetShootRadius }, + { &EV_FuncBeam_EndAlpha, SetEndAlpha }, + { &EV_FuncBeam_Persist, SetPersist }, + { &EV_FuncBeam_FindEndpoint, FindEndpoint }, + { &EV_FuncBeam_UpdateEndpoint, UpdateEndpoint }, + { &EV_FuncBeam_UpdateOrigin, UpdateOrigin }, + { &EV_FuncBeam_Shoot, Shoot }, + { NULL, NULL } + }; + +FuncBeam::FuncBeam() + { + setSolidType( SOLID_NOT ); + setOrigin(); + + damage = 0; + life = 0; + shootradius = 0; + use_angles = false; + + edict->s.renderfx |= RF_BEAM; + edict->s.eType = ET_BEAM; // Entity type beam + edict->s.modelindex = 1; // must be non-zero + SetBeamShader( "beamshader" ); + + if ( !LoadingSavegame ) + { + edict->s.alpha = 1; // alpha + edict->s.surfaces[4] = 4; // num segments + + BEAM_PARM_TO_PKT( 1, edict->s.surfaces[0] ); // life + edict->s.bone_angles[0][1] = 5; // Max offset + edict->s.torso_anim = ENTITYNUM_NONE; + BEAM_PARM_TO_PKT( 1, edict->s.surfaces[9] ); // endalpha + + if ( spawnflags & 0x0001 ) // Start On + PostEvent( EV_Activate, EV_POSTSPAWN ); + else + hideModel(); + edict->s.skinNum = 0; + if ( spawnflags & 0x0002 ) + edict->s.skinNum |= BEAM_PERSIST_EFFECT; + if ( spawnflags & 0x0004 ) + edict->s.skinNum |= BEAM_WAVE_EFFECT; + if ( spawnflags & 0x0008 ) + edict->s.skinNum |= BEAM_USE_NOISE; + + // Try to find the endpoint of this beam after everything has been spawned + PostEvent( EV_FuncBeam_FindEndpoint, EV_LINKBEAMS ); + } + } + +void FuncBeam::SetEndAlpha + ( + Event *ev + ) + + { + BEAM_PARM_TO_PKT( ev->GetFloat( 1 ), edict->s.surfaces[9] ); + } + +void FuncBeam::SetToggleDelay + ( + Event *ev + ) + + { + edict->s.skinNum |= BEAM_TOGGLE; + + if ( ev->NumArgs() > 2 ) + { + str arg = ev->GetString( 1 ); + if ( !arg.icmp( "random" ) ) + { + edict->s.skinNum |= BEAM_RANDOM_TOGGLEDELAY; + } + BEAM_PARM_TO_PKT( ev->GetFloat( 2 ), edict->s.surfaces[8] ); + } + else + { + BEAM_PARM_TO_PKT( ev->GetFloat( 1 ), edict->s.surfaces[8] ); + } + } + +void FuncBeam::SetSphereRadius + ( + Event *ev + ) + + { + edict->s.skinNum |= BEAM_SPHERE_EFFECT; + BEAM_PARM_TO_PKT( ev->GetFloat( 1 ), edict->s.surfaces[7] ); + } + +void FuncBeam::SetNumSphereBeams + ( + Event *ev + ) + + { + edict->s.skinNum |= BEAM_SPHERE_EFFECT; + edict->s.surfaces[6] = ev->GetInteger( 1 ); + } + +void FuncBeam::SetAngle + ( + Event *ev + ) + + { + Vector movedir; + + movedir = G_GetMovedir( ev->GetFloat( 1 ) ); + setAngles( movedir.toAngles() ); + } + +void FuncBeam::SetAngles + ( + Event *ev + ) + + { + setAngles( ev->GetVector( 1 ) ); + } + +// Override setAngles to update the endpoint of the beam if it's rotated +void FuncBeam::setAngles + ( + Vector angles + ) + + { + trace_t trace; + Vector endpoint; + + ScriptSlave::setAngles( angles ); + + // If there is no target, then use the angles to determine where to put the + // endpoint + if ( !end ) + { + endpoint = origin + Vector( orientation[0] ) * MAP_SIZE; + + trace = G_Trace( origin, vec_zero, vec_zero, endpoint, this, MASK_SOLID, false, "FuncBeam" ); + + VectorCopy( trace.endpos, edict->s.origin2 ); + + use_angles = true; + } + } + +void FuncBeam::SetEndPoint + ( + Event *ev + ) + + { + trace_t trace; + + end_point = ev->GetVector( 1 ); + + trace = G_Trace( origin, vec_zero, vec_zero, end_point, this, MASK_SOLID, false, "FuncBeam" ); + VectorCopy( trace.endpos, edict->s.origin2 ); + + use_angles = false; + } + +void FuncBeam::SetModel + ( + Event *ev + ) + + { + setModel( ev->GetString( 1 ) ); + edict->s.renderfx &= ~RF_BEAM; + edict->s.eType = ET_BEAM; + edict->s.skinNum |= BEAM_USEMODEL; + } + +void FuncBeam::SetDamage + ( + Event *ev + ) + + { + damage = ev->GetFloat( 1 ); + } + +void FuncBeam::SetLife + ( + Event *ev + ) + + { + BEAM_PARM_TO_PKT( ev->GetFloat( 1 ), edict->s.surfaces[0] ); + } + +void FuncBeam::SetColor + ( + Event *ev + ) + + { + Vector color = ev->GetVector( 1 ); + G_SetConstantLight( &edict->s.constantLight, &color[ 0 ], &color[ 1 ], &color[ 2 ], NULL ); + } + +void FuncBeam::SetSegments + ( + Event *ev + ) + + { + edict->s.surfaces[4] = ev->GetInteger( 1 ); + } + +void FuncBeam::SetBeamShader + ( + str beam_shader + ) + + { + str temp_shader; + + shader = beam_shader; + edict->s.tag_num = gi.imageindex( shader ); + + temp_shader = shader + ".spr"; + CacheResource( temp_shader, this ); + } + +void FuncBeam::SetBeamShader + ( + Event *ev + ) + + { + SetBeamShader( ev->GetString( 1 ) ); + } + +void FuncBeam::SetBeamTileShader + ( + Event *ev + ) + + { + SetBeamShader( ev->GetString( 1 ) ); + edict->s.skinNum |= BEAM_TILESHADER; + } + +void FuncBeam::SetMaxoffset + ( + Event *ev + ) + + { + edict->s.bone_angles[0][1] = ev->GetFloat( 1 ); + } + +void FuncBeam::SetMinoffset + ( + Event *ev + ) + + { + edict->s.bone_angles[0][0] = ev->GetFloat( 1 ); + } + +void FuncBeam::SetOverlap + ( + Event *ev + ) + + { + BEAM_PARM_TO_PKT( ev->GetFloat( 1 ), edict->s.surfaces[3] ); + } + +void FuncBeam::SetDelay + ( + Event *ev + ) + + { + if ( ev->NumArgs() > 2 ) + { + str arg = ev->GetString( 1 ); + if ( !arg.icmp( "random" ) ) + { + edict->s.skinNum |= BEAM_RANDOM_DELAY; + } + BEAM_PARM_TO_PKT( ev->GetFloat( 2 ), edict->s.surfaces[5] ); + } + else + { + BEAM_PARM_TO_PKT( ev->GetFloat( 1 ), edict->s.surfaces[5] ); + } + } + +void FuncBeam::Deactivate + ( + Event *ev + ) + + { + hideModel(); + + // Cancel all of the events to activate + CancelEventsOfType( EV_FuncBeam_Activate ); + CancelEventsOfType( EV_Activate ); + CancelEventsOfType( EV_FuncBeam_UpdateEndpoint ); + CancelEventsOfType( EV_FuncBeam_UpdateOrigin ); + } + +void FuncBeam::SetShootRadius + ( + Event *ev + ) + + { + shootradius = ev->GetFloat( 1 ); + } + +void FuncBeam::SetPersist + ( + Event *ev + ) + + { + qboolean persist = ev->GetBoolean( 1 ); + + if ( persist ) + edict->s.skinNum |= BEAM_PERSIST_EFFECT; + else + edict->s.skinNum &= ~BEAM_PERSIST_EFFECT; + } + +void FuncBeam::Shoot + ( + Event *ev + ) + + { + trace_t trace; + Vector start, end; + + start = edict->s.origin; + end = edict->s.origin2; + + Vector dir( end - start ); + Vector b1( -shootradius, -shootradius, -shootradius ); + Vector b2( shootradius, shootradius, shootradius ); + + trace = G_Trace( start, b1, b2, end, this, MASK_SHOT, false, "FuncBeam::Activate" ); + + if ( trace.ent && trace.ent->entity && trace.ent->entity->takedamage ) + { + // damage the ent + trace.ent->entity->Damage( this, + this, + damage, + trace.endpos, + dir, + trace.plane.normal, + 0, + 0, + MOD_BEAM + ); + } + + PostEvent( EV_FuncBeam_Shoot, 0.1f ); + } + +void FuncBeam::Activate + ( + Event *ev + ) + + { + Vector forward; + trace_t trace; + + showModel(); + + // An entity is targeted + if ( end ) + { + VectorCopy( end->origin, edict->s.origin2 ); + // Post an event so that the beam will update itself every frame + PostEvent( EV_FuncBeam_UpdateEndpoint, FRAMETIME ); + } + else if ( use_angles ) + { + angles.AngleVectors( &forward, NULL, NULL ); + + Vector endpoint( orientation[ 0 ] ); + endpoint *= MAP_SIZE; + + trace = G_Trace( origin, vec_zero, vec_zero, endpoint, this, MASK_SOLID, false, "FuncBeam::Activate" ); + VectorCopy( trace.endpos, edict->s.origin2 ); + } + else + { + trace = G_Trace( origin, vec_zero, vec_zero, end_point, this, MASK_SOLID, false, "FuncBeam::Activate" ); + VectorCopy( trace.endpos, edict->s.origin2 ); + } + + if ( origin_target ) + { + PostEvent( EV_FuncBeam_UpdateOrigin, FRAMETIME ); + } + + if ( damage ) + { + // Shoot beam and cause damage every frame + ProcessEvent( EV_FuncBeam_Shoot ); + } + + // If life is set, then post a deactivate message + if ( life > 0 && !EventPending( EV_FuncBeam_Deactivate ) ) + { + PostEvent( EV_FuncBeam_Deactivate, life ); + return; + } + } + +void FuncBeam::UpdateEndpoint + ( + Event *ev + ) + + { + if ( end ) + { + Event *ev1 = new Event( ev ); + + VectorCopy( end->origin, edict->s.origin2 ); + PostEvent( ev1, FRAMETIME ); + } + } + +void FuncBeam::UpdateOrigin + ( + Event *ev + ) + + { + if ( origin_target ) + { + Event *ev1 = new Event( ev ); + + setOrigin( origin_target->centroid ); + PostEvent( ev1, FRAMETIME ); + } + } + +void FuncBeam::FindEndpoint + ( + Event *ev + ) + + { + if ( target && strlen( target ) ) + { + end = G_FindTarget( NULL, target ); + if ( end ) + { + VectorCopy( end->origin, edict->s.origin2 ); + } + } + } + +FuncBeam *CreateBeam + ( + const char *model, + const char *shader, + Vector start, + Vector end, + int numsegments, + float scale, + float life, + float damage, + Entity *origin_target + ) + + { + FuncBeam *beam; + trace_t trace; + + // set start point + beam = new FuncBeam; + beam->setOrigin( start ); + + if ( origin_target ) + beam->origin_target = origin_target; + + // set endpoint + beam->end_point = end; + trace = G_Trace( start, vec_zero, vec_zero, end, beam, MASK_SOLID, false, "CreateBeam" ); + VectorCopy( trace.endpos, beam->edict->s.origin2 ); + beam->use_angles = false; + + if ( model ) + { + // set the model if we have one + beam->setModel( model ); + beam->edict->s.renderfx &= ~RF_BEAM; + beam->edict->s.eType = ET_BEAM; + beam->edict->s.skinNum |= BEAM_USEMODEL; + } + + if ( shader ) + { + // Set the shader as an image configstring + beam->SetBeamShader( shader ); + } + + // set num segments + beam->edict->s.surfaces[4] = numsegments; + + // set scale + beam->setScale( scale ); + + // set life + BEAM_PARM_TO_PKT( life, beam->edict->s.surfaces[0] ); + beam->life = life; + + // set damage + beam->damage = damage; + + // activate it + beam->ProcessEvent( EV_Activate ); + beam->PostEvent( EV_Remove, life ); + return beam; + } diff --git a/source/source/fgame/beam.h b/source/source/fgame/beam.h new file mode 100644 index 0000000..72962a7 --- /dev/null +++ b/source/source/fgame/beam.h @@ -0,0 +1,164 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/beam.h $ +// $Revision:: 17 $ +// $Author:: Markd $ +// $Date:: 6/23/00 11:49a $ +// +// Copyright (C) 1999 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/beam.h $ +// +// 17 6/23/00 11:49a Markd +// fixed various imagindexes and saved games +// +// 16 6/14/00 2:17p Markd +// fixed compiler warnings for Intel Compiler +// +// 15 5/30/00 10:59a Aldie +// Added Circle of Protection Powerup +// +// 14 5/25/00 7:52p Markd +// 2nd pass save game stuff +// +// 13 5/24/00 3:14p Markd +// first phase of save/load games +// +// 12 3/14/00 4:56p Aldie +// Added persist command +// +// 11 2/14/00 7:34p Aldie +// Fixed some beam rendering issues +// +// 10 1/26/00 5:07p Aldie +// Fixed beamdamage +// +// 9 1/21/00 5:39p Aldie +// Fixed another targeting bug +// +// 8 1/21/00 2:10p Aldie +// Fixed beam endpoint tracking +// +// 7 1/10/00 6:17p Jimdose +// more code cleanup +// +// 6 1/07/00 8:12p Jimdose +// cleaning up unused code +// +// 5 11/19/99 11:28a Steven +// Added ability to specify the end point of a beam. +// +// 4 10/19/99 11:57a Aldie +// Added some more beam features +// +// 3 10/18/99 3:58p Aldie +// Fix for beam endpoints +// +// 2 10/18/99 1:59p Aldie +// Lots of fixes for beams and stuff +// +// DESCRIPTION: +// +#ifndef __BEAM_H__ +#define __BEAM_H__ + +#include "g_local.h" +#include "scriptslave.h" + +extern Event EV_FuncBeam_Activate; +extern Event EV_FuncBeam_Deactivate; +extern Event EV_FuncBeam_Diameter; +extern Event EV_FuncBeam_Maxoffset; +extern Event EV_FuncBeam_Minoffset; +extern Event EV_FuncBeam_Overlap; +extern Event EV_FuncBeam_Color; +extern Event EV_FuncBeam_SetTarget; +extern Event EV_FuncBeam_SetAngle; +extern Event EV_FuncBeam_SetEndPoint; +extern Event EV_FuncBeam_SetLife; +extern Event EV_FuncBeam_Shader; +extern Event EV_FuncBeam_Segments; +extern Event EV_FuncBeam_Delay; +extern Event EV_FuncBeam_NumSphereBeams; +extern Event EV_FuncBeam_SphereRadius; +extern Event EV_FuncBeam_ToggleDelay; +extern Event EV_FuncBeam_FindEndpoint; +extern Event EV_FuncBeam_EndAlpha; + +class FuncBeam : public ScriptSlave + { + protected: + EntityPtr end,origin_target; + float damage; + float life; + Vector end_point; + qboolean use_angles; + float shootradius; + str shader; + + public: + CLASS_PROTOTYPE( FuncBeam ); + + FuncBeam(); + + void SetAngle( Event *ev ); + void SetAngles( Event *ev ); + void SetEndPoint( Event *ev ); + void SetModel( Event *ev ); + void SetDamage( Event *ev ); + void SetOverlap( Event *ev ); + void SetBeamStyle( Event *ev ); + void SetLife( Event *ev ); + void Activate( Event *ev ); + void Deactivate( Event *ev ); + void SetDiameter( Event *ev ); + void SetMaxoffset( Event *ev ); + void SetMinoffset( Event *ev ); + void SetColor( Event *ev ); + void SetSegments( Event *ev ); + void SetBeamShader( str shader ); + void SetBeamShader( Event *ev ); + void SetBeamTileShader( Event *ev ); + void SetDelay( Event *ev ); + void SetToggleDelay( Event *ev ); + void SetSphereRadius( Event *ev ); + void SetNumSphereBeams( Event *ev ); + void SetEndAlpha( Event *ev ); + void SetShootRadius( Event *ev ); + void SetPersist( Event *ev ); + void FindEndpoint( Event *ev ); + void UpdateEndpoint( Event *ev ); + void UpdateOrigin( Event *ev ); + void Shoot( Event *ev ); + + virtual void setAngles( Vector ang ); + virtual void Archive( Archiver &arc ); + + friend FuncBeam *CreateBeam( const char *model, const char *shader, Vector start, Vector end, int numsegments = 4, float scale = 1.0f, float life = 1.0f, float damage = 0.0f, Entity *origin_target=NULL ); + }; + +inline void FuncBeam::Archive + ( + Archiver &arc + ) + { + ScriptSlave::Archive( arc ); + arc.ArchiveSafePointer( &end ); + arc.ArchiveSafePointer( &origin_target ); + arc.ArchiveFloat( &damage ); + arc.ArchiveFloat( &life ); + arc.ArchiveVector( &end_point ); + arc.ArchiveBoolean( &use_angles ); + arc.ArchiveFloat( &shootradius ); + arc.ArchiveString( &shader ); + if ( arc.Loading() ) + { + SetBeamShader( shader ); + } + } + +#endif // __BEAM_H__ diff --git a/source/source/fgame/behavior.cpp b/source/source/fgame/behavior.cpp new file mode 100644 index 0000000..50afd96 --- /dev/null +++ b/source/source/fgame/behavior.cpp @@ -0,0 +1,7898 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/behavior.cpp $ +// $Revision:: 144 $ +// $Author:: Aldie $ +// $Date:: 7/30/00 2:21p $ +// +// Copyright (C) 1998 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/behavior.cpp $ +// +// 144 7/30/00 2:21p Aldie +// Fixed a problem in TurnTo allowing it to go forever. +// +// 143 7/29/00 1:25p Steven +// Took out teleport sound effects (are in effects now). +// +// 142 7/28/00 9:18p Steven +// Made a couple more fixes to Teleport. +// +// 141 7/28/00 6:56p Steven +// Added in some teleport effects to TeleportToPosition. +// +// 140 7/28/00 1:23p Steven +// Fixed entities origin while being dragged by the tr'angular and made player +// make lots of pain sounds when being eaten by a sucknblaugh. +// +// 139 7/27/00 10:53p Steven +// Made tr'angular do damage over time and made dropping victim much more +// robust. +// +// 138 7/27/00 10:31a Steven +// Added some effects when the spad body is hit by the ShockWater attack. +// +// 137 7/26/00 6:44p Steven +// Added some more animations to not break out of for talk. +// +// 136 7/24/00 8:35p Steven +// Added another animation not to interrupt. +// +// 135 7/23/00 12:27p Steven +// Changed sucknlaugh to pull entities to its centroid instead of its origin +// and fixed some TeleportToPosition problems. +// +// 134 7/22/00 8:36p Steven +// Made ghosts do a little bit more damage. +// +// 133 7/21/00 3:44p Steven +// Fixed burrowattack stuff, improved teleports a lot, and made anything that +// gets digested extinguish fire. +// +// 132 7/20/00 6:22p Steven +// Made jarts hurt anything that will take damage. +// +// 131 7/19/00 5:08p Steven +// Added electric water means of death. +// +// 130 7/18/00 4:26p Steven +// Modified which anims can not be interrupted by talking stuff a little and +// made flyclimb be able to set the speed. +// +// 129 7/17/00 4:42p Steven +// Added some more animations the talk behavior will not interrupt. +// +// 128 7/17/00 2:55p Steven +// Fixed it so Jart attack sets directio and position correctly so it can be +// blocked and made ghosts attackable longer and let players target them +// during this time. +// +// 127 7/16/00 4:36p Steven +// Added new fire means of death. +// +// 126 7/16/00 2:35p Steven +// Improved camera stuff when watching a talking actor. +// +// 125 7/13/00 7:29p Steven +// Made entity go back to solid again after being released from the +// tr'angular. +// +// 124 7/13/00 3:43p Steven +// Added next_think_time to GetCloseToEnemy for simple path finding. +// +// 123 7/12/00 11:26a Steven +// Added another animation that talk will not get out of, added a +// return_to_original_location bool to investigate, and made ghost stay solid +// longer. +// +// 122 7/11/00 7:08p Steven +// Made ghosts a little bit slower and not do as much damage. +// +// 121 7/11/00 9:12a Steven +// Made it so turnto doesn't rely on movedir being correct. +// +// 120 7/07/00 8:06a Steven +// Improved the investigation behavior to always look towards the noise +// position. +// +// 119 7/05/00 2:27p Steven +// Improved fleeing behavior a lot. +// +// 118 7/02/00 5:56p Steven +// Fixed FlyDive a little if hit something in movement and then it has moved +// out of the way when we try the trace. +// +// 117 7/02/00 5:08p Steven +// Made it so anything in the way when a actor teleports to a specific +// location gets telefragged. +// +// 116 7/02/00 2:45p Steven +// Fixed player getting removed when the sucknblaugh eats her. +// +// 115 7/02/00 1:11p Steven +// Changed TeleportToPosition to use named pathnodes instead of hardcoded +// positions. +// +// 114 6/30/00 3:08p Markd +// fixed rise animation issues +// +// 113 6/30/00 10:45a Markd +// added MOVETYPE_STATIONARY and revamped some physics +// +// 112 6/30/00 10:35a Steven +// Added max_pains to Pain behavior. +// +// 111 6/28/00 4:55p Aldie +// Added a MOD +// +// 110 6/26/00 5:50p Markd +// re-did some renderfx commands, fixed anti-sb juice stuff +// +// 109 6/23/00 4:54p Steven +// Removed a chatter function call. +// +// 108 6/21/00 5:28p Steven +// Improved the Digest behavior (fixed range a little, made gibs look better +// when spit out, and made it chew a little longer). +// +// 107 6/21/00 4:22p Steven +// Took out some chatter stuff from the idle behavior and moved the direction +// to fly in the Circle behavior to the args. +// +// 106 6/15/00 6:55p Steven +// Added moving head while talking stuff. +// +// 105 6/14/00 3:50p Markd +// Cleaned up more Intel Compiler warnings +// +// 104 6/13/00 3:06p Steven +// Fixed a problem in the Shock behavior where a beam was being referenced +// after it had been freed. +// +// 103 6/07/00 5:34p Steven +// Made it so actor would only try to return from investigating for so long, +// added TeleportToPosition and Levitate behaviors. +// +// 102 6/06/00 2:36p Steven +// Made GetCloseToEnemy not be able to use_nearest_node. +// +// 101 6/05/00 3:41p Steven +// Adde GotoDeadEnemy. +// +// 100 6/05/00 12:16p Markd +// fixed sound bug +// +// 99 6/03/00 5:23p Steven +// Made digest behavior spit out gibs instead of the dead creature. +// +// 98 6/01/00 5:47p Steven +// Made ghost attack hit a little easier. +// +// 97 5/27/00 2:31p Steven +// Added FlyCloseToPlayer, added a direction to the shock attack, made the +// actor turn immediately towards the enemy after a teleport, and improved the +// ghost attack a little. +// +// 96 5/24/00 4:08p Steven +// Added a forever variable to the HeadWatch behavior. +// +// 95 5/20/00 4:46p Steven +// Improved the Shock behavior. +// +// 94 5/11/00 11:11a Steven +// Improved the shock attack behaviors a little. +// +// 93 5/06/00 3:00p Steven +// Added speed to FlyCloseToEnemy and fixed actor's getting stuck on top of +// the player. +// +// 92 5/05/00 6:23p Steven +// Made it so fire would not cause constant pain in the pain behavior. +// +// 91 5/05/00 2:14p Steven +// Took out one of the sounds in GhostAttack. +// +// 90 5/04/00 4:13p Steven +// Fixed the BurrowAttack not hitting triggers and hard coded the BurrowAttack +// to start at a certain height to prevent height errors. +// +// 89 5/03/00 12:10p Steven +// Made it so the ghost bounces off shields if blocked. +// +// 88 5/03/00 11:27a Steven +// Added some sounds to the ghost attack and added the spooky ghost attack. +// +// 87 5/02/00 5:14p Steven +// Fixed the ghost attack so that MeleeAttack could tell what direction the +// attack was coming from. +// +// 86 5/02/00 3:14p Steven +// Added player watching actors that talk to her. +// +// 85 4/28/00 5:40p Steven +// Added use_last_known_pos to TurnToEnemy and BurrowAttack and made it so the +// burrowattack could hit solid entities as long as it isn't the world. +// +// 84 4/25/00 6:19p Steven +// Made it so the digest attack wouldn't eat stationary sentients and tweaked +// the range a little. +// +// 83 4/25/00 4:21p Steven +// Fixed the ghost spinning in circles around their attack target. +// +// 82 4/25/00 10:53a Steven +// Fixed a place where the ghost would fade all of the way back in. +// +// 81 4/25/00 10:12a Steven +// Lots of improvements to the GhostAttack behavior. +// +// 80 4/24/00 3:12p Steven +// Added allow fail to chase. +// +// 79 4/20/00 3:37p Steven +// Fixed a bug in HeadWatch, was never getting the current_head_angles +// correctly. +// +// 78 4/20/00 11:34a Steven +// Changed a range in the ShockWater behavior. +// +// 77 4/15/00 5:42p Steven +// Made it so the amount of time the sucknblaugh chews on its victim is +// determined by its weight. +// +// 76 4/15/00 3:39p Steven +// Made it so the pain animation will randomly choose between all available +// pain animations not just the first 2. +// +// 75 4/13/00 5:34p Steven +// Added the Teleport behavior and the GhostAttack behavior. +// +// 74 4/12/00 2:39p Steven +// Fixed TorsoTurn turning in circles forever problem (always trying to catch +// up to target). +// +// 73 4/11/00 4:01p Steven +// Added attack_min_height to MeleeAttack. +// +// 72 4/08/00 3:53p Steven +// Made headwatch snap head back to the forward position if lost the entity we +// were watching or if resetting the head and the behavior is stopped, took +// out the walking in PickupEntity, and set the actors animation to idle after +// done throwing an entity. +// +// 71 4/05/00 6:18p Steven +// Added dirt to where the Vymish Mama's burrow legs come out of the ground. +// +// 70 4/04/00 6:55p Steven +// Made it so HeadWatch doesn't snap to forward at end and if it doesn't have +// an entity to watch moves head back to forward position using max_speed. +// +// 69 4/01/00 2:39p Steven +// Made it so actor can fly clockwise or counter-clockwise in FlyCircle. +// +// 68 4/01/00 2:00p Steven +// Added a forever flag to GetCloseToEnemy. +// +// 67 3/31/00 5:32p Steven +// Made some changes to the Digest behavior so that I could get projectils and +// bullets to bounce off of the Sucknblaugh. +// +// 66 3/31/00 4:58p Steven +// Changed TurnToEnemy so that if actor is really close don't bother turning +// any more. +// +// 65 3/30/00 2:03p Steven +// More work on TorsoTurn. +// +// 64 3/28/00 6:49p Steven +// Lots of improvements to TorsoTurn. +// +// 63 3/24/00 6:33p Steven +// Fixed an animation issue, made lots of optimizations to flying behaviors +// and ChooseRandomDirection. +// +// 62 3/20/00 6:08p Steven +// Made sure GetCloseToEnemy gets animdone events (so actor is informed). +// +// 61 3/17/00 11:49a Steven +// Added jumping stuff. +// +// 60 3/14/00 12:06p Steven +// Added walkwatch stuff. +// +// 59 3/11/00 11:36a Steven +// Moved all actor booleans to 1 actor flags variable and made the stopping +// condition for TurnToEnemy a little better. +// +// 58 3/08/00 6:42p Steven +// Worked on the TorsoTurn behavior some more. +// +// 57 3/07/00 5:23p Steven +// Tweaked BurrowAttack a little to not spawn in so many dirt and water +// effects. +// +// 56 3/07/00 11:51a Steven +// Made lots of tweaks to the CircleEnemy behavior. +// +// 55 3/04/00 11:49a Steven +// Improved the FlyCircle, FlyDive, and FlyClimb behaviors. +// +// 54 3/03/00 5:26p Steven +// Added fast_bullet stuff. +// +// 53 3/02/00 11:02a Steven +// Added some tweaks to the digest behavior. +// +// 52 2/26/00 11:22a Steven +// Added partial immobile flag. +// +// 51 2/24/00 7:07p Steven +// Made talk so it would not stand up if already sitting and made it so the +// actor always tries to face whoever its talking to. +// +// 50 2/24/00 5:26p Steven +// Added a max speed parm to head watch and made sure playanim removes any +// anim done events still around when it ends. +// +// 49 2/23/00 5:19p Steven +// Improved the Wander behavior and improved the ChooseRandomDirection +// function. +// +// 48 2/23/00 11:57a Steven +// Moved utility behaviors to actor and improved BurrowAttack attack. +// +// 47 2/21/00 7:00p Steven +// Added a TorsoTurn behavior. +// +// 46 2/21/00 11:09a Steven +// Fixed some TurnTo issues. +// +// 45 2/17/00 5:42p Steven +// Moved NearestNode stuff out of Investigate to Actor. +// +// 44 2/16/00 6:04p Steven +// Tweaked the investigate behavior a lot. +// +// 43 2/16/00 10:43a Steven +// Added a Pain behavior, made an option for FlyWander to make the actor try +// to fly upwards, and improved the Investigate behavior. +// +// 42 2/11/00 6:41p Steven +// Improved headwatch a little and added pickup/throw. +// +// 41 2/09/00 6:48p Steven +// Made it so an actor would stay in talk mode until the player went far +// enough away. +// +// 40 2/07/00 6:45p Steven +// Made it so the FlyCloseToEnemy behavior doesn't choose a new goal so often. +// +// 39 2/04/00 1:55p Steven +// Added the talk behavior. +// +// 38 2/02/00 1:38p Steven +// Added turning animations to TurnTo, added the HeadWatch behavior, cleaned +// up flying code a little more, and improved the Suicide, DragEnemy, and +// ShockWater behaviors. +// +// 37 1/29/00 5:28p Steven +// Improoved the BurrowAttack and DragEnemy behaviors. +// +// 36 1/27/00 2:53p Steven +// Improved a lot of the flying code. +// +// 35 1/26/00 9:51a Steven +// Added a usefult debug message to GotoPathNode. +// +// 34 1/22/00 12:42p Jimdose +// got rid of calls to vec3() +// +// 33 1/21/00 6:45p Steven +// Made flee use chase instead of FollowPath. +// +// 32 1/19/00 7:08p Steven +// Fixed speed of flying creatures and tweaked BurrowAttack behavior a little. +// +// 31 1/19/00 12:11p Steven +// Fixed AimAndShoot behavior and improved the TurnToEnemy and BurrowAttack +// behaviors. +// +// 30 1/14/00 7:36p Steven +// Improved TurnToEnemy behavior a little. +// +// 29 1/14/00 5:06p Markd +// Removed surface num, tri_num and damage_multiplier from multiple functions +// and events +// +// 28 1/14/00 5:02p Steven +// Added gotonextstage and burrowattack behaviors. +// +// 27 1/13/00 7:07p Steven +// Lots and lots of cleanup. +// +// 26 1/07/00 8:12p Jimdose +// cleaning up unused code +// +// 25 1/06/00 11:08p Jimdose +// cleaning up unused code +// +// 24 1/06/00 6:49p Steven +// Cleaned up GetCloseToEnemy. +// +// 23 1/05/00 7:25p Jimdose +// made angle functions all use the same coordinate system +// AngleVectors now returns left instead of right +// no longer need to invert pitch +// +// 22 1/05/00 6:43p Steven +// Fixed the start and end point being backwards in a trace command. +// +// 21 1/05/00 3:07p Jimdose +// fixed inverted pitch in Aim::Evaluate +// +// 20 12/22/99 5:13p Steven +// Fixed some animation issues, some general clean up, and removed +// FemaleLympAttack. +// +// 19 12/17/99 5:51p Steven +// Made some temporary fixes to aiming behaviors and added the following +// behaviors : TurnTowardsEnemy, FlyCircle, FlyDive, and FlyClimb. +// +// 18 12/01/99 3:43p Steven +// Added a land behavior for flying creatures. +// +// 17 11/24/99 11:05a Steven +// More work on flying. +// +// 16 11/19/99 2:05p Steven +// Took out some unused code. +// +// 15 11/19/99 11:33a Steven +// Added new behaviors: CircleEnemy, ShockWater, Shock, and CircleAttack. +// +// 14 11/12/99 6:24p Steven +// Made state flags available to other part entities. +// +// 13 11/10/99 6:11p Steven +// Added the FlyCloseToEnemy behavior. +// +// 12 10/28/99 6:06p Steven +// Improved the drag behavior. +// +// 11 10/27/99 10:27a Steven +// Added GetNearestEnemy behavior and added more to the DragEnemy behavior. +// +// 10 10/19/99 7:52p Markd +// Removed three part model system +// +// 9 10/19/99 7:10p Steven +// Lots of AI work. +// +// 8 10/11/99 7:50p Steven +// Cleanup. +// +// 7 10/01/99 4:52p Markd +// Made Warning level 4 work on all projects +// +// 6 9/29/99 11:52a Markd +// removed some unused enums and variables form shared headers between cgame +// and fgame +// +// 5 9/28/99 7:24p Steven +// Event formatting. +// +// 4 9/22/99 4:47p Markd +// fixed more G_GetEntity, G_FindClass and G_GetNextEntity bugs +// +// 3 9/21/99 7:51p Markd +// Fixed a lot of entitynum_none issues +// +// 2 9/16/99 11:18a Markd +// Continuing merge of code, not functional yet but closer +// +// 1 9/10/99 10:53a Jimdose +// +// 1 9/08/99 3:15p Aldie +// +// 26 9/02/99 11:33p Jimdose +// fixed bug with sucknblaughs targeting +// +// 25 9/02/99 4:22p Steven +// Changed when sucknblaugh is solid and when it is not and fixed some aiming +// issues in AimAndShoot behavior. +// +// 24 9/01/99 8:16p Steven +// Fixed a typo and setting the anim back to idle after the AimAndShoot +// behavior. +// +// 23 8/31/99 9:21p Steven +// Added fall anim to jump behavior and tweaked digest behavior a little. +// +// 22 8/31/99 2:43p Steven +// Fixed some spin behavior bugs. +// +// 21 8/28/99 7:05p Steven +// Made it so the speed of the spinning for the spinner plant was a parameter. +// +// 20 8/28/99 11:42a Steven +// Added some spinning plant stuff. +// +// 19 8/27/99 5:05p Steven +// Worked on digest behavior, added spin, and optimized some of the movement. +// +// 18 8/24/99 11:25a Steven +// Made it so Sucknblaughs don't eat dead creatures. +// +// 17 8/18/99 3:29p Jimdose +// added cylindrical collision detection +// +// 16 8/18/99 3:22p Steven +// Added to Digest behavior. +// +// 15 8/17/99 4:59p Steven +// New digest behavior for the Sucknblaugh plant. +// +// 14 8/16/99 10:29a Steven +// More general work on AI. +// +// 13 8/11/99 7:24p Steven +// Redid the AimAndShoot behavior temporarily. +// +// 12 8/11/99 5:56p Steven +// More general AI work. +// +// 11 8/06/99 6:39p Aldie +// Started removing concept of currentWeapon +// +// 10 8/05/99 9:14a Steven +// New AI stuff. +// +// 9 7/07/99 11:25a Steven +// Added some stuff on the sector pathfinding approach. +// +// +// DESCRIPTION: +// Behaviors used by the AI. +// + +#include "g_local.h" +#include "behavior.h" +#include "actor.h" +#include "doors.h" +#include "object.h" +#include "explosion.h" +#include "weaputils.h" +#include "player.h" + +Event EV_Behavior_Args + ( + "args", + EV_DEFAULT, + "SSSSSS", + "token1 token2 token3 token4 token5 token6", + "Gives the current behavior arguments." + ); +Event EV_Behavior_AnimDone + ( + "animdone", + EV_DEFAULT, + NULL, + NULL, + "Tells the behavior that the current animation is done, " + "it is not meant to be called from script." + ); + +Vector ChooseRandomDirection( Actor &self, Vector previousdir, float *time, int disallowcontentsmask, qboolean usepitch ); + +/**************************************************************************** + + Behavior Class Definition + +****************************************************************************/ + +CLASS_DECLARATION( Listener, Behavior, NULL ) + { + { NULL, NULL } + }; + +Behavior::Behavior() + { + } + +void Behavior::ShowInfo + ( + Actor &self + ) + + { + if ( movegoal ) + { + gi.Printf( "movegoal: ( %f, %f, %f ) - '%s'\n", + movegoal->origin.x, movegoal->origin.y, movegoal->origin.z, movegoal->targetname.c_str() ); + } + else + { + gi.Printf( "movegoal: NULL\n" ); + } + } + +void Behavior::Begin + ( + Actor &self + ) + + { + } + +qboolean Behavior::Evaluate + ( + Actor &self + ) + + { + return false; + } + +void Behavior::End + ( + Actor &self + ) + + { + } + + + +/**************************************************************************** +***************************************************************************** + + General behaviors + +***************************************************************************** +****************************************************************************/ + + + +/**************************************************************************** + + Idle Class Definition + +****************************************************************************/ + +CLASS_DECLARATION( Behavior, Idle, NULL ) + { + { NULL, NULL } + }; + +void Idle::ShowInfo + ( + Actor &self + ) + + { + Behavior::ShowInfo( self ); + + gi.Printf( "\nnexttwitch : %f\n", nexttwitch ); + } + +void Idle::Begin + ( + Actor &self + ) + + { + nexttwitch = level.time + 10 + G_Random( 30 ); + } + +qboolean Idle::Evaluate + ( + Actor &self + ) + + { + if ( self.currentEnemy ) + { + return true; + } + + if ( nexttwitch < level.time ) + { + self.chattime += 10; + self.AddStateFlag( STATE_FLAG_TWITCH ); + return true; + } + else + { + //self.Chatter( "snd_idle", 1 ); + } + + return true; + } + +void Idle::End + ( + Actor &self + ) + + { + } + +/**************************************************************************** + + Pain Class Definition + +****************************************************************************/ + +CLASS_DECLARATION( Behavior, Pain, NULL ) + { + { &EV_Behavior_AnimDone, AnimDone }, + { NULL, NULL } + }; + +void Pain::SetPainAnim + ( + Actor &self, + int new_pain_type, + int new_anim_number + ) + + { + str anim_name; + + // Determine which pain type to play + + if ( new_pain_type == PAIN_SMALL ) + anim_name = "pain_small"; + else + anim_name = "pain"; + + // Try to find the correct anim to play + + anim_name += new_anim_number; + + if ( !self.HasAnim( anim_name.c_str() ) ) + { + if ( new_pain_type == PAIN_SMALL ) + anim_name = "pain_small1"; + else + anim_name = "pain1"; + + pain_anim_number = 1; + } + + anim_done = false; + + // Play the animation if we can + + if ( !self.HasAnim( anim_name.c_str() ) ) + anim_done = true; + else + self.SetAnim( anim_name.c_str(), EV_Actor_NotifyBehavior ); + } + +int Pain::GetNumberOfPainAnims + ( + Actor &self, + int new_pain_type + ) + + { + str anim_name; + str real_anim_name; + int i; + + + // Determine base animation name + + if ( new_pain_type == PAIN_SMALL ) + anim_name = "pain_small"; + else + anim_name = "pain"; + + // Find how many pain animations we have + + for( i = 1 ; i < 10 ; i++ ) + { + real_anim_name = anim_name + i; + + if ( !self.HasAnim( real_anim_name.c_str() ) ) + return( i - 1 ); + } + + return 9; + } + +void Pain::Begin + ( + Actor &self + ) + + { + str anim_name; + int num_pain_anims; + + num_pain_anims = GetNumberOfPainAnims( self, self.pain_type ); + + pain_anim_number = G_Random( num_pain_anims ) + 1; + + // Figure out which type of pain to do + + if ( self.pain_type == PAIN_SMALL ) + SetPainAnim( self, PAIN_SMALL, pain_anim_number ); + else + SetPainAnim( self, PAIN_BIG, pain_anim_number ); + + current_pain_type = self.pain_type; + number_of_pains = 1; + + // Make sure we don't have pain any more + + self.state_flags &= ~STATE_FLAG_SMALL_PAIN; + self.state_flags &= ~STATE_FLAG_IN_PAIN; + + max_pains = G_Random( 4 ) + 4; + } + +void Pain::AnimDone + ( + Event *ev + ) + { + anim_done = true; + } + +qboolean Pain::Evaluate + ( + Actor &self + ) + + { + str anim_name; + + if ( self.state_flags & STATE_FLAG_SMALL_PAIN ) + { + // See if we should play another pain animation + + if ( self.means_of_death != MOD_FIRE && self.means_of_death != MOD_ON_FIRE && self.means_of_death != MOD_FIRE_BLOCKABLE ) + { + if ( self.pain_type == PAIN_SMALL && current_pain_type == PAIN_SMALL && number_of_pains < max_pains ) + { + pain_anim_number++; + + number_of_pains++; + + SetPainAnim( self, PAIN_SMALL, pain_anim_number ); + } + else if ( self.pain_type == PAIN_BIG ) + { + pain_anim_number++; + + current_pain_type = PAIN_BIG; + + SetPainAnim( self, PAIN_BIG, pain_anim_number ); + } + } + + // Reset pain stuff + + self.state_flags &= ~STATE_FLAG_SMALL_PAIN; + self.state_flags &= ~STATE_FLAG_IN_PAIN; + } + + // If the pain animation has finished, then we are done + + if ( anim_done ) + return false; + + return true; + } + +void Pain::End + ( + Actor &self + ) + + { + self.bullet_hits = 0; + } + +/**************************************************************************** + + Watch Class Definition + +****************************************************************************/ + +CLASS_DECLARATION( Behavior, Watch, NULL ) + { + { &EV_Behavior_Args, SetArgs }, + { NULL, NULL } + }; + +Watch::Watch() + { + turn_speed = 360; + } + +void Watch::SetArgs + ( + Event *ev + ) + + { + turn_speed = ev->GetFloat( 1 ); + } + +void Watch::Begin + ( + Actor &self + ) + + { + ent_to_watch = self.currentEnemy; + + old_turn_speed = self.turnspeed; + self.turnspeed = turn_speed; + seek.Begin( self ); + } + +qboolean Watch::Evaluate + ( + Actor &self + ) + + { + Vector dir; + + if ( !ent_to_watch ) + return false; + + if ( self.IsEntityAlive( ent_to_watch ) ) + { + self.angles.AngleVectors( &dir ); + + seek.SetTargetPosition( ent_to_watch->centroid ); + seek.SetTargetVelocity( vec_zero ); + seek.SetPosition( self.centroid ); + seek.SetDir( dir ); + seek.Evaluate( self ); + + self.Accelerate( seek.steeringforce ); + } + + return true; + } + +void Watch::End + ( + Actor &self + ) + + { + self.turnspeed = old_turn_speed; + seek.End( self ); + } + +/**************************************************************************** + + Turn Class Definition + +****************************************************************************/ + +CLASS_DECLARATION( Behavior, Turn, NULL ) + { + { &EV_Behavior_Args, SetArgs }, + { NULL, NULL } + }; + +Turn::Turn() + { + turn_speed = 5; + } + +void Turn::SetArgs + ( + Event *ev + ) + + { + turn_speed = ev->GetFloat( 1 ); + } + +void Turn::Begin + ( + Actor &self + ) + + { + } + +qboolean Turn::Evaluate + ( + Actor &self + ) + + { + self.angles[YAW] += turn_speed; + + self.setAngles( self.angles ); + + return true; + } + +void Turn::End + ( + Actor &self + ) + + { + } + +/**************************************************************************** + + Aim Class Definition + +****************************************************************************/ + +CLASS_DECLARATION( Behavior, Aim, NULL ) + { + { NULL, NULL } + }; + +void Aim::SetTarget + ( + Entity *ent + ) + + { + target = ent; + } + +void Aim::ShowInfo + ( + Actor &self + ) + + { + Behavior::ShowInfo( self ); + + gi.Printf( "\nseek:\n" ); + seek.ShowInfo( self ); + if ( target ) + { + gi.Printf( "\ntarget : #%d '%s'\n", target->entnum, target->targetname.c_str() ); + } + else + { + gi.Printf( "\ntarget : NULL\n" ); + } + } + +void Aim::Begin + ( + Actor &self + ) + + { + seek.Begin( self ); + } + +qboolean Aim::Evaluate + ( + Actor &self + ) + + { + Vector dir; + Vector ang; + Vector pos; + + if ( !target ) + { + return false; + } + + // + // get my gun pos + // + + // Fixme ? + //pos = self.GunPosition(); + //ang = self.MyGunAngles( pos, false ); + pos = self.centroid; + ang = self.angles; + ang.AngleVectors( &dir, NULL, NULL ); + + seek.SetTargetPosition( target->centroid ); + seek.SetTargetVelocity( target->velocity ); + seek.SetPosition( self.centroid ); + seek.SetDir( dir ); + seek.SetMaxSpeed( 1400 + skill->value * 600 ); + seek.Evaluate( self ); + + // Fixme? + /* if ( ( fabs( seek.steeringforce.y ) > 5 ) && ( self.enemyRange > RANGE_MELEE ) ) + { + seek.steeringforce.y *= 2; + } */ + + self.Accelerate( seek.steeringforce ); + if ( seek.steeringforce.y < 0.25f ) + { + // dead on + return false; + } + + return true; + } + +void Aim::End + ( + Actor &self + ) + + { + seek.End( self ); + } + +/**************************************************************************** + + TurnTo Class Definition + +****************************************************************************/ + +CLASS_DECLARATION( Behavior, TurnTo, NULL ) + { + { &EV_Behavior_AnimDone, AnimDone }, + { NULL, NULL } + }; + +TurnTo::TurnTo() + { + dir = Vector( 1, 0, 0 ); + mode = 0; + ent = NULL; + yaw = 0; + anim_done = true; + } + +void TurnTo::SetDirection + ( + float yaw + ) + + { + Vector ang; + + ang = Vector( 0, yaw, 0 ); + this->yaw = anglemod( yaw ); + ang.AngleVectors( &dir, NULL, NULL ); + dir *= 100; + mode = 1; + } + +void TurnTo::SetTarget + ( + Entity *ent + ) + + { + this->ent = ent; + mode = 2; + } + +void TurnTo::AnimDone + ( + Event *ev + ) + + { + anim_done = true; + } + +void TurnTo::ShowInfo + ( + Actor &self + ) + + { + Behavior::ShowInfo( self ); + + gi.Printf( "\nseek:\n" ); + seek.ShowInfo( self ); + + if ( ent ) + { + gi.Printf( "\nent: #%d '%s'\n", ent->entnum, ent->targetname.c_str() ); + } + else + { + gi.Printf( "\nent: NULL\n" ); + } + + gi.Printf( "dir: ( %f, %f, %f )\n", dir.x, dir.y, dir.z ); + gi.Printf( "yaw: %f\n", yaw ); + gi.Printf( "mode: %d\n", mode ); + } + +void TurnTo::Begin + ( + Actor &self + ) + + { + self.SetAnim( "idle" ); + seek.Begin( self ); + } + +qboolean TurnTo::Evaluate + ( + Actor &self + ) + + { + Vector delta; + float ang; + str anim_name; + Vector forward; + + + switch( mode ) + { + case 1 : + ang = angledist( yaw - self.angles.yaw() ); + if ( fabs( ang ) < 1 ) + { + self.Accelerate( Vector( 0, ang, 0 ) ); + + // If turned all the way wait for animation to finish + + if ( anim_done || self.animname == "idle" ) + return false; + else + return true; + } + + seek.SetTargetPosition( self.origin + dir ); + seek.SetTargetVelocity( vec_zero ); + break; + + case 2 : + if ( !ent ) + { + return false; + } + + delta = ent->origin - self.origin; + yaw = delta.toYaw(); + + seek.SetTargetPosition( ent->origin ); + seek.SetTargetVelocity( vec_zero ); + break; + + default : + return false; + } + + seek.SetPosition( self.origin ); + + self.angles.AngleVectors( &forward ); + seek.SetDir( forward ); + //seek.SetDir( self.movedir ); + + seek.SetMaxSpeed( self.movespeed ); + seek.Evaluate( self ); + + if ( seek.steeringforce[YAW] > 1 ) + { + anim_name = "turn_left"; + anim_done = false; + } + else if ( seek.steeringforce[YAW] < -1 ) + { + anim_name = "turn_right"; + anim_done = false; + } + else if ( anim_done ) + { + anim_name = "idle"; + } + else + { + anim_name = self.animname; + } + + if ( gi.Anim_NumForName( self.edict->s.modelindex, anim_name.c_str() ) != -1 ) + { + if ( anim_name != self.animname ) + self.SetAnim( anim_name.c_str(), EV_Actor_NotifyBehavior ); + } + else + { + anim_done = true; + } + + self.Accelerate( seek.steeringforce ); + + return true; + } + +void TurnTo::End + ( + Actor &self + ) + + { + seek.End( self ); + self.SetAnim( "idle" ); + } + +/**************************************************************************** + + HeadWatch Class Definition + +****************************************************************************/ + +CLASS_DECLARATION( Behavior, HeadWatch, NULL ) + { + { &EV_Behavior_Args, SetArgs }, + { NULL, NULL } + }; + +HeadWatch::HeadWatch() + { + max_speed = 10; + forever = true; + } + +void HeadWatch::SetArgs + ( + Event *ev + ) + + { + ent_to_watch = ev->GetEntity( 1 ); + + if ( ev->NumArgs() > 1 ) + max_speed = ev->GetFloat( 2 ); + + if ( ev->NumArgs() > 2 ) + forever = ev->GetBoolean( 3 ); + } + + +void HeadWatch::ShowInfo + ( + Actor &self + ) + + { + Behavior::ShowInfo( self ); + } + +void HeadWatch::Begin + ( + Actor &self + ) + + { + self.SetControllerTag( ACTOR_HEAD_TAG, gi.Tag_NumForName( self.edict->s.modelindex, "Bip01 Head" ) ); + + current_head_angles = self.GetControllerAngles( ACTOR_HEAD_TAG ); + + self.SetActorFlag( ACTOR_FLAG_TURNING_HEAD, true ); + } + +qboolean HeadWatch::Evaluate + ( + Actor &self + ) + + { + Vector dir; + Vector angles; + int tag_num; + Vector tag_pos; + Vector angles_diff; + Vector watch_position; + Actor *act = NULL; + Vector change; + + if ( ent_to_watch ) + { + tag_num = gi.Tag_NumForName( self.edict->s.modelindex, "Bip01 Head" ); + + if ( tag_num < 0 ) + return false; + + self.GetTag( "Bip01 Head", &tag_pos ); + + if ( ent_to_watch->isSubclassOf( Actor ) ) + act = (Actor *)(Entity *)ent_to_watch; + + if ( act && act->watch_offset != vec_zero ) + { + MatrixTransformVector( act->watch_offset, ent_to_watch->orientation, watch_position ); + watch_position += ent_to_watch->origin; + } + else + { + watch_position = ent_to_watch->centroid; + } + + dir = watch_position - tag_pos; + angles = dir.toAngles(); + + angles_diff = angles - self.angles; + } + else + { + angles_diff = vec_zero; + } + + angles_diff[YAW] = AngleNormalize180( angles_diff[YAW] ); + angles_diff[PITCH] = AngleNormalize180( angles_diff[PITCH] ); + + // Make sure we don't turn neck too far + + if ( angles_diff[YAW] < -80 ) + angles_diff[YAW] = -80; + else if ( angles_diff[YAW] > 80 ) + angles_diff[YAW] = 80; + + if ( angles_diff[PITCH] < -45 ) + angles_diff[PITCH] = -45; + else if ( angles_diff[PITCH] > 45 ) + angles_diff[PITCH] = 45; + + angles_diff[ROLL] = 0; + + // Make sure we don't change our head angles too much at once + + change = angles_diff - current_head_angles; + + if ( change[YAW] > max_speed ) + angles_diff[YAW] = current_head_angles[YAW] + max_speed; + else if ( change[YAW] < -max_speed ) + angles_diff[YAW] = current_head_angles[YAW] - max_speed; + + if ( change[PITCH] > max_speed ) + angles_diff[PITCH] = current_head_angles[PITCH] + max_speed; + else if ( change[PITCH] < -max_speed ) + angles_diff[PITCH] = current_head_angles[PITCH] - max_speed; + + self.SetControllerAngles( ACTOR_HEAD_TAG, angles_diff ); + self.real_head_pitch = angles_diff[PITCH]; + + current_head_angles = angles_diff; + + if ( !ent_to_watch && current_head_angles == vec_zero ) + return false; + + if ( !forever && change[YAW] < max_speed && change[YAW] > -max_speed && change[PITCH] < max_speed && change[PITCH] > -max_speed ) + return false; + + return true; + } + +void HeadWatch::End + ( + Actor &self + ) + + { + // Snap head back into position if we have lost our target or we are doing a resethead + + if ( !ent_to_watch ) + { + self.SetControllerAngles( ACTOR_HEAD_TAG, vec_zero ); + self.real_head_pitch = 0; + } + + self.SetActorFlag( ACTOR_FLAG_TURNING_HEAD, false ); + } + +/**************************************************************************** + + TorsoTurn Class Definition + +****************************************************************************/ + +CLASS_DECLARATION( Behavior, TorsoTurn, NULL ) + { + { &EV_Behavior_Args, SetArgs }, + { NULL, NULL } + }; + +void TorsoTurn::SetArgs + ( + Event *ev + ) + + { + turn_towards_enemy = ev->GetInteger( 1 ); + speed = ev->GetFloat( 2 ); + forever = ev->GetInteger( 3 ); + + if ( ev->NumArgs() > 3 ) + tag_name = ev->GetString( 4 ); + + if ( ev->NumArgs() > 4 ) + tolerance = ev->GetFloat( 5 ); + else + tolerance = 0; + } + + +void TorsoTurn::ShowInfo + ( + Actor &self + ) + + { + Behavior::ShowInfo( self ); + } + +void TorsoTurn::Begin + ( + Actor &self + ) + + { + Vector controller_angles; + + self.SetControllerTag( ACTOR_TORSO_TAG, gi.Tag_NumForName( self.edict->s.modelindex, "Bip01 Spine1" ) ); + + controller_angles = self.GetControllerAngles( ACTOR_TORSO_TAG ); + + current_yaw = controller_angles[YAW]; + current_pitch = controller_angles[PITCH]; + } + +qboolean TorsoTurn::Evaluate + ( + Actor &self + ) + + { + Vector dir; + Vector angles; + int tag_num; + float yaw_diff; + float pitch_diff; + Vector new_angles; + float yaw_change; + float pitch_change; + Vector tag_pos; + Vector tag_forward; + Vector tag_angles; + + + tag_num = gi.Tag_NumForName( self.edict->s.modelindex, "Bip01 Spine1" ); + + if ( tag_num < 0 ) + return false; + + // Determine the angle we want to go to + + if ( turn_towards_enemy ) + { + if ( !self.currentEnemy ) + return false; + + if ( tag_name.length() ) + { + self.GetTag( tag_name.c_str(), &tag_pos, &tag_forward ); + tag_angles = tag_forward.toAngles(); + dir = self.currentEnemy->centroid - tag_pos; + } + else + { + dir = self.currentEnemy->centroid - self.centroid; + } + + angles = dir.toAngles(); + + yaw_diff = AngleNormalize180( angles[YAW] - self.angles[YAW] ); + pitch_diff = AngleNormalize180( angles[PITCH] - self.angles[PITCH] ); + } + else + { + yaw_diff = 0; + pitch_diff = 0; + } + + // Determine the angle change + + yaw_change = AngleNormalize180( yaw_diff - current_yaw ); + pitch_change = AngleNormalize180( pitch_diff - current_pitch ); + + if ( tolerance && yaw_change < tolerance && yaw_change > -tolerance && pitch_change < tolerance && pitch_change > -tolerance ) + { + if ( forever ) + return true; + else + return false; + } + + // Make sure we don't change our torso angles too much at once + + if ( yaw_change > speed ) + yaw_diff = current_yaw + speed; + else if ( yaw_change < -speed ) + yaw_diff = current_yaw - speed; + + if ( pitch_change > speed ) + pitch_diff = current_pitch + speed; + else if ( yaw_change < -speed ) + pitch_diff = current_pitch - speed; + + // Determine our new angles + + new_angles[YAW] = yaw_diff; + new_angles[PITCH] = pitch_diff; + new_angles[ROLL] = 0; + + // Make sure we don't turn too far + + //if ( new_angles[YAW] > 120 || new_angles[YAW] < -120 ) + // return false; + + if ( new_angles[PITCH] > 45 || new_angles[PITCH] < -45 ) + return false; + + // Set our new angles + + self.SetControllerAngles( ACTOR_TORSO_TAG, new_angles ); + + current_yaw = yaw_diff; + current_pitch = pitch_diff; + + // See if we are turned the correct direction now + + if ( !forever && (yaw_change < speed) && (yaw_change > -speed) && (pitch_change < speed) && (pitch_change > -speed) ) + return false; + + return true; + } + +void TorsoTurn::End + ( + Actor &self + ) + + { + } + +/**************************************************************************** + + GotoPathNode Class Definition + +****************************************************************************/ + +CLASS_DECLARATION( Behavior, GotoPathNode, NULL ) + { + { &EV_Behavior_AnimDone, AnimDone }, + { &EV_Behavior_Args, SetArgs }, + { NULL, NULL } + }; + +GotoPathNode::GotoPathNode() + { + usevec = false; + movegoal = NULL; + goal = vec_zero; + goalent = NULL; + } + +void GotoPathNode::SetArgs + ( + Event *ev + ) + + { + anim = ev->GetString( 1 ); + + if ( ev->IsVectorAt( 2 ) ) + { + goal = ev->GetVector( 2 ); + usevec = true; + } + else + { + usevec = false; + movegoal = AI_FindNode( ev->GetString( 2 ) ); + if ( !movegoal ) + { + goalent = ev->GetEntity( 2 ); + } + } + + if ( ev->NumArgs() > 2 ) + entity_to_watch = ev->GetEntity( 3 ); + } + +void GotoPathNode::AnimDone + ( + Event *ev + ) + + { + turnto.ProcessEvent( EV_Behavior_AnimDone ); + } + +void GotoPathNode::SetGoal + ( + PathNode *node + ) + + { + usevec = false; + movegoal = node; + } + +void GotoPathNode::ShowInfo + ( + Actor &self + ) + + { + Behavior::ShowInfo( self ); + + gi.Printf( "\nturnto:\n" ); + turnto.ShowInfo( self ); + + gi.Printf( "\nchase:\n" ); + chase.ShowInfo( self ); + + gi.Printf( "\nstate: %d\n", state ); + gi.Printf( "usevec: %d\n", usevec ); + gi.Printf( "time: %f\n", time ); + gi.Printf( "anim: %s\n", anim.c_str() ); + + if ( goalent ) + { + gi.Printf( "\ngoalent: #%d '%s'\n", goalent->entnum, goalent->targetname.c_str() ); + } + else + { + gi.Printf( "\ngoalent: NULL\n" ); + } + + gi.Printf( "goal: ( %f, %f, %f )\n", goal.x, goal.y, goal.z ); + } + +void GotoPathNode::Begin + ( + Actor &self + ) + + { + Event *ev; + + state = 0; + chase.Begin( self ); + turnto.Begin( self ); + if ( goalent ) + { + chase.SetTarget( goalent ); + } + else if ( movegoal ) + { + chase.SetGoal( movegoal ); + } + else + { + chase.SetGoalPos( goal ); + } + + // don't check for new paths as often + chase.SetPathRate( 4 ); + + chase.AllowFail( true ); + + if ( anim.length() ) + { + self.SetAnim( anim ); + } + + // Setup head watch stuff + + head_watch.Begin( self ); + + ev = new Event( EV_Behavior_Args ); + ev->AddEntity( entity_to_watch ); + head_watch.ProcessEvent( ev ); + } + +qboolean GotoPathNode::Evaluate + ( + Actor &self + ) + + { + float yaw; + + if ( !usevec && !goalent && !movegoal ) + { + gi.DPrintf( "GotoPathNode::No goal\n" ); + return false; + } + + if ( entity_to_watch ) + head_watch.Evaluate( self ); + + switch( state ) + { + case 0 : + if ( chase.Evaluate( self ) ) + { + break; + } + + state = 1; + self.SetAnim( "idle" ); + + // cascade down to case 1 + case 1 : + if ( !movegoal ) + { + return false; + } + + if ( movegoal->setangles ) + { + yaw = movegoal->angles.yaw(); + turnto.SetDirection( yaw ); + if ( turnto.Evaluate( self ) ) + { + break; + } + } + + if ( movegoal->animname == "" ) + { + self.SetAnim( "idle" ); + return false; + } + + self.SetAnim( movegoal->animname, EV_Actor_FinishedBehavior ); + state = 2; + break; + + case 2 : + break; + } + + return true; + } + +void GotoPathNode::End + ( + Actor &self + ) + + { + chase.End( self ); + head_watch.End( self ); + } + +/**************************************************************************** + + Flee Class Definition + +****************************************************************************/ + +CLASS_DECLARATION( Behavior, Flee, NULL ) + { + { &EV_Behavior_Args, SetArgs }, + { NULL, NULL } + }; + +void Flee::SetArgs + ( + Event *ev + ) + + { + anim = ev->GetString( 1 ); + } + +void Flee::ShowInfo + ( + Actor &self + ) + + { + Behavior::ShowInfo( self ); + + gi.Printf( "\nchase:\n" ); + chase.ShowInfo( self ); + } + +void Flee::Begin + ( + Actor &self + ) + + { + if ( anim.length() ) + { + self.SetAnim( anim ); + } + + chase.Begin( self ); + FindFleeNode( self ); + } + +void Flee::FindFleeNode + ( + Actor &self + ) + { + int i; + PathNode *start_node; + pathway_t *path; + PathNode *current_node; + int max_nodes_to_look_at; + int nodes_looked_at; + qboolean found; + + + // Get closest node + + start_node = PathManager.NearestNode( self.origin, &self ); + + // Find a random node that is connected to this node + + found = false; + + if ( start_node ) + { + max_nodes_to_look_at = G_Random( 5 ) + 10; + nodes_looked_at = 0; + current_node = start_node; + + while( !found ) + { + nodes_looked_at++; + + if ( nodes_looked_at >= max_nodes_to_look_at && current_node != start_node ) + { + found = true; + flee_node = current_node; + } + + if ( current_node->numChildren == 0 ) + break; + + path = ¤t_node->Child[ (int)G_Random( current_node->numChildren ) ]; + current_node = AI_GetNode( path->node ); + } + } + + if ( !found ) + { + // If still not found, use old method + + for( i = 0; i < 5; i++ ) + { + flee_node = AI_GetNode( ( int )G_Random( ai_maxnode + 1 ) ); + if ( flee_node ) + break; + } + } + } + +qboolean Flee::Evaluate + ( + Actor &self + ) + + { + // Make sure we have somewhere to flee to + + if ( !flee_node ) + return false; + + chase.SetGoal( flee_node ); + + // Make a racket + + self.Chatter( "snd_panic", 3 ); + + // Try to get to flee node + + if ( !chase.Evaluate( self ) ) + { + // See if we are done fleeing + + if ( !self.currentEnemy || !self.CanSee( self.currentEnemy ) ) + { + return false; + } + + // Find a new spot to flee to + + FindFleeNode( self ); + } + + return true; + } + +void Flee::End + ( + Actor &self + ) + + { + chase.End( self ); + } + +/**************************************************************************** + + PlayAnim Class Definition + +****************************************************************************/ + +CLASS_DECLARATION( Behavior, PlayAnim, NULL ) + { + { &EV_Behavior_Args, SetArgs }, + { NULL, NULL } + }; + +void PlayAnim::SetArgs + ( + Event *ev + ) + + { + anim = ev->GetString( 1 ); + } + +void PlayAnim::ShowInfo + ( + Actor &self + ) + + { + Behavior::ShowInfo( self ); + + gi.Printf( "\nanim: %s\n", anim.c_str() ); + } + +void PlayAnim::Begin + ( + Actor &self + ) + + { + if ( anim.length() ) + { + if ( !self.SetAnim( anim, EV_Actor_FinishedBehavior ) ) + { + self.PostEvent( EV_Actor_FinishedBehavior, 0 ); + } + } + } + +qboolean PlayAnim::Evaluate + ( + Actor &self + ) + + { + return true; + } + +void PlayAnim::End + ( + Actor &self + ) + + { + self.RemoveAnimDoneEvent(); + } + +/**************************************************************************** + + Talk Class Definition + +****************************************************************************/ + +#define TALK_MODE_TURN_TO 0 +#define TALK_MODE_TALK 1 +#define TALK_MODE_WAIT 2 +#define TALK_MODE_TURN_BACK 3 + +CLASS_DECLARATION( Behavior, Talk, NULL ) + { + { &EV_Behavior_AnimDone, AnimDone }, + { NULL, NULL } + }; + +void Talk::SetUser + ( + Sentient *user + ) + + { + ent_listening = user; + } + +void Talk::AnimDone + ( + Event *ev + ) + + { + turnto.ProcessEvent( EV_Behavior_AnimDone ); + } + +void Talk::Begin + ( + Actor &self + ) + + { + Vector dir; + Vector angles; + const char *anim_name; + + + anim_name = self.animname; + + if ( strncmp( anim_name, "sit_leanover", 12 ) == 0 ) + { + move_allowed = false; + } + else if ( strncmp( anim_name, "sit", 3 ) == 0 ) + { + move_allowed = false; + self.SetAnim( "sit_talk" ); + } + else if ( strncmp( anim_name, "talk_sit_stunned", 15 ) == 0 ) + { + move_allowed = false; + } + else if ( strncmp( anim_name, "talk_headset", 12 ) == 0 ) + { + move_allowed = true; + } + else if ( strncmp( anim_name, "stand_hypnotized", 16 ) == 0 ) + { + move_allowed = false; + } + else if ( strncmp( anim_name, "talk_hipnotic", 13 ) == 0 ) + { + move_allowed = false; + } + else if ( strncmp( anim_name, "rope", 4 ) == 0 ) + { + move_allowed = false; + } + else + { + move_allowed = true; + self.SetAnim( "talk" ); + } + + mode = TALK_MODE_TURN_TO; + original_yaw = self.angles[YAW]; + + dir = ent_listening->centroid - self.centroid; + angles = dir.toAngles(); + yaw = angles[YAW]; + } + +qboolean Talk::Evaluate + ( + Actor &self + ) + + { + Vector dir; + Vector angles; + Event *event; + + if ( !ent_listening ) + mode = TALK_MODE_TURN_BACK; + + switch( mode ) + { + case TALK_MODE_TURN_TO : + if ( move_allowed ) + { + turnto.SetDirection( yaw ); + + if ( !turnto.Evaluate( self ) ) + { + mode = TALK_MODE_TALK; + self.PlayDialog( ent_listening ); + + event = new Event( EV_Player_WatchActor ); + event->AddEntity( &self ); + ent_listening->PostEvent( event, 0.05 ); + } + } + else + { + mode = TALK_MODE_TALK; + self.PlayDialog( ent_listening ); + + event = new Event( EV_Player_WatchActor ); + event->AddEntity( &self ); + ent_listening->PostEvent( event, 0.05 ); + } + break; + case TALK_MODE_TALK : + + if ( move_allowed ) + { + dir = ent_listening->centroid - self.centroid; + angles = dir.toAngles(); + turnto.SetDirection( angles[YAW] ); + turnto.Evaluate( self ); + } + + if ( !self.GetActorFlag( ACTOR_FLAG_DIALOG_PLAYING ) ) + { + mode = TALK_MODE_WAIT; + self.state_flags &= ~STATE_FLAG_USED; + + // Tell player to stop watching us + + event = new Event( EV_Player_StopWatchingActor ); + event->AddEntity( &self ); + ent_listening->PostEvent( event, 0 ); + + ent_listening->CancelEventsOfType( EV_Player_WatchActor ); + } + break; + case TALK_MODE_WAIT : + + if ( move_allowed ) + { + dir = ent_listening->centroid - self.centroid; + angles = dir.toAngles(); + turnto.SetDirection( angles[YAW] ); + turnto.Evaluate( self ); + } + + if ( !self.WithinDistance( ent_listening, 100 ) ) + mode = TALK_MODE_TURN_BACK; + + if ( self.state_flags & STATE_FLAG_USED ) + { + mode = TALK_MODE_TURN_TO; + + dir = ent_listening->centroid - self.centroid; + angles = dir.toAngles(); + yaw = angles[YAW]; + + self.state_flags &= ~STATE_FLAG_USED; + + event = new Event( EV_Player_WatchActor ); + event->AddEntity( &self ); + ent_listening->PostEvent( event, 0.05 ); + } + break; + case TALK_MODE_TURN_BACK : + if ( move_allowed ) + { + turnto.SetDirection( original_yaw ); + + if ( !turnto.Evaluate( self ) ) + return false; + } + else + { + return false; + } + + break; + } + + return true; + } + +void Talk::End + ( + Actor &self + ) + + { + Event *event; + + event = new Event( EV_Player_StopWatchingActor ); + event->AddEntity( &self ); + ent_listening->PostEvent( event, 0 ); + + ent_listening->CancelEventsOfType( EV_Player_WatchActor ); + } + +/**************************************************************************** + + FindCover Class Definition + +****************************************************************************/ + +CLASS_DECLARATION( Behavior, FindCover, NULL ) + { + { &EV_Behavior_Args, SetArgs }, + { NULL, NULL } + }; + +void FindCover::SetArgs + ( + Event *ev + ) + + { + anim = ev->GetString( 1 ); + + if ( ev->NumArgs() > 1 ) + crouch_anim = ev->GetString( 2 ); + } + +PathNode *FindCover::FindCoverNode + ( + Actor &self + ) + + { + int i; + PathNode *bestnode; + float bestdist; + PathNode *desperatebestnode; + float desperatebestdist; + PathNode *node; + FindCoverPath find; + Path *path; + Vector delta; + float dist; + Vector pos; + + pos = self.origin; + + // greater than ( 8192 * sqr(2) ) ^ 2 -- maximum squared distance + bestdist = 999999999; + bestnode = NULL; + + // greater than ( 8192 * sqr(2) ) ^ 2 -- maximum squared distance + desperatebestdist = 999999999; + desperatebestnode = NULL; + + for( i = 0; i <= ai_maxnode; i++ ) + { + node = AI_GetNode( i ); + if ( node && ( node->nodeflags & ( AI_DUCK | AI_COVER ) ) && + ( ( node->occupiedTime <= level.time ) || ( node->entnum == self.entnum ) ) ) + { + // get the distance squared (faster than getting real distance) + delta = node->origin - pos; + dist = delta * delta; + if ( ( dist < bestdist ) && ( !self.CanSeeEnemyFrom( node->origin ) ||//) )//|| + ( ( node->nodeflags & AI_DUCK ) && !self.CanSeeEnemyFrom( node->origin - Vector( 0, 0, 32 ) ) ) ) ) + { + bestnode = node; + bestdist = dist; + } + else if ( ( dist < desperatebestdist ) && ( desperatebestdist > ( 64 * 64 ) ) ) + { + desperatebestnode = node; + desperatebestdist = dist; + } + } + } + + if ( !bestnode ) + { + bestnode = desperatebestnode; + } + + if ( bestnode ) + { + find.heuristic.self = &self; + find.heuristic.setSize( self.size ); + find.heuristic.entnum = self.entnum; + + path = find.FindPath( self.origin, bestnode->origin ); + if ( path ) + { + node = path->End(); + + // Mark node as occupied for a short time + node->occupiedTime = level.time + 1.5; + node->entnum = self.entnum; + + chase.SetGoal( node ); + chase.SetPath( path ); + + return node; + } + } + + return NULL; + } + +void FindCover::ShowInfo + ( + Actor &self + ) + + { + Behavior::ShowInfo( self ); + + gi.Printf( "\nchase:\n" ); + chase.ShowInfo( self ); + + gi.Printf( "\nstate: %d\n", state ); + gi.Printf( "anim: %s\n", anim.c_str() ); + gi.Printf( "nextsearch: %f\n", nextsearch ); + } + +void FindCover::Begin + ( + Actor &self + ) + + { + if ( !anim.length() ) + { + anim = "run"; + } + + if ( !crouch_anim.length() ) + { + crouch_anim = "crouch_down"; + } + + movegoal = NULL; + state = 0; + } + +qboolean FindCover::Evaluate + ( + Actor &self + ) + + { + if ( !movegoal ) + { + state = 0; + } + + switch( state ) + { + case 0 : + // Checking for cover + chase.Begin( self ); + movegoal = FindCoverNode( self ); + if ( !movegoal ) + { + // Couldn't find any! + return false; + } + + // Found cover, going to it + if ( anim.length() && ( anim != self.animname || self.newanim.length() ) ) + { + self.SetAnim( anim ); + } + + state = 1; + nextsearch = level.time + 1; + + case 1 : + if ( chase.Evaluate( self ) ) + { + if ( nextsearch < level.time ) + { + state = 0; + } + return true; + } + + // Reached cover + if ( self.CanSeeEnemyFrom( self.origin ) ) + { + state = 0; + } + + if ( movegoal->nodeflags & AI_DUCK ) + { + // ducking + self.SetAnim( crouch_anim.c_str() ); + } + else + { + // standing + self.SetAnim( "idle" ); + } + + chase.End( self ); + return false; + break; + } + + return true; + } + +void FindCover::End + ( + Actor &self + ) + + { + chase.End( self ); + } + +/**************************************************************************** + + FindFlee Class Definition + +****************************************************************************/ + +CLASS_DECLARATION( Behavior, FindFlee, NULL ) + { + { &EV_Behavior_Args, SetArgs }, + { NULL, NULL } + }; + +void FindFlee::SetArgs + ( + Event *ev + ) + + { + anim = ev->GetString( 1 ); + } + +PathNode *FindFlee::FindFleeNode + ( + Actor &self + ) + + { + int i; + PathNode *bestnode; + float bestdist; + PathNode *desperatebestnode; + float desperatebestdist; + PathNode *node; + FindFleePath find; + Path *path; + Vector delta; + float dist; + Vector pos; + + pos = self.origin; + + // greater than ( 8192 * sqr(2) ) ^ 2 -- maximum squared distance + bestdist = 999999999; + bestnode = NULL; + + // greater than ( 8192 * sqr(2) ) ^ 2 -- maximum squared distance + desperatebestdist = 999999999; + desperatebestnode = NULL; + + for( i = 0; i <= ai_maxnode; i++ ) + { + node = AI_GetNode( i ); + if ( node && ( node->nodeflags & AI_FLEE ) && + ( ( node->occupiedTime <= level.time ) || ( node->entnum == self.entnum ) ) ) + { + // get the distance squared (faster than getting real distance) + delta = node->origin - pos; + dist = delta * delta; + if ( ( dist < bestdist ) && !self.CanSeeEnemyFrom( node->origin ) ) + { + bestnode = node; + bestdist = dist; + } + else if ( ( dist < desperatebestdist ) && ( desperatebestdist > ( 64 * 64 ) ) ) + { + desperatebestnode = node; + desperatebestdist = dist; + } + } + } + + if ( !bestnode ) + { + bestnode = desperatebestnode; + } + + if ( bestnode ) + { + find.heuristic.self = &self; + find.heuristic.setSize( self.size ); + find.heuristic.entnum = self.entnum; + + path = find.FindPath( self.origin, bestnode->origin ); + if ( path ) + { + node = path->End(); + + // Mark node as occupied for a short time + node->occupiedTime = level.time + 1.5; + node->entnum = self.entnum; + + chase.SetGoal( node ); + chase.SetPath( path ); + + return node; + } + } + + return NULL; + } + +void FindFlee::ShowInfo + ( + Actor &self + ) + + { + Behavior::ShowInfo( self ); + + gi.Printf( "\nchase:\n" ); + chase.ShowInfo( self ); + + gi.Printf( "\nstate: %d\n", state ); + gi.Printf( "anim: %s\n", anim.c_str() ); + gi.Printf( "nextsearch: %f\n", nextsearch ); + } + +void FindFlee::Begin + ( + Actor &self + ) + + { + if ( !anim.length() ) + { + anim = "run"; + } + + movegoal = NULL; + state = 0; + } + +qboolean FindFlee::Evaluate + ( + Actor &self + ) + + { + if ( !movegoal ) + { + state = 0; + } + + switch( state ) + { + case 0 : + // Checking for flee node + chase.Begin( self ); + movegoal = FindFleeNode( self ); + if ( !movegoal ) + { + // Couldn't find any! + return false; + } + + // Found flee node, going to it + if ( anim.length() && ( anim != self.animname || self.newanim.length() ) ) + { + self.SetAnim( anim ); + } + + state = 1; + nextsearch = level.time + 1; + + case 1 : + if ( chase.Evaluate( self ) ) + { + if ( nextsearch < level.time ) + { + state = 0; + } + return true; + } + + // Reached cover + if ( self.CanSeeEnemyFrom( self.origin ) ) + { + state = 0; + } + else + { + // standing + self.SetAnim( "idle" ); + chase.End( self ); + return false; + } + break; + } + + return true; + } + +void FindFlee::End + ( + Actor &self + ) + + { + chase.End( self ); + } + +/**************************************************************************** + + FindEnemy Class Definition + +****************************************************************************/ + +CLASS_DECLARATION( Behavior, FindEnemy, NULL ) + { + { &EV_Behavior_Args, SetArgs }, + { NULL, NULL } + }; + +void FindEnemy::SetArgs + ( + Event *ev + ) + + { + anim = ev->GetString( 1 ); + } + +void FindEnemy::ShowInfo + ( + Actor &self + ) + + { + Behavior::ShowInfo( self ); + + gi.Printf( "\nchase:\n" ); + chase.ShowInfo( self ); + + gi.Printf( "\nstate: %d\n", state ); + gi.Printf( "nextsearch: %f\n", nextsearch ); + gi.Printf( "anim: %s\n", anim.c_str() ); + } + +void FindEnemy::Begin + ( + Actor &self + ) + + { + if ( !anim.length() ) + { + anim = "run"; + } + + movegoal = NULL; + lastSearchNode = NULL; + state = 0; + } + +PathNode *FindEnemy::FindClosestSightNode + ( + Actor &self + ) + + { + int i; + PathNode *bestnode; + float bestdist; + PathNode *node; + Vector delta; + float dist; + Vector pos; + + if ( self.currentEnemy ) + { + pos = self.currentEnemy->origin; + } + else + { + pos = self.origin; + } + + // greater than ( 8192 * sqr(2) ) ^ 2 -- maximum squared distance + bestdist = 999999999; + bestnode = NULL; + + for( i = 0; i <= ai_maxnode; i++ ) + { + node = AI_GetNode( i ); + if ( node && ( ( node->occupiedTime <= level.time ) || ( node->entnum != self.entnum ) ) ) + { + // get the distance squared (faster than getting real distance) + delta = node->origin - pos; + dist = delta * delta; + if ( ( dist < bestdist ) && self.CanSeeFrom( node->origin, self.currentEnemy ) ) + { + bestnode = node; + bestdist = dist; + } + } + } + + return bestnode; + } + +qboolean FindEnemy::Evaluate + ( + Actor &self + ) + + { + if ( !self.currentEnemy ) + { + return false; + } + + if ( nextsearch < level.time ) + { + // check if we should search for the first time + if ( !lastSearchNode ) + { + state = 0; + } + else + { + // search less often if we're far away + nextsearch = self.DistanceTo( self.currentEnemy ) * ( 1.0 / 512.0 ); + if ( nextsearch < 1 ) + { + nextsearch = 1; + } + nextsearch += level.time; + + // don't search again if our enemy hasn't moved very far + if ( !self.currentEnemy->WithinDistance( lastSearchPos, 256 ) ) + { + state = 0; + } + } + } + + switch( state ) + { + case 0 : + // Searching for enemy + chase.Begin( self ); + lastSearchPos = self.currentEnemy->origin; + movegoal = PathManager.NearestNode( lastSearchPos, &self ); + if ( !movegoal ) + { + movegoal = PathManager.NearestNode( lastSearchPos, &self, false ); + } + + lastSearchNode = movegoal; + if ( movegoal ) + { + Path *path; + FindEnemyPath find; + PathNode *from; + + find.heuristic.self = &self; + find.heuristic.setSize( self.size ); + find.heuristic.entnum = self.entnum; + + from = PathManager.NearestNode( self.origin, &self ); + if ( ( from == movegoal ) && ( self.DistanceTo( from->origin ) < 8 ) ) + { + movegoal = NULL; + from = NULL; + } + + if ( from ) + { + path = find.FindPath( from, movegoal ); + if ( path ) + { + chase.SetGoal( movegoal ); + chase.SetPath( path ); + } + else + { + movegoal = NULL; + } + } + } + + if ( !movegoal ) + { + if ( self.CanSee( self.currentEnemy ) || ( !self.currentEnemy->groundentity && !self.waterlevel ) ) + { + chase.SetGoalPos( self.currentEnemy->origin ); + } + else + { + // Couldn't find enemy + // since we can't reach em + // clear out enemy state + self.ClearEnemies(); + return false; + } + } + + // Found enemy, going to it + if ( anim.length() && ( anim != self.animname || self.newanim.length() ) ) + { + self.SetAnim( anim ); + } + + state = 1; + + case 1 : + if ( self.CanShoot( self.currentEnemy, false ) ) + { + // Reached enemy + chase.End( self ); + return false; + } + + if ( !chase.Evaluate( self ) ) + { + state = 0; + nextsearch = 0; + } + break; + } + + return true; + } + +void FindEnemy::End + ( + Actor &self + ) + + { + chase.End( self ); + } + +/**************************************************************************** + + AimAndShoot Class Definition + +****************************************************************************/ + +CLASS_DECLARATION( Behavior, AimAndShoot, NULL ) + { + { &EV_Behavior_Args, SetArgs }, + { &EV_Behavior_AnimDone, AnimDone }, + { NULL, NULL } + }; + +AimAndShoot::AimAndShoot() + { + maxshots = 1; + numshots = 0; + } + +void AimAndShoot::ShowInfo + ( + Actor &self + ) + + { + Behavior::ShowInfo( self ); + + gi.Printf( "\naim:\n" ); + aim.ShowInfo( self ); + + gi.Printf( "\nmode: %d\n", mode ); + gi.Printf( "maxshots: %d\n", maxshots ); + gi.Printf( "numshots: %d\n", numshots ); + gi.Printf( "animdone: %d\n", animdone ); + } + +void AimAndShoot::Begin + ( + Actor &self + ) + + { + enemy_health = 0; + animdone = false; + + if ( aimanim.length() ) + { + self.SetAnim( aimanim.c_str() ); + mode = 0; + } + else + { + self.SetAnim( "idle" ); + mode = 1; + } + } + +void AimAndShoot::SetMaxShots + ( + int num + ) + + { + maxshots = (num>>1) + G_Random( num ); + } + +void AimAndShoot::SetArgs + ( + Event *ev + ) + + { + fireanim = ev->GetString( 1 ); + + if ( ev->NumArgs() > 1 ) + { + maxshots = ev->GetInteger ( 2 ); + } + + if ( ev->NumArgs() > 2 ) + { + aimanim = ev->GetString ( 3 ); + } + } + +void AimAndShoot::AnimDone + ( + Event *ev + ) + + { + animdone = true; + } + +qboolean AimAndShoot::Evaluate + ( + Actor &self + ) + + { + Vector dir; + Vector angles; + + switch( mode ) + { + case 0 : + if ( !self.currentEnemy ) + { + return false; + } + + if ( !self.CanShoot( self.currentEnemy, false ) ) + { + return false; + } + + // start Aiming + animdone = false; + if ( aimanim.length() ) + { + self.SetAnim( aimanim.c_str() ); + } + + // + // save off time, in case we aim for too long + // + aim_time = level.time + 1; + mode = 1; + + case 1 : + // Aiming + if ( aimanim.length() ) + { + if ( !self.currentEnemy ) + { + return false; + } + + // see if we aimed for too long + if ( aim_time < level.time ) + { + return false; + } + + aim.SetTarget( self.currentEnemy ); + + if ( aim.Evaluate( self ) ) + { + break; + } + } + else + { + if ( self.IsEntityAlive( self.currentEnemy ) ) + { + dir = self.currentEnemy->centroid - self.origin; + angles = dir.toAngles(); + + self.angles[YAW] = angles[YAW]; + self.setAngles( self.angles ); + } + } + + // don't go into our firing animation until our weapon is ready, and we are on target + if ( self.currentEnemy && self.CanShoot( self.currentEnemy, true ) ) + { + animdone = false; + self.Chatter( "snd_inmysights", 5 ); + self.SetAnim( fireanim.c_str(), EV_Actor_NotifyBehavior ); + enemy_health = self.currentEnemy->health; + mode = 2; + } + else if ( !self.currentEnemy || self.currentEnemy->deadflag || + ( self.currentEnemy->health <= 0 ) || !self.CanShoot( self.currentEnemy, false ) ) + { + // either our enemy is dead, or we can't shoot the enemy from here + return false; + } + break; + + case 2 : + // Fire + if ( animdone ) + { + aim.SetTarget( self.currentEnemy ); + aim.Evaluate( self ); + + self.times_done++; + + if ( !self.currentEnemy || ( self.currentEnemy->health < enemy_health ) ) + { + self.Chatter( "snd_attacktaunt", 4 ); + } + else + { + self.Chatter( "snd_missed", 7 ); + } + + animdone = false; + numshots++; + + if ( ( numshots >= maxshots ) || !self.currentEnemy || self.currentEnemy->deadflag || + ( self.currentEnemy->health <= 0 ) || !self.CanShoot( self.currentEnemy, false ) ) + { + // either we're out of shots, our enemy is dead, or we can't shoot the enemy from here + + return false; + } + else if ( !self.CanShoot( self.currentEnemy, false ) ) + { + // weapon not ready or not aimed at enemy, so just keep trying to get enemy in our sights + if ( aimanim.length() ) + { + self.SetAnim( aimanim.c_str() ); + } + // + // save off time, in case we aim for too long + // + aim_time = level.time + 1; + mode = 1; + } + else + { + // keep firing + self.SetAnim( fireanim.c_str(), EV_Actor_NotifyBehavior ); + enemy_health = self.currentEnemy->health; + } + } + break; + } + + return true; + } + +void AimAndShoot::End + ( + Actor &self + ) + + { + aim.End( self ); + //self.SetAnim( "idle" ); + } + +/**************************************************************************** + + AimAndMelee Class Definition + +****************************************************************************/ + +CLASS_DECLARATION( Behavior, AimAndMelee, NULL ) + { + { &EV_Behavior_Args, SetArgs }, + { &EV_Behavior_AnimDone, AnimDone }, + { NULL, NULL } + }; + +AimAndMelee::AimAndMelee() + { + maxshots = 1; + anim_name = "melee"; + } + +void AimAndMelee::ShowInfo + ( + Actor &self + ) + + { + Behavior::ShowInfo( self ); + + gi.Printf( "\naim:\n" ); + aim.ShowInfo( self ); + + gi.Printf( "\nmode: %d\n", mode ); + gi.Printf( "maxshots: %d\n", maxshots ); + gi.Printf( "numshots: %d\n", numshots ); + gi.Printf( "animdone: %d\n", animdone ); + } + +void AimAndMelee::Begin + ( + Actor &self + ) + + { + mode = 0; + numshots = 0; + animdone = false; + + self.SetAnim( "idle" ); + } + +void AimAndMelee::SetArgs + ( + Event *ev + ) + + { + anim_name = ev->GetString( 1 ); + + if ( ev->NumArgs() > 1 ) + { + maxshots = ev->GetInteger( 2 ); + } + } + +void AimAndMelee::AnimDone + ( + Event *ev + ) + + { + animdone = true; + } + +qboolean AimAndMelee::Evaluate + ( + Actor &self + ) + + { + Vector dir; + + switch( mode ) + { + case 0 : + if ( !self.currentEnemy ) + { + return false; + } + + if ( self.IsEntityAlive( self.currentEnemy ) ) + { + dir = self.currentEnemy->centroid - self.origin; + self.angles[YAW] = dir.toYaw(); + self.setAngles( self.angles ); + } + + numshots++; + animdone = false; + + // melee + self.SetAnim( anim_name.c_str() , EV_Actor_NotifyBehavior ); + self.Chatter( "snd_attacktaunt", 4 ); + mode = 1; + + case 1 : + // finish up the attack + if ( animdone ) + { + self.times_done++; + if ( numshots >= maxshots ) + { + return false; + } + + mode = 0; + } + break; + } + + return true; + } + +void AimAndMelee::End + ( + Actor &self + ) + + { + aim.End( self ); + } + +/**************************************************************************** + + JumpToPathNode Class Definition + +****************************************************************************/ + +CLASS_DECLARATION( Behavior, JumpToPathNode, NULL ) + { + { &EV_Behavior_Args, SetArgs }, + { NULL, NULL } + }; + +void JumpToPathNode::SetArgs + ( + Event *ev + ) + { + Entity *ent; + + + movegoal = AI_FindNode( ev->GetString( 1 ) ); + + if ( movegoal ) + jump.SetGoal( movegoal->targetname ); + else + { + ent = ev->GetEntity( 1 ); + + if ( ent ) + jump.SetEntity( ent ); + } + + if ( ev->NumArgs() > 1 ) + jump.SetSpeed( ev->GetFloat( 2 ) ); + else + jump.SetSpeed( 200 ); + } + +void JumpToPathNode::Begin + ( + Actor &self + ) + + { + jump.Begin( self ); + } + +qboolean JumpToPathNode::Evaluate + ( + Actor &self + ) + + { + return jump.Evaluate( self ); + } + +void JumpToPathNode::End + ( + Actor &self + ) + + { + jump.End( self ); + } + +/**************************************************************************** + + FlyToPoint Class Definition + +****************************************************************************/ + + +CLASS_DECLARATION( Behavior, FlyToPoint, NULL ) + { + { NULL, NULL } + }; + +FlyToPoint::FlyToPoint() + { + turn_speed = 10.0; + speed = 480.0; + random_allowed = true; + force_goal = false; + } + +void FlyToPoint::SetTurnSpeed( float new_turn_speed ) + { + turn_speed = new_turn_speed; + } + +void FlyToPoint::SetGoalPoint( Vector goal_point ) + { + if ( goal_point != goal ) + avoidtime = 0; + + goal = goal_point; + } + +void FlyToPoint::SetRandomAllowed( qboolean allowed ) + { + random_allowed = allowed; + } + +void FlyToPoint::SetSpeed( float speed_value ) + { + speed = speed_value; + } + +void FlyToPoint::ForceGoal( void ) + { + force_goal = true; + } + +void FlyToPoint::ShowInfo + ( + Actor &self + ) + + { + Behavior::ShowInfo( self ); + } + +void FlyToPoint::Begin + ( + Actor &self + ) + + { + avoidtime = 0; + old_forward_speed = self.forwardspeed; + stuck = 0; + use_temp_goal = false; + } + +qboolean FlyToPoint::Evaluate + ( + Actor &self + ) + + { + trace_t trace; + Vector dir; + Vector ang; + float time; + float length; + float old_yaw; + float old_pitch; + + if ( self.lastmove != STEPMOVE_OK ) + stuck++; + else + stuck = 0; + + if ( stuck > 2 || ( avoidtime <= level.time ) ) + { + time = G_Random( .3 ) + .3; + + use_temp_goal = false; + + if ( !force_goal ) + { + trace = G_Trace( self.origin, self.mins, self.maxs, goal, &self, self.edict->clipmask, false, "FlyToPoint" ); + + if ( trace.fraction < 0.5f || stuck > 2 ) + { + temp_goal = ChooseRandomDirection( self, goal, &time, MASK_WATER, true ); + use_temp_goal = true; + avoidtime = level.time + time; + + stuck = 0; + } + else + { + goal = trace.endpos; + avoidtime = level.time + time; + } + } + else + { + avoidtime = level.time + time; + } + + if ( use_temp_goal ) + dir = temp_goal - self.origin; + else + dir = goal - self.origin; + + length = dir.length(); + dir.normalize(); + ang = dir.toAngles(); + + if ( length > 150 && random_allowed && !use_temp_goal ) + { + ang[YAW] += G_Random( 20 ) - 10.0; + ang[PITCH] += G_Random( 20 ) - 10.0; + } + + target_angle = ang; + + target_angle[YAW] = AngleNormalize360( target_angle[YAW] ); + target_angle[PITCH] = AngleNormalize360( target_angle[PITCH] ); + } + + if ( (self.angles[YAW] != target_angle[YAW]) || (self.angles[PITCH] != target_angle[PITCH]) ) + { + self.forwardspeed = speed * 0.8f; + } + else + { + self.forwardspeed = speed; + } + + old_yaw = self.angles[YAW]; + old_pitch = self.angles[PITCH]; + + ang[YAW] = LerpAngle( self.angles[YAW], target_angle[YAW], turn_speed ); + ang[PITCH] = LerpAngle( self.angles[PITCH], target_angle[PITCH], turn_speed ); + ang[ROLL] = self.angles[ROLL]; + + if ( (AngleDelta( ang[YAW], old_yaw ) > 0) && (ang[ROLL] > 315 || ang[ROLL] <= 45) ) + { + ang[ROLL] -= 5; + } + else if ( (AngleDelta( ang[YAW], old_yaw ) < 0) && (ang[ROLL] < 45 || ang[ROLL] >= 315) ) + { + ang[ROLL] += 5; + } + else if ( AngleDelta( ang[YAW], old_yaw ) == 0 ) + { + if ( ang[ROLL] != 0 ) + { + if ( ang[ROLL] < 180 ) + ang[ROLL] -= 5; + else + ang[ROLL] += 5; + } + } + + ang[YAW] = AngleNormalize360( ang[YAW] ); + ang[PITCH] = AngleNormalize360( ang[PITCH] ); + ang[ROLL] = AngleNormalize360( ang[ROLL] ); + + // Don't get stuck if still turning + + if ( ( AngleDelta( ang[YAW], old_yaw ) > .5 ) || ( AngleDelta( ang[YAW], old_yaw ) < -.5 ) || + ( AngleDelta( ang[PITCH], old_pitch ) > .5 ) || ( AngleDelta( ang[PITCH], old_pitch ) < -.5 ) ) + { + stuck = 0; + } + + self.setAngles( ang ); + + return true; + } + +float FlyToPoint::LerpAngle( float old_angle, float new_angle, float lerp_amount ) + { + float diff; + float abs_diff; + float lerp_angle; + + new_angle = AngleNormalize360( new_angle ); + old_angle = AngleNormalize360( old_angle ); + + diff = new_angle - old_angle; + + if ( diff > 180 ) + { + diff -= 360; + } + + if ( diff < -180 ) + { + diff += 360; + } + + lerp_angle = old_angle; + + abs_diff = diff; + + if ( abs_diff < 0 ) + { + abs_diff = -abs_diff; + } + + if ( abs_diff < lerp_amount ) + { + lerp_amount = abs_diff; + } + + if ( diff < 0 ) + { + lerp_angle -= lerp_amount; + } + else if ( diff > 0 ) + { + lerp_angle += lerp_amount; + } + + lerp_angle = AngleNormalize360( lerp_angle ); + + return lerp_angle; + } + +void FlyToPoint::End + ( + Actor &self + ) + + { + self.forwardspeed = old_forward_speed; + } + +/**************************************************************************** + + FlyCloseToEnemy Class Definition + +****************************************************************************/ + + +CLASS_DECLARATION( Behavior, FlyCloseToEnemy, NULL ) + { + { &EV_Behavior_Args, SetArgs }, + { NULL, NULL } + }; + +FlyCloseToEnemy::FlyCloseToEnemy() + { + speed = 0; + turn_speed = 10.0; + anim = "fly"; + } + +void FlyCloseToEnemy::SetArgs + ( + Event *ev + ) + + { + anim = ev->GetString( 1 ); + + if ( ev->NumArgs() > 1 ) + turn_speed = ev->GetFloat( 2 ); + + if ( ev->NumArgs() > 2 ) + speed = ev->GetFloat( 3 ); + } + +void FlyCloseToEnemy::ShowInfo + ( + Actor &self + ) + + { + Behavior::ShowInfo( self ); + } + +void FlyCloseToEnemy::Begin + ( + Actor &self + ) + + { + if ( anim.length() ) + { + self.SetAnim( anim ); + } + + fly.Begin( self ); + fly.SetTurnSpeed( turn_speed ); + + if ( speed ) + fly.SetSpeed( speed ); + + next_goal_time = 0; + } + +qboolean FlyCloseToEnemy::Evaluate + ( + Actor &self + ) + + { + Vector goal; + + + if ( !self.IsEntityAlive( self.currentEnemy ) ) + return false; + + if ( next_goal_time <= level.time ) + { + goal = self.currentEnemy->centroid; + + goal[0] += G_Random( 30 ) - 15.0; + goal[1] += G_Random( 30 ) - 15.0; + goal[2] += G_Random( 60 ) - 30.0; + + fly.SetGoalPoint( goal ); + + next_goal_time = level.time + .5; + } + + fly.Evaluate( self ); + + return true; + } + +void FlyCloseToEnemy::End + ( + Actor &self + ) + + { + fly.End( self ); + } + +/**************************************************************************** + + FlyCloseToPlayer Class Definition + +****************************************************************************/ + + +CLASS_DECLARATION( Behavior, FlyCloseToPlayer, NULL ) + { + { &EV_Behavior_Args, SetArgs }, + { NULL, NULL } + }; + +FlyCloseToPlayer::FlyCloseToPlayer() + { + speed = 0; + turn_speed = 10.0; + anim = "fly"; + } + +void FlyCloseToPlayer::SetArgs + ( + Event *ev + ) + + { + anim = ev->GetString( 1 ); + + if ( ev->NumArgs() > 1 ) + turn_speed = ev->GetFloat( 2 ); + + if ( ev->NumArgs() > 2 ) + speed = ev->GetFloat( 3 ); + } + +void FlyCloseToPlayer::ShowInfo + ( + Actor &self + ) + + { + Behavior::ShowInfo( self ); + } + +void FlyCloseToPlayer::Begin + ( + Actor &self + ) + + { + if ( anim.length() ) + { + self.SetAnim( anim ); + } + + fly.Begin( self ); + fly.SetTurnSpeed( turn_speed ); + + if ( speed ) + fly.SetSpeed( speed ); + + next_goal_time = 0; + } + +qboolean FlyCloseToPlayer::Evaluate + ( + Actor &self + ) + + { + Vector goal; + Entity *player; + + + player = g_entities[ 0 ].entity; + + + if ( !self.IsEntityAlive( player ) ) + return false; + + if ( next_goal_time <= level.time ) + { + goal = player->centroid; + + goal[0] += G_Random( 30 ) - 15.0; + goal[1] += G_Random( 30 ) - 15.0; + goal[2] += G_Random( 60 ) - 30.0; + + fly.SetGoalPoint( goal ); + + next_goal_time = level.time + .5; + } + + fly.Evaluate( self ); + + return true; + } + +void FlyCloseToPlayer::End + ( + Actor &self + ) + + { + fly.End( self ); + } + +/**************************************************************************** + + FlyWander Class Definition + +****************************************************************************/ + + +CLASS_DECLARATION( Behavior, FlyWander, NULL ) + { + { &EV_Behavior_Args, SetArgs }, + { NULL, NULL } + }; + +FlyWander::FlyWander() + { + turn_speed = 10.0; + anim = "fly"; + change_course_time = 5.0; + speed = 200; + try_to_go_up = false; + } + +void FlyWander::SetArgs + ( + Event *ev + ) + + { + anim = ev->GetString( 1 ); + + if ( ev->NumArgs() > 1 ) + { + speed = ev->GetFloat( 2 ); + } + + if ( ev->NumArgs() > 2 ) + { + turn_speed = ev->GetFloat( 3 ); + } + + if ( ev->NumArgs() > 3 ) + { + change_course_time = ev->GetFloat( 4 ); + } + + if ( ev->NumArgs() > 4 ) + { + try_to_go_up = ev->GetFloat( 5 ); + } + } + +void FlyWander::ShowInfo + ( + Actor &self + ) + + { + Behavior::ShowInfo( self ); + } + +void FlyWander::Begin + ( + Actor &self + ) + + { + next_change_course_time = 0; + + original_z = self.origin.z; + + if ( anim.length() ) + self.SetAnim( anim ); + + fly.Begin( self ); + fly.SetTurnSpeed( turn_speed ); + fly.SetSpeed( speed ); + } + +qboolean FlyWander::Evaluate + ( + Actor &self + ) + + { + trace_t trace; + Vector dir; + float length; + int goal_try; + Vector temp_goal; + float max_dist = 0; + + + dir = goal - self.origin; + length = dir.length(); + + if ( next_change_course_time <= level.time || length < 100 ) //self.lastmove != STEPMOVE_OK ) + { + for( goal_try = 0 ; goal_try < 5 ; goal_try++ ) + { + temp_goal = self.origin; + + temp_goal[0] += G_Random( 10000 ) - 5000.0; + temp_goal[1] += G_Random( 10000 ) - 5000.0; + + if ( try_to_go_up ) + temp_goal[2] += G_Random( 1000 ) - 250.0; + else + temp_goal[2] += G_Random( 100 ) - 50.0; + + trace = G_Trace( self.origin, self.mins, self.maxs, temp_goal, &self, self.edict->clipmask, false, "FlyWander" ); + + temp_goal = trace.endpos; + + dir = temp_goal - self.origin; + length = dir.length(); + + if ( length > max_dist ) + { + max_dist = length; + goal = temp_goal; + + if ( length > 1000 ) + break; + } + } + + fly.SetGoalPoint( goal ); + + next_change_course_time = level.time + change_course_time; + } + + fly.Evaluate( self ); + + return true; + } + +void FlyWander::End + ( + Actor &self + ) + + { + fly.End( self ); + } + +/**************************************************************************** + + FlyCircle Class Definition + +****************************************************************************/ + + +CLASS_DECLARATION( Behavior, FlyCircle, NULL ) + { + { &EV_Behavior_Args, SetArgs }, + { NULL, NULL } + }; + +FlyCircle::FlyCircle() + { + anim = "fly"; + } + +void FlyCircle::SetArgs + ( + Event *ev + ) + + { + anim = ev->GetString( 1 ); + + fly_clockwise = ev->GetBoolean( 2 ); + } + +void FlyCircle::ShowInfo + ( + Actor &self + ) + + { + Behavior::ShowInfo( self ); + } + +void FlyCircle::Begin + ( + Actor &self + ) + + { + original_z = self.origin.z; + + if ( anim.length() ) + { + self.SetAnim( anim ); + } + + fly.Begin( self ); + fly.SetTurnSpeed( 5.0 ); + } + +qboolean FlyCircle::Evaluate + ( + Actor &self + ) + + { + Vector goal; + trace_t trace; + Vector dir; + Vector angle; + Vector left; + qboolean too_far = false; + Vector new_dir; + Vector fly_dir; + + if ( !self.IsEntityAlive( self.currentEnemy ) ) + { + return false; + } + + if ( self.lastmove == STEPMOVE_OK ) + { + fly.SetTurnSpeed( 5.0 ); + + dir = self.currentEnemy->centroid - self.origin; + dir.z = 0; + + if ( dir.length() > (self.origin.z - self.currentEnemy->centroid.z) / 2 ) + { + too_far = true; + } + + angle = dir.toAngles(); + + angle.AngleVectors( NULL, &left, NULL ); + + if ( fly_clockwise ) + fly_dir = left; + else + fly_dir = left * -1; + + dir.normalize(); + + if ( too_far ) + { + new_dir = fly_dir * 0.5 + dir * 0.5; + new_dir.normalize(); + } + else + { + new_dir = fly_dir; + } + + goal = self.origin + new_dir * 200; + + trace = G_Trace( self.origin, self.mins, self.maxs, goal, &self, self.edict->clipmask, false, "FlyCircle" ); + + if ( trace.fraction < 1 ) + { + if ( too_far ) + trace.fraction /= 2; + + new_dir = fly_dir * trace.fraction + dir * (1 - trace.fraction); + new_dir.normalize(); + + goal = self.origin + new_dir * 200; + } + else + { + goal = trace.endpos; + } + + fly.SetGoalPoint( goal ); + } + else + { + fly.SetTurnSpeed( 20.0 ); + } + + fly.Evaluate( self ); + + return true; + } + +void FlyCircle::End + ( + Actor &self + ) + + { + fly.End( self ); + } + +/**************************************************************************** + + FlyDive Class Definition + +****************************************************************************/ + + +CLASS_DECLARATION( Behavior, FlyDive, NULL ) + { + { &EV_Behavior_Args, SetArgs }, + { NULL, NULL } + }; + +FlyDive::FlyDive() + { + anim = "fly"; + speed = 2000; + damage = 10; + } + +void FlyDive::SetArgs + ( + Event *ev + ) + + { + anim = ev->GetString( 1 ); + + if ( ev->NumArgs() > 1 ) + { + speed = ev->GetFloat( 2 ); + } + + if ( ev->NumArgs() > 2 ) + { + damage = ev->GetFloat( 3 ); + } + } + +void FlyDive::ShowInfo + ( + Actor &self + ) + + { + Behavior::ShowInfo( self ); + } + +void FlyDive::Begin + ( + Actor &self + ) + + { + if ( anim.length() ) + self.SetAnim( anim ); + + fly.Begin( self ); + + if ( !self.IsEntityAlive( self.currentEnemy ) ) + { + return; + } + + goal = self.currentEnemy->centroid - self.origin; + goal.normalize(); + goal *= 10000; + goal += self.origin; + + fly.SetGoalPoint( goal ); + + fly.SetTurnSpeed( 100 ); + fly.SetSpeed( speed ); + fly.SetRandomAllowed( false ); + fly.ForceGoal(); + } + +qboolean FlyDive::Evaluate + ( + Actor &self + ) + + { + trace_t trace; + Vector dir; + Entity *hit_entity; + qboolean stuck; + + + if ( !self.IsEntityAlive( self.currentEnemy ) ) + return false; + + if ( self.origin.z < self.currentEnemy->origin.z - 100 ) + return false; + + if ( self.lastmove == STEPMOVE_STUCK || self.lastmove == STEPMOVE_BLOCKED_BY_WATER ) + { + stuck = true; + + dir = self.movedir * 100; + + trace = G_Trace( self.origin, self.mins, self.maxs, self.origin + dir, &self, self.edict->clipmask, false, "FlyDive" ); + + if ( trace.entityNum != ENTITYNUM_NONE ) + { + hit_entity = G_GetEntity( trace.entityNum ); + + // Damage entity hit + //if ( hit_entity->isSubclassOf( Sentient ) ) + if ( hit_entity->takedamage ) + { + //hit_entity->Damage( &self, &self, damage, Vector (0, 0, 0), Vector (0, 0, 0), Vector (0, 0, 0), 0, 0, MOD_CRUSH ); + dir.normalize(); + hit_entity->Damage( &self, &self, damage, self.centroid, dir, vec_zero, 0, 0, MOD_CRUSH ); + self.AddStateFlag( STATE_FLAG_MELEE_HIT ); + stuck = false; + } + } + + // Make sure we really are still stuck + + if ( trace.fraction > 0.05 ) + stuck = false; + + self.angles[PITCH] = 0; + self.setAngles( self.angles ); + + if ( stuck ) + self.AddStateFlag( STATE_FLAG_STUCK ); + + return false; + } + + fly.Evaluate( self ); + + return true; + } + +void FlyDive::End + ( + Actor &self + ) + + { + fly.End( self ); + } + +/**************************************************************************** + + FlyClimb Class Definition + +****************************************************************************/ + + +CLASS_DECLARATION( Behavior, FlyClimb, NULL ) + { + { &EV_Behavior_Args, SetArgs }, + { NULL, NULL } + }; + +FlyClimb::FlyClimb() + { + anim = "fly"; + height = 500; + speed = 0; + } + +void FlyClimb::SetArgs + ( + Event *ev + ) + + { + anim = ev->GetString( 1 ); + + if ( ev->NumArgs() > 1 ) + height = ev->GetFloat( 2 ); + + if ( ev->NumArgs() > 2 ) + speed = ev->GetFloat( 3 ); + } + +void FlyClimb::ShowInfo + ( + Actor &self + ) + + { + Behavior::ShowInfo( self ); + } + +void FlyClimb::Begin + ( + Actor &self + ) + + { + if ( anim.length() ) + { + self.SetAnim( anim ); + } + + fly.Begin( self ); + + if ( self.currentEnemy ) + height = self.currentEnemy->origin.z + height; + else + height = self.origin.z + height; + + goal = self.origin; + goal.z = height; + + fly.SetTurnSpeed( 10 ); + + fly.SetGoalPoint( goal ); + + next_height_check = level.time + 2.0; + last_check_height = self.origin.z; + + if ( speed ) + fly.SetSpeed( speed ); + } + +qboolean FlyClimb::Evaluate + ( + Actor &self + ) + + { + + if ( self.origin.z >= height ) + { + return false; + } + + if ( next_height_check < level.time ) + { + if ( self.origin.z < last_check_height + 25 ) + return false; + + next_height_check = level.time + 2.0; + last_check_height = self.origin.z; + } + + if ( self.lastmove == STEPMOVE_OK ) + fly.SetGoalPoint( goal ); + + fly.Evaluate( self ); + + return true; + } + +void FlyClimb::End + ( + Actor &self + ) + + { + fly.End( self ); + } + +/**************************************************************************** + + Land Class Definition + +****************************************************************************/ + + +CLASS_DECLARATION( Behavior, Land, NULL ) + { + { &EV_Behavior_Args, SetArgs }, + { NULL, NULL } + }; + +Land::Land() + { + anim = "fly"; + } + +void Land::SetArgs + ( + Event *ev + ) + + { + anim = ev->GetString( 1 ); + } + +void Land::ShowInfo + ( + Actor &self + ) + + { + Behavior::ShowInfo( self ); + } + +void Land::Begin + ( + Actor &self + ) + + { + if ( anim.length() ) + { + self.SetAnim( anim ); + } + + self.velocity = "0 0 -20"; + } + +qboolean Land::Evaluate + ( + Actor &self + ) + + { + self.angles[PITCH] = 0; + self.angles[ROLL] = 0; + + self.setAngles( self.angles ); + + self.velocity.z -= 20; + + if ( self.velocity.z < -200 ) + { + self.velocity.z = -200; + } + + return !self.groundentity; + } + +void Land::End + ( + Actor &self + ) + + { + } + +/**************************************************************************** + + Wander Class Definition + +****************************************************************************/ + + +CLASS_DECLARATION( Behavior, Wander, NULL ) + { + { &EV_Behavior_Args, SetArgs }, + { NULL, NULL } + }; + +void Wander::SetArgs + ( + Event *ev + ) + + { + anim = ev->GetString( 1 ); + } + +void Wander::ShowInfo + ( + Actor &self + ) + + { + Behavior::ShowInfo( self ); + + gi.Printf( "\nseek:\n" ); + seek.ShowInfo( self ); + + //gi.Printf( "\navoid:\n" ); + //avoid.ShowInfo( self ); + } + +void Wander::Begin + ( + Actor &self + ) + + { + avoidtime = 0; + avoidvec = vec_zero; + + //avoid.Begin( self ); + seek.Begin( self ); + seek.SetTargetVelocity( vec_zero ); + if ( anim.length() ) + { + self.SetAnim( anim ); + } + } + + +qboolean Wander::Evaluate + ( + Actor &self + ) + + { + if ( ( self.lastmove != STEPMOVE_OK ) || ( avoidtime <= level.time ) ) + { + Vector dir; + Vector ang; + float time; + + time = 5; + //self.Chatter( "snd_idle", 4 ); + avoidvec = ChooseRandomDirection( self, avoidvec, &time, 0, false ); + avoidtime = level.time + time; + } + + if ( self.movespeed != 1 ) + seek.SetMaxSpeed( self.movespeed ); + else + seek.SetMaxSpeed( 100 ); + + seek.SetPosition( self.origin ); + seek.SetDir( self.movedir ); + seek.SetTargetPosition( avoidvec ); + + if ( !seek.Evaluate( self ) ) + { + // we have reached the goal, re-evaluate + avoidtime = 0; + } + + /* avoid.SetMaxSpeed( self.movespeed * 2 ); + avoid.SetPosition( self.origin ); + avoid.SetDir( self.movedir ); + avoid.Evaluate( self ); */ + + //self.Accelerate( seek.steeringforce + avoid.steeringforce ); + + self.Accelerate( seek.steeringforce ); + + return true; + } + +void Wander::End + ( + Actor &self + ) + + { + //avoid.End( self ); + seek.End( self ); + } + +/**************************************************************************** + + GetCloseToEnemy Class Definition + +****************************************************************************/ + +CLASS_DECLARATION( Behavior, GetCloseToEnemy, NULL ) + { + { &EV_Behavior_Args, SetArgs }, + { NULL, NULL } + }; + +void GetCloseToEnemy::SetArgs + ( + Event *ev + ) + + { + anim = ev->GetString( 1 ); + + if ( ev->NumArgs() > 1 ) + forever = ev->GetBoolean( 2 ); + else + forever = true; + } + +void GetCloseToEnemy::ShowInfo + ( + Actor &self + ) + + { + Behavior::ShowInfo( self ); + + gi.Printf( "\nchase:\n" ); + chase.ShowInfo( self ); + } + +void GetCloseToEnemy::Begin + ( + Actor &self + ) + + { + if ( !anim.length() ) + { + anim = "run"; + } + + if ( anim != self.animname || self.newanim.length() ) + { + self.SetAnim( anim, EV_Actor_NotifyBehavior ); + } + + chase.UseNearestNode( false ); + chase.Begin( self ); + wander.Begin( self ); + + next_think_time = 0; + } + +qboolean GetCloseToEnemy::Evaluate + ( + Actor &self + ) + + { + qboolean result; + + if ( !self.currentEnemy ) + return false; + + if ( next_think_time <= level.time ) + { + if ( self.groundentity && self.groundentity->s.number == self.currentEnemy->entnum ) + { + wander.Evaluate( self ); + result = true; + } + else + { + chase.SetTarget( self.currentEnemy ); + + result = chase.Evaluate( self ); + } + + if ( self.GetActorFlag( ACTOR_FLAG_SIMPLE_PATHFINDING ) ) + next_think_time = level.time + 2 * FRAMETIME; + else + next_think_time = 0; + } + else + result = true; + + if ( !forever && !result ) + return false; + + return true; + } + +void GetCloseToEnemy::End + ( + Actor &self + ) + + { + chase.End( self ); + wander.End( self ); + } + +/**************************************************************************** + + GotoDeadEnemy Class Definition + +****************************************************************************/ + +CLASS_DECLARATION( Behavior, GotoDeadEnemy, NULL ) + { + { &EV_Behavior_Args, SetArgs }, + { NULL, NULL } + }; + +void GotoDeadEnemy::SetArgs + ( + Event *ev + ) + + { + anim = ev->GetString( 1 ); + } + +void GotoDeadEnemy::ShowInfo + ( + Actor &self + ) + + { + Behavior::ShowInfo( self ); + + gi.Printf( "\nchase:\n" ); + chase.ShowInfo( self ); + } + +void GotoDeadEnemy::Begin + ( + Actor &self + ) + + { + if ( !anim.length() ) + { + anim = "run"; + } + + if ( anim != self.animname || self.newanim.length() ) + { + self.SetAnim( anim, EV_Actor_NotifyBehavior ); + } + + chase.Begin( self ); + } + +qboolean GotoDeadEnemy::Evaluate + ( + Actor &self + ) + + { + qboolean result; + + if ( !self.currentEnemy ) + return false; + + if ( !self.currentEnemy->deadflag ) + return false; + + chase.SetGoalPos( self.currentEnemy->origin ); + + result = chase.Evaluate( self ); + + if ( !result ) + return false; + + return true; + } + +void GotoDeadEnemy::End + ( + Actor &self + ) + + { + chase.End( self ); + } + +/**************************************************************************** + + Investigate Class Definition + +****************************************************************************/ + +CLASS_DECLARATION( Behavior, Investigate, NULL ) + { + { &EV_Behavior_Args, SetArgs }, + { NULL, NULL } + }; + +#define INVESTIGATE_MODE_INVESTIGATE 0 +#define INVESTIGATE_MODE_TURN1 1 +#define INVESTIGATE_MODE_RETURN 2 +#define INVESTIGATE_MODE_TURN2 3 + +Investigate::Investigate() + { + investigate_time = 10; + anim = "run"; + } + +void Investigate::SetArgs + ( + Event *ev + ) + + { + anim = ev->GetString( 1 ); + + if ( ev->NumArgs() > 1 ) + investigate_time = ev->GetFloat( 2 ); + + if ( ev->NumArgs() > 2 ) + return_to_original_location = ev->GetBoolean( 3 ); + else + return_to_original_location = true; + } + +void Investigate::ShowInfo + ( + Actor &self + ) + + { + Behavior::ShowInfo( self ); + + gi.Printf( "\nchase:\n" ); + chase.ShowInfo( self ); + gi.Printf( "\nanim: %s\n", anim.c_str() ); + gi.Printf( "curioustime: %f\n", curioustime ); + gi.Printf( "goal: ( %f, %f, %f )\n", goal.x, goal.y, goal.z ); + } + +void Investigate::Begin + ( + Actor &self + ) + + { + trace_t trace; + Vector trace_start_pos; + Vector trace_end_pos; + PathNode *goal_node; + Vector delta; + float xydist; + + + // Find the goal position + + trace_start_pos = self.noise_position; + trace_end_pos = trace_start_pos - "0 0 1000"; + + trace = G_Trace( trace_start_pos, vec_zero, vec_zero, trace_end_pos, NULL, MASK_SOLID, false, "Investigate" ); + + goal = trace.endpos; + + // Find the nearest node to our goal + + goal_node = self.NearestNodeInPVS( goal ); + real_goal_position = self.noise_position; + + if ( goal_node ) + goal = goal_node->origin; + + self.SetActorFlag( ACTOR_FLAG_INVESTIGATING, true ); + + // We are only interested for a short period, if we can't get there, lets go back to what we were doing + + curioustime = level.time + investigate_time; + self.Chatter( "snd_investigate", 10 ); + + chase.Begin( self ); + chase.SetGoal( goal_node ); + + turnto.Begin( self ); + + // Don't allow guys to change their anim if we're already close enough to the goal + + delta = goal - self.origin; + delta.z = 0; + + xydist = delta.length(); + + if ( xydist >= 100 && anim.length() ) + { + self.SetAnim( anim ); + } + + mode = INVESTIGATE_MODE_INVESTIGATE; + + start_pos = self.origin; + start_yaw = self.angles[YAW]; + } + +qboolean Investigate::Evaluate + ( + Actor &self + ) + + { + Vector dir; + Vector angles; + Vector delta; + float xydist; + + + switch ( mode ) + { + case INVESTIGATE_MODE_INVESTIGATE : + + // Go to spot where the noise was heard + + if ( !chase.Evaluate( self ) ) + { + mode = INVESTIGATE_MODE_TURN1; + self.SetAnim( "idle" ); + } + + // See if we have investigated long enough + + if ( curioustime < level.time ) + { + mode = INVESTIGATE_MODE_RETURN; + curioustime = level.time + investigate_time * 2; + } + else + { + // See if have gotten close enough to the noise position + + delta = goal - self.origin; + delta.z = 0; + + xydist = delta.length(); + + if ( xydist < 100 ) + { + mode = INVESTIGATE_MODE_TURN1; + self.SetAnim( "idle" ); + } + } + + break; + case INVESTIGATE_MODE_TURN1 : + + // Turn towards the noise position + + dir = real_goal_position - self.origin; + angles = dir.toAngles(); + turnto.SetDirection( angles[YAW] ); + + if ( !turnto.Evaluate( self ) ) + { + mode = INVESTIGATE_MODE_RETURN; + curioustime = level.time + investigate_time * 2; + self.SetAnim( anim ); + } + + break; + case INVESTIGATE_MODE_RETURN : + + if ( !return_to_original_location ) + return false; + + // Return back to our original position + + chase.SetGoalPos( start_pos ); + + if ( !chase.Evaluate( self ) ) + mode = INVESTIGATE_MODE_TURN2; + + if ( curioustime < level.time ) + return false; + + break; + case INVESTIGATE_MODE_TURN2 : + + self.SetAnim( "idle" ); + + // Turn back to our original direction + + turnto.SetDirection( start_yaw ); + if ( !turnto.Evaluate( self ) ) + return false; + + break; + } + + return true; + } + +void Investigate::End + ( + Actor &self + ) + + { + self.SetActorFlag( ACTOR_FLAG_INVESTIGATING, false ); + self.SetActorFlag( ACTOR_FLAG_NOISE_HEARD, false ); + chase.End( self ); + turnto.End( self ); + } + +/**************************************************************************** + + TurnInvestigate Class Definition + +****************************************************************************/ + +CLASS_DECLARATION( Behavior, TurnInvestigate, NULL ) + { + { &EV_Behavior_Args, SetArgs }, + { NULL, NULL } + }; + +void TurnInvestigate::SetArgs + ( + Event *ev + ) + + { + left_anim = ev->GetString( 1 ); + right_anim = ev->GetString( 2 ); + turn_speed = ev->GetFloat( 3 ); + } + +void TurnInvestigate::ShowInfo + ( + Actor &self + ) + + { + Behavior::ShowInfo( self ); + + gi.Printf( "goal: ( %f, %f, %f )\n", goal.x, goal.y, goal.z ); + } + +void TurnInvestigate::Begin + ( + Actor &self + ) + + { + goal = self.noise_position; + self.SetActorFlag( ACTOR_FLAG_INVESTIGATING, true ); + + seek.Begin( self ); + seek.SetTargetPosition( goal ); + + self.SetAnim( "idle" ); + } + +qboolean TurnInvestigate::Evaluate + ( + Actor &self + ) + + { + str turn_anim_name; + Vector dir; + + self.angles.AngleVectors( &dir ); + + seek.SetTargetVelocity( vec_zero ); + seek.SetPosition( self.centroid ); + seek.SetDir( dir ); + seek.Evaluate( self ); + + // See if we have turned all of the way to the noise position + + if ( seek.steeringforce[YAW] < .5 && seek.steeringforce[YAW] > -.5 ) + return false; + + // Make sure we are not turning faster than out turn speed + + if ( seek.steeringforce[YAW] > turn_speed ) + { + seek.steeringforce[YAW] = turn_speed; + } + + if ( seek.steeringforce[YAW] < -turn_speed ) + { + seek.steeringforce[YAW] = -turn_speed; + } + + seek.steeringforce[PITCH] = 0; + seek.steeringforce[ROLL] = 0; + + // Set the correct animation (left or right) + + if ( seek.steeringforce[YAW] > 0 ) + turn_anim_name = left_anim; + else + turn_anim_name = right_anim; + + if ( turn_anim_name != self.animname ) + self.SetAnim( turn_anim_name ); + + // Actually turn here + + self.Accelerate( seek.steeringforce ); + + return true; + } + +void TurnInvestigate::End + ( + Actor &self + ) + + { + self.SetActorFlag( ACTOR_FLAG_INVESTIGATING, false ); + self.SetActorFlag( ACTOR_FLAG_NOISE_HEARD, false ); + seek.End( self ); + } + +/**************************************************************************** + + TurnToEnemy Class Definition + +****************************************************************************/ + +CLASS_DECLARATION( Behavior, TurnToEnemy, NULL ) + { + { &EV_Behavior_Args, SetArgs }, + { &EV_Behavior_AnimDone, AnimDone }, + { NULL, NULL } + }; + +void TurnToEnemy::SetArgs + ( + Event *ev + ) + + { + left_anim = ev->GetString( 1 ); + right_anim = ev->GetString( 2 ); + turn_speed = ev->GetFloat( 3 ); + forever = ev->GetBoolean( 4 ); + + if ( ev->NumArgs() > 4 ) + use_last_known_position = ev->GetBoolean( 5 ); + else + use_last_known_position = false; + } + +void TurnToEnemy::ShowInfo + ( + Actor &self + ) + + { + Behavior::ShowInfo( self ); + } + +void TurnToEnemy::Begin + ( + Actor &self + ) + + { + seek.Begin( self ); + + self.SetAnim( "idle" ); + } + +void TurnToEnemy::AnimDone + ( + Event *ev + ) + + { + anim_done = true; + } + + +qboolean TurnToEnemy::Evaluate + ( + Actor &self + ) + + { + str turn_anim_name; + Vector dir; + + if ( !self.currentEnemy ) + return false; + + self.angles.AngleVectors( &dir ); + + if ( use_last_known_position ) + seek.SetTargetPosition( self.last_known_enemy_pos ); + else + seek.SetTargetPosition( self.currentEnemy->origin ); + + seek.SetTargetVelocity( vec_zero ); + seek.SetPosition( self.centroid ); + seek.SetDir( dir ); + seek.Evaluate( self ); + + // See if we have turned all of the way to the enemy position + + if ( seek.steeringforce[YAW] < .5 && seek.steeringforce[YAW] > -.5 ) + seek.steeringforce[YAW] = 0; + + // Make sure we are not turning faster than out turn speed + + if ( seek.steeringforce[YAW] > turn_speed ) + { + seek.steeringforce[YAW] = turn_speed; + } + + if ( seek.steeringforce[YAW] < -turn_speed ) + { + seek.steeringforce[YAW] = -turn_speed; + } + + seek.steeringforce[PITCH] = 0; + seek.steeringforce[ROLL] = 0; + + // Set the correct animation (left or right) + + if ( seek.steeringforce[YAW] > 0 ) + turn_anim_name = left_anim; + else if ( seek.steeringforce[YAW] < 0 ) + turn_anim_name = right_anim; + else if ( anim_done ) + turn_anim_name = "idle"; + else + turn_anim_name = self.animname.c_str(); + + if ( turn_anim_name != self.animname ) + self.SetAnim( turn_anim_name, EV_Actor_NotifyBehavior ); + + // Actually turn here + + self.Accelerate( seek.steeringforce ); + + // See if we have turned all of the way to the enemy position + + if ( seek.steeringforce[YAW] < turn_speed && seek.steeringforce[YAW] > -turn_speed && !forever ) + return false; + + anim_done = false; + + return true; + } + +void TurnToEnemy::End + ( + Actor &self + ) + + { + seek.End( self ); + } + +/**************************************************************************** + + PickupEntity Class Definition + +****************************************************************************/ + + +CLASS_DECLARATION( Behavior, PickupEntity, NULL ) + { + { &EV_Behavior_Args, SetArgs }, + { &EV_Behavior_AnimDone, AnimDone }, + { NULL, NULL } + }; + +void PickupEntity::SetArgs + ( + Event *ev + ) + + { + ent_to_pickup = ev->GetEntity( 1 ); + pickup_anim_name = ev->GetString( 2 ); + } + +void PickupEntity::Begin + ( + Actor &self + ) + + { + anim_done = false; + self.pickup_ent = ent_to_pickup; + + self.SetAnim( pickup_anim_name.c_str(), EV_Actor_NotifyBehavior ); + } + +void PickupEntity::AnimDone + ( + Event *ev + ) + + { + anim_done = true; + } + + +qboolean PickupEntity::Evaluate + ( + Actor &self + ) + + { + if ( !ent_to_pickup ) + return false; + + if ( anim_done ) + return false; + + return true; + } + +void PickupEntity::End + ( + Actor &self + ) + + { + self.SetAnim( "idle" ); + self.pickup_ent = NULL; + } + +/**************************************************************************** + + ThrowEntity Class Definition + +****************************************************************************/ + +CLASS_DECLARATION( Behavior, ThrowEntity, NULL ) + { + { &EV_Behavior_Args, SetArgs }, + { &EV_Behavior_AnimDone, AnimDone }, + { NULL, NULL } + }; + +void ThrowEntity::SetArgs + ( + Event *ev + ) + + { + throw_anim_name = ev->GetString( 1 ); + } + +void ThrowEntity::Begin + ( + Actor &self + ) + + { + anim_done = false; + self.SetAnim( throw_anim_name, EV_Actor_NotifyBehavior ); + } + +void ThrowEntity::AnimDone + ( + Event *ev + ) + + { + anim_done = true; + } + + +qboolean ThrowEntity::Evaluate + ( + Actor &self + ) + + { + if ( anim_done ) + return false; + + return true; + } + +void ThrowEntity::End + ( + Actor &self + ) + + { + self.SetAnim( "idle" ); + } + + + +/**************************************************************************** +***************************************************************************** + + Behaviors for specific creatures + +***************************************************************************** +****************************************************************************/ + + + +/**************************************************************************** + + BurrowAttack Class Definition + +****************************************************************************/ + +#define BURROW_MODE_MOVING 0 +#define BURROW_MODE_ATTACK 1 + +CLASS_DECLARATION( Behavior, BurrowAttack, NULL ) + { + { NULL, NULL } + }; + +void BurrowAttack::SetArgs + ( + Event *ev + ) + + { + use_last_known_position = ev->GetBoolean( 1 ); + } + +void BurrowAttack::Begin + ( + Actor &self + ) + + { + Vector attack_dir; + Vector start_pos; + Vector end_pos; + trace_t trace; + + if ( self.animname != "idle_down" ) + self.SetAnim( "idle_down" ); + + // Setup our goal point + + if ( self.currentEnemy ) + { + if ( use_last_known_position ) + goal = self.last_known_enemy_pos; + else + goal = self.currentEnemy->origin; + + start_pos = goal + "0 0 10"; + end_pos = start_pos + "0 0 -250"; + + trace = G_Trace( start_pos, vec_zero, vec_zero, end_pos, NULL, MASK_DEADSOLID, false, "BurrowAttack::Begin" ); + + goal = trace.endpos; + } + + // Setup our starting point, a little ways in front of our origin + + attack_dir = goal - self.origin; + + too_close = false; + + if ( attack_dir.length() < 300 ) + too_close = true; + + attack_dir.normalize(); + + attack_origin = self.origin + attack_dir * 100; + + burrow_mode = BURROW_MODE_MOVING; + + stage = self.stage; + + burrow_speed = 80; + + if ( stage == 3 ) + { + attacks_left = 2; + } + else if ( stage == 4 ) + { + attacks_left = 3 + G_Random( 3 ); + burrow_speed = 120; + } + } + +qboolean BurrowAttack::Evaluate + ( + Actor &self + ) + + { + Vector attack_dir; + Vector new_origin; + float total_dist; + Vector start_pos; + Vector end_pos; + Animate *dirt; + trace_t trace; + Vector temp_angles; + int cont; + Vector temp_endpos; + + if ( !self.currentEnemy ) + return false; + + if ( too_close ) + return false; + + switch ( burrow_mode ) + { + case BURROW_MODE_MOVING : + + attack_dir = goal - attack_origin; + total_dist = attack_dir.length(); + attack_dir.normalize(); + + if ( total_dist < burrow_speed ) + { + new_origin = goal; + } + else + { + new_origin = attack_origin + attack_dir * burrow_speed; + total_dist = burrow_speed; + } + + // Spawn in dirt or water + + start_pos = attack_origin + attack_dir + "0 0 10"; + end_pos = start_pos + "0 0 -250"; + + trace = G_Trace( start_pos, vec_zero, vec_zero, end_pos, NULL, MASK_DEADSOLID | MASK_WATER, false, "BurrowAttack" ); + + temp_endpos = trace.endpos; + temp_endpos -= "0 0 5"; + cont = gi.pointcontents( temp_endpos, 0 ); + + dirt = new Animate; + + dirt->setOrigin( trace.endpos ); + + temp_angles = vec_zero; + + if (cont & MASK_WATER) + dirt->setModel( "fx_splashsmall.tik" ); + else + dirt->setModel( "fx_dirtcloud.tik" ); + + dirt->setAngles( temp_angles ); + + dirt->RandomAnimate( "idle" ); + + dirt->PostEvent( EV_Remove, 5 ); + + attack_origin = new_origin; + + if ( attack_origin == goal ) + { + // Got to our goal position, do attack + + if ( stage == 1 ) + { + SpawnArm( self, leg1, attack_origin + " 25 25 0", "attack1", 0 ); + SpawnArm( self, leg2, attack_origin + " 25 -25 0", "attack1", 0 ); + SpawnArm( self, leg3, attack_origin + "-25 25 0", "attack1", 0 ); + SpawnArm( self, leg4, attack_origin + "-25 -25 0", "attack1", 0 ); + } + else if ( stage == 2 ) + { + SpawnArm( self, leg1, attack_origin + " 25 0 0", "attack2", 0 ); + SpawnArm( self, leg2, attack_origin + "-25 25 0", "attack2", 120 ); + SpawnArm( self, leg3, attack_origin + "-25 -25 0", "attack2", 240 ); + } + else + { + SpawnArm( self, leg1, attack_origin, "attack1", 0 ); + } + + burrow_mode = BURROW_MODE_ATTACK; + } + + break; + case BURROW_MODE_ATTACK : + + // Wait until all of the legs are done + + if ( !leg1 && !leg2 && !leg3 && !leg4 ) + { + if ( self.animname != "idle_down" ) + self.SetAnim( "idle_down" ); + + if ( stage == 1 || stage == 2 ) + { + return false; + } + else + { + attacks_left--; + + if ( attacks_left > 0 ) + { + if ( use_last_known_position ) + if ( self.CanReallySee( self.currentEnemy ) ) + goal = self.currentEnemy->origin; + else + return false; + else + goal = self.currentEnemy->origin; + + burrow_mode = BURROW_MODE_MOVING; + } + else + { + return false; + } + } + } + + break; + } + + return true; + } + +void BurrowAttack::SpawnArm + ( + Actor &self, + AnimatePtr &leg, + Vector arm_origin, + const char *anim_name, + float angle + ) + + { + Vector angles; + trace_t trace; + Vector start_pos; + Vector end_pos; + str anim_to_play; + Animate *leg_animate_ptr; + Vector dir; + Animate *dirt; + + + // Find correct spot to spawn + + arm_origin[2] = -575; + + start_pos = arm_origin + "0 0 64"; + end_pos = arm_origin - "0 0 100"; + + //trace = G_Trace( start_pos, Vector(-5, -5, 0), Vector(5, 5, 0), end_pos, NULL, MASK_DEADSOLID, false, "BurrowAttack" ); + trace = G_Trace( start_pos, Vector(-10, -10, 0), Vector(10, 10, 0), end_pos, NULL, MASK_DEADSOLID, false, "BurrowAttack" ); + + arm_origin = trace.endpos; + + // Make sure can spawn here + + end_pos = arm_origin + "0 0 50"; + + trace = G_Trace( arm_origin, Vector(-10, -10, 0), Vector(10, 10, 0), end_pos, NULL, MASK_DEADSOLID, false, "BurrowAttack" ); + + if ( trace.fraction < 1 || trace.startsolid || trace.allsolid ) + { + if ( trace.entityNum == ENTITYNUM_WORLD || !( trace.ent && trace.ent->entity && trace.ent->entity->takedamage ) ) + return; + } + + // Spawn some dirt + + dirt = new Animate; + + dirt->setOrigin( arm_origin ); + dirt->setModel( "fx_dirtcloud.tik" ); + dirt->setAngles( vec_zero ); + dirt->RandomAnimate( "idle" ); + dirt->PostEvent( EV_Remove, 5 ); + + // Spawn leg + + leg = new Animate; + + leg->setModel( "vmama_arm.tik" ); + leg->setOrigin( arm_origin ); + + leg->ProcessPendingEvents(); + + //leg->edict->clipmask = MASK_MONSTERSOLID; + leg->setContents( 0 ); + leg->setSolidType( SOLID_NOT ); + + leg->PostEvent( EV_BecomeNonSolid, 0 ); + + angles = vec_zero; + angles[YAW] = angle; + + leg->setAngles( angles ); + + anim_to_play = anim_name; + + // See if we should get stuck or not + + if ( strcmp( anim_name, "attack1" ) == 0 ) + { + end_pos = arm_origin + "0 0 250"; + + leg_animate_ptr = leg; + + trace = G_Trace( arm_origin, Vector(-5, -5, 0), Vector(5, 5, 0), end_pos, leg_animate_ptr, MASK_DEADSOLID, false, "BurrowAttack" ); + + if ( trace.fraction != 1.0 ) + { + if ( self.animname != "struggle" ) + self.SetAnim( "struggle" ); + + anim_to_play = "getstuck"; + } + } + + // Damage entities in way + + if ( strcmp( anim_name, "attack1" ) == 0 ) + { + start_pos = arm_origin; + end_pos = arm_origin + "0 0 250"; + + dir = Vector ( G_CRandom( 5 ), G_CRandom( 5 ), 10 ); + } + else + { + start_pos = arm_origin + "0 0 10"; + + angles.AngleVectors( &dir ); + + end_pos = start_pos + dir * 250; + } + + leg_animate_ptr = leg; + + MeleeAttack( start_pos, end_pos, 50, &self, MOD_IMPALE, 10, 0, 0, 100 ); + + leg->RandomAnimate( anim_to_play.c_str(), EV_Remove ); + } + +void BurrowAttack::End + ( + Actor &self + ) + + { + } + +/**************************************************************************** + + CircleEnemy Class Definition + +****************************************************************************/ + +CLASS_DECLARATION( Behavior, CircleEnemy, NULL ) + { + { &EV_Behavior_Args, SetArgs }, + { NULL, NULL } + }; + +void CircleEnemy::SetArgs + ( + Event *ev + ) + + { + center_part_name = ev->GetString( 1 ); + } + +void CircleEnemy::Begin + ( + Actor &self + ) + + { + ent_to_circle = self.currentEnemy; + last_angle_change = 0; + } + +float CircleEnemy::GetAngleDiff + ( + Actor &self, + Actor *center_actor, + Vector origin + ) + + { + Vector dir; + Vector enemy_angles; + Vector actor_angles; + float angle_diff; + + dir = ent_to_circle->origin - center_actor->origin; + enemy_angles = dir.toAngles(); + + dir = origin - center_actor->origin; + actor_angles = dir.toAngles(); + + angle_diff = AngleDelta( actor_angles[YAW], enemy_angles[YAW] ); + + return angle_diff; + } + +#define MAX_CIRCLE_ACCELERATION .125 +#define MAX_CIRCLE_VELOCITY 10 + +qboolean CircleEnemy::Evaluate + ( + Actor &self + ) + + { + Vector dir; + Actor *center_actor; + Vector actor_angles; + float angle_diff; + float other_angle_diff; + float abs_angle_diff; + float other_abs_angle_diff = 180; + float angle_change = MAX_CIRCLE_VELOCITY; + float length; + float real_angle_change; + Actor *other; + + + if ( !ent_to_circle ) + return false; + + center_actor = self.FindPartActor( center_part_name.c_str() ); + + if ( !center_actor ) + return false; + + angle_diff = GetAngleDiff( self, center_actor, self.origin ); + + if ( angle_diff < 0 ) + abs_angle_diff = -angle_diff; + else + abs_angle_diff = angle_diff; + + other = self.FindPartActor( self.part_name ); + + if ( other ) + { + other_angle_diff = GetAngleDiff( self, center_actor, other->origin ); + + if ( other_angle_diff < 0 ) + other_abs_angle_diff = -other_angle_diff; + else + other_abs_angle_diff = other_angle_diff; + } + + if ( abs_angle_diff < other_abs_angle_diff ) + { + // Turn towards enemy + + if ( abs_angle_diff < angle_change ) + angle_change = abs_angle_diff; + + if ( angle_diff < 0 ) + real_angle_change = angle_change; + else + real_angle_change = -angle_change; + } + else + { + // Turn away from enemy + + if ( 180 - abs_angle_diff < angle_change ) + angle_change = 180 - abs_angle_diff; + + if ( angle_diff < 0 ) + real_angle_change = -angle_change; + else + real_angle_change = angle_change; + } + + if ( real_angle_change < 1.0 && real_angle_change > -1.0 ) + real_angle_change = 0; + + if ( real_angle_change > 0 ) + { + if ( real_angle_change > last_angle_change + MAX_CIRCLE_ACCELERATION ) + real_angle_change = last_angle_change + MAX_CIRCLE_ACCELERATION; + } + else if ( real_angle_change < 0 ) + { + if ( real_angle_change < last_angle_change - MAX_CIRCLE_ACCELERATION ) + real_angle_change = last_angle_change - MAX_CIRCLE_ACCELERATION; + } + + last_angle_change = real_angle_change; + + dir = self.origin - center_actor->origin; + length = dir.length(); + + actor_angles = dir.toAngles(); + actor_angles[YAW] += real_angle_change; + + // Find new position + + actor_angles.AngleVectors( &dir, NULL, NULL ); + + dir *= length; + dir.z = 0; + + self.setOrigin( center_actor->origin + dir ); + + // Set the actors angle to look at the center + + dir[0] = -dir[0]; + dir[1] = -dir[1]; + dir[2] = -dir[2]; + + self.angles[YAW] = dir.toYaw(); + self.setAngles( self.angles ); + + return true; + } + +void CircleEnemy::End + ( + Actor &self + ) + + { + } + +/**************************************************************************** + + ShockWater Class Definition + +****************************************************************************/ + +CLASS_DECLARATION( Behavior, ShockWater, NULL ) + { + { NULL, NULL } + }; + +ShockWater::ShockWater() + { + left_beam = NULL; + right_beam = NULL; + center_beam = NULL; + already_started = false; + } + +void ShockWater::Begin + ( + Actor &self + ) + + { + } + +qboolean ShockWater::Evaluate + ( + Actor &self + ) + + { + Vector left_tag_orig; + Vector right_tag_orig; + Vector end_pos; + Vector center_point; + Actor *center_actor; + trace_t trace; + Entity *hit_entity; + Vector diff_vect; + float diff; + Vector dir; + + if ( !self.currentEnemy ) + return false; + + if ( self.newanimnum == -1 && !already_started ) + { + // Get tag positions + self.GetTag( "tag_left", &left_tag_orig ); + self.GetTag( "tag_right", &right_tag_orig ); + + // Get end position + end_pos = left_tag_orig + right_tag_orig; + end_pos *= .5; + end_pos[2] -= 120; + + dir = end_pos - self.origin; + dir.z = 0; + dir *= 0.5; + + end_pos += dir; + + // Add the left and right beams + left_beam = CreateBeam( NULL, "emap1", left_tag_orig, end_pos, 10, 1.5f, 0.2f ); + right_beam = CreateBeam( NULL, "emap1", right_tag_orig, end_pos, 10, 1.5f, 0.2f ); + + center_actor = self.FindPartActor( "body" ); + if ( center_actor ) + { + center_point = center_actor->origin; + } + + trace = G_Trace( center_point, vec_zero, vec_zero, end_pos, &self, MASK_SHOT, false, "ShockAttack" ); + if ( trace.fraction < 1.0 && trace.entityNum != center_actor->entnum ) + { + hit_entity = G_GetEntity( trace.entityNum ); + if ( hit_entity ) + { + center_point = hit_entity->origin; + } + } + else + { + // Shock head + center_actor->AddStateFlag( STATE_FLAG_IN_PAIN ); + + center_actor->SpawnEffect( "fx_elecstrike.tik", center_actor->origin ); + center_actor->Sound( "sound/weapons/sword/electric/hitmix2.wav", 0, 1, 500 ); + } + + // create the center beam + center_beam = CreateBeam( NULL, "emap1", end_pos, center_point, 20, 3.0f, 0.2f ); + + // Damage player if in water + if ( center_actor ) + { + diff_vect = self.currentEnemy->origin - center_actor->origin; + diff_vect[2] = 0; + + diff = diff_vect.length(); + //if ( diff < 240 && self.currentEnemy->groundentity ) + if ( diff < 350 && self.currentEnemy->groundentity ) + { + self.currentEnemy->Damage( &self, &self, 10, Vector (0, 0, 0), Vector (0, 0, 0), Vector (0, 0, 0), 0, 0, MOD_ELECTRICWATER ); + } + } + already_started = true; + } + + return true; + } + +void ShockWater::End + ( + Actor &self + ) + + { + delete left_beam; + delete right_beam; + delete center_beam; + } + +/**************************************************************************** + + Shock Class Definition + +****************************************************************************/ + +CLASS_DECLARATION( Behavior, Shock, NULL ) + { + { &EV_Behavior_Args, SetArgs }, + { NULL, NULL } + }; + +Shock::Shock() + { + beam = NULL; + damage = 10; + already_started = false; + random_angle = 0; + } + +void Shock::SetArgs + ( + Event *ev + ) + + { + tag_name = ev->GetString( 1 ); + + if ( ev->NumArgs() > 1 ) + { + damage = ev->GetInteger( 2 ); + } + + if ( ev->NumArgs() > 2 ) + { + random_angle = ev->GetFloat( 3 ); + } + } + +void Shock::Begin + ( + Actor &self + ) + + { + } + +qboolean Shock::Evaluate + ( + Actor &self + ) + + { + Vector tag_orig; + Vector angles; + Vector end_pos; + trace_t trace; + Vector dir; + float yaw_diff; + + + if ( !self.currentEnemy ) + return false; + + if ( self.newanimnum == -1 && !already_started ) + { + // Get tag position + if ( tag_name.length() == 0 ) + { + return false; + } + + self.GetTag( tag_name.c_str(), &tag_orig ); + + // See if the enemy is in front of us + + dir = self.currentEnemy->origin - self.origin; + angles = dir.toAngles(); + + yaw_diff = AngleNormalize180( angles[YAW] - self.angles[YAW] ); + + if ( yaw_diff < 60 && yaw_diff > -60 ) + { + // The enemy is in front of us + + angles[YAW] += G_CRandom( random_angle ); + + angles.AngleVectors( &end_pos, NULL, NULL ); + end_pos *= 500; + end_pos += tag_orig; + end_pos.z -= 100; + } + else + { + // Get end position + angles = self.angles; + + angles[YAW] += G_Random( random_angle ) - random_angle / 2; + angles[PITCH] = 0; + angles[ROLL] = 0; + + angles.AngleVectors( &end_pos, NULL, NULL ); + end_pos *= 500; + end_pos += tag_orig; + end_pos.z -= 100; + } + + trace = G_Trace( tag_orig, Vector (-15, -15, -15), Vector (15, 15, 15), end_pos, &self, MASK_SHOT, false, "ShockAttack" ); + + if ( trace.fraction < 1.0 && trace.entityNum == self.currentEnemy->entnum ) + { + end_pos = self.currentEnemy->centroid; + dir = end_pos - tag_orig; + dir.normalize(); + self.currentEnemy->Damage( &self, &self, damage, vec_zero, dir, vec_zero, 0, 0, MOD_ELECTRIC ); + } + + // Add the beam + beam = CreateBeam( NULL, "emap1", tag_orig, end_pos, 20, 1.5f, 0.2f ); + + already_started = true; + } + else if ( already_started ) + { + self.GetTag( tag_name.c_str(), &tag_orig ); + + if ( beam ) + beam->setOrigin( tag_orig ); + } + + return true; + } + +void Shock::End + ( + Actor &self + ) + + { + if ( beam ) + { + beam->ProcessEvent( EV_Remove ); + beam = NULL; + } + } + +/**************************************************************************** + + CircleAttack Class Definition + +****************************************************************************/ + +CLASS_DECLARATION( Behavior, CircleAttack, NULL ) + { + { &EV_Behavior_Args, SetArgs }, + { NULL, NULL } + }; + +CircleAttack::CircleAttack() + { + } + +void CircleAttack::SetArgs + ( + Event *ev + ) + + { + command = ev->GetString( 1 ); + direction = ev->GetString( 2 ); + } + +Actor *CircleAttack::FindClosestPart + ( + Actor &self, + float angle + ) + { + float closest_diff = 360; + int i; + part_t *part; + Entity *partent; + Actor *partact; + Vector dir; + Vector angles; + float angle_diff; + Actor *closest_part = NULL; + + for( i = 1 ; i <= self.parts.NumObjects(); i++ ) + { + part = &self.parts.ObjectAt( i ); + + partent = part->ent; + partact = ( Actor * )partent; + + if ( partact && partact->part_name == "smallarm" ) + { + dir = partact->origin - self.origin; + angles = dir.toAngles(); + + angle_diff = AngleDelta( angles[ YAW ], angle ); + + if ( angle_diff < 0 ) + { + angle_diff = -angle_diff; + } + + if ( angle_diff < closest_diff ) + { + closest_part = partact; + closest_diff = angle_diff; + } + } + } + + return closest_part; + } + +void CircleAttack::Begin + ( + Actor &self + ) + + { + float random_direction; + Actor *closest_part; + + // Pick which arm to start with + random_direction = G_Random( 360 ); + + closest_part = FindClosestPart( self, random_direction ); + if ( closest_part != NULL ) + { + first_part = closest_part; + current_part = closest_part; + + closest_part->command = command; + next_time = level.time + 0.2f; + } + + current_direction = 1; + + if ( direction == "counterclockwise" ) + { + current_direction = 0; + } + + number_of_attacks = 1; + } + +qboolean CircleAttack::Evaluate + ( + Actor &self + ) + + { + Entity *current_part_entity; + Actor *current_part_actor; + Vector dir; + Vector angles; + Actor *closest_part; + + if ( level.time >= next_time ) + { + current_part_entity = current_part; + current_part_actor = ( Actor * )current_part_entity; + + // Find the next part + + dir = current_part_actor->origin - self.origin; + angles = dir.toAngles(); + + if ( direction == "changing" ) + { + if ( number_of_attacks >= 20 ) + { + return false; + } + + if ( G_Random( 1 ) < .3 ) + { + current_direction = !current_direction; + } + } + + if ( current_direction == 1 ) + { + angles[YAW] -= 360 / 8; + } + else + { + angles[YAW] += 360 / 8; + } + + closest_part = FindClosestPart( self, angles[YAW] ); + + if ( ( closest_part == first_part ) && ( direction != "changing" ) ) + { + return false; + } + + current_part = closest_part; + + closest_part->command = command; + next_time = level.time + 0.2f; + + number_of_attacks++; + } + + return true; + } + +void CircleAttack::End + ( + Actor &self + ) + + { + } + +/**************************************************************************** + + DragEnemy Class Definition + +****************************************************************************/ + +CLASS_DECLARATION( Behavior, DragEnemy, NULL ) + { + { &EV_Behavior_Args, SetArgs }, + { NULL, NULL } + }; + +void DragEnemy::SetArgs + ( + Event *ev + ) + + { + tag_name = ev->GetString( 1 ); + damage = ev->GetInteger( 2 ); + + if ( ev->NumArgs() > 2 ) + drop = ev->GetBoolean( 3 ); + else + drop = false; + } + +void DragEnemy::Begin + ( + Actor &self + ) + + { + Actor *body; + Vector dir; + Vector angles; + + ent_to_drag = self.currentEnemy; + + attached = false; + + if ( damage > 0 && !drop ) + { + ent_to_drag->Damage( &self, &self, damage, vec_zero, vec_zero, vec_zero, 0, 0, MOD_EAT ); + } + + body = self.FindPartActor( "body" ); + + if ( body ) + { + dir = body->origin - self.origin; + angles = dir.toAngles(); + + target_yaw = angles[ YAW ]; + last_turn_time = level.time; + } + else + { + target_yaw = self.angles[ YAW ]; + } + } + +qboolean DragEnemy::Evaluate + ( + Actor &self + ) + + { + Vector orig; + str anim_name; + + if ( ent_to_drag ) + { + if ( drop && damage > 0 ) + { + if ( self.GetTag( tag_name.c_str(), &orig ) ) + { + if ( ent_to_drag->isClient() ) + { + orig[ 2 ] -= 85; + } + else + { + offset[ 2 ] = ( ent_to_drag->absmin[ 2 ] - ent_to_drag->absmax[ 2 ] ) * 0.5f; + + if ( offset[ 2 ] < -40 ) + { + offset[ 2 ] -= 25; + } + orig += offset; + } + + ent_to_drag->setOrigin( orig ); + } + + ent_to_drag->Damage( &self, &self, damage, vec_zero, vec_zero, vec_zero, 0, 0, MOD_EAT ); + } + + if ( ent_to_drag->deadflag ) + return false; + + anim_name = self.AnimName(); + + if ( ( anim_name == "raise" ) && ( self.newanim == "" ) ) + { + if ( !attached ) + { + Event *ev; + + if ( damage > 0 ) + { + if ( ent_to_drag->isClient() ) + { + offset[ 2 ] -= 85; + } + else + { + offset[ 2 ] = ( ent_to_drag->absmin[ 2 ] - ent_to_drag->absmax[ 2 ] ) * 0.5f; + + if ( offset[ 2 ] < -40 ) + { + offset[ 2 ] -= 25; + } + } + + ev = new Event( EV_Attach ); + ev->AddEntity( &self ); + ev->AddString( tag_name.c_str() ); + ev->AddInteger( qfalse ); + ev->AddVector( offset ); + ent_to_drag->ProcessEvent( ev ); + + ent_to_drag->flags |= FL_PARTIAL_IMMOBILE; + } + + attached = true; + } + + if ( target_yaw != self.angles[ YAW ] ) + { + float yaw_diff = target_yaw - self.angles[ YAW ]; + + if ( yaw_diff > 180 ) + { + target_yaw -= 360; + yaw_diff -= 360; + } + + if ( yaw_diff < -180 ) + { + target_yaw += 360; + yaw_diff += 360; + } + + if ( yaw_diff < 0 ) + { + self.angles[ YAW ] -= 90 * (level.time - last_turn_time); + + if ( self.angles[ YAW ] < 0 ) + { + self.angles[ YAW ] += 360; + } + + if ( self.angles[ YAW ] < target_yaw ) + { + self.angles[ YAW ] = target_yaw; + } + + self.setAngles( self.angles ); + } + else if ( yaw_diff > 0 ) + { + self.angles[ YAW ] += 90 * (level.time - last_turn_time); + + if ( self.angles[ YAW ] > 360 ) + { + self.angles[ YAW ] -= 360; + } + + if ( self.angles[ YAW ] > target_yaw ) + { + self.angles[ YAW ] = target_yaw; + } + + self.setAngles( self.angles ); + } + + last_turn_time = level.time; + } + } + } + + return true; + } + +void DragEnemy::End + ( + Actor &self + ) + + { + Vector orig; + Event *ev; + trace_t trace; + + if ( drop || strcmp( self.currentState->getName(), "SUICIDE" ) == 0 ) + { + ent_to_drag->flags &= ~FL_PARTIAL_IMMOBILE; + + ev = new Event( EV_Detach ); + ent_to_drag->ProcessEvent( ev ); + + ent_to_drag->setSolidType( SOLID_BBOX ); + + if ( self.GetTag( tag_name.c_str(), &orig ) ) + { + trace = G_Trace( orig - "0 0 100", ent_to_drag->mins, ent_to_drag->maxs, orig, ent_to_drag, ent_to_drag->edict->clipmask, false, "DragEnemy" ); + + if ( trace.allsolid ) + gi.DPrintf( "Dropping entity into a solid!\n" ); + + ent_to_drag->setOrigin( trace.endpos ); + + /* if ( ent_to_drag->isClient() ) + { + offset[2] = -85; + } + else + { + offset[2] = ( ent_to_drag->absmin[2] - ent_to_drag->absmax[2] ) * 0.5; + + if ( offset[2] < -40 ) + { + offset[2] -= 25; + } + } + + ent_to_drag->setOrigin( orig + offset ); */ + } + } + + ent_to_drag->velocity = "0 0 -20"; + } + +/**************************************************************************** + + Spin Class Definition + +****************************************************************************/ + +CLASS_DECLARATION( Behavior, Spin, NULL ) + { + { &EV_Behavior_Args, SetArgs }, + { NULL, NULL } + }; + +Spin::Spin() + { + speed = 500.0; + } + +void Spin::SetArgs + ( + Event *ev + ) + + { + speed = ev->GetFloat( 1 ); + } + +void Spin::Begin + ( + Actor &self + ) + + { + SpinningPlant *spinningPlant = (SpinningPlant *)&self; + + if ( spinningPlant->spinner_clip ) + { + spinningPlant->spinner_clip->avelocity.y = speed; + } + } + +qboolean Spin::Evaluate + ( + Actor &self + ) + + { + return true; + } + +void Spin::End + ( + Actor &self + ) + + { + SpinningPlant *spinningPlant = ( SpinningPlant * )&self; + + if ( spinningPlant->spinner_clip ) + { + spinningPlant->spinner_clip->avelocity.y = 0; + } + } + +/**************************************************************************** + + Digest Class Definition + +****************************************************************************/ + +CLASS_DECLARATION( Behavior, Digest, NULL ) + { + { &EV_Behavior_AnimDone, AnimDone }, + { NULL, NULL } + }; + + +void Digest::ShowInfo + ( + Actor &self + ) + + { + Behavior::ShowInfo( self ); + } + +void Digest::Begin + ( + Actor &self + ) + + { + float range = 150; + Entity *ent_in_range; + + // Init some stuff + spitting = false; + spit = false; + yuck = false; + + self.SetAnim( "digest" ); + + // Default digest time to current level time + + digest_time = level.time; + + // See if we caught anything + + ent_in_range = findradius( NULL, self.origin, range ); + + while ( ent_in_range ) + { + if ( + ( &self != ent_in_range ) && + ( ent_in_range->movetype != MOVETYPE_NONE ) && + ( ent_in_range->movetype != MOVETYPE_STATIONARY ) && + !(ent_in_range->flags & FL_NOTARGET) && + !ent_in_range->deadflag && + ent_in_range->health > 0 + ) + { + if ( Vector( self.origin - ent_in_range->origin ).length() < range ) + Eat( ent_in_range, self ); + } + + ent_in_range = findradius( ent_in_range, self.origin, range ); + } + + // Make sure to spit out immediately if its yucky + + if ( yuck ) + digest_time = 0; + + // Make sure we are solid will digesting things + + self.setContents( CONTENTS_SOLID ); + self.setSize( "-32 -32 0", "32 32 192" ); + } + +void Digest::Eat + ( + Entity *food, + Actor &self + ) + + { + float mass; + SafePtr food_ptr = food; + + // Hide the caught entity + + food->hideModel(); + food->flags |= FL_IMMOBILE; + + food->origin[0] = self.centroid[0]; + food->origin[1] = self.centroid[1]; + food->origin[2] = self.centroid[2]; + + food->setOrigin( food->origin ); + + // See if we want to eat this or spit out immediately + + if ( food->edict->s.eFlags & EF_ANTISBJUICE ) + yuck = true; + + // Add to the digest time + + mass = food->mass; + + if ( mass < 50 ) + mass = 50; + + if ( mass > 300 ) + mass = 300; + + digest_time += ( mass / 50 ) + 1; + + foodlist.AddObject( food_ptr ); + + // Extinguish fire on this entity if on fire + + food->ProcessEvent( EV_Sentient_StopOnFire ); + + if ( !yuck && food->isSubclassOf( Player ) ) + food->Sound( "snd_longdeath" ); + } + +qboolean Digest::Evaluate + ( + Actor &self + ) + + { + Vector dir; + Entity *food; + int i; + float m; + Vector momentum; + Entity *targetent; + qboolean killed; + + if ( !spitting && digest_time < level.time ) + { + if ( foodlist.NumObjects() > 0 ) + { + // Done digesting, start spitting anim + spitting = true; + anim_done = false; + self.SetAnim( "spit", EV_Actor_NotifyBehavior ); + spit_time = level.time + 0.25; + } + else + { + self.setSize( "-64 -64 0", "64 64 32" ); + self.ProcessEvent( EV_ActorOnlyShootable ); + return false; + } + } + + if ( spitting && !spit && spit_time < level.time) + { + spit = true; + + self.setSize( "-64 -64 0", "64 64 32" ); + self.ProcessEvent( EV_ActorOnlyShootable ); + + // Spit all of the digested entities out + for( i = 1 ; i <= foodlist.NumObjects() ; i++ ) + { + food = foodlist.ObjectAt( i ); + + if ( food != NULL ) + { + killed = false; + + // Only damage the entity if we digested it + if ( !yuck ) + { + food->Damage( &self, &self, 1000, Vector (0, 0, 0), Vector (0, 0, 0), Vector (0, 0, 0), 0, 0, MOD_EAT ); + + if ( food->health <= 0 ) + killed = true; + } + + food->origin[0] = self.centroid[0]; + food->origin[1] = self.centroid[1]; + food->origin[2] = self.centroid[2]; + + if ( food->mass < 50 ) + { + m = 50; + } + else + { + m = food->mass; + } + + if ( killed ) + { + Event *event; + int number_of_gibs; + + // Entity was killed, just spit out some gibs + + food->origin[2] += 60; + + food->setOrigin( food->origin ); + + number_of_gibs = ( ( m - 50 ) / 300 ) * 5 + 2; + + if ( number_of_gibs > 7 ) + number_of_gibs = 7; + + event = new Event( EV_Sentient_SpawnBloodyGibs ); + event->AddInteger( number_of_gibs ); + food->PostEvent( event, 0 ); + + event = new Event( EV_Sentient_SpawnBloodyGibs ); + event->AddInteger( number_of_gibs ); + food->PostEvent( event, 0 ); + + if ( !food->isSubclassOf( Player ) ) + food->PostEvent( EV_Remove, 0 ); + } + else + { + // Entity wasn't killed spit it out + + food->setOrigin( food->origin ); + + food->showModel(); + food->flags ^= FL_IMMOBILE; + + // Spit the entity out + + targetent = NULL; + if ( self.target.length() > 0 ) + { + // Spit the entity to the targeted position + targetent = G_FindTarget( &self, self.target.c_str() ); + } + + if ( targetent ) + { + food->velocity = G_CalculateImpulse( food->origin, targetent->origin, 350, 1 ); + } + else + { + // Spit the entity to a random place + dir[0] = G_Random( 200 ) - 100; + dir[1] = G_Random( 200 ) - 100; + dir[2] = 200; + + dir.normalize(); + + momentum = dir * ( 500.0f * 500 / m ); + food->velocity += momentum; + } + food->VelocityModified(); + } + } + } + } + + if ( spitting && anim_done ) + { + // We are done spitting + return false; + } + + return true; + } + +void Digest::AnimDone + ( + Event *ev + ) + + { + anim_done = true; + } + +void Digest::End + ( + Actor &self + ) + + { + } + +/**************************************************************************** + + Teleport Class Definition + +****************************************************************************/ + +#define TELEPORT_BEHIND 0 +#define TELEPORT_TOLEFT 1 +#define TELEPORT_TORIGHT 2 +#define TELEPORT_INFRONT 3 + +#define TELEPORT_NUMBER_OF_POSITIONS 4 + +CLASS_DECLARATION( Behavior, Teleport, NULL ) + { + { NULL, NULL } + }; + + +void Teleport::ShowInfo + ( + Actor &self + ) + + { + Behavior::ShowInfo( self ); + } + +void Teleport::Begin + ( + Actor &self + ) + + { + + } + +qboolean Teleport::TestPosition + ( + Actor &self, + int test_pos, + Vector &good_position, + qboolean use_enemy_dir + ) + { + Vector test_position; + Vector enemy_angles; + Vector enemy_forward; + Vector enemy_left; + trace_t trace; + + + // Get the position to test + + if ( use_enemy_dir ) + { + // Get the enemy direction info + + enemy_angles = self.currentEnemy->angles; + enemy_angles.AngleVectors( &enemy_forward, &enemy_left ); + + test_position = self.currentEnemy->origin; + + if ( test_pos == TELEPORT_BEHIND ) + test_position -= enemy_forward * 75; + else if ( test_pos == TELEPORT_INFRONT ) + test_position += enemy_forward * 75; + else if ( test_pos == TELEPORT_TOLEFT ) + test_position += enemy_left * 75; + else + test_position -= enemy_left * 75; + } + else + { + test_position = self.currentEnemy->origin; + + if ( test_pos == TELEPORT_BEHIND ) + test_position += "-60 0 0"; + else if ( test_pos == TELEPORT_INFRONT ) + test_position += "60 0 0"; + else if ( test_pos == TELEPORT_TOLEFT ) + test_position += "0 -60 0"; + else + test_position += "0 60 0"; + } + + //test_position += "0 0 16"; + test_position += "0 0 64"; + + // Test to see if we can fit at the new position + + trace = G_Trace( test_position, self.mins, self.maxs, test_position - "0 0 1000", &self, self.edict->clipmask, false, "Teleport::TestPosition" ); + + if ( trace.allsolid || trace.startsolid ) + //if ( trace.allsolid ) + return false; + + // Make sure we can see the enemy from this position + + //if ( !self.CanSeeEnemyFrom( trace.endpos ) ) + if ( !self.IsEntityAlive( self.currentEnemy ) || !self.CanSeeFrom( trace.endpos, self.currentEnemy ) ) + return false; + + // This is a good position + + good_position = trace.endpos; + return true; + } + +qboolean Teleport::Evaluate + ( + Actor &self + ) + + { + int current_position; + float random_number; + Vector teleport_position; + qboolean teleport_position_found; + Vector new_position; + int i; + Vector dir; + Vector angles; + + + // Make sure we stll have an enemy to teleport near + + if ( !self.currentEnemy ) + return false; + + // Default the teleport position to where we are now + + teleport_position = self.origin; + teleport_position_found = false; + + // Determine which position to try first + + random_number = G_Random(); + + if ( random_number < .5 ) + current_position = TELEPORT_BEHIND; + else if ( random_number < .7 ) + current_position = TELEPORT_TOLEFT; + else if ( random_number < .9 ) + current_position = TELEPORT_TORIGHT; + else + current_position = TELEPORT_INFRONT; + + // Try positions + + for( i = 0 ; i < TELEPORT_NUMBER_OF_POSITIONS ; i++ ) + { + // Test this position + + if ( TestPosition( self, current_position, new_position, true ) ) + { + teleport_position = new_position; + teleport_position_found = true; + break; + } + + // Try the next position + + current_position++; + + if ( current_position >= TELEPORT_NUMBER_OF_POSITIONS ) + current_position = 0; + } + + if ( !teleport_position_found ) + { + // Try again with not using the enemies angles + + if ( current_position >= TELEPORT_NUMBER_OF_POSITIONS ) + current_position = 0; + + for( i = 0 ; i < TELEPORT_NUMBER_OF_POSITIONS ; i++ ) + { + // Test this position + + if ( TestPosition( self, current_position, new_position, false ) ) + { + teleport_position = new_position; + teleport_position_found = true; + break; + } + + // Try the next position + + current_position++; + + if ( current_position >= TELEPORT_NUMBER_OF_POSITIONS ) + current_position = 0; + } + } + + // Do teleport stuff + + if ( teleport_position_found ) + { + self.setOrigin( teleport_position ); + self.NoLerpThisFrame(); + + dir = self.currentEnemy->origin - teleport_position; + angles = dir.toAngles(); + + angles[ROLL] = 0; + angles[PITCH] = 0; + + self.setAngles( angles ); + + if ( self.currentEnemy->isSubclassOf( Player ) ) + { + Player *player = (Player *)(Entity *)self.currentEnemy; + + player->RemoveTarget( &self ); + } + } + + return false; + } + +void Teleport::End + ( + Actor &self + ) + + { + } + +/**************************************************************************** + + TeleportToPosition Class Definition + +****************************************************************************/ + + +CLASS_DECLARATION( Behavior, TeleportToPosition, NULL ) + { + { &EV_Behavior_Args, SetArgs }, + { NULL, NULL } + }; + +void TeleportToPosition::ShowInfo + ( + Actor &self + ) + + { + Behavior::ShowInfo( self ); + } + +void TeleportToPosition::SetArgs + ( + Event *ev + ) + + { + teleport_position_name = ev->GetString( 1 ); + number_of_teleport_positions = ev->GetInteger( 2 ); + } + +void TeleportToPosition::Begin + ( + Actor &self + ) + + { + } + +qboolean TeleportToPosition::Evaluate + ( + Actor &self + ) + + { + Vector dir; + Vector angles; + trace_t trace; + str pathnode_name; + PathNode *goal; + Vector teleport_position; + Vector attack_position; + float half_height; + Animate *effect; + + + // Get the pathnode name to teleport to + + pathnode_name = teleport_position_name; + pathnode_name += (int)( G_Random( number_of_teleport_positions ) + 1 ); + + // Find the path node + + goal = AI_FindNode( pathnode_name ); + + if ( !goal ) + { + gi.DPrintf( "Can't find position %s\n", pathnode_name.c_str() ); + return false; + } + + // Set the teleport position + + teleport_position = goal->origin; + + // Kill anything at this position + + half_height = self.maxs.z / 2; + attack_position = teleport_position; + attack_position.z += half_height; + + MeleeAttack( attack_position, attack_position, 10000, &self, MOD_TELEFRAG, self.maxs.x, -half_height, half_height, 0 ); + + // Test to see if we can fit at the new position + + trace = G_Trace( teleport_position + "0 0 64", self.mins, self.maxs, teleport_position - "0 0 128", &self, MASK_PATHSOLID, false, "TeleportToPosition" ); + //trace = G_Trace( teleport_position, self.mins, self.maxs, teleport_position, &self, MASK_PATHSOLID, false, "TeleportToPosition" ); + + if ( trace.allsolid ) + { + gi.DPrintf( "Failed to teleport to %s\n", goal->targetname.c_str() ); + return false; + } + + teleport_position = trace.endpos; + + // Do teleport stuff + + // Spawn in teleport effect at old position + + effect = new Animate; + effect->setModel( "fx_teleport3.tik" ); + effect->setOrigin( self.origin ); + effect->setScale( 2 ); + effect->setSolidType( SOLID_NOT ); + effect->RandomAnimate( "idle", EV_Remove ); + //effect->Sound( "snd_teleport" ); + + // Set new position + + self.setOrigin( teleport_position ); + + // Spawn in teleport effect at new position + + effect = new Animate; + effect->setModel( "fx_teleport3.tik" ); + effect->setOrigin( self.origin ); + effect->setScale( 2 ); + effect->setSolidType( SOLID_NOT ); + effect->RandomAnimate( "idle", EV_Remove ); + //effect->Sound( "snd_teleport" ); + + self.NoLerpThisFrame(); + + if ( self.currentEnemy ) + { + dir = self.currentEnemy->origin - teleport_position; + angles = dir.toAngles(); + + angles[ROLL] = 0; + angles[PITCH] = 0; + + self.setAngles( angles ); + + if ( self.currentEnemy->isSubclassOf( Player ) ) + { + Player *player = (Player *)(Entity *)self.currentEnemy; + + player->RemoveTarget( &self ); + } + } + + return false; + } + +void TeleportToPosition::End + ( + Actor &self + ) + + { + } + +/**************************************************************************** + + GhostAttack Class Definition + +****************************************************************************/ + +#define GHOST_ATTACK_START 0 +#define GHOST_ATTACK_END 1 + +#define GHOST_ATTACK_SPEED 350 + +CLASS_DECLARATION( Behavior, GhostAttack, NULL ) + { + { &EV_Behavior_Args, SetArgs }, + { NULL, NULL } + }; + +void GhostAttack::SetArgs + ( + Event *ev + ) + + { + real_attack = ev->GetBoolean( 1 ); + } + + +void GhostAttack::ShowInfo + ( + Actor &self + ) + + { + Behavior::ShowInfo( self ); + } + +void GhostAttack::Begin + ( + Actor &self + ) + + { + mode = GHOST_ATTACK_START; + + fly.Begin( self ); + fly.SetTurnSpeed( 25 ); + fly.SetRandomAllowed( false ); + fly.SetSpeed( GHOST_ATTACK_SPEED ); + + if ( self.currentEnemy ) + attack_position = self.currentEnemy->centroid; + else + attack_position = self.origin; + + if ( !real_attack ) + { + attack_position[0] += G_CRandom( 300 ); + attack_position[1] += G_CRandom( 300 ); + attack_position[2] += G_Random( 100 ); + } + + fly.SetGoalPoint( attack_position ); + + attack_dir = attack_position - self.origin; + + if ( attack_dir == vec_zero ) + attack_dir = "1 1 0"; + + attack_dir.normalize(); + + self.Sound( "snd_fadein", CHAN_VOICE ); + } + +qboolean GhostAttack::Evaluate + ( + Actor &self + ) + + { + Vector dir; + float dist; + float zdist; + Vector new_pos; + float new_alpha; + float light_radius; + float r, g, b; + qboolean success; + Vector start; + Vector end; + Event *event; + + + if ( !self.currentEnemy ) + return false; + + if ( mode == GHOST_ATTACK_START ) + { + // Move closer to the enemy + + fly.Evaluate( self ); + + // Get the new distance info + + dir = attack_position - self.origin; + + dist = dir.length(); + + zdist = dir.z; + + if ( zdist < 0 ) + zdist = -zdist; + + dir.z = 0; + + // If we are close enough change to shootable_only + + if ( real_attack && dist < 200 ) + { + // Attackable now + + self.setSolidType( SOLID_BBOX ); + self.setContents( CONTENTS_SHOOTABLE_ONLY ); + + event = new Event( EV_Actor_SetTargetable ); + event->AddInteger( 1 ); + self.ProcessEvent( event ); + } + + // If we are close enough damage enemy and goto end mode + + start = self.origin; + end = self.origin + attack_dir * 1; + + if ( real_attack ) + { + success = MeleeAttack( start, end, 7.5, &self, MOD_LIFEDRAIN, 32, 0, 64, 0 ); + self.AddStateFlag( STATE_FLAG_MELEE_HIT ); + } + else + success = false; + + if ( success || dist <= GHOST_ATTACK_SPEED / 40 ) + { + // Attack mode is done go to retreat mode + + if ( self.attack_blocked && self.attack_blocked_time == level.time ) + { + Vector retreat_angles; + + dir = attack_dir * -1; + + retreat_angles = dir.toAngles(); + retreat_angles[YAW] += G_CRandom( 45 ); + retreat_angles[PITCH] += G_CRandom( 30 ); + retreat_angles.AngleVectors( &dir ); + + dir *= 500; + + self.setAngles( retreat_angles ); + } + else + { + dir = attack_dir; + + dir.z = 0; + dir.normalize(); + dir *= 1000; + dir.z = 300; + } + + retreat_position = self.origin + dir; + + fly.SetGoalPoint( retreat_position ); + + mode = GHOST_ATTACK_END; + } + + // Fade in depending on how close we are to attack position + + if ( dist > 400 ) + new_alpha = 0; + else + new_alpha = ( 400 - dist ) / 400; + + if ( new_alpha > 0.4 ) + new_alpha = 0.4; + + r = new_alpha / 0.4; + g = new_alpha / 0.4; + b = new_alpha / 0.4; + + light_radius = 0; + + G_SetConstantLight( &self.edict->s.constantLight, &r, &g, &b, &light_radius ); + + self.setAlpha( new_alpha ); + } + else + { + // Move away from enemy + + fly.Evaluate( self ); + + // Get the new distance info + + dir = attack_position - self.origin; + dist = dir.length(); + + if ( real_attack && dist > 200 ) + { + // Not attackable again + + self.setSolidType( SOLID_NOT ); + self.setContents( 0 ); + + event = new Event( EV_Actor_SetTargetable ); + event->AddInteger( 0 ); + self.ProcessEvent( event ); + } + + // Fade out depending on how far we are from the attack position + + if ( dist > 400 ) + new_alpha = 0; + else + new_alpha = ( 400 - dist ) / 400; + + if ( new_alpha > 0.4 ) + new_alpha = 0.4; + + r = new_alpha / 0.4; + g = new_alpha / 0.4; + b = new_alpha / 0.4; + + light_radius = 0; + + G_SetConstantLight( &self.edict->s.constantLight, &r, &g, &b, &light_radius ); + + self.setAlpha( new_alpha ); + + // See if we are far enough to be done + + if ( new_alpha == 0 ) + return false; + } + return true; + } + +void GhostAttack::End + ( + Actor &self + ) + + { + // Make sure we can't be shot any more + + self.setSolidType( SOLID_NOT ); + self.setContents( 0 ); + + fly.End( self ); + } + +/**************************************************************************** + + Levitate Class Definition + +****************************************************************************/ + +CLASS_DECLARATION( Behavior, Levitate, NULL ) + { + { &EV_Behavior_Args, SetArgs }, + { NULL, NULL } + }; + +void Levitate::SetArgs + ( + Event *ev + ) + + { + distance = ev->GetFloat( 1 ); + speed = ev->GetFloat( 2 ); + } + + +void Levitate::ShowInfo + ( + Actor &self + ) + + { + Behavior::ShowInfo( self ); + } + +void Levitate::Begin + ( + Actor &self + ) + + { + final_z = self.origin.z + distance; + } + +qboolean Levitate::Evaluate + ( + Actor &self + ) + + { + trace_t trace; + Vector start; + Vector end; + + + start = self.origin; + end = self.origin; + + if ( final_z < self.origin.z ) + { + end.z -= speed; + + if ( end.z < final_z ) + end.z = final_z; + } + else + { + end.z += speed; + + if ( end.z > final_z ) + end.z = final_z; + } + + trace = G_Trace( start, self.mins, self.maxs, end, &self, self.edict->clipmask, false, "Levitate" ); + + if ( trace.fraction != 1 ) + return false; + + if ( end.z == final_z ) + return false; + + self.setOrigin( trace.endpos ); + + return true; + } + +void Levitate::End + ( + Actor &self + ) + + { + } + +/**************************************************************************** +***************************************************************************** + + Utility functions + +***************************************************************************** +****************************************************************************/ + + + +Vector ChooseRandomDirection + ( + Actor &self, + Vector previousdir, + float *time, + int disallowcontentsmask, + qboolean usepitch + ) + { + //static float x[ 9 ] = { 0, 22, -22, 45, -45, 0, 22, -22, 45 }; + static float x[ 9 ] = { 0, 22, -22, 0, 22 }; + Vector dir; + Vector ang; + Vector bestdir; + Vector newdir; + Vector step; + Vector endpos; + Vector groundend; + float bestfraction; + trace_t trace; + trace_t groundtrace; + int i; + int k; + int t; + int u; + int contents; + Vector centroid; + float random_yaw; + float movespeed; + + if ( self.movespeed != 1 ) + movespeed = self.movespeed; + else + movespeed = 100; + + centroid = self.centroid - self.origin; + + step = Vector( 0, 0, STEPSIZE ); + bestfraction = -1; + bestdir = self.origin; + + random_yaw = G_Random( 360 ); + + for( i = 0; i <= 8; i++ ) + { + t = random_yaw + i * 45; + + ang.y = self.angles.y + t; + + if ( usepitch ) + { + u = ( int )G_Random( 5 ); + + //for( k = 0; k < 5; k++ ) + for( k = 0; k < 3; k++ ) + { + ang.x = x[ k + u ]; + ang.AngleVectors( &dir, NULL, NULL ); + + dir *= movespeed * (*time); + dir += self.origin; + trace = G_Trace( self.origin, self.mins, self.maxs, dir, &self, self.edict->clipmask, false, "ChooseRandomDirection 1" ); + + if ( !trace.startsolid && !trace.allsolid ) + { + newdir = Vector( trace.endpos ); + + if ( disallowcontentsmask ) + { + contents = gi.pointcontents( ( newdir + centroid ), 0 ); + + if ( contents & disallowcontentsmask ) + continue; + } + + if ( + ( trace.fraction > bestfraction ) && + ( newdir != bestdir ) && + ( newdir != previousdir ) + ) + { + bestdir = newdir; + bestfraction = trace.fraction; + + if ( bestfraction > .9 ) + { + *time *= bestfraction; + + return bestdir; + } + } + } + } + } + else + { + ang.x = 0; + ang.AngleVectors( &dir, NULL, NULL ); + + endpos = self.origin + dir * movespeed * (*time) + step; + + trace = G_Trace( self.origin + step, self.mins, self.maxs, endpos, &self, self.edict->clipmask, false, "ChooseRandomDirection 2" ); + + if ( !trace.startsolid && !trace.allsolid ) + { + newdir = Vector( trace.endpos ); + + if ( disallowcontentsmask ) + { + contents = gi.pointcontents( ( newdir + centroid ), 0 ); + + if ( contents & disallowcontentsmask ) + continue; + } + + if ( + ( trace.fraction > bestfraction ) && + ( newdir != bestdir ) && + ( newdir != previousdir ) + ) + { + groundend = endpos - step * 2; + + groundtrace = G_Trace( endpos, self.mins, self.maxs, groundend, &self, self.edict->clipmask, false, "Chase::ChooseRandomDirection 3" ); + + if ( groundtrace.fraction == 1 ) + trace.fraction /= 2; + + if ( trace.fraction > bestfraction ) + { + bestdir = newdir; + bestfraction = trace.fraction; + + if ( bestfraction > .9 ) + { + *time *= bestfraction; + + return bestdir; + } + } + } + } + } + } + + if ( bestfraction > 0 ) + { + *time *= bestfraction; + } + else + { + *time = 0; + } + + return bestdir; + } diff --git a/source/source/fgame/behavior.h b/source/source/fgame/behavior.h new file mode 100644 index 0000000..44f3820 --- /dev/null +++ b/source/source/fgame/behavior.h @@ -0,0 +1,1887 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/behavior.h $ +// $Revision:: 62 $ +// $Author:: Steven $ +// $Date:: 7/27/00 10:55p $ +// +// Copyright (C) 1998 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/behavior.h $ +// +// 62 7/27/00 10:55p Steven +// Improved DragEnemy stuff. +// +// 61 7/21/00 3:47p Steven +// Improved teleport a lot. +// +// 60 7/18/00 4:27p Steven +// Added speed to FlyClimb. +// +// 59 7/13/00 3:43p Steven +// Added next_think_time to GetCloseToEnemy for simple path finding. +// +// 58 7/12/00 11:37a Steven +// Added return_to_original_location to investigate. +// +// 57 7/07/00 8:06a Steven +// Improved the investigation behavior to always look towards the noise +// position. +// +// 56 7/05/00 2:28p Steven +// Improved fleeing behavior a lot. +// +// 55 7/02/00 1:11p Steven +// Changed TeleportToPosition to use named pathnodes instead of hardcoded +// positions. +// +// 54 6/30/00 10:35a Steven +// Added max_pains to Pain behavior. +// +// 53 6/22/00 3:45p Markd +// fixed a bunch of saved game issues +// +// 52 6/07/00 5:34p Steven +// Added TeleportToPosition and Levitate. +// +// 51 6/05/00 3:41p Steven +// Adde GotoDeadEnemy. +// +// 50 5/27/00 2:32p Steven +// Added FlyCloseToPlayer. +// +// 49 5/25/00 7:52p Markd +// 2nd pass save game stuff +// +// 48 5/24/00 4:08p Steven +// Added a forever variable to the HeadWatch behavior. +// +// 47 5/24/00 3:14p Markd +// first phase of save/load games +// +// 46 5/20/00 4:47p Steven +// Improved Shock behavior. +// +// 45 5/06/00 3:00p Steven +// Added speed to FlyCloseToEnemy and fixed actor's getting stuck on top of +// the player. +// +// 44 5/03/00 11:27a Steven +// Added some sounds to the ghost attack and added the spooky ghost attack. +// +// 43 4/28/00 5:40p Steven +// Added use_last_known_pos to TurnToEnemy and BurrowAttack. +// +// 42 4/25/00 10:12a Steven +// Lots of improvements to the GhostAttack behavior. +// +// 41 4/15/00 3:39p Steven +// Made it so the pain animation will randomly choose between all available +// pain animations not just the first 2. +// +// 40 4/13/00 5:34p Steven +// Added the Teleport behavior and the GhostAttack behavior. +// +// 39 4/08/00 3:58p Steven +// Took out walking stuff from PickupEntity. +// +// 38 4/01/00 2:39p Steven +// Made it so actor can fly clockwise or counter-clockwise in FlyCircle. +// +// 37 4/01/00 2:00p Steven +// Added a forever flag to GetCloseToEnemy. +// +// 36 3/30/00 2:03p Steven +// More work on TorsoTurn. +// +// 35 3/28/00 6:49p Steven +// Lots of improvements to TorsoTurn. +// +// 34 3/17/00 11:52a Steven +// Added jumping stuff. +// +// 33 3/14/00 12:07p Steven +// Added walkwatch stuff. +// +// 32 3/07/00 11:51a Steven +// Made lots of tweaks to the CircleEnemy behavior. +// +// 31 3/03/00 5:26p Steven +// Fixed up some save stuff. +// +// 30 2/24/00 7:07p Steven +// Made talk so it would not stand up if already sitting and made it so the +// actor always tries to face whoever its talking to. +// +// 29 2/24/00 5:26p Steven +// Added a max speed parm to head watch. +// +// 28 2/23/00 11:57a Steven +// Moved utility behaviors to actor. +// +// 27 2/21/00 7:00p Steven +// Added a TorsoTurn behavior. +// +// 26 2/17/00 5:43p Steven +// Moved NearestNode stuff out of Investigate to Actor. +// +// 25 2/16/00 6:04p Steven +// Tweaked the investigate behavior a lot. +// +// 24 2/16/00 10:43a Steven +// Added a Pain behavior, made an option for FlyWander to make the actor try +// to fly upwards, and improved the Investigate behavior. +// +// 23 2/11/00 6:41p Steven +// Improved headwatch a little and added pickup/throw. +// +// 22 2/07/00 6:45p Steven +// Made it so the FlyCloseToEnemy behavior doesn't choose a new goal so often. +// +// 21 2/04/00 1:55p Steven +// Added the talk behavior. +// +// 20 2/02/00 1:39p Steven +// Added turning animations to TurnTo, added the HeadWatch behavior, and +// cleaned up flying code a little more. +// +// 19 1/29/00 5:28p Steven +// Improved the BurrowAttack and DragEnemy behaviors. +// +// 18 1/27/00 2:54p Steven +// Improved a lot of the flying code. +// +// 17 1/21/00 6:45p Steven +// Made flee use chase instead of FollowPath. +// +// 16 1/19/00 12:12p Steven +// Improved the TurnToEnemy and BurrowAttack behaviors. +// +// 15 1/14/00 5:02p Steven +// Added gotonextstage and burrowattack behaviors. +// +// 14 1/13/00 7:08p Steven +// Lots and lots of cleanup. +// +// 13 1/07/00 8:12p Jimdose +// cleaning up unused code +// +// 12 1/06/00 6:50p Steven +// Cleaned up GetCloseToEnemy. +// +// 11 12/22/99 5:14p Steven +// Fixed some animation issues, some general clean up, and removed +// FemaleLympAttack. +// +// 10 12/17/99 5:51p Steven +// Added the following behaviors : TurnTowardsEnemy, FlyCircle, FlyDive, and +// FlyClimb. +// +// 9 12/01/99 3:43p Steven +// Added a land behavior for flying creatures. +// +// 8 11/24/99 11:05a Steven +// More work on flying. +// +// 7 11/19/99 2:05p Steven +// Made sure all behavior stuff would save correctly. +// +// 6 11/19/99 11:33a Steven +// Added new behaviors: CircleEnemy, ShockWater, Shock, and CircleAttack. +// +// 5 11/10/99 6:11p Steven +// Added the FlyCloseToEnemy behavior. +// +// 4 10/28/99 6:07p Steven +// Improved the drag behavior. +// +// 3 10/27/99 10:29a Steven +// Added GetNearestEnemy behavior and added more to the DragEnemy behavior. +// +// 2 10/19/99 7:11p Steven +// Lots of AI work. +// +// 1 9/10/99 10:53a Jimdose +// +// 1 9/08/99 3:15p Aldie +// +// 10 8/28/99 7:06p Steven +// Added a speed parameter to the spin behavior. +// +// 9 8/28/99 11:46a Steven +// Added some spinning plant stuff. +// +// 8 8/27/99 5:05p Steven +// Worked on digest behavior,and added spin. +// +// 7 8/18/99 3:23p Steven +// Added to Digest behavior. +// +// 6 8/17/99 4:59p Steven +// New digest behavior for the Sucknblaugh plant. +// +// 5 8/11/99 5:57p Steven +// More general AI work. +// +// 4 8/05/99 9:15a Steven +// New AI stuff. +// +// DESCRIPTION: +// Standard class for creating AI behaviors +// + +#ifndef __BEHAVIOR_H__ +#define __BEHAVIOR_H__ + +#include "g_local.h" +#include "entity.h" +#include "path.h" +#include "steering.h" +#include "beam.h" +#include "sentient.h" + +extern Event EV_Behavior_Args; +extern Event EV_Behavior_AnimDone; + +class Actor; + +class Behavior : public Listener + { + protected: + PathNodePtr movegoal; + + public: + CLASS_PROTOTYPE( Behavior ); + + Behavior(); + + virtual void ShowInfo( Actor &self ); + virtual void Begin( Actor &self ); + virtual qboolean Evaluate( Actor &self ); + virtual void End( Actor &self ); + virtual void Archive( Archiver &arc ); + }; + +inline void Behavior::Archive + ( + Archiver &arc + ) + { + Listener::Archive( arc ); + + arc.ArchiveSafePointer( &movegoal ); + } + +typedef SafePtr BehaviorPtr; + +class Idle : public Behavior + { + private: + float nexttwitch; + + public: + CLASS_PROTOTYPE( Idle ); + + void ShowInfo( Actor &self ); + void Begin( Actor &self ); + qboolean Evaluate( Actor &self ); + void End( Actor &self ); + virtual void Archive( Archiver &arc ); + }; + +inline void Idle::Archive + ( + Archiver &arc + ) + { + Behavior::Archive( arc ); + + arc.ArchiveFloat( &nexttwitch ); + } + +class Pain : public Behavior + { + private: + int current_pain_type; + int pain_anim_number; + qboolean anim_done; + int number_of_pains; + int max_pains; + + public: + CLASS_PROTOTYPE( Pain ); + + void AnimDone( Event *ev ); + + void SetPainAnim( Actor &self, int new_pain_type, int new_anim_number ); + int GetNumberOfPainAnims( Actor &self, int new_pain_type ); + void Begin( Actor &self ); + qboolean Evaluate( Actor &self ); + void End( Actor &self ); + virtual void Archive( Archiver &arc ); + }; + +inline void Pain::Archive + ( + Archiver &arc + ) + { + Behavior::Archive( arc ); + + arc.ArchiveInteger( ¤t_pain_type ); + arc.ArchiveInteger( &pain_anim_number ); + arc.ArchiveBoolean( &anim_done ); + arc.ArchiveInteger( &number_of_pains ); + arc.ArchiveInteger( &max_pains ); + } + +class Watch : public Behavior + { + private: + EntityPtr ent_to_watch; + Seek seek; + float turn_speed; + float old_turn_speed; + + public: + CLASS_PROTOTYPE( Watch ); + + Watch(); + void SetArgs( Event *ev ); + void Begin( Actor &self ); + qboolean Evaluate( Actor &self ); + void End( Actor &self ); + virtual void Archive( Archiver &arc ); + }; + +inline void Watch::Archive + ( + Archiver &arc + ) + { + Behavior::Archive( arc ); + + arc.ArchiveSafePointer( &ent_to_watch ); + arc.ArchiveObject( &seek ); + arc.ArchiveFloat( &turn_speed ); + arc.ArchiveFloat( &old_turn_speed ); + } + +class Turn : public Behavior + { + private: + float turn_speed; + + public: + CLASS_PROTOTYPE( Turn ); + + Turn(); + void SetArgs( Event *ev ); + void Begin( Actor &self ); + qboolean Evaluate( Actor &self ); + void End( Actor &self ); + virtual void Archive( Archiver &arc ); + }; + +inline void Turn::Archive + ( + Archiver &arc + ) + { + Behavior::Archive( arc ); + + arc.ArchiveFloat( &turn_speed ); + } + +class CircleEnemy : public Behavior + { + private: + EntityPtr ent_to_circle; + str center_part_name; + float last_angle_change; + + public: + CLASS_PROTOTYPE( CircleEnemy ); + + void SetArgs( Event *ev ); + float GetAngleDiff( Actor &self, Actor *center_actor, Vector origin ); + void Begin( Actor &self ); + qboolean Evaluate( Actor &self ); + void End( Actor &self ); + virtual void Archive( Archiver &arc ); + }; + +inline void CircleEnemy::Archive + ( + Archiver &arc + ) + { + Behavior::Archive( arc ); + + arc.ArchiveSafePointer( &ent_to_circle ); + arc.ArchiveString( ¢er_part_name ); + arc.ArchiveFloat( &last_angle_change ); + } + +class BurrowAttack : public Behavior + { + private: + Vector goal; + Vector attack_origin; + int burrow_mode; + AnimatePtr leg1; + AnimatePtr leg2; + AnimatePtr leg3; + AnimatePtr leg4; + int stage; + int attacks_left; + float burrow_speed; + qboolean too_close; + qboolean use_last_known_position; + public: + CLASS_PROTOTYPE( BurrowAttack ); + + void SetArgs( Event *ev ); + void Begin( Actor &self ); + qboolean Evaluate( Actor &self ); + void End( Actor &self ); + void SpawnArm( Actor &self, AnimatePtr &leg, Vector arm_origin, const char *anim_name, float angle ); + virtual void Archive( Archiver &arc ); + }; + +inline void BurrowAttack::Archive + ( + Archiver &arc + ) + { + Behavior::Archive( arc ); + + arc.ArchiveVector( &goal ); + arc.ArchiveVector( &attack_origin ); + arc.ArchiveInteger( &burrow_mode ); + arc.ArchiveSafePointer( &leg1 ); + arc.ArchiveSafePointer( &leg2 ); + arc.ArchiveSafePointer( &leg3 ); + arc.ArchiveSafePointer( &leg4 ); + arc.ArchiveInteger( &stage ); + arc.ArchiveInteger( &attacks_left ); + arc.ArchiveFloat( &burrow_speed ); + arc.ArchiveBoolean( &too_close ); + arc.ArchiveBoolean( &use_last_known_position ); + } + +class ShockWater : public Behavior + { + private: + EntityPtr left_beam; + EntityPtr right_beam; + EntityPtr center_beam; + qboolean already_started; + + public: + CLASS_PROTOTYPE( ShockWater ); + + ShockWater(); + void Begin( Actor &self ); + qboolean Evaluate( Actor &self ); + void End( Actor &self ); + virtual void Archive( Archiver &arc ); + }; + +inline void ShockWater::Archive + ( + Archiver &arc + ) + { + Behavior::Archive( arc ); + + arc.ArchiveSafePointer( &left_beam ); + arc.ArchiveSafePointer( &right_beam ); + arc.ArchiveSafePointer( ¢er_beam ); + arc.ArchiveBoolean( &already_started ); + } + +class Shock : public Behavior + { + private: + EntityPtr beam; + str tag_name; + float damage; + qboolean already_started; + float random_angle; + public: + CLASS_PROTOTYPE( Shock ); + + Shock(); + void SetArgs( Event *ev ); + void Begin( Actor &self ); + qboolean Evaluate( Actor &self ); + void End( Actor &self ); + virtual void Archive( Archiver &arc ); + }; + +inline void Shock::Archive + ( + Archiver &arc + ) + { + Behavior::Archive( arc ); + + arc.ArchiveSafePointer( &beam ); + arc.ArchiveString( &tag_name ); + arc.ArchiveFloat( &damage ); + arc.ArchiveBoolean( &already_started ); + arc.ArchiveFloat( &random_angle ); + } + +class CircleAttack : public Behavior + { + private: + EntityPtr first_part; + EntityPtr current_part; + str command; + str direction; + float next_time; + int current_direction; + int number_of_attacks; + public: + CLASS_PROTOTYPE( CircleAttack ); + + CircleAttack(); + Actor *FindClosestPart( Actor &self, float angle ); + void SetArgs( Event *ev ); + void Begin( Actor &self ); + qboolean Evaluate( Actor &self ); + void End( Actor &self ); + virtual void Archive( Archiver &arc ); + }; + +inline void CircleAttack::Archive + ( + Archiver &arc + ) + { + Behavior::Archive( arc ); + + arc.ArchiveSafePointer( &first_part ); + arc.ArchiveSafePointer( ¤t_part ); + arc.ArchiveString( &command ); + arc.ArchiveString( &direction ); + arc.ArchiveFloat( &next_time ); + arc.ArchiveInteger( ¤t_direction ); + arc.ArchiveInteger( &number_of_attacks ); + } + +class DragEnemy : public Behavior + { + private: + EntityPtr ent_to_drag; + str tag_name; + int damage; + float target_yaw; + float last_turn_time; + qboolean attached; + Vector offset; + qboolean drop; + public: + CLASS_PROTOTYPE( DragEnemy ); + + void SetArgs( Event *ev ); + void Begin( Actor &self ); + qboolean Evaluate( Actor &self ); + void End( Actor &self ); + virtual void Archive( Archiver &arc ); + }; + +inline void DragEnemy::Archive + ( + Archiver &arc + ) + { + Behavior::Archive( arc ); + + arc.ArchiveSafePointer( &ent_to_drag ); + arc.ArchiveString( &tag_name ); + arc.ArchiveInteger( &damage ); + arc.ArchiveFloat( &target_yaw ); + arc.ArchiveFloat( &last_turn_time ); + arc.ArchiveBoolean( &attached ); + arc.ArchiveVector( &offset ); + arc.ArchiveBoolean( &drop ); + } + +class Spin : public Behavior + { + private: + float speed; + + public: + CLASS_PROTOTYPE( Spin ); + + Spin(); + void Begin( Actor &self ); + qboolean Evaluate( Actor &self ); + void End( Actor &self ); + void SetArgs( Event *ev ); + virtual void Archive( Archiver &arc ); + }; + +inline void Spin::Archive + ( + Archiver &arc + ) + { + Behavior::Archive( arc ); + + arc.ArchiveFloat( &speed ); + } + +class Digest : public Behavior + { + private: + float digest_time; + float spit_time; + Container foodlist; + qboolean anim_done; + qboolean spitting; + qboolean spit; + qboolean yuck; + + void AnimDone( Event *ev ); + + public: + CLASS_PROTOTYPE( Digest ); + + void ShowInfo( Actor &self ); + void Begin( Actor &self ); + qboolean Evaluate( Actor &self ); + void End( Actor &self ); + void Eat( Entity *food, Actor &self ); + virtual void Archive( Archiver &arc ); + }; + +inline void Digest::Archive + ( + Archiver &arc + ) + { + EntityPtr *temp; + int num; + int i; + + Behavior::Archive( arc ); + + arc.ArchiveFloat( &digest_time ); + arc.ArchiveFloat( &spit_time ); + + if ( arc.Loading() ) + { + foodlist.FreeObjectList(); + } + else + { + num = foodlist.NumObjects(); + } + arc.ArchiveInteger( &num ); + if ( arc.Loading() ) + { + foodlist.Resize( num ); + } + for( i = 1; i <= num; i++ ) + { + temp = foodlist.AddressOfObjectAt( i ); + arc.ArchiveSafePointer( temp ); + } + + arc.ArchiveBoolean( &anim_done ); + arc.ArchiveBoolean( &spitting ); + arc.ArchiveBoolean( &spit ); + arc.ArchiveBoolean( &yuck ); + } + +class Aim : public Behavior + { + private: + Seek seek; + EntityPtr target; + + public: + CLASS_PROTOTYPE( Aim ); + + void SetTarget( Entity *ent ); + void ShowInfo( Actor &self ); + void Begin( Actor &self ); + qboolean Evaluate( Actor &self ); + void End( Actor &self ); + virtual void Archive( Archiver &arc ); + }; + +inline void Aim::Archive + ( + Archiver &arc + ) + { + Behavior::Archive( arc ); + + arc.ArchiveObject( &seek ); + arc.ArchiveSafePointer( &target ); + } + +class TurnTo : public Behavior + { + private: + Seek seek; + EntityPtr ent; + Vector dir; + float yaw; + int mode; + qboolean anim_done; + + public: + CLASS_PROTOTYPE( TurnTo ); + + TurnTo(); + void SetDirection( float yaw ); + void SetTarget( Entity *ent ); + void AnimDone( Event *ev ); + void ShowInfo( Actor &self ); + void Begin( Actor &self ); + qboolean Evaluate( Actor &self ); + void End( Actor &self ); + virtual void Archive( Archiver &arc ); + }; + +inline void TurnTo::Archive + ( + Archiver &arc + ) + { + Behavior::Archive( arc ); + + arc.ArchiveObject( &seek ); + arc.ArchiveSafePointer( &ent ); + arc.ArchiveVector( &dir ); + arc.ArchiveFloat( &yaw ); + arc.ArchiveInteger( &mode ); + arc.ArchiveBoolean( &anim_done ); + } + +class PickupEntity : public Behavior + { + private: + str pickup_anim_name; + qboolean anim_done; + EntityPtr ent_to_pickup; + + public: + CLASS_PROTOTYPE( PickupEntity ); + + void SetArgs( Event *ev ); + void AnimDone( Event *ev ); + void Begin( Actor &self ); + qboolean Evaluate( Actor &self ); + void End( Actor &self ); + virtual void Archive( Archiver &arc ); + }; + +inline void PickupEntity::Archive + ( + Archiver &arc + ) + { + Behavior::Archive( arc ); + + arc.ArchiveString( &pickup_anim_name ); + arc.ArchiveBoolean( &anim_done ); + arc.ArchiveSafePointer( &ent_to_pickup ); + } + +class ThrowEntity : public Behavior + { + private: + str throw_anim_name; + qboolean anim_done; + + public: + CLASS_PROTOTYPE( ThrowEntity ); + + void SetArgs( Event *ev ); + void AnimDone( Event *ev ); + void Begin( Actor &self ); + qboolean Evaluate( Actor &self ); + void End( Actor &self ); + virtual void Archive( Archiver &arc ); + }; + +inline void ThrowEntity::Archive + ( + Archiver &arc + ) + { + Behavior::Archive( arc ); + + arc.ArchiveString( &throw_anim_name ); + arc.ArchiveBoolean( &anim_done ); + } + +class HeadWatch : public Behavior + { + private: + EntityPtr ent_to_watch; + Vector current_head_angles; + float max_speed; + qboolean forever; + public: + CLASS_PROTOTYPE( HeadWatch ); + + HeadWatch(); + void SetArgs( Event *ev ); + void ShowInfo( Actor &self ); + void Begin( Actor &self ); + qboolean Evaluate( Actor &self ); + void End( Actor &self ); + virtual void Archive( Archiver &arc ); + }; + +inline void HeadWatch::Archive + ( + Archiver &arc + ) + { + Behavior::Archive( arc ); + + arc.ArchiveSafePointer( &ent_to_watch ); + arc.ArchiveVector( ¤t_head_angles ); + arc.ArchiveFloat( &max_speed ); + arc.ArchiveBoolean( &forever ); + } + +class TorsoTurn : public Behavior + { + private: + int turn_towards_enemy; + float speed; + int forever; + float current_yaw; + float current_pitch; + str tag_name; + float tolerance; + public: + CLASS_PROTOTYPE( TorsoTurn ); + + void SetArgs( Event *ev ); + void ShowInfo( Actor &self ); + void Begin( Actor &self ); + qboolean Evaluate( Actor &self ); + void End( Actor &self ); + virtual void Archive( Archiver &arc ); + }; + +inline void TorsoTurn::Archive + ( + Archiver &arc + ) + { + Behavior::Archive( arc ); + + arc.ArchiveInteger( &turn_towards_enemy ); + arc.ArchiveFloat( &speed ); + arc.ArchiveInteger( &forever ); + arc.ArchiveFloat( ¤t_yaw ); + arc.ArchiveFloat( ¤t_pitch ); + arc.ArchiveString( &tag_name ); + arc.ArchiveFloat( &tolerance ); + } + +class GotoPathNode : public Behavior + { + private: + TurnTo turnto; + Chase chase; + int state; + qboolean usevec; + float time; + str anim; + EntityPtr goalent; + Vector goal; + EntityPtr entity_to_watch; + HeadWatch head_watch; + + public: + CLASS_PROTOTYPE( GotoPathNode ); + + GotoPathNode(); + void SetArgs( Event *ev ); + void SetGoal( PathNode *node ); + void AnimDone( Event *ev ); + void ShowInfo( Actor &self ); + void Begin( Actor &self ); + qboolean Evaluate( Actor &self ); + void End( Actor &self ); + virtual void Archive( Archiver &arc ); + }; + +inline void GotoPathNode::Archive + ( + Archiver &arc + ) + { + Behavior::Archive( arc ); + + arc.ArchiveObject( &turnto ); + arc.ArchiveObject( &chase ); + arc.ArchiveInteger( &state ); + arc.ArchiveBoolean( &usevec ); + arc.ArchiveFloat( &time ); + arc.ArchiveString( &anim ); + arc.ArchiveSafePointer( &goalent ); + arc.ArchiveVector( &goal ); + arc.ArchiveSafePointer( &entity_to_watch ); + arc.ArchiveObject( &head_watch ); + } + +class Flee : public Behavior + { + private: + Chase chase; + str anim; + PathNodePtr flee_node; + + public: + CLASS_PROTOTYPE( Flee ); + + void SetArgs( Event *ev ); + void ShowInfo( Actor &self ); + void Begin( Actor &self ); + void FindFleeNode( Actor &self ); + qboolean Evaluate( Actor &self ); + void End( Actor &self ); + virtual void Archive( Archiver &arc ); + }; + +inline void Flee::Archive + ( + Archiver &arc + ) + { + Behavior::Archive( arc ); + + arc.ArchiveObject( &chase ); + arc.ArchiveString( &anim ); + arc.ArchiveSafePointer( &flee_node ); + } + +class PlayAnim : public Behavior + { + private: + str anim; + + public: + CLASS_PROTOTYPE( PlayAnim ); + + void SetArgs( Event *ev ); + void ShowInfo( Actor &self ); + void Begin( Actor &self ); + qboolean Evaluate( Actor &self ); + void End( Actor &self ); + virtual void Archive( Archiver &arc ); + }; + +inline void PlayAnim::Archive + ( + Archiver &arc + ) + { + Behavior::Archive( arc ); + + arc.ArchiveString( &anim ); + } + +class Talk : public Behavior + { + private: + TurnTo turnto; + SentientPtr ent_listening; + float original_yaw; + float yaw; + int mode; + qboolean move_allowed; + + public: + CLASS_PROTOTYPE( Talk ); + + void SetUser( Sentient *user ); + void AnimDone( Event *ev ); + void Begin( Actor &self ); + qboolean Evaluate( Actor &self ); + void End( Actor &self ); + virtual void Archive( Archiver &arc ); + }; + +inline void Talk::Archive + ( + Archiver &arc + ) + { + Behavior::Archive( arc ); + + arc.ArchiveObject( &turnto ); + arc.ArchiveSafePointer( &ent_listening ); + arc.ArchiveFloat( &original_yaw ); + arc.ArchiveFloat( &yaw ); + arc.ArchiveInteger( &mode ); + arc.ArchiveBoolean( &move_allowed ); + } + +class FindCover : public Behavior + { + private: + str anim; + str crouch_anim; + Chase chase; + int state; + float nextsearch; + + public: + CLASS_PROTOTYPE( FindCover ); + + void SetArgs( Event *ev ); + PathNode *FindCoverNode( Actor &self ); + void ShowInfo( Actor &self ); + void Begin( Actor &self ); + qboolean Evaluate( Actor &self ); + void End( Actor &self ); + virtual void Archive( Archiver &arc ); + }; + +inline void FindCover::Archive + ( + Archiver &arc + ) + { + Behavior::Archive( arc ); + + arc.ArchiveString( &anim ); + arc.ArchiveString( &crouch_anim ); + arc.ArchiveObject( &chase ); + arc.ArchiveInteger( &state ); + arc.ArchiveFloat( &nextsearch ); + } + +class FindFlee : public Behavior + { + private: + str anim; + Chase chase; + int state; + float nextsearch; + + public: + CLASS_PROTOTYPE( FindFlee ); + + void SetArgs( Event *ev ); + PathNode *FindFleeNode( Actor &self ); + void ShowInfo( Actor &self ); + void Begin( Actor &self ); + qboolean Evaluate( Actor &self ); + void End( Actor &self ); + virtual void Archive( Archiver &arc ); + }; + +inline void FindFlee::Archive + ( + Archiver &arc + ) + { + Behavior::Archive( arc ); + + arc.ArchiveString( &anim ); + arc.ArchiveObject( &chase ); + arc.ArchiveInteger( &state ); + arc.ArchiveFloat( &nextsearch ); + } + +class FindEnemy : public Behavior + { + private: + str anim; + Chase chase; + int state; + float nextsearch; + PathNodePtr lastSearchNode; + Vector lastSearchPos; + + public: + CLASS_PROTOTYPE( FindEnemy ); + + PathNode *FindClosestSightNode( Actor &self ); + void SetArgs( Event *ev ); + void ShowInfo( Actor &self ); + void Begin( Actor &self ); + qboolean Evaluate( Actor &self ); + void End( Actor &self ); + virtual void Archive( Archiver &arc ); + }; + +inline void FindEnemy::Archive + ( + Archiver &arc + ) + { + Behavior::Archive( arc ); + + arc.ArchiveString( &anim ); + arc.ArchiveObject( &chase ); + arc.ArchiveInteger( &state ); + arc.ArchiveFloat( &nextsearch ); + arc.ArchiveSafePointer( &lastSearchNode ); + arc.ArchiveVector( &lastSearchPos ); + } + +class AimAndShoot : public Behavior + { + private: + Aim aim; + int mode; + int maxshots; + int numshots; + qboolean animdone; + float enemy_health; + float aim_time; + str animprefix; + str aimanim; + str fireanim; + + public: + CLASS_PROTOTYPE( AimAndShoot ); + + AimAndShoot(); + void SetMaxShots( int num ); + void SetArgs( Event *ev ); + void AnimDone( Event *ev ); + void ShowInfo( Actor &self ); + void Begin( Actor &self ); + qboolean Evaluate( Actor &self ); + void End( Actor &self ); + virtual void Archive( Archiver &arc ); + }; + +inline void AimAndShoot::Archive + ( + Archiver &arc + ) + { + Behavior::Archive( arc ); + + arc.ArchiveObject( &aim ); + arc.ArchiveInteger( &mode ); + arc.ArchiveInteger( &maxshots ); + arc.ArchiveInteger( &numshots ); + arc.ArchiveBoolean( &animdone ); + arc.ArchiveFloat( &enemy_health ); + arc.ArchiveFloat( &aim_time ); + arc.ArchiveString( &animprefix ); + arc.ArchiveString( &aimanim ); + arc.ArchiveString( &fireanim ); + } + +class AimAndMelee : public Behavior + { + private: + Aim aim; + int mode; + int maxshots; + int numshots; + qboolean animdone; + str anim_name; + + public: + CLASS_PROTOTYPE( AimAndMelee ); + + AimAndMelee(); + void SetArgs( Event *ev ); + void AnimDone( Event *ev ); + void ShowInfo( Actor &self ); + void Begin( Actor &self ); + qboolean Evaluate( Actor &self ); + void End( Actor &self ); + virtual void Archive( Archiver &arc ); + }; + +inline void AimAndMelee::Archive + ( + Archiver &arc + ) + { + Behavior::Archive( arc ); + + arc.ArchiveObject( &aim ); + arc.ArchiveInteger( &mode ); + arc.ArchiveInteger( &maxshots ); + arc.ArchiveInteger( &numshots ); + arc.ArchiveBoolean( &animdone ); + arc.ArchiveString( &anim_name ); + } + +class JumpToPathNode : public Behavior + { + private: + Jump jump; + public: + CLASS_PROTOTYPE( JumpToPathNode ); + + void SetArgs( Event *ev ); + void Begin( Actor &self ); + qboolean Evaluate( Actor &self ); + void End( Actor &self ); + virtual void Archive( Archiver &arc ); + }; + +inline void JumpToPathNode::Archive + ( + Archiver &arc + ) + { + Behavior::Archive( arc ); + + arc.ArchiveObject( &jump ); + } + +class FlyToPoint : public Behavior + { + private: + float avoidtime; + Vector target_angle; + float turn_speed; + float speed; + float old_forward_speed; + Vector goal; + qboolean random_allowed; + qboolean force_goal; + int stuck; + Vector temp_goal; + qboolean use_temp_goal; + + public: + CLASS_PROTOTYPE( FlyToPoint ); + + FlyToPoint(); + + void SetTurnSpeed( float new_turn_speed ); + void SetGoalPoint( Vector goal_point ); + void SetRandomAllowed( qboolean allowed ); + void SetSpeed( float speed_value ); + void ForceGoal( void ); + void ShowInfo( Actor &self ); + void Begin( Actor &self ); + qboolean Evaluate( Actor &self ); + float LerpAngle( float old_angle, float new_angle, float lerp_amount ); + void End( Actor &self ); + virtual void Archive( Archiver &arc ); + }; + +inline void FlyToPoint::Archive + ( + Archiver &arc + ) + { + Behavior::Archive( arc ); + + arc.ArchiveFloat( &avoidtime ); + arc.ArchiveVector( &target_angle ); + arc.ArchiveFloat( &turn_speed ); + arc.ArchiveFloat( &speed ); + arc.ArchiveFloat( &old_forward_speed ); + arc.ArchiveVector( &goal ); + arc.ArchiveBoolean( &random_allowed ); + arc.ArchiveBoolean( &force_goal ); + arc.ArchiveInteger( &stuck ); + arc.ArchiveVector( &temp_goal ); + arc.ArchiveBoolean( &use_temp_goal ); + } + +class FlyCloseToEnemy : public Behavior + { + private: + str anim; + float turn_speed; + float speed; + FlyToPoint fly; + float next_goal_time; + + public: + CLASS_PROTOTYPE( FlyCloseToEnemy ); + + FlyCloseToEnemy(); + + void SetArgs( Event *ev ); + void ShowInfo( Actor &self ); + void Begin( Actor &self ); + qboolean Evaluate( Actor &self ); + void End( Actor &self ); + virtual void Archive( Archiver &arc ); + }; + +inline void FlyCloseToEnemy::Archive + ( + Archiver &arc + ) + { + Behavior::Archive( arc ); + + arc.ArchiveString( &anim ); + arc.ArchiveFloat( &turn_speed ); + arc.ArchiveFloat( &speed ); + arc.ArchiveObject( &fly ); + arc.ArchiveFloat( &next_goal_time ); + } + +class FlyCloseToPlayer : public Behavior + { + private: + str anim; + float turn_speed; + float speed; + FlyToPoint fly; + float next_goal_time; + + public: + CLASS_PROTOTYPE( FlyCloseToPlayer ); + + FlyCloseToPlayer(); + + void SetArgs( Event *ev ); + void ShowInfo( Actor &self ); + void Begin( Actor &self ); + qboolean Evaluate( Actor &self ); + void End( Actor &self ); + virtual void Archive( Archiver &arc ); + }; + +inline void FlyCloseToPlayer::Archive + ( + Archiver &arc + ) + { + Behavior::Archive( arc ); + + arc.ArchiveString( &anim ); + arc.ArchiveFloat( &turn_speed ); + arc.ArchiveFloat( &speed ); + arc.ArchiveObject( &fly ); + arc.ArchiveFloat( &next_goal_time ); + } + +class FlyWander : public Behavior + { + private: + str anim; + float turn_speed; + float speed; + FlyToPoint fly; + float change_course_time; + float next_change_course_time; + float original_z; + Vector goal; + qboolean try_to_go_up; + + public: + CLASS_PROTOTYPE( FlyWander ); + + FlyWander(); + + void SetArgs( Event *ev ); + void ShowInfo( Actor &self ); + void Begin( Actor &self ); + qboolean Evaluate( Actor &self ); + void End( Actor &self ); + virtual void Archive( Archiver &arc ); + }; + +inline void FlyWander::Archive + ( + Archiver &arc + ) + { + Behavior::Archive( arc ); + + arc.ArchiveString( &anim ); + arc.ArchiveFloat( &turn_speed ); + arc.ArchiveFloat( &speed ); + arc.ArchiveObject( &fly ); + arc.ArchiveFloat( &change_course_time ); + arc.ArchiveFloat( &next_change_course_time ); + arc.ArchiveFloat( &original_z ); + arc.ArchiveVector( &goal ); + arc.ArchiveBoolean( &try_to_go_up ); + } + +class FlyCircle : public Behavior + { + private: + str anim; + FlyToPoint fly; + float original_z; + qboolean fly_clockwise; + + public: + CLASS_PROTOTYPE( FlyCircle ); + + FlyCircle(); + + void SetArgs( Event *ev ); + void ShowInfo( Actor &self ); + void Begin( Actor &self ); + qboolean Evaluate( Actor &self ); + void End( Actor &self ); + virtual void Archive( Archiver &arc ); + }; + +inline void FlyCircle::Archive + ( + Archiver &arc + ) + { + Behavior::Archive( arc ); + + arc.ArchiveString( &anim ); + arc.ArchiveObject( &fly ); + arc.ArchiveFloat( &original_z ); + arc.ArchiveBoolean( &fly_clockwise ); + } + + +class FlyDive : public Behavior + { + private: + str anim; + FlyToPoint fly; + Vector goal; + float speed; + float old_speed; + float damage; + + public: + CLASS_PROTOTYPE( FlyDive ); + + FlyDive(); + + void SetArgs( Event *ev ); + void ShowInfo( Actor &self ); + void Begin( Actor &self ); + qboolean Evaluate( Actor &self ); + void End( Actor &self ); + virtual void Archive( Archiver &arc ); + }; + +inline void FlyDive::Archive + ( + Archiver &arc + ) + { + Behavior::Archive( arc ); + + arc.ArchiveString( &anim ); + arc.ArchiveObject( &fly ); + arc.ArchiveVector( &goal ); + arc.ArchiveFloat( &speed ); + arc.ArchiveFloat( &old_speed ); + arc.ArchiveFloat( &damage ); + } + +class FlyClimb : public Behavior + { + private: + str anim; + FlyToPoint fly; + Vector goal; + float height; + float speed; + float next_height_check; + float last_check_height; + + public: + CLASS_PROTOTYPE( FlyClimb ); + + FlyClimb(); + + void SetArgs( Event *ev ); + void ShowInfo( Actor &self ); + void Begin( Actor &self ); + qboolean Evaluate( Actor &self ); + void End( Actor &self ); + virtual void Archive( Archiver &arc ); + }; + +inline void FlyClimb::Archive + ( + Archiver &arc + ) + { + Behavior::Archive( arc ); + + arc.ArchiveString( &anim ); + arc.ArchiveObject( &fly ); + arc.ArchiveVector( &goal ); + arc.ArchiveFloat( &height ); + arc.ArchiveFloat( &speed ); + arc.ArchiveFloat( &next_height_check ); + arc.ArchiveFloat( &last_check_height ); + } + +class Land : public Behavior + { + private: + str anim; + + public: + CLASS_PROTOTYPE( Land ); + + Land(); + + void SetArgs( Event *ev ); + void ShowInfo( Actor &self ); + void Begin( Actor &self ); + qboolean Evaluate( Actor &self ); + void End( Actor &self ); + virtual void Archive( Archiver &arc ); + }; + +inline void Land::Archive + ( + Archiver &arc + ) + { + Behavior::Archive( arc ); + + arc.ArchiveString( &anim ); + } + +// Fixme / don't think this works right now + +class Wander : public Behavior + { + private: + Seek seek; + //ObstacleAvoidance avoid; + str anim; + float avoidtime; + Vector avoidvec; + + public: + CLASS_PROTOTYPE( Wander ); + + void SetArgs( Event *ev ); + void ShowInfo( Actor &self ); + void Begin( Actor &self ); + qboolean Evaluate( Actor &self ); + void End( Actor &self ); + virtual void Archive( Archiver &arc ); + }; + +inline void Wander::Archive + ( + Archiver &arc + ) + { + Behavior::Archive( arc ); + + arc.ArchiveObject( &seek ); + //arc.ArchiveObject( &avoid ); + arc.ArchiveString( &anim ); + arc.ArchiveFloat( &avoidtime ); + arc.ArchiveVector( &avoidvec ); + } + +class GetCloseToEnemy : public Behavior + { + private: + str anim; + Chase chase; + Wander wander; + qboolean forever; + float next_think_time; + + public: + CLASS_PROTOTYPE( GetCloseToEnemy ); + + void SetArgs( Event *ev ); + void ShowInfo( Actor &self ); + void Begin( Actor &self ); + qboolean Evaluate( Actor &self ); + void End( Actor &self ); + virtual void Archive( Archiver &arc ); + }; + +inline void GetCloseToEnemy::Archive + ( + Archiver &arc + ) + + { + Behavior::Archive( arc ); + + arc.ArchiveString( &anim ); + arc.ArchiveObject( &chase ); + arc.ArchiveObject( &wander ); + arc.ArchiveBoolean( &forever ); + arc.ArchiveFloat( &next_think_time ); + } + +class GotoDeadEnemy : public Behavior + { + private: + str anim; + Chase chase; + + public: + CLASS_PROTOTYPE( GotoDeadEnemy ); + + void SetArgs( Event *ev ); + void ShowInfo( Actor &self ); + void Begin( Actor &self ); + qboolean Evaluate( Actor &self ); + void End( Actor &self ); + virtual void Archive( Archiver &arc ); + }; + +inline void GotoDeadEnemy::Archive + ( + Archiver &arc + ) + + { + Behavior::Archive( arc ); + + arc.ArchiveString( &anim ); + arc.ArchiveObject( &chase ); + } + +class Investigate : public Behavior + { + private: + Chase chase; + str anim; + Vector goal; + Vector real_goal_position; + float curioustime; + TurnTo turnto; + float investigate_time; + int mode; + Vector start_pos; + float start_yaw; + qboolean return_to_original_location; + + public: + CLASS_PROTOTYPE( Investigate ); + Investigate(); + void SetArgs( Event *ev ); + void ShowInfo( Actor &self ); + void Begin( Actor &self ); + qboolean Evaluate( Actor &self ); + void End( Actor &self ); + virtual void Archive( Archiver &arc ); + }; + +inline void Investigate::Archive + ( + Archiver &arc + ) + { + Behavior::Archive( arc ); + + arc.ArchiveObject( &chase ); + arc.ArchiveString( &anim ); + arc.ArchiveVector( &goal ); + arc.ArchiveVector( &real_goal_position ); + arc.ArchiveFloat( &curioustime ); + arc.ArchiveObject( &turnto ); + arc.ArchiveFloat( &investigate_time ); + arc.ArchiveInteger( &mode ); + arc.ArchiveVector( &start_pos ); + arc.ArchiveFloat( &start_yaw ); + arc.ArchiveBoolean( &return_to_original_location ); + } + + +class TurnInvestigate : public Behavior + { + private: + Seek seek; + str left_anim; + str right_anim; + float turn_speed; + Vector goal; + public: + CLASS_PROTOTYPE( TurnInvestigate ); + + void SetArgs( Event *ev ); + void ShowInfo( Actor &self ); + void Begin( Actor &self ); + qboolean Evaluate( Actor &self ); + void End( Actor &self ); + virtual void Archive( Archiver &arc ); + }; + +inline void TurnInvestigate::Archive + ( + Archiver &arc + ) + { + Behavior::Archive( arc ); + + arc.ArchiveObject( &seek ); + arc.ArchiveString( &left_anim ); + arc.ArchiveString( &right_anim ); + arc.ArchiveFloat( &turn_speed ); + arc.ArchiveVector( &goal ); + } + +class TurnToEnemy : public Behavior + { + private: + Seek seek; + str left_anim; + str right_anim; + float turn_speed; + qboolean forever; + qboolean anim_done; + qboolean use_last_known_position; + public: + CLASS_PROTOTYPE( TurnToEnemy ); + + void SetArgs( Event *ev ); + void AnimDone( Event *ev ); + void ShowInfo( Actor &self ); + void Begin( Actor &self ); + qboolean Evaluate( Actor &self ); + void End( Actor &self ); + virtual void Archive( Archiver &arc ); + }; + +inline void TurnToEnemy::Archive + ( + Archiver &arc + ) + { + Behavior::Archive( arc ); + + arc.ArchiveObject( &seek ); + arc.ArchiveString( &left_anim ); + arc.ArchiveString( &right_anim ); + arc.ArchiveFloat( &turn_speed ); + arc.ArchiveBoolean( &forever ); + arc.ArchiveBoolean( &anim_done ); + arc.ArchiveBoolean( &use_last_known_position ); + } + +class Teleport : public Behavior + { + private: + public: + CLASS_PROTOTYPE( Teleport ); + + void ShowInfo( Actor &self ); + void Begin( Actor &self ); + qboolean TestPosition( Actor &self, int test_pos, Vector &good_position, qboolean use_enemy_dir ); + qboolean Evaluate( Actor &self ); + void End( Actor &self ); + }; + +class TeleportToPosition : public Behavior + { + private: + str teleport_position_name; + int number_of_teleport_positions; + public: + CLASS_PROTOTYPE( TeleportToPosition ); + + void SetArgs( Event *ev ); + void ShowInfo( Actor &self ); + void Begin( Actor &self ); + qboolean TestPosition( Actor &self, int test_pos, Vector &good_position ); + qboolean Evaluate( Actor &self ); + void End( Actor &self ); + virtual void Archive( Archiver &arc ); + }; + +inline void TeleportToPosition::Archive + ( + Archiver &arc + ) + { + Behavior::Archive( arc ); + + arc.ArchiveString( &teleport_position_name ); + arc.ArchiveInteger( &number_of_teleport_positions ); + } + +class GhostAttack : public Behavior + { + private: + int mode; + Vector attack_dir; + Vector attack_position; + Vector retreat_position; + FlyToPoint fly; + qboolean real_attack; + public: + CLASS_PROTOTYPE( GhostAttack ); + + void SetArgs( Event *ev ); + void ShowInfo( Actor &self ); + void Begin( Actor &self ); + qboolean Evaluate( Actor &self ); + void End( Actor &self ); + virtual void Archive( Archiver &arc ); + }; + +inline void GhostAttack::Archive + ( + Archiver &arc + ) + { + Behavior::Archive( arc ); + + arc.ArchiveInteger( &mode ); + arc.ArchiveVector( &attack_dir ); + arc.ArchiveVector( &attack_position ); + arc.ArchiveVector( &retreat_position ); + arc.ArchiveObject( &fly ); + arc.ArchiveBoolean( &real_attack ); + } + +class Levitate : public Behavior + { + private: + float distance; + float speed; + float final_z; + public: + CLASS_PROTOTYPE( Levitate ); + + void SetArgs( Event *ev ); + void ShowInfo( Actor &self ); + void Begin( Actor &self ); + qboolean Evaluate( Actor &self ); + void End( Actor &self ); + virtual void Archive( Archiver &arc ); + }; + +inline void Levitate::Archive + ( + Archiver &arc + ) + { + Behavior::Archive( arc ); + + arc.ArchiveFloat( &distance ); + arc.ArchiveFloat( &speed ); + arc.ArchiveFloat( &final_z ); + } + +#endif /* behavior.h */ diff --git a/source/source/fgame/bg_local.h b/source/source/fgame/bg_local.h new file mode 100644 index 0000000..1f403e0 --- /dev/null +++ b/source/source/fgame/bg_local.h @@ -0,0 +1,98 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/bg_local.h $ +// $Revision:: 4 $ +// $Date:: 6/01/00 7:00p $ +// +// Copyright (C) 1999 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source is may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/bg_local.h $ +// +// 4 6/01/00 7:00p Markd +// added partial friciton for slippery surfaces +// +// 3 12/11/99 3:37p Markd +// q3a gold checkin, first time +// +// 2 9/10/99 3:08p Jimdose +// merge +// +// DESCRIPTION: +// bg_local.h -- local definitions for the bg (both games) files +// + +#ifndef __BG_LOCAL_H__ +#define __BG_LOCAL_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +#define MIN_WALK_NORMAL 0.7 // can't walk on very steep slopes + +#define STEPSIZE 18 + +#define JUMP_VELOCITY 270 + +#define TIMER_LAND 130 +#define TIMER_GESTURE (34*66+50) + +#define OVERCLIP 1.001 + +// all of the locals will be zeroed before each +// pmove, just to make damn sure we don't have +// any differences when running on client or server +typedef struct { + vec3_t forward, right, up; + float frametime; + + int msec; + + qboolean walking; + qboolean groundPlane; + trace_t groundTrace; + + float impactSpeed; + + vec3_t previous_origin; + vec3_t previous_velocity; + int previous_waterlevel; +} pml_t; + +extern pmove_t *pm; +extern pml_t pml; + +// movement parameters +extern float pm_stopspeed; +extern float pm_duckScale; +extern float pm_swimScale; +extern float pm_wadeScale; + +extern float pm_accelerate; +extern float pm_airaccelerate; +extern float pm_wateraccelerate; +extern float pm_flyaccelerate; + +extern float pm_friction; +extern float pm_waterfriction; +extern float pm_flightfriction; +extern float pm_slipperyfriction; + +extern int c_pmove; + +void PM_ClipVelocity( vec3_t in, vec3_t normal, vec3_t out, float overbounce ); +void PM_AddTouchEnt( int entityNum ); +void PM_AddEvent( int newEvent ); + +qboolean PM_SlideMove( qboolean gravity ); +void PM_StepSlideMove( qboolean gravity ); + +#ifdef __cplusplus + } +#endif + +#endif /* !__BG_LOCAL_H__ */ diff --git a/source/source/fgame/bg_misc.c b/source/source/fgame/bg_misc.c new file mode 100644 index 0000000..0cffc03 --- /dev/null +++ b/source/source/fgame/bg_misc.c @@ -0,0 +1,117 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/bg_misc.c $ +// $Revision:: 8 $ +// $Author:: Markd $ +// $Date:: 10/12/99 2:23p $ +// +// Copyright (C) 1998 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/bg_misc.c $ +// +// 8 10/12/99 2:23p Markd +// Rewrote camera and player movetype system +// +// 7 10/05/99 6:01p Aldie +// Added headers +// +// DESCRIPTION: +// Misc functions that are used in the client and server game dlls + +// included in both game dll and client + +#include "q_shared.h" +#include "bg_public.h" + +/* +================ +EvaluateTrajectory + +================ +*/ +void EvaluateTrajectory( const trajectory_t *tr, int atTime, vec3_t result ) { + float deltaTime; + float phase; + + switch( tr->trType ) { + case TR_STATIONARY: + case TR_INTERPOLATE: + VectorCopy( tr->trBase, result ); + break; + case TR_LINEAR: + deltaTime = ( atTime - tr->trTime ) * 0.001; // milliseconds to seconds + VectorMA( tr->trBase, deltaTime, tr->trDelta, result ); + break; + case TR_SINE: + deltaTime = ( atTime - tr->trTime ) / (float) tr->trDuration; + phase = sin( deltaTime * M_PI * 2 ); + VectorMA( tr->trBase, phase, tr->trDelta, result ); + break; + case TR_LINEAR_STOP: + if ( atTime > tr->trTime + tr->trDuration ) { + atTime = tr->trTime + tr->trDuration; + } + deltaTime = ( atTime - tr->trTime ) * 0.001; // milliseconds to seconds + if ( deltaTime < 0 ) { + deltaTime = 0; + } + VectorMA( tr->trBase, deltaTime, tr->trDelta, result ); + break; + case TR_GRAVITY: + deltaTime = ( atTime - tr->trTime ) * 0.001; // milliseconds to seconds + VectorMA( tr->trBase, deltaTime, tr->trDelta, result ); + result[2] -= 0.5 * DEFAULT_GRAVITY * deltaTime * deltaTime; // FIXME: local gravity... + break; + default: + Com_Error( ERR_DROP, "EvaluateTrajectory: unknown trType: %i", tr->trType ); + break; + } +} + +/* +================ +EvaluateTrajectoryDelta + +================ +*/ +void EvaluateTrajectoryDelta( const trajectory_t *tr, int atTime, vec3_t result ) { + float deltaTime; + float phase; + + switch( tr->trType ) { + case TR_STATIONARY: + case TR_INTERPOLATE: + VectorClear( result ); + break; + case TR_LINEAR: + VectorCopy( tr->trDelta, result ); + break; + case TR_SINE: + deltaTime = ( atTime - tr->trTime ) / (float) tr->trDuration; + phase = cos( deltaTime * M_PI * 2 ); // derivative of sin = cos + phase *= 0.5; + VectorScale( tr->trDelta, phase, result ); + break; + case TR_LINEAR_STOP: + if ( atTime > tr->trTime + tr->trDuration ) { + VectorClear( result ); + return; + } + VectorCopy( tr->trDelta, result ); + break; + case TR_GRAVITY: + deltaTime = ( atTime - tr->trTime ) * 0.001; // milliseconds to seconds + VectorCopy( tr->trDelta, result ); + result[2] -= DEFAULT_GRAVITY * deltaTime; // FIXME: local gravity... + break; + default: + Com_Error( ERR_DROP, "EvaluateTrajectoryDelta: unknown trType: %i", tr->trTime ); + break; + } +} + + diff --git a/source/source/fgame/bg_pmove.c b/source/source/fgame/bg_pmove.c new file mode 100644 index 0000000..4716499 --- /dev/null +++ b/source/source/fgame/bg_pmove.c @@ -0,0 +1,2558 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/bg_pmove.c $ +// $Revision:: 47 $ +// $Date:: 7/26/00 11:22p $ +// +// Copyright (C) 1999 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source is may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/bg_pmove.c $ +// +// 47 7/26/00 11:22p Markd +// changed sampling time in pmove to be 20FPS not 15 +// +// 46 7/25/00 2:41p Markd +// made terminal velocity lethal +// +// 45 7/25/00 12:47p Markd +// Added new player sounds +// +// 44 7/24/00 12:46p Markd +// fixed rope movment +// +// 43 7/16/00 10:28a Markd +// fixed some movement code issues +// +// 42 7/11/00 1:36p Steven +// Tweaked falling values a little. +// +// 41 7/10/00 6:50p Markd +// fixed some issues with water running +// +// 40 6/28/00 3:38p Markd +// Tweaked fatal falling distance +// +// 39 6/26/00 7:14p Markd +// tweaked stuck move code +// +// 38 6/25/00 12:37p Markd +// fixed player getting stuck +// +// 37 6/25/00 11:21a Markd +// fixed slime code for player +// +// 36 6/20/00 3:43p Markd +// fixed walking animations +// +// 35 6/14/00 11:18a Markd +// cleaned up code using Intel compiler +// +// 34 6/06/00 7:41p Markd +// Turned on an extraneous PM_ClipVelocity which was in Q3 +// +// 33 6/06/00 5:02p Markd +// fixed player movement stuff +// +// 32 6/01/00 7:00p Markd +// added partial friciton for slippery surfaces +// +// 31 5/11/00 11:05a Steven +// Added pushing of actors out of the way. +// +// 30 5/06/00 5:25p Markd +// fixed camera and pipe hang issues +// +// 29 4/27/00 11:59a Jimdose +// trying new slidemove +// +// 28 4/15/00 5:40p Markd +// fixed falling damage and getting into and out of water +// +// 27 4/15/00 1:30p Markd +// added check_was_running code so that player does not always stop short +// +// 26 4/07/00 3:00p Markd +// Added legs dangling code for pipehanging +// +// 25 2/24/00 4:16p Jimdose +// moved defines into bg_pulic.h +// +// 24 2/23/00 4:51p Jimdose +// added AddPlane +// +// 23 2/23/00 10:07a Markd +// Fixed slick surface support +// +// 22 2/18/00 4:15p Jimdose +// Pmove_GroundTrace now calls PM_CheckDuck to ensure that the bounding boxes +// are set +// +// 21 2/17/00 4:20p Jimdose +// improved sliding on slopes +// removed auto wall avoidance and replaced it with slide move +// +// 20 2/15/00 8:56p Jimdose +// added move feedback checks for state system +// added wall avoidance code +// +// 19 2/11/00 2:20p Markd +// Added water support to turbo movement +// +// 18 2/11/00 10:35a Markd +// Added faster running when run is held down a sufficient time +// +// 17 1/27/00 11:35a Markd +// Fixed solid/notsolid client side entities +// +// 16 1/25/00 8:07p Jimdose +// changed stepsize to 31 +// +// 15 1/22/00 12:44p Jimdose +// PM_StepMove no clears out the velocity when blocked +// +// 14 1/19/00 10:01p Jimdose +// no longer restrict movement when in air +// +// 13 1/12/00 8:02p Markd +// Fixed msec command for dropping timers in pmove +// +// 12 1/05/00 7:25p Jimdose +// made angle functions all use the same coordinate system +// AngleVectors now returns left instead of right +// no longer need to invert pitch +// +// 11 12/09/99 3:40p Jimdose +// fixed speed going up slopes +// +// 10 12/09/99 11:00a Markd +// merged in latest player movement code and broke jumping, yay! +// +// 9 10/27/99 10:21a Steven +// Added new flag PMF_NO_MOVE. +// +// 8 10/12/99 2:23p Markd +// Rewrote camera and player movetype system +// +// 7 10/08/99 2:09p Markd +// Added PM_LOCKVIEW to changing view while in camera +// +// 6 9/16/99 7:43p Jimdose +// fixed up merge +// +// DESCRIPTION: +// + +#include "q_shared.h" +#include "bg_public.h" + +// all of the locals will be zeroed before each +// pmove, just to make damn sure we don't have +// any differences when running on client or server +typedef struct { + vec3_t forward, left, up; + vec3_t flat_forward, flat_left, flat_up; + float forward_speed, side_speed; + float frametime; + + int msec; + + qboolean walking; + qboolean groundPlane; + trace_t groundTrace; + + float impactSpeed; + + vec3_t previous_origin; + vec3_t previous_velocity; + int previous_waterlevel; +} pml_t; + +pmove_t *pm; +pml_t pml; + +// movement parameters +const float pm_stopspeed = 50; +const float pm_duckScale = 0.25f; +const float pm_swimScale = 0.50f; +const float pm_wadeScale = 0.70f; +const float pm_accelerate = 10; + +const float pm_airaccelerate = 2; +const float pm_wateraccelerate = 6; +const float pm_flyaccelerate = 8; + +const float pm_friction = 6; +const float pm_waterfriction = 1; +const float pm_slipperyfriction = 0.25f; +const float pm_flightfriction = 3; + +int c_pmove = 0; + +void PM_CrashLand( void ); + +/* +=============== +PM_AddTouchEnt +=============== +*/ +void PM_AddTouchEnt + ( + int entityNum + ) + + { + int i; + + if ( entityNum == ENTITYNUM_WORLD ) + { + return; + } + + if ( pm->numtouch == MAXTOUCH ) + { + return; + } + + // see if it is already added + for( i = 0; i < pm->numtouch; i++ ) + { + if ( pm->touchents[ i ] == entityNum ) + { + return; + } + } + + // add it + pm->touchents[ pm->numtouch ] = entityNum; + pm->numtouch++; + } + +/* +================== +PM_ClipVelocity + +Slide off of the impacting surface +================== +*/ +void PM_ClipVelocity + ( + vec3_t in, + vec3_t normal, + vec3_t out, + float overbounce + ) + + { + float backoff; + float change; + int i; + + backoff = DotProduct( in, normal ); + + if ( backoff < 0 ) + { + backoff *= overbounce; + } + else + { + backoff /= overbounce; + } + + for( i = 0; i < 3; i++ ) + { + change = normal[ i ] * backoff; + out[ i ] = in[ i ] - change; + } + } + +/* +================== +PM_SlideMove + +Returns qtrue if the velocity was clipped in some way +================== +*/ +#define MAX_CLIP_PLANES 5 +qboolean PM_SlideMove( qboolean gravity ) { + int bumpcount, numbumps; + vec3_t dir; + float d; + int numplanes; + vec3_t planes[MAX_CLIP_PLANES]; + vec3_t primal_velocity; + vec3_t clipVelocity; + int i, j, k; + trace_t trace; + vec3_t end; + float time_left; + float into; + vec3_t endVelocity; + vec3_t endClipVelocity; + + numbumps = 4; + + VectorCopy (pm->ps->velocity, primal_velocity); + + if ( gravity ) { + VectorCopy( pm->ps->velocity, endVelocity ); + endVelocity[2] -= pm->ps->gravity * pml.frametime; + pm->ps->velocity[2] = ( pm->ps->velocity[2] + endVelocity[2] ) * 0.5; + primal_velocity[2] = endVelocity[2]; + if ( pml.groundPlane ) { + // slide along the ground plane + PM_ClipVelocity (pm->ps->velocity, pml.groundTrace.plane.normal, + pm->ps->velocity, OVERCLIP ); + } + } + + time_left = pml.frametime; + + // never turn against the ground plane + if ( pml.groundPlane ) { + numplanes = 1; + VectorCopy( pml.groundTrace.plane.normal, planes[0] ); + } else { + numplanes = 0; + } + + // never turn against original velocity + VectorNormalize2( pm->ps->velocity, planes[numplanes] ); + numplanes++; + + for ( bumpcount=0 ; bumpcount < numbumps ; bumpcount++ ) { + + // calculate position we are trying to move to + VectorMA( pm->ps->origin, time_left, pm->ps->velocity, end ); + + // see if we can make it there + pm->trace ( &trace, pm->ps->origin, pm->mins, pm->maxs, end, pm->ps->clientNum, pm->tracemask, qtrue ); + + if ( trace.startsolid && trace.entityNum != ENTITYNUM_WORLD ) + { + // stuck in an entity, so try to pretend it's not there + pm->trace ( &trace, pm->ps->origin, pm->mins, pm->maxs, end, trace.entityNum, pm->tracemask, qtrue ); + } + + if (trace.allsolid) { + // entity is completely trapped in another solid + pm->ps->velocity[2] = 0; // don't build up falling damage, but allow sideways acceleration + return qtrue; + } + + if ( pm->trypush && pm->trypush( trace.entityNum, pm->ps->origin, end ) ) + continue; + + if (trace.fraction > 0) { + // actually covered some distance + VectorCopy (trace.endpos, pm->ps->origin); + } + + if (trace.fraction == 1) { + break; // moved the entire distance + } + + if ( ( trace.plane.normal[ 2 ] < MIN_WALK_NORMAL ) && ( trace.plane.normal[ 2 ] > 0 ) ) + { + // treat steep walls as vertical + trace.plane.normal[ 2 ] = 0; + VectorNormalize( trace.plane.normal ); + } + + // save entity for contact + PM_AddTouchEnt( trace.entityNum ); + + time_left -= time_left * trace.fraction; + + if (numplanes >= MAX_CLIP_PLANES) { + // this shouldn't really happen + VectorClear( pm->ps->velocity ); + return qtrue; + } + + // + // if this is the same plane we hit before, nudge velocity + // out along it, which fixes some epsilon issues with + // non-axial planes + // + for ( i = 0 ; i < numplanes ; i++ ) { + if ( DotProduct( trace.plane.normal, planes[i] ) > 0.99 ) { + VectorAdd( trace.plane.normal, pm->ps->velocity, pm->ps->velocity ); + break; + } + } + if ( i < numplanes ) { + continue; + } + VectorCopy (trace.plane.normal, planes[numplanes]); + numplanes++; + + // + // modify velocity so it parallels all of the clip planes + // + + // find a plane that it enters + for ( i = 0 ; i < numplanes ; i++ ) { + into = DotProduct( pm->ps->velocity, planes[i] ); + if ( into >= 0.1 ) { + continue; // move doesn't interact with the plane + } + + // see how hard we are hitting things + if ( -into > pml.impactSpeed ) { + pml.impactSpeed = -into; + } + + // slide along the plane + PM_ClipVelocity (pm->ps->velocity, planes[i], clipVelocity, OVERCLIP ); + + // slide along the plane + PM_ClipVelocity (endVelocity, planes[i], endClipVelocity, OVERCLIP ); + + // see if there is a second plane that the new move enters + for ( j = 0 ; j < numplanes ; j++ ) { + if ( j == i ) { + continue; + } + if ( DotProduct( clipVelocity, planes[j] ) >= 0.1 ) { + continue; // move doesn't interact with the plane + } + + // try clipping the move to the plane + PM_ClipVelocity( clipVelocity, planes[j], clipVelocity, OVERCLIP ); + PM_ClipVelocity( endClipVelocity, planes[j], endClipVelocity, OVERCLIP ); + + // see if it goes back into the first clip plane + if ( DotProduct( clipVelocity, planes[i] ) >= 0 ) { + continue; + } + + // slide the original velocity along the crease + CrossProduct (planes[i], planes[j], dir); + VectorNormalize( dir ); + d = DotProduct( dir, pm->ps->velocity ); + VectorScale( dir, d, clipVelocity ); + + CrossProduct (planes[i], planes[j], dir); + VectorNormalize( dir ); + d = DotProduct( dir, endVelocity ); + VectorScale( dir, d, endClipVelocity ); + + // see if there is a third plane the the new move enters + for ( k = 0 ; k < numplanes ; k++ ) { + if ( k == i || k == j ) { + continue; + } + if ( DotProduct( clipVelocity, planes[k] ) >= 0.1 ) { + continue; // move doesn't interact with the plane + } + + // stop dead at a tripple plane interaction + VectorClear( pm->ps->velocity ); + return qtrue; + } + } + + // if we have fixed all interactions, try another move + VectorCopy( clipVelocity, pm->ps->velocity ); + VectorCopy( endClipVelocity, endVelocity ); + break; + } + } + + if ( gravity ) { + VectorCopy( endVelocity, pm->ps->velocity ); + } + + // don't change velocity if in a timer (FIXME: is this correct?) + if ( pm->ps->pm_time ) { + VectorCopy( primal_velocity, pm->ps->velocity ); + } + + return ( bumpcount != 0 ); +} + +/* +================== +PM_StepSlideMove + +================== +*/ +void PM_StepSlideMove( qboolean gravity ) { + vec3_t start_o, start_v; + trace_t trace; +// float down_dist, up_dist; +// vec3_t delta, delta2; + vec3_t up, down; + + VectorCopy (pm->ps->origin, start_o); + VectorCopy (pm->ps->velocity, start_v); + + if ( PM_SlideMove( gravity ) == 0 ) { + return; // we got exactly where we wanted to go first try + } + + VectorCopy(start_o, down); + down[2] -= STEPSIZE; + pm->trace (&trace, start_o, pm->mins, pm->maxs, down, pm->ps->clientNum, pm->tracemask, qtrue); + VectorSet(up, 0, 0, 1); + // never step up when you still have up velocity + if ( pm->ps->velocity[2] > 0 && (trace.fraction == 1.0 || + DotProduct(trace.plane.normal, up) < 0.7)) { + return; + } + + VectorCopy (start_o, up); + up[2] += STEPSIZE; + + // test the player position if they were a stepheight higher + pm->trace (&trace, up, pm->mins, pm->maxs, up, pm->ps->clientNum, pm->tracemask, qtrue); + if ( trace.allsolid ) { + if ( pm->debugLevel ) { + Com_Printf("%i:bend can't step\n", c_pmove); + } + return; // can't step up + } + + // try slidemove from this position + VectorCopy (up, pm->ps->origin); + VectorCopy (start_v, pm->ps->velocity); + + PM_SlideMove( gravity ); + + // push down the final amount + VectorCopy (pm->ps->origin, down); + down[2] -= STEPSIZE; + pm->trace (&trace, pm->ps->origin, pm->mins, pm->maxs, down, pm->ps->clientNum, pm->tracemask, qtrue ); + if ( !trace.allsolid ) + { + if ( ( trace.fraction < 1.0 ) && trace.plane.normal[ 2 ] < MIN_WALK_NORMAL ) + { + VectorCopy (start_o, pm->ps->origin); + return; + } + } + VectorCopy (trace.endpos, pm->ps->origin); + + if ( trace.fraction < 1.0 ) { + PM_ClipVelocity( pm->ps->velocity, trace.plane.normal, pm->ps->velocity, OVERCLIP ); + } + + // use the step move + pm->stepped = qtrue; + if ( pm->debugLevel ) { + Com_Printf("%i:stepped\n", c_pmove); + } +} + + +/* +================== +PM_Friction + +Handles both ground friction and water friction +================== +*/ +void PM_Friction + ( + void + ) + + { + vec3_t vec; + float *vel; + float speed; + float newspeed; + float control; + float drop; + + vel = pm->ps->velocity; + + VectorCopy( vel, vec ); + if ( pml.walking ) + { + // ignore slope movement + vec[ 2 ] = 0; + } + + speed = VectorLength( vec ); + if ( speed < 1 ) + { + // allow sinking underwater + vel[ 0 ] = 0; + vel[ 1 ] = 0; + + return; + } + + drop = 0; + + // apply ground friction + if ( pml.walking ) + { + // if getting knocked back, no friction + if ( !( pm->ps->pm_flags & PMF_TIME_KNOCKBACK ) ) + { + control = ( speed < pm_stopspeed ) ? pm_stopspeed : speed; + if ( pml.groundTrace.surfaceFlags & SURF_SLICK ) + { + drop += control * pm_slipperyfriction * pml.frametime; + } + else + { + drop += control * pm_friction * pml.frametime; + } + } + } + + // apply water friction + if ( pm->waterlevel ) + { + if ( pm->watertype & CONTENTS_SLIME ) + { + drop += speed * pm_waterfriction * 5 * pm->waterlevel * pml.frametime; + //drop += speed * pm_waterfriction * 2 * pml.frametime; + } + else + { + drop += speed * pm_waterfriction * pm->waterlevel * pml.frametime; + } + } + + // scale the velocity + newspeed = speed - drop; + if ( newspeed < 0 ) + { + newspeed = 0; + } + + newspeed /= speed; + + vel[0] = vel[ 0 ] * newspeed; + vel[1] = vel[ 1 ] * newspeed; + vel[2] = vel[ 2 ] * newspeed; + } + + +/* +============== +PM_Accelerate + +Handles user intended acceleration +============== +*/ +void PM_Accelerate + ( + vec3_t wishdir, + float wishspeed, + float accel + ) + + { + int i; + float addspeed; + float accelspeed; + float currentspeed; + + currentspeed = DotProduct( pm->ps->velocity, wishdir ); + addspeed = wishspeed - currentspeed; + if ( addspeed <= 0 ) + { + return; + } + + accelspeed = accel * pml.frametime * wishspeed; + if ( accelspeed > addspeed ) + { + accelspeed = addspeed; + } + + for( i = 0; i < 3; i++ ) + { + pm->ps->velocity[ i ] += accelspeed * wishdir[ i ]; + } + } + + +/* +============ +PM_CmdScale + +Returns the scale factor to apply to cmd movements +This allows the clients to use axial -127 to 127 values for all directions +without getting a sqrt(2) distortion in speed. +============ +*/ + +float PM_CmdScale + ( + usercmd_t *cmd + ) + + { + int max; + float total; + float scale; + + max = abs( cmd->forwardmove ); + if ( abs( cmd->rightmove ) > max ) + { + max = abs( cmd->rightmove ); + } + + if ( abs( cmd->upmove ) > max ) + { + max = abs( cmd->upmove ); + } + + if ( !max ) + { + return 0; + } + + total = sqrt( cmd->forwardmove * cmd->forwardmove + cmd->rightmove * cmd->rightmove + cmd->upmove * cmd->upmove ); + scale = pm->ps->speed * max / ( 127.0 * total ); + + return scale; + } + +/* +============= +PM_CheckWaterJump +============= +*/ +qboolean PM_CheckWaterJump + ( + void + ) + + { + vec3_t spot; + int cont; + + if ( pm->ps->pm_time ) + { + return qfalse; + } + + // check for water jump + if ( ( pm->waterlevel < 2 ) ) + { + return qfalse; + } + // if we are below the surface and not in slime, return + if ( !( pm->watertype & CONTENTS_SLIME ) && ( pm->waterlevel == 3 ) ) + { + return qfalse; + } + + VectorMA( pm->ps->origin, 80, pml.flat_forward, spot ); + spot[ 2 ] += pm->ps->viewheight - 16 ; + cont = pm->pointcontents( spot, pm->ps->clientNum ); + if ( !( cont & pm->tracemask ) ) + { + return qfalse; + } + + spot[ 2 ] += 48; + cont = pm->pointcontents( spot, pm->ps->clientNum ); + if ( cont ) + { + return qfalse; + } + + // jump out of water + VectorScale( pml.flat_forward, 150, pm->ps->velocity ); + pm->ps->velocity[ 2 ] = 600; + + pm->ps->pm_flags |= PMF_TIME_WATERJUMP; + pm->ps->pm_time = 2000; + + return qtrue; + } + +//============================================================================ + + +/* +=================== +PM_WaterJumpMove + +Flying out of the water +=================== +*/ +void PM_WaterJumpMove + ( + void + ) + + { + // waterjump has no control, but falls + PM_StepSlideMove( !( pm->ps->pm_flags & PMF_NO_GRAVITY ) ); + + pm->ps->velocity[ 2 ] -= pm->ps->gravity * pml.frametime; + if ( pm->ps->velocity[ 2 ] < 0 ) + { + // cancel as soon as we are falling down again + pm->ps->pm_flags &= ~PMF_ALL_TIMES; + pm->ps->pm_time = 0; + } + } + +#define SLIME_SINK_SPEED -10.0f +/* +=================== +PM_WaterMove + +=================== +*/ +void PM_WaterMove + ( + void + ) + + { + int i; + vec3_t wishvel; + float wishspeed; + vec3_t wishdir; + float scale; + + if ( PM_CheckWaterJump() ) + { + PM_WaterJumpMove(); + return; + } + + // + // clamp our speed if we are in slime + // + if ( pm->watertype & CONTENTS_SLIME ) + { + if ( pm->ps->velocity[ 2 ] < SLIME_SINK_SPEED ) + { + pm->ps->velocity[ 2 ] = SLIME_SINK_SPEED; + } + } + + PM_Friction(); + + scale = PM_CmdScale( &pm->cmd ); + + // + // user intentions + // + if ( !scale ) + { + wishvel[ 0 ] = 0; + wishvel[ 1 ] = 0; + if ( pm->watertype & CONTENTS_SLIME ) + { + wishvel[ 2 ] = SLIME_SINK_SPEED; // sink towards bottom + } + else + { + wishvel[ 2 ] = -60; // sink towards bottom + } + } + else + { + for( i = 0; i < 3; i++ ) + { + wishvel[ i ] = scale * pml.flat_forward[ i ] * pm->cmd.forwardmove - scale * pml.flat_left[ i ] * pm->cmd.rightmove; + } + + wishvel[ 2 ] += scale * pm->cmd.upmove; + } + if ( ( pm->watertype & CONTENTS_SLIME ) && ( pm->waterlevel > 2 ) && ( wishvel[ 2 ] < 0 ) ) + { + wishvel[ 2 ] = 0; + } + + VectorCopy( wishvel, wishdir ); + wishspeed = VectorNormalize( wishdir ); + + if ( wishspeed > pm->ps->speed * pm_swimScale ) + { + wishspeed = pm->ps->speed * pm_swimScale; + } + + PM_Accelerate( wishdir, wishspeed, pm_wateraccelerate ); + + PM_SlideMove( qfalse ); + } + +/* +=================== +PM_StuckJumpMove + +Flying out of someplace we were stuck +=================== +*/ +void PM_StuckJumpMove + ( + void + ) + + { + // stuckjump has no control, but falls + PM_StepSlideMove( !( pm->ps->pm_flags & PMF_NO_GRAVITY ) ); + + pm->ps->velocity[ 2 ] -= pm->ps->gravity * pml.frametime; + if ( pm->ps->velocity[ 2 ] < -48 ) + { + // cancel as soon as we are falling at decent clip again + pm->ps->pm_flags &= ~PMF_ALL_TIMES; + pm->ps->pm_time = 0; + } + } + +/* +============= +PM_CheckStuckJump +============= +*/ +#define MAX_XY_VELOCITY 50 +qboolean PM_CheckStuckJump + ( + void + ) + + { + vec3_t diff; + + if ( pm->ps->pm_time ) + { + return qfalse; + } + + if ( pm->waterlevel > 1 ) + { + return qfalse; + } + + VectorSubtract( pm->ps->origin, pml.previous_origin, diff ); + if ( VectorLength( diff ) ) + { + return qfalse; + } + if ( VectorLength( pm->ps->velocity ) < 100 ) + { + return qfalse; + } + + // we have been falling, we haven't moved and our velocity is getting dangerously high + // let's give ourselves a boost straight up and opposite our current velocity + pm->ps->velocity[ 0 ] = -pm->ps->velocity[ 0 ]; + if ( pm->ps->velocity[ 0 ] > MAX_XY_VELOCITY ) + pm->ps->velocity[ 0 ] = MAX_XY_VELOCITY; + else if ( pm->ps->velocity[ 0 ] < -MAX_XY_VELOCITY ) + pm->ps->velocity[ 0 ] = -MAX_XY_VELOCITY; + + pm->ps->velocity[ 1 ] = -pm->ps->velocity[ 1 ]; + if ( pm->ps->velocity[ 1 ] > MAX_XY_VELOCITY ) + pm->ps->velocity[ 1 ] = MAX_XY_VELOCITY; + else if ( pm->ps->velocity[ 1 ] < -MAX_XY_VELOCITY ) + pm->ps->velocity[ 1 ] = -MAX_XY_VELOCITY; + + pm->ps->velocity[ 2 ] = 500; + + pm->ps->pm_flags |= PMF_TIME_STUCKJUMP; + pm->ps->pm_time = 2000; + + return qtrue; + } + +/* +============= +PM_CheckTerminalVelocity +============= +*/ +#define TERMINAL_VELOCITY 1200 +void PM_CheckTerminalVelocity + ( + void + ) + { + float oldspeed; + float speed; + + // + // how fast were we falling + // + oldspeed = -pml.previous_velocity[ 2 ]; + + // + // how fast are we falling + // + speed = -pm->ps->velocity[ 2 ]; + + if ( speed <= 0 ) + { + return; + } + + if ( ( oldspeed <= TERMINAL_VELOCITY ) && ( speed > TERMINAL_VELOCITY ) ) + { + pm->pmoveEvent = EV_TERMINAL_VELOCITY; + } + } + +/* +=================== +PM_AirMove + +=================== +*/ +void PM_AirMove + ( + void + ) + + { + vec3_t wishvel; + float fmove; + float smove; + vec3_t wishdir; + float wishspeed; + float scale; + usercmd_t cmd; + + //PM_Friction(); + + fmove = pm->cmd.forwardmove; + smove = pm->cmd.rightmove; + pm->ps->pm_runtime = 0; + + cmd = pm->cmd; + scale = PM_CmdScale( &cmd ); + + wishvel[ 0 ] = pml.flat_forward[ 0 ] * fmove - pml.flat_left[ 0 ] * smove; + wishvel[ 1 ] = pml.flat_forward[ 1 ] * fmove - pml.flat_left[ 1 ] * smove; + wishvel[ 2 ] = 0; + + VectorCopy( wishvel, wishdir ); + wishspeed = VectorNormalize( wishdir ); + wishspeed *= scale; + + // not on ground, so little effect on velocity + PM_Accelerate( wishdir, wishspeed, pm_airaccelerate ); + + // we may have a ground plane that is very steep, even + // though we don't have a groundentity + // slide along the steep plane + if ( pml.groundPlane ) + { + PM_ClipVelocity( pm->ps->velocity, pml.groundTrace.plane.normal, pm->ps->velocity, OVERCLIP ); + } + + if ( !pml.walking && pml.groundPlane ) + { + vec3_t vel; + + VectorCopy( pm->ps->velocity, vel ); + vel[ 2 ] -= pm->ps->gravity * pml.frametime; + pm->ps->velocity[ 2 ] = ( pm->ps->velocity[ 2 ] + vel[ 2 ] ) * 0.5; + PM_SlideMove( qfalse ); + VectorCopy( vel, pm->ps->velocity ); + } + else + { + PM_SlideMove( !( pm->ps->pm_flags & PMF_NO_GRAVITY ) ); + } + + if ( PM_CheckStuckJump() ) + { + PM_StuckJumpMove(); + } + PM_CheckTerminalVelocity(); + } + +void AddPlane + ( + vec3_t norm, + vec3_t planes[ MAX_CLIP_PLANES ], + int *numplanes + ) + + { + int i; + + if ( *numplanes >= MAX_CLIP_PLANES ) + { + return; + } + + for( i = 0; i < *numplanes; i++ ) + { + if ( VectorCompare( planes[ i ], norm ) ) + { + // don't add the plane twice + return; + } + } + + VectorCopy( norm, planes[ *numplanes ] ); + ( *numplanes )++; + } + +/* +================== +PM_FakkSlideMove + +Returns qtrue if the velocity was clipped in some way +================== +*/ +qboolean PM_FakkSlideMove + ( + void + ) + + { + int bumpcount, numbumps; + vec3_t dir; + float d; + int numplanes; + vec3_t planes[ MAX_CLIP_PLANES ]; + vec3_t clipVelocity; + vec3_t temp; + int i, j, k; + trace_t trace; + vec3_t end; + float time_left; + float into; + + numbumps = 4; + + time_left = pml.frametime; + + // never turn against the ground plane + if ( pml.groundPlane ) + { + numplanes = 1; + VectorCopy( pml.groundTrace.plane.normal, planes[ 0 ] ); + } + else + { + numplanes = 0; + } + + // never turn against original velocity + VectorNormalize2( pm->ps->velocity, temp ); + AddPlane( temp, planes, &numplanes ); + + for( bumpcount = 0; bumpcount < numbumps; bumpcount++ ) + { + // calculate position we are trying to move to + VectorMA( pm->ps->origin, time_left, pm->ps->velocity, end ); + + // see if we can make it there + pm->trace( &trace, pm->ps->origin, pm->mins, pm->maxs, end, pm->ps->clientNum, pm->tracemask, qtrue ); + + if ( trace.allsolid ) + { + // entity is completely trapped in another solid + // don't build up falling damage, but allow sideways acceleration + pm->ps->velocity[ 2 ] = 0; + + if ( pm->debugLevel ) + { + Com_Printf( "All solid, %d planes : ", numplanes ); + for( i = 0; i < numplanes; i++ ) + { + Com_Printf( "(%.2f,%.2f,%.2f) ", planes[ i ][ 0 ], planes[ i ][ 1 ], planes[ i ][ 2 ] ); + } + Com_Printf( "\n" ); + } + + return qtrue; + } + + if ( trace.fraction > 0 ) + { + // actually covered some distance + VectorCopy( trace.endpos, pm->ps->origin ); + } + + if ( trace.fraction == 1 ) + { + // moved the entire distance + break; + } + + // save entity for contact + if ( trace.entityNum != ENTITYNUM_NONE ) + { + PM_AddTouchEnt( trace.entityNum ); + } + + time_left -= time_left * trace.fraction; + + if ( numplanes >= MAX_CLIP_PLANES ) + { + // this shouldn't really happen + VectorClear( pm->ps->velocity ); + + if ( pm->debugLevel ) + { + Com_Printf( "maxplanes, %d planes : ", numplanes ); + for( i = 0; i < numplanes; i++ ) + { + Com_Printf( "(%.2f,%.2f,%.2f) ", planes[ i ][ 0 ], planes[ i ][ 1 ], planes[ i ][ 2 ] ); + } + Com_Printf( "\n" ); + } + return qtrue; + } + + // altering move slightly by the normal reduces the chance that the next move + // will hit the same surface + VectorAdd( pm->ps->velocity, trace.plane.normal, pm->ps->velocity ); + + if ( ( trace.plane.normal[ 2 ] < MIN_WALK_NORMAL ) && ( trace.plane.normal[ 2 ] > 0 ) ) + { + // treat steep walls as vertical + trace.plane.normal[ 2 ] = 0; + VectorNormalize2( trace.plane.normal, temp ); + AddPlane( temp, planes, &numplanes ); + } + else + { + AddPlane( trace.plane.normal, planes, &numplanes ); + } + + // + // modify velocity so it parallels all of the clip planes + // + + // find a plane that it enters + for( i = 0; i < numplanes; i++ ) + { + into = DotProduct( pm->ps->velocity, planes[ i ] ); + if ( into >= 0.1f ) + { + // move doesn't interact with the plane + continue; + } + + // see how hard we are hitting things + if ( -into > pml.impactSpeed ) + { + pml.impactSpeed = -into; + } + + // slide along the plane + PM_ClipVelocity( pm->ps->velocity, planes[ i ], clipVelocity, OVERCLIP ); + + // see if there is a second plane that the new move enters + for ( j = 0; j < numplanes; j++ ) + { + if ( j == i ) + { + continue; + } + + if ( DotProduct( clipVelocity, planes[ j ] ) >= 0.1f ) + { + // move doesn't interact with the plane + continue; + } + + // try clipping the move to the plane + PM_ClipVelocity( clipVelocity, planes[ j ], clipVelocity, OVERCLIP ); + + // see if it goes back into the first clip plane + if ( DotProduct( clipVelocity, planes[ i ] ) >= 0 ) + { + continue; + } + + // slide the original velocity along the crease + CrossProduct( planes[ i ], planes[ j ], dir ); + VectorNormalize( dir ); + d = DotProduct( dir, pm->ps->velocity ); + VectorScale( dir, d, clipVelocity ); + + // see if there is a third plane the the new move enters + for( k = 0; k < numplanes; k++ ) + { + if ( k == i || k == j ) + { + continue; + } + + if ( DotProduct( clipVelocity, planes[ k ] ) >= 0.1f ) + { + // move doesn't interact with the plane + continue; + } + + PM_ClipVelocity( clipVelocity, planes[ k ], clipVelocity, OVERCLIP ); + + if ( ( DotProduct( clipVelocity, planes[ i ] ) >= 0 ) && ( DotProduct( clipVelocity, planes[ j ] ) >= 0 ) ) + { + continue; + } + + // stop dead at a triple plane interaction + if ( pm->debugLevel ) + { + Com_Printf( "Dead stop, %d planes : ", numplanes ); + for( i = 0; i < numplanes; i++ ) + { + Com_Printf( "(%.2f,%.2f,%.2f) ", planes[ i ][ 0 ], planes[ i ][ 1 ], planes[ i ][ 2 ] ); + } + Com_Printf( "\n" ); + } + VectorClear( pm->ps->velocity ); + return qtrue; + } + } + + // if we have fixed all interactions, try another move + VectorCopy( clipVelocity, pm->ps->velocity ); + break; + } + } + + if ( pm->debugLevel ) + { + Com_Printf( "move ok, %d planes : ", numplanes ); + for( i = 0; i < numplanes; i++ ) + { + Com_Printf( "(%.2f,%.2f,%.2f) ", planes[ i ][ 0 ], planes[ i ][ 1 ], planes[ i ][ 2 ] ); + } + Com_Printf( "\n" ); + } + + return ( bumpcount != 0 ); + } + + +void PM_StepMove + ( + void + ) + + { + trace_t trace; + vec3_t up; + vec3_t down; + vec3_t oldvelocity; + vec3_t oldorigin; + vec3_t velocity1; + vec3_t origin1; + + VectorCopy( pm->ps->velocity, oldvelocity ); + VectorCopy( pm->ps->origin, oldorigin ); + +// if ( PM_FakkSlideMove() ) + if ( PM_SlideMove( !( pm->ps->pm_flags & PMF_NO_GRAVITY ) ) ) + { + VectorCopy( pm->ps->velocity, velocity1 ); + VectorCopy( pm->ps->origin, origin1 ); + + VectorCopy( oldvelocity, pm->ps->velocity ); + + VectorCopy( oldorigin, up ); + up[ 2 ] += STEPSIZE; + + //pm->trace( &trace, oldorigin, pm->mins, pm->maxs, up, pm->ps->clientNum, pm->tracemask, qtrue ); + pm->trace( &trace, up, pm->mins, pm->maxs, up, pm->ps->clientNum, pm->tracemask, qtrue ); + VectorCopy( trace.endpos, pm->ps->origin ); + + //PM_FakkSlideMove(); + PM_SlideMove( !( pm->ps->pm_flags & PMF_NO_GRAVITY ) ); + + VectorCopy( pm->ps->origin, down ); + down[ 2 ] = oldorigin[ 2 ]; + + pm->trace( &trace, pm->ps->origin, pm->mins, pm->maxs, down, pm->ps->clientNum, pm->tracemask, qtrue ); + if ( trace.plane.normal[ 2 ] < MIN_WALK_NORMAL ) + { + // use the first move + VectorCopy( velocity1, pm->ps->velocity ); + VectorCopy( origin1, pm->ps->origin ); + } + else + { + VectorCopy( trace.endpos, pm->ps->origin ); + pm->stepped = qtrue; + } + } + } + +static vec3_t min3x3 = { -3, -3, 0 }; +static vec3_t max3x3 = { 3, 3, 8 }; +//static vec3_t base_rightfoot_pos = { 0, -7, 0 }; +//static vec3_t base_leftfoot_pos = { 0, 7, 0 }; +static vec3_t base_rightfoot_pos = { -5.25301, -3.10885, 0 }; +static vec3_t base_leftfoot_pos = { -0.123711, 10.4893, 0 }; + +qboolean PM_FeetOnGround + ( + vec3_t pos + ) + + { + vec3_t start; + vec3_t end; + vec3_t rightfoot; + vec3_t leftfoot; + vec3_t ang; + float mat[ 3 ][ 3 ]; + trace_t trace; + + VectorSet( ang, 0, pm->ps->viewangles[ 1 ], 0 ); + AngleVectors( ang, mat[ 0 ], mat[ 1 ], mat[ 2 ] ); + + MatrixTransformVector( base_rightfoot_pos, mat, rightfoot ); + MatrixTransformVector( base_leftfoot_pos, mat, leftfoot ); + VectorAdd( rightfoot, pos, rightfoot ); + VectorAdd( leftfoot, pos, leftfoot ); + + VectorCopy( rightfoot, start ); + VectorCopy( rightfoot, end ); + end[ 2 ] -= 16.1f; + + pm->trace( &trace, start, min3x3, max3x3, end, pm->ps->clientNum, pm->tracemask, qtrue ); + if ( trace.fraction == 1.0f ) + { + return qfalse; + } + + // try the left foot + VectorCopy( leftfoot, start ); + VectorCopy( leftfoot, end ); + end[ 2 ] -= 16.1f; + + pm->trace( &trace, start, min3x3, max3x3, end, pm->ps->clientNum, pm->tracemask, qtrue ); + if ( trace.fraction == 1.0f ) + { + return qfalse; + } + + return qtrue; + } + +#if 0 +qboolean PM_FindBestFallPos + ( + vec3_t pos, + vec3_t bestdir + ) + + { + trace_t trace; + vec3_t ang; + vec3_t dir; + vec3_t start; + vec3_t end; + vec3_t move; + float best; + float len; + int i; + qboolean set; + float radius; + + set = qfalse; + + radius = pm->maxs[ 0 ] - pm->mins[ 0 ] + 1.0f; + + VectorCopy( pos, start ); + start[ 2 ] -= 16.1f; + + best = 1000.0f; + VectorSet( ang, 0, pm->ps->viewangles[ 1 ], 0 ); + for( i = 0; i < 16; i++, ang[ 1 ] += 22.5f ) + { + AngleVectors( ang, dir, NULL, NULL ); + VectorMA( pos, radius, dir, move ); + + pm->trace( &trace, pos, pm->mins, pm->maxs, move, pm->ps->clientNum, pm->tracemask, qtrue ); + + VectorCopy( trace.endpos, end ); + end[ 2 ] = start[ 2 ]; + + pm->trace( &trace, trace.endpos, pm->mins, pm->maxs, end, pm->ps->clientNum, pm->tracemask, qtrue ); + if ( trace.fraction == 1.0f ) + { + VectorCopy( trace.endpos, end ); + pm->trace( &trace, end, pm->mins, pm->maxs, start, pm->ps->clientNum, pm->tracemask, qtrue ); + VectorSubtract( trace.endpos, start, end ); + end[ 2 ] = 0; + + len = VectorLength( end ); + if ( len && ( len < best ) ) + { + best = len; + VectorScale( end, 1.0f / len, bestdir ); + set = qtrue; + } + } + } + + return set; + } +#else +qboolean PM_FindBestFallPos + ( + vec3_t pos, + vec3_t bestdir + ) + + { + trace_t trace; + vec3_t ang; + vec3_t dir; + vec3_t start; + vec3_t end; + vec3_t move; + int i; + qboolean set; + float radius; + + VectorClear( bestdir ); + + set = qfalse; + + radius = pm->maxs[ 0 ] - pm->mins[ 0 ] + 1.0f; + + VectorCopy( pos, start ); + start[ 2 ] -= 16.1f; + + VectorSet( ang, 0, pm->ps->viewangles[ 1 ], 0 ); + for( i = 0; i < 16; i++, ang[ 1 ] += 22.5f ) + { + AngleVectors( ang, dir, NULL, NULL ); + VectorMA( pos, radius, dir, move ); + + pm->trace( &trace, pos, pm->mins, pm->maxs, move, pm->ps->clientNum, pm->tracemask, qtrue ); + + VectorCopy( trace.endpos, end ); + end[ 2 ] = start[ 2 ]; + + pm->trace( &trace, trace.endpos, pm->mins, pm->maxs, end, pm->ps->clientNum, pm->tracemask, qtrue ); + if ( trace.fraction == 1.0f ) + { + VectorCopy( trace.endpos, end ); + pm->trace( &trace, end, pm->mins, pm->maxs, start, pm->ps->clientNum, pm->tracemask, qtrue ); + + if ( trace.fraction < 1.0f ) + { + VectorAdd( bestdir, trace.plane.normal, bestdir ); + set = qtrue; + } + } + } + + if ( !set || !VectorNormalize( bestdir ) ) + { + return qfalse; + } + + return qtrue; + } +#endif + +void PM_CheckFeet + ( + void + ) + + { + trace_t trace; + vec3_t temp; + + if ( pm->stepped ) + { + pm->ps->feetfalling = 0; + return; + } + + // check if our feet are properly on the ground + if ( pm->ps->walking ) + { + VectorMA( pm->ps->origin, 0.2f, pm->ps->velocity, temp ); //FIXME frametime + temp[ 2 ] = pm->ps->origin[ 2 ] + 2; + if ( PM_FeetOnGround( pm->ps->origin ) || PM_FeetOnGround( temp ) ) + { + pm->ps->feetfalling = 0; + return; + } + + if ( pm->ps->feetfalling > 0 ) + { + pm->ps->feetfalling--; + } + + if ( !pm->ps->feetfalling ) + { + if ( !PM_FindBestFallPos( pm->ps->origin, pm->ps->falldir ) ) + { + return; + } + + pm->ps->feetfalling = 5; + } + + // shove the player a little bit + VectorMA( pm->ps->origin, 2.0f, pm->ps->falldir, temp ); + pm->trace( &trace, pm->ps->origin, pm->mins, pm->maxs, temp, pm->ps->clientNum, pm->tracemask, qtrue ); + if ( trace.fraction == 0 ) + { + pm->ps->feetfalling = 0; + } + else + { + pm->ps->walking = qfalse; + VectorCopy( trace.endpos, pm->ps->origin ); + } + } + } + + +/* +=================== +PM_WalkMove + +=================== +*/ + +void PM_WalkMove + ( + void + ) + + { + int i; + vec3_t wishvel; + float fmove; + float smove; + vec3_t wishdir; + float wishspeed; + float scale; + usercmd_t cmd; + float accelerate; + float waterScale; + + if ( ( pm->waterlevel > 1 ) && DotProduct( pml.forward, pml.groundTrace.plane.normal ) > 0 ) + { + // begin swimming + PM_WaterMove(); + + return; + } + + PM_Friction(); + + fmove = pm->cmd.forwardmove; + smove = pm->cmd.rightmove; + + cmd = pm->cmd; + scale = PM_CmdScale( &cmd ); + + if ( ( pm->cmd.buttons & BUTTON_RUN ) && fmove && !smove ) + { + pm->ps->pm_runtime += pml.msec; + } + else + { + pm->ps->pm_runtime = 0; + } + + // + // only run faster if we have exceeded our running time + // + if ( ( pm->ps->stats[STAT_WATER_LEVEL] >= MINIMUM_WATER_FOR_TURBO ) && ( pm->ps->pm_runtime > WATER_TURBO_TIME ) ) + { + scale *= WATER_TURBO_SPEED; + } + + // project the forward and right directions onto the ground plane + PM_ClipVelocity (pml.flat_forward, pml.groundTrace.plane.normal, pml.flat_forward, OVERCLIP ); + PM_ClipVelocity (pml.flat_left, pml.groundTrace.plane.normal, pml.flat_left, OVERCLIP ); + // + VectorNormalize (pml.flat_forward); + VectorNormalize (pml.flat_left); + + for( i = 0 ; i < 3 ; i++ ) + { + wishvel[ i ] = pml.flat_forward[ i ] * fmove - pml.flat_left[ i ] * smove; + } + + VectorCopy( wishvel, wishdir ); + wishspeed = VectorNormalize( wishdir ); + wishspeed *= scale; + + // clamp the speed lower if ducking + if ( pm->ps->pm_flags & PMF_DUCKED ) + { + if ( wishspeed > pm->ps->speed * pm_duckScale ) + { + wishspeed = pm->ps->speed * pm_duckScale; + } + } + + // clamp the speed lower if wading or walking on the bottom + if ( pm->waterlevel ) + { + waterScale = pm->waterlevel / 3.0; + waterScale = 1.0 - ( 1.0 - pm_swimScale ) * waterScale; + if ( wishspeed > pm->ps->speed * waterScale ) + { + wishspeed = pm->ps->speed * waterScale; + } + } + + // when a player gets hit, they temporarily lose + // full control, which allows them to be moved a bit + if ( ( pml.groundTrace.surfaceFlags & SURF_SLICK ) || pm->ps->pm_flags & PMF_TIME_KNOCKBACK ) + { + accelerate = pm_airaccelerate; + } + else + { + accelerate = pm_accelerate; + } + + PM_Accelerate( wishdir, wishspeed, accelerate ); + + if ( ( pml.groundTrace.surfaceFlags & SURF_SLICK ) || pm->ps->pm_flags & PMF_TIME_KNOCKBACK ) + { + pm->ps->velocity[ 2 ] -= pm->ps->gravity * pml.frametime; + } + + // don't do anything if standing still + if ( !pm->ps->velocity[ 0 ] && !pm->ps->velocity[ 1 ] ) + { + PM_CheckFeet(); + return; + } + + //PM_StepMove(); + PM_StepSlideMove ( !( pm->ps->pm_flags & PMF_NO_GRAVITY ) ); + + + PM_CheckFeet(); + } + +/* +============== +PM_DeadMove +============== +*/ +void PM_DeadMove + ( + void + ) + + { + float forward; + + if ( !pml.walking ) + { + return; + } + + // extra friction + forward = VectorLength( pm->ps->velocity ); + forward -= 20; + if ( forward <= 0 ) + { + VectorClear( pm->ps->velocity ); + } + else + { + VectorNormalize( pm->ps->velocity ); + VectorScale( pm->ps->velocity, forward, pm->ps->velocity ); + } + } + + +/* +=============== +PM_NoclipMove +=============== +*/ +void PM_NoclipMove + ( + void + ) + + { + float speed; + float drop; + float friction; + float control; + float newspeed; + int i; + vec3_t wishvel; + float fmove; + float smove; + vec3_t wishdir; + float wishspeed; + float scale; + + pm->ps->viewheight = DEFAULT_VIEWHEIGHT; + + // friction + + speed = VectorLength( pm->ps->velocity ); + if ( speed < 1 ) + { + VectorCopy( vec3_origin, pm->ps->velocity ); + } + else + { + drop = 0; + + // extra friction + friction = pm_friction * 1.5; + + control = speed < pm_stopspeed ? pm_stopspeed : speed; + drop += control * friction * pml.frametime; + + // scale the velocity + newspeed = speed - drop; + if ( newspeed < 0 ) + { + newspeed = 0; + } + newspeed /= speed; + + VectorScale( pm->ps->velocity, newspeed, pm->ps->velocity ); + } + + // accelerate + // allow the player to move twice as fast in noclip + scale = PM_CmdScale( &pm->cmd ) * 2; + + fmove = pm->cmd.forwardmove; + smove = pm->cmd.rightmove; + pm->ps->pm_runtime = 0; + + for( i = 0; i < 3; i++ ) + { + wishvel[ i ] = pml.flat_forward[ i ] * fmove - pml.flat_left[ i ] * smove; + } + + wishvel[ 2 ] += pm->cmd.upmove; + + VectorCopy( wishvel, wishdir ); + wishspeed = VectorNormalize( wishdir ); + wishspeed *= scale; + + PM_Accelerate( wishdir, wishspeed, pm_accelerate ); + + // move + VectorMA( pm->ps->origin, pml.frametime, pm->ps->velocity, pm->ps->origin ); + } + +//============================================================================ + +/* +============= +PM_CorrectAllSolid +============= +*/ +void PM_CorrectAllSolid + ( + void + ) + + { + if ( pm->debugLevel ) + { + Com_Printf( "%i:allsolid\n", c_pmove ); + } + + // FIXME: jitter around + pm->ps->groundEntityNum = ENTITYNUM_NONE; + pml.groundPlane = qfalse; + pml.walking = qfalse; + } + +/* +============= +PM_GroundTrace +============= +*/ +void PM_GroundTrace + ( + void + ) + + { + vec3_t point; + trace_t trace; + + point[ 0 ] = pm->ps->origin[ 0 ]; + point[ 1 ] = pm->ps->origin[ 1 ]; + point[ 2 ] = pm->ps->origin[ 2 ] - 0.25; + + pm->trace( &trace, pm->ps->origin, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask, qtrue ); + pml.groundTrace = trace; + pm->ps->groundTrace = trace; + + // do something corrective if the trace starts in a solid... + if ( trace.allsolid ) + { + PM_CorrectAllSolid(); + + pm->ps->walking = pml.walking; + pm->ps->groundPlane = pml.groundPlane; + + return; + } + + // if the trace didn't hit anything, we are in free fall + if ( trace.fraction == 1.0 ) + { + if ( pm->ps->groundEntityNum != ENTITYNUM_NONE ) + { + if ( pm->debugLevel ) + { + Com_Printf( "%i:lift\n", c_pmove ); + } + } + + pm->ps->groundEntityNum = ENTITYNUM_NONE; + pml.groundPlane = qfalse; + pml.walking = qfalse; + + pm->ps->walking = pml.walking; + pm->ps->groundPlane = pml.groundPlane; + + return; + } + + // slopes that are too steep will not be considered onground + if ( trace.plane.normal[ 2 ] < MIN_WALK_NORMAL ) + { + vec3_t oldvel; + float d; + + if ( pm->debugLevel ) + { + Com_Printf( "%i:steep\n", c_pmove ); + } + + // if they can't slide down the slope, let them + // walk (sharp crevices) + VectorCopy( pm->ps->velocity, oldvel ); + VectorSet( pm->ps->velocity, 0, 0, -1 / pml.frametime ); + PM_SlideMove( qfalse ); + + d = VectorLength( pm->ps->velocity ); + VectorCopy( oldvel, pm->ps->velocity ); + + if ( d > ( 0.1f / pml.frametime ) ) + { + pm->ps->groundEntityNum = ENTITYNUM_NONE; + pml.groundPlane = qtrue; + pml.walking = qfalse; + + pm->ps->walking = pml.walking; + pm->ps->groundPlane = pml.groundPlane; + + return; + } + } + + // check if getting thrown off the ground + if ( pm->ps->velocity[ 2 ] > 0 && DotProduct( pm->ps->velocity, trace.plane.normal ) > 10 ) + { + if ( pm->debugLevel ) + { + Com_Printf( "%i:kickoff\n", c_pmove ); + } + + pm->ps->groundEntityNum = ENTITYNUM_NONE; + pml.groundPlane = qfalse; + pml.walking = qfalse; + + pm->ps->walking = pml.walking; + pm->ps->groundPlane = pml.groundPlane; + + return; + } + + pml.groundPlane = qtrue; + pml.walking = qtrue; + + // hitting solid ground will end a waterjump + if ( pm->ps->pm_flags & PMF_TIME_WATERJUMP ) + { + pm->ps->pm_flags &= ~( PMF_TIME_WATERJUMP ); + pm->ps->pm_time = 0; + } + + // hitting solid ground will end a stuckjump + if ( pm->ps->pm_flags & PMF_TIME_STUCKJUMP ) + { + pm->ps->pm_flags &= ~( PMF_TIME_STUCKJUMP ); + pm->ps->pm_time = 0; + } + + if ( pm->ps->groundEntityNum == ENTITYNUM_NONE ) + { + // just hit the ground + if ( pm->debugLevel ) + { + Com_Printf( "%i:Land\n", c_pmove ); + } + + PM_CrashLand(); + } + + pm->ps->groundEntityNum = trace.entityNum; + + //if ( !( pml.groundTrace.surfaceFlags & SURF_SLICK ) ) + pm->ps->velocity[ 2 ] = 0; + + PM_AddTouchEnt( trace.entityNum ); + + pm->ps->walking = pml.walking; + pm->ps->groundPlane = pml.groundPlane; + } + + +/* +============= +PM_SetWaterLevel FIXME: avoid this twice? certainly if not moving +============= +*/ +void PM_SetWaterLevel + ( + void + ) + + { + vec3_t point; + int cont; + int sample1; + int sample2; + + // + // get waterlevel, accounting for ducking + // + pm->waterlevel = 0; + pm->watertype = 0; + + sample2 = pm->ps->viewheight - MINS_Z; + sample1 = sample2 * 3 / 4; + + VectorCopy( pm->ps->origin, point ); + point[ 2 ] += MINS_Z + 1; + cont = pm->pointcontents( point, pm->ps->clientNum ); + if ( cont & MASK_WATER ) + { + pm->watertype = cont; + pm->waterlevel = 1; + + point[ 2 ] = pm->ps->origin[ 2 ] + MINS_Z + sample1; + cont = pm->pointcontents( point, 0 ); + if ( cont & MASK_WATER ) + { + pm->waterlevel = 2; + point[ 2 ] = pm->ps->origin[ 2 ] + MINS_Z + sample2; + cont = pm->pointcontents( point, 0 ); + if ( cont & MASK_WATER ) + { + pm->waterlevel = 3; + } + } + } + } + + +/* +============== +PM_CheckDuck + +Sets mins, maxs, and pm->ps->viewheight +============== +*/ +void PM_CheckDuck + ( + void + ) + + { + pm->mins[ 0 ] = MINS_X; + pm->mins[ 1 ] = MINS_Y; + + pm->maxs[ 0 ] = MAXS_X; + pm->maxs[ 1 ] = MAXS_Y; + + pm->mins[ 2 ] = MINS_Z; + + if ( pm->ps->pm_type == PM_DEAD ) + { + pm->maxs[ 2 ] = DEAD_MINS_Z; + pm->ps->viewheight = DEAD_VIEWHEIGHT; + + return; + } + + if ( pm->ps->pm_flags & PMF_DUCKED ) + { + pm->maxs[ 2 ] = CROUCH_MAXS_Z; + pm->ps->viewheight = CROUCH_VIEWHEIGHT; + } + else if ( pm->ps->pm_flags & PMF_LEGS_LIFTED ) + { + pm->maxs[ 2 ] = MAXS_Z; + pm->mins[ 2 ] = CROUCH_MAXS_Z; + pm->ps->viewheight = DEFAULT_VIEWHEIGHT; + } + else + { + pm->maxs[ 2 ] = MAXS_Z; + pm->ps->viewheight = DEFAULT_VIEWHEIGHT; + } + } + + +//=================================================================== + +/* +================= +PM_CrashLand + +Check for hard landings that generate sound events + + fall from 128: 400 = 160000 + fall from 256: 580 = 336400 + fall from 384: 720 = 518400 + fall from 512: 800 = 640000 + fall from 640: 960 = + + damage = deltavelocity*deltavelocity * 0.0001 + +================= +*/ +void PM_CrashLand + ( + void + ) + + { + float delta; + float dist; + float vel; + float acc; + float t; + float a, b, c, den; + + // calculate the exact velocity on landing + dist = pm->ps->origin[ 2 ] - pml.previous_origin[ 2 ]; + vel = pml.previous_velocity[ 2 ]; + acc = -pm->ps->gravity; + + a = acc / 2; + b = vel; + c = -dist; + + den = b * b - 4 * a * c; + if ( den < 0 ) + { + return; + } + + t = ( -b - sqrt( den ) ) / ( 2 * a ); + + delta = vel + t * acc; + delta = delta * delta * 0.0001; + + // never take falling damage if completely underwater + if ( pm->waterlevel == 3 ) + { + return; + } + + // reduce falling damage if there is standing water + if ( pm->waterlevel == 2 ) + { + delta *= 0.25f; + } + + if ( pm->waterlevel == 1 ) + { + delta *= 0.5f; + } + + if ( delta < 1 ) + { + return; + } + + // SURF_NODAMAGE is used for bounce pads where you don't ever + // want to take damage or play a crunch sound + if ( !( pml.groundTrace.surfaceFlags & SURF_NODAMAGE ) ) + { + if ( delta > 135 ) + { + pm->pmoveEvent = EV_FALL_FATAL; + } + else if ( delta > 95 ) + { + pm->pmoveEvent = EV_FALL_FAR; + } + else if ( delta > 60 ) + { + pm->pmoveEvent = EV_FALL_MEDIUM; + } + else if ( delta > 14 ) + { + pm->pmoveEvent = EV_FALL_SHORT; + } + } + } + +/* +============== +PM_WaterEvents + +Generate sound events for entering and leaving water +============== +*/ +void PM_WaterEvents + ( + void + ) + + { + // FIXME? + // + // if just entered a water volume, play a sound + // + if ( !pml.previous_waterlevel && pm->waterlevel ) + { + pm->pmoveEvent = EV_WATER_TOUCH; + } + + // + // if just completely exited a water volume, play a sound + // + if ( pml.previous_waterlevel && ! pm->waterlevel ) + { + pm->pmoveEvent = EV_WATER_LEAVE; + } + + // + // check for head just going under water + // + if ( ( pml.previous_waterlevel != 3 ) && ( pm->waterlevel == 3 ) ) + { + pm->pmoveEvent = EV_WATER_UNDER; + } + + // + // check for head just coming out of water + // + if ( ( pml.previous_waterlevel == 3 ) && ( pm->waterlevel != 3 ) ) + { + pm->pmoveEvent = EV_WATER_CLEAR; + } + } + +/* +================ +PM_DropTimers +================ +*/ +void PM_DropTimers + ( + void + ) + + { + // drop misc timing counter + if ( pm->ps->pm_time ) + { + if ( pml.msec >= pm->ps->pm_time ) + { + pm->ps->pm_flags &= ~PMF_ALL_TIMES; + pm->ps->pm_time = 0; + } + else + { + pm->ps->pm_time -= pml.msec; + } + } + } + +/* +================ +PM_UpdateViewAngles + +This can be used as another entry point when only the viewangles +are being updated isntead of a full move +================ +*/ +void PM_UpdateViewAngles + ( + playerState_t *ps, + const usercmd_t *cmd + ) + + { + short temp; + int i; + + if ( ps->pm_flags & PMF_FROZEN ) + { + // no view changes at all + return; + } + + if ( ps->stats[ STAT_HEALTH ] <= 0 ) + { + // no view changes at all + return; + } + + // circularly clamp the angles with deltas + for( i = 0; i < 3; i++ ) + { + temp = cmd->angles[ i ] + ps->delta_angles[ i ]; + if ( i == PITCH ) + { + // don't let the player look up or down more than 90 degrees + if ( temp > 16000 ) + { + ps->delta_angles[ i ] = 16000 - cmd->angles[ i ]; + temp = 16000; + } + else if ( temp < -16000 ) + { + ps->delta_angles[ i ] = -16000 - cmd->angles[ i ]; + temp = -16000; + } + } + + ps->viewangles[ i ] = SHORT2ANGLE( temp ); + } + } + +void Pmove_GroundTrace + ( + pmove_t *pmove + ) + + { + memset (&pml, 0, sizeof(pml)); + pml.msec = 1; + pml.frametime = 0.001f; + pm = pmove; + PM_CheckDuck(); + PM_GroundTrace(); + } + + +/* +================ +Pmove + +Can be called by either the server or the client +================ +*/ +void PmoveSingle (pmove_t *pmove) + { + vec3_t tempVec; + qboolean walking; + + pm = pmove; + + // this counter lets us debug movement problems with a journal + // by setting a conditional breakpoint fot the previous frame + c_pmove++; + + // clear results + pm->numtouch = 0; + pm->watertype = 0; + pm->waterlevel = 0; + + if ( pm->ps->stats[STAT_HEALTH] <= 0 ) + { + pm->tracemask &= ~CONTENTS_BODY; // corpses can fly through bodies + } + + // adding fake talk balloons + if ( pmove->cmd.buttons & BUTTON_TALK ) + { + pmove->cmd.buttons = 0; + pmove->cmd.forwardmove = 0; + pmove->cmd.rightmove = 0; + pmove->cmd.upmove = 0; + } + + // clear all pmove local vars + memset (&pml, 0, sizeof(pml)); + + // determine the time + pml.msec = pmove->cmd.serverTime - pm->ps->commandTime; + if ( pml.msec < 1 ) + { + pml.msec = 1; + } + else if ( pml.msec > 200 ) + { + pml.msec = 200; + } + + pm->ps->commandTime = pmove->cmd.serverTime; + + // save old org in case we get stuck + VectorCopy( pm->ps->origin, pml.previous_origin ); + + // save old velocity for crashlanding + VectorCopy( pm->ps->velocity, pml.previous_velocity ); + + pml.frametime = pml.msec * 0.001f; + + // update the viewangles + PM_UpdateViewAngles( pm->ps, &pm->cmd ); + + AngleVectors( pm->ps->viewangles, pml.forward, pml.left, pml.up ); + VectorClear( tempVec ); + tempVec[ YAW ] = pm->ps->viewangles[ YAW ]; + AngleVectors( tempVec, pml.flat_forward, pml.flat_left, pml.flat_up ); + + if ( pm->ps->pm_type >= PM_DEAD ) + { + pm->cmd.forwardmove = 0; + pm->cmd.rightmove = 0; + pm->cmd.upmove = 0; + } + + if ( pm->ps->pm_type == PM_NOCLIP ) + { + PM_NoclipMove (); + PM_DropTimers (); + return; + } + + if ( pm->ps->pm_flags & PMF_FROZEN || pm->ps->pm_flags & PMF_NO_MOVE ) + { + return; // no movement at all + } + + // set watertype, and waterlevel + PM_SetWaterLevel(); + pml.previous_waterlevel = pmove->waterlevel; + + // set mins, maxs, and viewheight + PM_CheckDuck(); + + // set groundentity + PM_GroundTrace(); + + if ( pm->ps->pm_type == PM_DEAD ) + { + PM_DeadMove(); + } + + PM_DropTimers(); + + if ( pm->ps->pm_flags & PMF_TIME_WATERJUMP ) + { + PM_WaterJumpMove(); + } + else if ( pml.walking ) + { + // walking on ground + PM_WalkMove(); + } + else if ( pm->waterlevel > 1 ) + { + // swimming + PM_WaterMove(); + } + else if ( pm->ps->pm_flags & PMF_TIME_STUCKJUMP ) + { + PM_StuckJumpMove(); + } + else + { + // airborne + PM_AirMove(); + } + + walking = pml.walking; + + // set groundentity, watertype, and waterlevel + PM_GroundTrace(); + PM_SetWaterLevel(); + + // don't fall down stairs or do really short falls + if ( !pml.walking && ( walking || ( ( pml.previous_velocity[ 2 ] >= 0 ) && ( pm->ps->velocity[ 2 ] <= 0 ) ) ) ) + { + vec3_t point; + trace_t trace; + + point[ 0 ] = pm->ps->origin[ 0 ]; + point[ 1 ] = pm->ps->origin[ 1 ]; + point[ 2 ] = pm->ps->origin[ 2 ] - STEPSIZE; + + pm->trace( &trace, pm->ps->origin, pm->mins, pm->maxs, point, pm->ps->clientNum, pm->tracemask, qtrue ); + if ( ( trace.fraction < 1.0f ) && ( !trace.allsolid ) ) + { + VectorCopy( trace.endpos, pm->ps->origin ); + + // allow client to smooth out the step + pm->stepped = qtrue; + + // requantify the player's position + PM_GroundTrace(); + PM_SetWaterLevel(); + } + } + + // entering / leaving water splashes + PM_WaterEvents(); + + // snap some parts of playerstate to save network bandwidth + SnapVector( pm->ps->velocity ); + } + +/* +================ +Pmove + +Can be called by either the server or the client +================ +*/ +void Pmove (pmove_t *pmove) { + int finalTime; + + finalTime = pmove->cmd.serverTime; + + if ( finalTime < pmove->ps->commandTime ) { + return; // should not happen + } + + if ( finalTime > pmove->ps->commandTime + 1000 ) { + pmove->ps->commandTime = finalTime - 1000; + } + + // chop the move up if it is too long, to prevent framerate + // dependent behavior + while ( pmove->ps->commandTime != finalTime ) { + int msec; + + msec = finalTime - pmove->ps->commandTime; + + if ( msec > 50 ) { + msec = 50; + } + pmove->cmd.serverTime = pmove->ps->commandTime + msec; + PmoveSingle( pmove ); + } + +} diff --git a/source/source/fgame/bg_public.h b/source/source/fgame/bg_public.h new file mode 100644 index 0000000..97bec6c --- /dev/null +++ b/source/source/fgame/bg_public.h @@ -0,0 +1,783 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/bg_public.h $ +// $Revision:: 109 $ +// $Author:: Steven $ +// $Date:: 7/27/00 10:56p $ +// +// Copyright (C) 1998 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/bg_public.h $ +// +// 109 7/27/00 10:56p Steven +// Added means of death eat. +// +// 108 7/27/00 3:52p Aldie +// Changed over letterboxing and fades to the game code. They are sent over in +// player stats and fields now. +// +// 107 7/25/00 12:47p Markd +// Added new player sounds +// +// 106 7/24/00 6:46p Steven +// Changed sv_cinematic from a cvar to a player stat. +// +// 105 7/24/00 12:46p Markd +// fixed rope movment +// +// 104 7/23/00 5:02p Markd +// Added boss health stat +// +// 103 7/19/00 8:19p Steven +// Added gas blockable means of death. +// +// 102 7/19/00 5:10p Steven +// Added electric water means of death. +// +// 101 7/16/00 4:39p Steven +// Added a new fire means of death. +// +// 100 7/13/00 12:33p Steven +// Added poison means of death. +// +// 99 7/10/00 11:54p Markd +// added exit level code +// +// 98 7/10/00 6:50p Markd +// fixed some issues with water running +// +// 97 7/02/00 1:11p Steven +// Changed means of death light to lightsword. +// +// 96 7/01/00 12:02p Steven +// Added electricsword and plasmashotgun means of death. +// +// 95 6/28/00 7:55p Aldie +// Added some MOD +// +// 94 6/26/00 5:50p Markd +// re-did some renderfx commands, fixed anti-sb juice stuff +// +// 93 6/25/00 12:38p Markd +// added STUCK_JUMP code +// +// 92 6/14/00 5:43p Steven +// Added plasmabeam means of death. +// +// 91 6/14/00 3:50p Markd +// Cleaned up more Intel Compiler warnings +// +// 90 6/14/00 11:18a Markd +// cleaned up code using Intel compiler +// +// 89 6/13/00 3:42p Steven +// Added gib means of death. +// +// 88 6/08/00 1:45p Steven +// Added means of death light. +// +// 87 6/06/00 2:51p Steven +// Added sting2 means of death. +// +// 86 6/05/00 6:42p Steven +// Added radiation means of death. +// +// 85 6/05/00 2:24p Markd +// Added CONTENTS_CAMERACLIP to MASK_OPAQUE +// +// 84 6/02/00 6:51p Markd +// added better camera look features +// +// 83 5/30/00 10:59a Aldie +// Added Circle of Protection Powerup +// +// 82 5/27/00 8:07p Markd +// Saved games 3rd pass +// +// 81 5/22/00 5:13p Aldie +// First version of soulsucker +// +// 80 5/20/00 5:14p Markd +// Added ITEM special effects +// +// 79 5/15/00 2:19p Aldie +// Added new tempmodel system and added player accumulated pain +// +// 78 5/11/00 11:08a Steven +// Added trypush to player move stuff. +// +// 77 5/10/00 10:25a Steven +// Added firesword means of death. +// +// 76 5/06/00 5:25p Markd +// fixed camera and pipe hang issues +// +// 75 5/05/00 2:17p Steven +// Addec chainsword and on_fire means of death. +// +// 74 5/04/00 12:46p Steven +// Added an axe means of death. +// +// 73 4/27/00 12:05p Steven +// Added crush_every_frame means of death. +// +// 72 4/27/00 11:58a Jimdose +// Changed OVERCLIP constant +// +// 71 4/15/00 5:40p Markd +// fixed falling damage and getting into and out of water +// +// 70 4/15/00 1:30p Markd +// added check_was_running code so that player does not always stop short +// +// 69 4/13/00 5:46p Steven +// Added poo_explosion means of death for Vymish Mama. +// +// 68 4/13/00 3:45p Aldie +// Added more flashbang support. Added damage_type to entities used to specify +// what type of damage they take. +// +// 67 4/12/00 6:57p Steven +// Added lifedrain means of death. +// +// 66 4/10/00 4:10p Markd +// Added CONTENTS_WEAPONCLIP to weapon masks +// +// 65 4/10/00 2:38p Markd +// eliminated the use of bg_public.h in some files +// +// 64 4/10/00 11:16a Markd +// added rope code +// +// 63 4/08/00 9:22a Markd +// Changed MASK_USE to include CONTENTS_BODY +// +// 62 4/07/00 3:00p Markd +// Added legs dangling code for pipehanging +// +// 61 4/06/00 10:59a Markd +// fixed player speed when player has full water +// +// 60 4/05/00 7:13p Aldie +// Lots of inventory functionality changes. +// +// 59 4/04/00 5:26p Markd +// moved static array from header into c file +// +// 58 3/31/00 1:01p Steven +// Added vortex means of death. +// +// 57 3/28/00 1:15p Steven +// Added means of death fire. +// +// 56 3/23/00 12:19p Markd +// increased range of dynamic light radius +// +// 55 3/21/00 5:06p Markd +// Added vehicle MOD +// +// 54 3/20/00 5:00p Aldie +// Fixes for entry and exit commands +// +// 53 3/14/00 3:22p Aldie +// Changed some client side emitter functionality and added func_emitter +// +// 52 3/13/00 11:26a Markd +// increased maximum number of animations +// +// 51 3/07/00 12:11p Steven +// Cleaned up means of death strings. +// +// 50 3/04/00 11:45a Markd +// Added light style support and malloc and free to the cgame +// +// 49 3/03/00 5:26p Steven +// Added MOD_FAST_BULLET means of death. +// +// 48 3/02/00 4:43p Aldie +// Added some ammo functionality for the HUD +// +// 47 2/26/00 12:51p Jimdose +// changed DEAD_VIEWHEIGHT +// +// 46 2/24/00 4:17p Jimdose +// moved some defines from bg_pmove.cpp +// +// 45 2/22/00 11:30a Steven +// Added means of death MOD_BULLET. +// +// 44 2/21/00 7:03p Markd +// Added skyalpha support +// +// 43 2/17/00 4:19p Jimdose +// added prototype for Pmove_GroundTrace +// +// 42 2/15/00 8:58p Jimdose +// added moveresult +// +// 41 2/14/00 5:37p Jimdose +// removed ANIM_BLEND_TORSO +// +// 40 2/12/00 3:24p Jimdose +// renamed ANIM_BLEND_TORSO to ANIM_BLEND +// +// 39 2/10/00 2:56p Markd +// changed FRAME_EXPLICIT mask from 128 to 512. +// +// 38 2/04/00 6:35p Markd +// Made animations dynamically allocated when loaded, fixed up messaging system +// to handle up to 1024 for each animation +// +// 37 1/29/00 2:48p Aldie +// Added impact mark functionality and Decal class +// +// 36 1/27/00 11:35a Markd +// Fixed solid/notsolid client side entities +// +// 35 1/19/00 7:14p Markd +// made camera's clip to all forms of water +// +// 34 1/19/00 6:37p Steven +// Added a MOD_NONE to fix some problems when a means of death is not +// specified. +// +// 33 1/19/00 10:44a Markd +// Cleaned up MOD messages and fixed music starting because of falling damage +// +// 32 1/19/00 10:23a Steven +// Added a sling means of death. +// +// 31 1/15/00 3:57p Markd +// Added MASK_USABLE +// +// 30 1/12/00 8:03p Markd +// Added Camera Cut bit +// +// 29 1/11/00 7:45p Aldie +// added water level +// +// 28 1/06/00 11:08p Jimdose +// cleaning up unused code +// +// 27 1/03/00 5:08p Markd +// put in camera offsets for player and state machine +// +// 26 12/17/99 8:26p Jimdose +// got rid of unused vars and functions +// +// 25 12/11/99 5:51p Markd +// First wave of bug fixes after q3a gold merge +// +// 24 12/11/99 3:37p Markd +// q3a gold checkin, first time +// +// 23 12/03/99 7:02p Aldie +// More ammo joy +// +// 22 12/02/99 6:53p Aldie +// Changed naming conventions from "both" to "dualhanded" Also put in the +// inventory renderer for the hud file +// +// 21 12/01/99 11:26a Aldie +// Couple of fixes for emitters and more ammo stuff +// +// 20 11/22/99 6:46p Aldie +// Started working on ammo changes - will finish after Thanksgiving break +// +// 19 11/10/99 6:08p Steven +// Added the sting means of death. +// +// 18 11/10/99 2:19p Jimdose +// added ANIM_BLEND_TORSO flag +// +// 17 10/29/99 7:16p Aldie +// Updated rope stuff +// +// 16 10/27/99 10:23a Steven +// Added new flag PMF_NO_MOVE and new contents type CONTENTS_SHOOTABLE_ONLY.. +// +// 15 10/19/99 7:52p Markd +// Removed three part model system +// +// 14 10/18/99 1:59p Aldie +// Lots of fixes for beams and stuff +// +// 13 10/12/99 6:56p Markd +// Fixed some player interpolation bugs and also interpolated camera +// +// 12 10/12/99 2:23p Markd +// Rewrote camera and player movetype system +// +// 11 10/08/99 2:11p Markd +// Re-ordered PM_TYPES +// +// 10 10/07/99 3:08p Aldie +// more beam fun +// +// 9 10/06/99 5:37p Jimdose +// updated tag bits to support the number of bones skeletal models can have +// added TAG_NUMBITS +// +// 8 9/30/99 4:37p Aldie +// Added ET_SPRITE +// +// 7 9/29/99 11:52a Markd +// removed some unused enums and variables form shared headers between cgame +// and fgame +// +// 6 9/27/99 5:44p Markd +// began documentation and cleanup phase after merge +// +// 5 9/16/99 12:27p Aldie +// code merge +// +// 4 9/13/99 4:22p Jimdose +// merge +// +// 3 9/10/99 6:51p Aldie +// restored trace function to new calling method +// +// 2 9/10/99 5:24p Aldie +// Merge code +// +// 1 9/10/99 10:53a Jimdose +// +// 2 9/09/99 3:30p Aldie +// Merge +// +// 1 9/08/99 3:15p Aldie +// +// 22 9/01/99 5:46p Aldie +// Fixed some weapon stuff for ECTS +// +// 21 8/31/99 2:45p Steven +// Added sword and plasma means of death. +// +// 20 8/29/99 8:09p Markd +// fixed up monstersolid and camerasolid MASK's +// +// 19 8/18/99 3:28p Jimdose +// added cylindrical collision detection +// +// 18 8/11/99 5:57p Steven +// Added acid means of death. +// +// 17 8/04/99 10:49a Steven +// Added gas as a new means of death. +// +// 16 7/06/99 8:33p Jimdose +// removed unused player code +// added state machine for player animation +// +// DESCRIPTION: +// Definitions shared by both the server game and client game modules + +#ifndef __BG_PUBLIC_H__ +#define __BG_PUBLIC_H__ + +#ifdef __cplusplus +extern "C" { +#endif + +// because games can change separately from the main system version, we need a +// second version that must match between game and cgame +#define GAME_VERSION "fakk-base-1" + +#define DEFAULT_GRAVITY 800 + +// CS_SERVERINFO and CS_SYSTEMINFO and CS_NAME are defined in q_shared.h +#define CS_SOUNDTRACK 8 +#define CS_FOGINFO 9 +#define CS_SKYINFO 10 +#define CS_GAME_VERSION 11 +#define CS_LEVEL_START_TIME 12 // so the timer only shows the current level +#define CS_MODELS 32 +#define CS_SOUNDS (CS_MODELS+MAX_MODELS) +#define CS_IMAGES (CS_SOUNDS+MAX_SOUNDS) +#define CS_LIGHTSTYLES (CS_IMAGES+MAX_IMAGES) +#define CS_PLAYERS (CS_LIGHTSTYLES+MAX_LIGHTSTYLES) +#define CS_ITEMS (CS_PLAYERS+MAX_CLIENTS) // strings for item names +#define CS_AMMO (CS_ITEMS+MAX_ITEMS) // strings for ammo names +#define CS_LOCATIONS (CS_AMMO+MAX_AMMO) +#define CS_MAX (CS_LOCATIONS+MAX_LOCATIONS) + +#if (CS_MAX) > MAX_CONFIGSTRINGS +#error overflow: (CS_MAX) > MAX_CONFIGSTRINGS +#endif + +typedef enum { + GT_FFA, // free for all + GT_TOURNAMENT, // one on one tournament + GT_SINGLE_PLAYER, // single player tournament + + //-- team games go after this -- + + GT_TEAM, // team deathmatch + GT_CTF, // capture the flag + + GT_MAX_GAME_TYPE +} gametype_t; + + +// +// scale to use when evaluating constantLight scale +// +#define CONSTANTLIGHT_RADIUS_SCALE 8 + +/* +=================================================================================== + +PMOVE MODULE + +The pmove code takes a player_state_t and a usercmd_t and generates a new player_state_t +and some other output data. Used for local prediction on the client game and true +movement on the server game. +=================================================================================== +*/ + +#define MAX_CLIP_PLANES 5 +#define MIN_WALK_NORMAL 0.7f // can't walk on very steep slopes + +#define STEPSIZE 31 + +#define MINS_X -15 +#define MINS_Y -15 +#define MAXS_X 15 +#define MAXS_Y 15 + +#define MINS_Z 0 +#define MAXS_Z 96 + +#define DEAD_MINS_Z 32 +#define CROUCH_MAXS_Z 49 +#define DEFAULT_VIEWHEIGHT 90 +#define CROUCH_VIEWHEIGHT 45 +#define DEAD_VIEWHEIGHT 90 + +#define WATER_TURBO_SPEED 1.35f +#define WATER_TURBO_TIME 1200 +#define MINIMUM_RUNNING_TIME 800 +#define MINIMUM_WATER_FOR_TURBO 90 + +#define OVERCLIP 1.001f + +typedef enum { + PM_NORMAL, // normal movement mode + PM_NOCLIP, // noclip movement + PM_DEAD // no acceleration or turning, but free falling +} pmtype_t; + +// entityState_t->event values +// entity events are for effects that take place reletive +// to an existing entities origin. Very network efficient. +typedef enum { + EV_NONE, + + EV_FALL_SHORT, + EV_FALL_MEDIUM, + EV_FALL_FAR, + EV_FALL_FATAL, + EV_TERMINAL_VELOCITY, + + EV_WATER_TOUCH, // foot touches + EV_WATER_LEAVE, // foot leaves + EV_WATER_UNDER, // head touches + EV_WATER_CLEAR, // head leaves + + EV_LAST_PREDICTED // just a marker point + + // events generated by non-players or never predicted +} entity_event_t; + +// pmove->pm_flags +#define PMF_DUCKED ( 1<<0 ) // player is ducked +#define PMF_TIME_LAND ( 1<<1 ) // pm_time is time before rejump +#define PMF_TIME_KNOCKBACK ( 1<<2 ) // pm_time is an air-accelerate only time +#define PMF_TIME_WATERJUMP ( 1<<3 ) // pm_time is waterjump +#define PMF_TIME_TELEPORT ( 1<<4 ) // pm_time is teleport +#define PMF_NO_PREDICTION ( 1<<5 ) // no prediction +#define PMF_FROZEN ( 1<<6 ) // player cannot move or look around +#define PMF_INTERMISSION ( 1<<7 ) // intermission view + +// +// the following flag is required by the server and cannot be changed +// +#define PMF_CAMERA_VIEW ( 1<<8 ) // use camera view instead of ps view + +#define PMF_NO_MOVE ( 1<<9 ) // player cannot move but can still look around +#define PMF_LEGS_LIFTED ( 1<<10 ) // player has pulled up his legs so that he occupies only the top of his bounding box +#define PMF_TIME_STUCKJUMP ( 1<<11 ) // pm_time is stuckjump +#define PMF_LEVELEXIT ( 1<<12 ) // player is near an exit +#define PMF_NO_GRAVITY ( 1<<13 ) // do not apply gravity to the player + +#define PMF_ALL_TIMES (PMF_TIME_WATERJUMP|PMF_TIME_LAND|PMF_TIME_KNOCKBACK|PMF_TIME_TELEPORT|PMF_TIME_STUCKJUMP) + +#define MAXTOUCH 32 + +#define MOVERESULT_NONE 0 // nothing blocking +#define MOVERESULT_TURNED 1 // move blocked, but player turned to avoid it +#define MOVERESULT_BLOCKED 2 // move blocked by slope or wall +#define MOVERESULT_HITWALL 3 // player ran into wall + +typedef struct { + // state (in / out) + playerState_t *ps; + + // command (in) + usercmd_t cmd; + int tracemask; // collide against these types of surfaces + int debugLevel; // if set, diagnostic output will be printed + qboolean noFootsteps; // if the game is setup for no footsteps by the server + + // results (out) + int numtouch; + int touchents[MAXTOUCH]; + + int moveresult; // indicates whether 2the player's movement was blocked and how + + qboolean stepped; // made a non-smooth step that can be + // smoothed on the client side + + int pmoveEvent; // events predicted on client side + vec3_t mins, maxs; // bounding box size + int watertype; + int waterlevel; + + // callbacks to test the world + // these will be different functions during game and cgame + void (*trace)( trace_t *result, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int passEntityNum, int contentMask, qboolean cylinder ); + int (*pointcontents)( const vec3_t point, int passEntityNum ); + qboolean (*trypush)( int entnum, vec3_t move_origin, vec3_t move_end ); +} pmove_t; + +// if a full pmove isn't done on the client, you can just update the angles +void PM_UpdateViewAngles( playerState_t *ps, const usercmd_t *cmd ); +void Pmove_GroundTrace( pmove_t *pmove ); +void Pmove (pmove_t *pmove); + +//=================================================================================== + +// content masks +#define MASK_ALL (-1) +#define MASK_SOLID (CONTENTS_SOLID) +#define MASK_USABLE (CONTENTS_SOLID|CONTENTS_BODY) +#define MASK_PLAYERSOLID (CONTENTS_SOLID|CONTENTS_PLAYERCLIP|CONTENTS_BODY) +#define MASK_DEADSOLID (CONTENTS_SOLID|CONTENTS_PLAYERCLIP) +#define MASK_MONSTERSOLID (CONTENTS_SOLID|CONTENTS_MONSTERCLIP|CONTENTS_BODY) +#define MASK_WATER (CONTENTS_WATER|CONTENTS_LAVA|CONTENTS_SLIME) +#define MASK_OPAQUE (CONTENTS_SOLID|CONTENTS_SLIME|CONTENTS_LAVA|CONTENTS_CAMERACLIP) +#define MASK_SHOT (CONTENTS_SOLID|CONTENTS_BODY|CONTENTS_CORPSE|CONTENTS_WEAPONCLIP|CONTENTS_SHOOTABLE_ONLY) +#define MASK_PROJECTILE (CONTENTS_SOLID|CONTENTS_BODY|CONTENTS_CORPSE|CONTENTS_WEAPONCLIP|CONTENTS_SHOOTABLE_ONLY) +#define MASK_MELEE (CONTENTS_SOLID|CONTENTS_BODY|CONTENTS_CORPSE|CONTENTS_WEAPONCLIP|CONTENTS_SHOOTABLE_ONLY) +#define MASK_PATHSOLID (CONTENTS_SOLID|CONTENTS_MONSTERCLIP) +#define MASK_CAMERASOLID (CONTENTS_SOLID|CONTENTS_PLAYERCLIP|CONTENTS_CAMERACLIP|CONTENTS_BODY|MASK_WATER) +#define MASK_CURRENT (CONTENTS_CURRENT_0|CONTENTS_CURRENT_90|CONTENTS_CURRENT_180|CONTENTS_CURRENT_270|CONTENTS_CURRENT_UP|CONTENTS_CURRENT_DOWN) + +// player_state->persistant[] indexes +// these fields are the only part of player_state that isn't +// cleared on respawn +typedef enum { + PERS_SCORE, // !!! MUST NOT CHANGE, SERVER AND GAME BOTH REFERENCE !!! + PERS_TEAM +} persEnum_t; + +// entityState_t->eFlags +#define EF_EVENT_BIT1 0x00000001 // toggled every time an event changes +#define EF_EVENT_BIT2 0x00000002 // toggled every time an event changes +#define EF_EVENT_BITS (EF_EVENT_BIT1|EF_EVENT_BIT2) +#define EF_TELEPORT_BIT (1<<2) // toggled every time the origin abruptly changes +#define EF_EVERYFRAME (1<<3) // def commands will be run every client frame +#define EF_ANTISBJUICE (1<<4) // anti sucknblow juice +#define EF_LEFT_TARGETED (1<<5) // this entity is being targeted by the left hand +#define EF_RIGHT_TARGETED (1<<6) // this entity is being targeted by the right hand +#define EF_DONT_PROCESS_COMMANDS (1<<7) // don't process client commands for this entity + +// flip the togglebit every time an animation +// changes so a restart of the same anim can be detected +#define ANIM_TOGGLEBIT (1<<9) +#define ANIM_BLEND (1<<10) +#define ANIM_NUMBITS 11 + +// server side anim bits +#define ANIM_SERVER_EXITCOMMANDS_PROCESSED (1<<12) + +#define ANIM_MASK ( ~( ANIM_TOGGLEBIT | ANIM_BLEND | ANIM_SERVER_EXITCOMMANDS_PROCESSED ) ) + +// if FRAME_EXPLICIT is set, don't auto animate +#define FRAME_EXPLICIT 512 +#define FRAME_MASK ( ~FRAME_EXPLICIT ) + +// +// Tag specific flags +// +#define TAG_NUMBITS 10 // number of bits required to send over network +#define TAG_MASK ( ( 1 << 10 ) - 1 ) + + +// +// Camera Flags +// +#define CF_CAMERA_ANGLES_ABSOLUTE ( 1 << 0 ) +#define CF_CAMERA_ANGLES_IGNORE_PITCH ( 1 << 1 ) +#define CF_CAMERA_ANGLES_IGNORE_YAW ( 1 << 2 ) +#define CF_CAMERA_ANGLES_ALLOWOFFSET ( 1 << 3 ) +#define CF_CAMERA_CUT_BIT ( 1 << 7 ) // this bit gets toggled everytime we do a hard camera cut + +typedef enum { + MOD_NONE, + MOD_DROWN, + MOD_SUICIDE, + MOD_CRUSH, + MOD_CRUSH_EVERY_FRAME, + MOD_TELEFRAG, + MOD_LAVA, + MOD_SLIME, + MOD_FALLING, + MOD_LAST_SELF_INFLICTED, + MOD_EXPLOSION, + MOD_EXPLODEWALL, + MOD_ELECTRIC, + MOD_ELECTRICWATER, + MOD_THROWNOBJECT, + MOD_BEAM, + MOD_ROCKET, + MOD_IMPACT, + MOD_GAS, + MOD_GAS_BLOCKABLE, + MOD_ACID, + MOD_SWORD, + MOD_PLASMA, + MOD_PLASMABEAM, + MOD_PLASMASHOTGUN, + MOD_STING, + MOD_STING2, + MOD_SLING, + MOD_BULLET, + MOD_FAST_BULLET, + MOD_VEHICLE, + MOD_FIRE, + MOD_FIRE_BLOCKABLE, + MOD_VORTEX, + MOD_LIFEDRAIN, + MOD_FLASHBANG, + MOD_POO_EXPLOSION, + MOD_AXE, + MOD_CHAINSWORD, + MOD_ON_FIRE, + MOD_FIRESWORD, + MOD_ELECTRICSWORD, + MOD_CIRCLEOFPROTECTION, + MOD_RADIATION, + MOD_LIGHTSWORD, + MOD_GIB, + MOD_IMPALE, + MOD_UPPERCUT, + MOD_POISON, + MOD_EAT, + + MOD_TOTAL_NUMBER + } meansOfDeath_t; + +// If you add to the enum above go add a string to the means_of_death_strings in g_utils.cpp +extern char means_of_death_strings[ MOD_TOTAL_NUMBER ][ 32 ]; + +//--------------------------------------------------------- + + +// g_dmflags->integer flags + +#define DF_NO_HEALTH (1<<0) +#define DF_NO_POWERUPS (1<<1) +#define DF_WEAPONS_STAY (1<<2) +#define DF_NO_FALLING (1<<3) +#define DF_INSTANT_ITEMS (1<<4) +#define DF_SAME_LEVEL (1<<5) +#define DF_SKINTEAMS (1<<6) +#define DF_MODELTEAMS (1<<7) +#define DF_FRIENDLY_FIRE (1<<8) +#define DF_SPAWN_FARTHEST (1<<9) +#define DF_FORCE_RESPAWN (1<<10) +#define DF_NO_ARMOR (1<<11) +#define DF_FAST_WEAPONS (1<<12) +#define DF_NOEXIT (1<<13) +#define DF_INFINITE_AMMO (1<<14) +#define DF_FIXED_FOV (1<<15) +#define DF_NO_DROP_WEAPONS (1<<16) +#define DF_NO_FOOTSTEPS (1<<17) + +// teamflags->integer flags +#define TF_TEAMPLAY 1 +#define TF_NO_FRIENDLY_FIRE 2 + +// +// entityState_t->eType +// +typedef enum { + ET_MODELANIM, + ET_PLAYER, + ET_ITEM, + ET_GENERAL, + ET_MISSILE, + ET_MOVER, + ET_BEAM, + ET_MULTIBEAM, + ET_SPRITE, + ET_PORTAL, + ET_EVENT_ONLY, + ET_RAIN, + ET_LEAF, + ET_SPEAKER, + ET_PUSH_TRIGGER, + ET_TELEPORT_TRIGGER, + ET_DECAL, + ET_EMITTER, + ET_ROPE, + ET_EVENTS +} entityType_t; + +void EvaluateTrajectory( const trajectory_t *tr, int atTime, vec3_t result ); +void EvaluateTrajectoryDelta( const trajectory_t *tr, int atTime, vec3_t result ); + +// Added for FAKK + +typedef enum + { + STAT_HEALTH, + STAT_DEAD_YAW, // cleared each frame + STAT_AMMO_LEFT, // ammo in current weapon in left hand or primary ammo in 2 handed weapons + STAT_AMMO_RIGHT, // ammo in current weapon in right hand or alternate ammo in 2 handed weapons + STAT_CLIPAMMO_LEFT, // ammo in left weapon clip + STAT_CLIPAMMO_RIGHT, // ammo in right weapon clip + STAT_WATER_LEVEL, + STAT_MAXAMMO_LEFT, // maxammo for left weapon + STAT_MAXAMMO_RIGHT, // maxammo for right weapon + STAT_MAXCLIPAMMO_LEFT, // maxammo in left weapon clip + STAT_MAXCLIPAMMO_RIGHT, // maxammo in right weapon clip + STAT_LAST_PAIN, // Last amount of damage the player took + STAT_ACCUMULATED_PAIN, // Accumulated damage + STAT_BOSSHEALTH, // if we are fighting a boss, how much health he currently has + STAT_CINEMATIC, // This is set when we go into cinematics + STAT_ADDFADE, // This is set when we need to do an addblend for the fade + STAT_LETTERBOX, // This is set to the fraction of the letterbox + STAT_LAST_STAT + } playerstat_t + ; + +#define MAX_LETTERBOX_SIZE 0x7fff + +#define ITEM_NAME_AMMO_LEFT 0 +#define ITEM_NAME_AMMO_RIGHT 1 +#define ITEM_NAME_WEAPON_LEFT 2 +#define ITEM_NAME_WEAPON_RIGHT 3 +#define ITEM_NAME_WEAPON_DUAL 4 + +#ifdef __cplusplus + } +#endif + +#endif // __BG_PUBLIC_H__ + diff --git a/source/source/fgame/bspline.cpp b/source/source/fgame/bspline.cpp new file mode 100644 index 0000000..303ba95 --- /dev/null +++ b/source/source/fgame/bspline.cpp @@ -0,0 +1,1008 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/bspline.cpp $ +// $Revision:: 14 $ +// $Author:: Markd $ +// $Date:: 6/23/00 9:27a $ +// +// Copyright (C) 1998 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source is may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/bspline.cpp $ +// +// 14 6/23/00 9:27a Markd +// pushed spline path creation till after full spawn +// +// 13 4/05/00 6:16p Markd +// fixed destruction problem +// +// 12 3/15/00 6:54p Markd +// fixed no num_control_points DrawCurve bug +// +// 11 3/15/00 2:04p Markd +// fixed up camera node system and added new debug oriented circle +// +// 10 2/01/00 5:40p Markd +// Fixed Camera cutting issues +// +// 9 1/26/00 9:53a Markd +// Changed FOV command to an fov command +// +// 8 11/09/99 8:08p Markd +// revamped some functions because of changes to camera system +// +// 7 11/05/99 5:55p Markd +// Added user-interface to camera system +// +// 6 11/04/99 10:03a Markd +// complete overhaul of the camera system +// +// 5 10/04/99 10:53a Aldie +// fix warning +// +// 4 9/28/99 7:24p Steven +// Event formatting. +// +// 3 9/22/99 4:47p Markd +// fixed more G_GetEntity, G_FindClass and G_GetNextEntity bugs +// +// 2 9/21/99 7:51p Markd +// Fixed a lot of entitynum_none issues +// +// 1 9/10/99 10:53a Jimdose +// +// 1 9/08/99 3:15p Aldie +// +// 9 9/01/99 9:05p Jimdose +// added setthread event +// +// 8 9/01/99 8:00p Jimdose +// added triggertarget event +// +// DESCRIPTION: +// Uniform non-rational bspline class. +// + +#include "g_local.h" +#include "BSpline.h" + +void BSpline::Set + ( + Vector *control_points_, + int num_control_points_, + splinetype_t type + ) + + { + int i; + + SetType( type ); + + has_orientation = false; + + if ( control_points ) + { + delete [] control_points; + control_points = NULL; + } + + num_control_points = num_control_points_; + if ( num_control_points ) + { + control_points = new BSplineControlPoint[ num_control_points ]; + assert( control_points ); + + for( i = 0; i < num_control_points; i++ ) + { + control_points[ i ].Set( control_points_[ i ] ); + } + } + } + +void BSpline::Set + ( + Vector *control_points_, + Vector *control_orients_, + float *control_speeds_, + int num_control_points_, + splinetype_t type + ) + + { + int i; + + SetType( type ); + + has_orientation = true; + + if ( control_points ) + { + delete [] control_points; + control_points = NULL; + } + + num_control_points = num_control_points_; + if ( num_control_points ) + { + control_points = new BSplineControlPoint[ num_control_points ]; + assert( control_points ); + + for( i = 0; i < num_control_points; i++ ) + { + control_points[ i ].Set( control_points_[ i ], control_orients_[ i ], control_speeds_[ i ] ); + } + } + } + +void BSpline::Clear + ( + void + ) + + { + if( control_points ) + { + delete [] control_points; + control_points = NULL; + } + num_control_points = 0; + has_orientation = false; + } + +inline float BSpline::EvalNormal + ( + float u, + Vector& pos, + Vector& orient + ) + + { + int segment_id; + float B[ 4 ]; + float tmp; + float u_2; + float u_3; + Vector ang; + float roll; + float speed; + + segment_id = ( int )u; + if ( segment_id < 0 ) + { + segment_id = 0; + } + if ( segment_id > num_control_points - 4 ) + { + segment_id = num_control_points - 4; + } + u -= ( float )segment_id; + + u_2 = u * u; + u_3 = u * u_2; + + tmp = 1 - u; + B[ 0 ] = ( tmp * tmp * tmp ) * ( 1.0f / 6.0f ); + B[ 1 ] = ( 3.0f * u_3 - 6.0f * u_2 + 4.0f ) * ( 1.0f / 6.0f ); + B[ 2 ] = ( -3.0f * u_3 + 3.0f * u_2 + 3.0f * u + 1 ) * ( 1.0f / 6.0f ); + B[ 3 ] = u_3 * ( 1.0f / 6.0f ); + + pos = + *control_points[ 0 + segment_id ].GetPosition() * B[ 0 ] + + *control_points[ 1 + segment_id ].GetPosition() * B[ 1 ] + + *control_points[ 2 + segment_id ].GetPosition() * B[ 2 ] + + *control_points[ 3 + segment_id ].GetPosition() * B[ 3 ]; + + ang = + *control_points[ 0 + segment_id ].GetOrientation() * B[ 0 ] + + *control_points[ 1 + segment_id ].GetOrientation() * B[ 1 ] + + *control_points[ 2 + segment_id ].GetOrientation() * B[ 2 ] + + *control_points[ 3 + segment_id ].GetOrientation() * B[ 3 ]; + + roll = + *control_points[ 0 + segment_id ].GetRoll() * B[ 0 ] + + *control_points[ 1 + segment_id ].GetRoll() * B[ 1 ] + + *control_points[ 2 + segment_id ].GetRoll() * B[ 2 ] + + *control_points[ 3 + segment_id ].GetRoll() * B[ 3 ]; + + speed = + *control_points[ 0 + segment_id ].GetSpeed() * B[ 0 ] + + *control_points[ 1 + segment_id ].GetSpeed() * B[ 1 ] + + *control_points[ 2 + segment_id ].GetSpeed() * B[ 2 ] + + *control_points[ 3 + segment_id ].GetSpeed() * B[ 3 ]; + + orient = ang.toAngles(); + orient[ ROLL ] = roll; + + return speed; + } + +inline float BSpline::EvalLoop + ( + float t, + Vector& pos, + Vector& orient + ) + + { + Vector retval; + Vector ang; + float speed; + float roll; + int segment_id; + int next_id; + float B[ 4 ]; + float tmp; + float u; + float u_2; + float u_3; + int i; + int j; + + segment_id = ( int )floor( t ); + u = t - floor( t ); + + segment_id %= num_control_points; + if ( segment_id < 0 ) + { + segment_id += num_control_points; + } + + u_2 = u * u; + u_3 = u * u_2; + + tmp = 1 - u; + B[ 0 ] = ( tmp * tmp * tmp ) * ( 1.0f / 6.0f ); + B[ 1 ] = ( 3.0f * u_3 - 6.0f * u_2 + 4.0f ) * ( 1.0f / 6.0f ); + B[ 2 ] = ( -3.0f * u_3 + 3.0f * u_2 + 3.0f * u + 1 ) * ( 1.0f / 6.0f ); + B[ 3 ] = u_3 * ( 1.0f / 6.0f ); + + speed = 0; + roll = 0; + + for( i = 0, j = segment_id; i < 4; i++, j++ ) + { + if ( j >= num_control_points ) + { + j -= ( num_control_points - loop_control_point ); + } + + retval += *control_points[ j ].GetPosition() * B[ i ]; + ang += *control_points[ j ].GetOrientation() * B[ i ]; + speed += *control_points[ j ].GetSpeed() * B[ i ]; + roll += *control_points[ j ].GetRoll() * B[ i ]; + } + + pos = retval; + + next_id = segment_id + 1; + if ( next_id >= num_control_points ) + { + next_id -= ( num_control_points - loop_control_point ); + } + orient = ang.toAngles(); + orient[ ROLL ] = roll; + + return speed; + } + +inline float BSpline::EvalClamp + ( + float t, + Vector& pos, + Vector& orient + ) + + { + Vector retval; + Vector ang; + int segment_id; + int next_id; + float B[ 4 ]; + float tmp; + float u; + float u_2; + float u_3; + int i; + int j; + float speed; + float roll; + + segment_id = ( int )floor( t ); + u = t - floor( t ); + + u_2 = u * u; + u_3 = u * u_2; + + tmp = 1 - u; + B[ 0 ] = ( tmp * tmp * tmp ) * ( 1.0f / 6.0f ); + B[ 1 ] = ( 3.0f * u_3 - 6.0f * u_2 + 4.0f ) * ( 1.0f / 6.0f ); + B[ 2 ] = ( -3.0f * u_3 + 3.0f * u_2 + 3.0f * u + 1 ) * ( 1.0f / 6.0f ); + B[ 3 ] = u_3 * ( 1.0f / 6.0f ); + + speed = 0; + roll = 0; + for( i = 0; i < 4; i++, segment_id++ ) + { + j = segment_id; + if ( j < 0 ) + { + j = 0; + } + else if ( j >= num_control_points ) + { + j = num_control_points - 1; + } + + retval += *control_points[ j ].GetPosition() * B[ i ]; + ang += *control_points[ j ].GetOrientation() * B[ i ]; + speed += *control_points[ j ].GetSpeed() * B[ i ]; + roll += *control_points[ j ].GetRoll() * B[ i ]; + } + + pos = retval; + + next_id = segment_id + 1; + if ( segment_id < 0 ) + { + segment_id = 0; + } + if ( segment_id >= num_control_points ) + { + segment_id = num_control_points - 1; + } + if ( next_id < 0 ) + { + next_id = 0; + } + if ( next_id >= num_control_points ) + { + next_id = num_control_points - 1; + } + orient = ang.toAngles(); + orient[ ROLL ] = roll; + + return speed; + } + + +Vector BSpline::Eval + ( + float u + ) + + { + Vector pos; + Vector orient; + + switch( curvetype ) + { + default: + case SPLINE_NORMAL : + EvalNormal( u, pos, orient ); + break; + + case SPLINE_CLAMP: + EvalClamp( u, pos, orient ); + break; + + case SPLINE_LOOP: + if ( u < 0 ) + { + EvalClamp( u, pos, orient ); + } + else + { + EvalLoop( u, pos, orient ); + } + break; + } + return pos; + } + +float BSpline::Eval + ( + float u, + Vector &pos, + Vector &orient + ) + + { + switch( curvetype ) + { + default: + case SPLINE_NORMAL : + return EvalNormal( u, pos, orient ); + break; + + case SPLINE_CLAMP: + return EvalClamp( u, pos, orient ); + break; + + case SPLINE_LOOP: + if ( u < 0 ) + { + return EvalClamp( u, pos, orient ); + } + else + { + return EvalLoop( u, pos, orient ); + } + break; + } + } + +void BSpline::DrawControlSegments + ( + void + ) + + { + int i; + + G_BeginLine(); + for( i = 0; i < num_control_points; i++ ) + { + G_Vertex( *control_points[ i ].GetPosition() ); + } + G_EndLine(); + } + +void BSpline::DrawCurve + ( + int num_subdivisions + ) + + { + float u; + float du; + + if ( !num_control_points ) + { + return; + } + + du = 1.0f / ( float )num_subdivisions; + + G_BeginLine(); + for( u = -2.0f; u <= ( float )num_control_points; u += du ) + { + G_Vertex( ( Vector )Eval( u ) ); + } + G_EndLine(); + } + +void BSpline::DrawCurve + ( + Vector offset, + int num_subdivisions + ) + + { + float u; + float du; + + du = 1.0f / ( float )num_subdivisions; + + G_BeginLine(); + for( u = -2.0f; u <= ( float )num_control_points; u += du ) + { + G_Vertex( offset + ( Vector )Eval( u ) ); + } + G_EndLine(); + } + +void BSpline::AppendControlPoint + ( + const Vector& new_control_point + ) + + { + BSplineControlPoint *old_control_points; + int i; + + old_control_points = control_points; + num_control_points++; + + control_points = new BSplineControlPoint[num_control_points]; + assert( control_points ); + + if ( old_control_points ) + { + for( i = 0; i < num_control_points - 1; i++ ) + { + control_points[ i ] = old_control_points[ i ]; + } + delete [] old_control_points; + } + + control_points[ num_control_points - 1 ].Set( new_control_point ); + } + +void BSpline::AppendControlPoint + ( + const Vector& new_control_point, + const float& speed + ) + + { + BSplineControlPoint *old_control_points; + int i; + + old_control_points = control_points; + num_control_points++; + + control_points = new BSplineControlPoint[num_control_points]; + assert( control_points ); + + if ( old_control_points ) + { + for( i = 0; i < num_control_points - 1; i++ ) + { + control_points[ i ] = old_control_points[ i ]; + } + delete [] old_control_points; + } + + control_points[ num_control_points - 1 ].Set( new_control_point, speed ); + } + +void BSpline::AppendControlPoint + ( + const Vector& new_control_point, + const Vector& new_control_orient, + const float& new_control_speed + ) + + { + BSplineControlPoint *old_control_points; + int i; + + has_orientation = true; + + old_control_points = control_points; + num_control_points++; + + control_points = new BSplineControlPoint[num_control_points]; + assert( control_points ); + + if ( old_control_points ) + { + for( i = 0; i < num_control_points - 1; i++ ) + { + control_points[ i ] = old_control_points[ i ]; + } + delete [] old_control_points; + } + + control_points[ num_control_points - 1 ].Set( new_control_point, new_control_orient, new_control_speed ); + } + +void BSpline::SetLoopPoint + ( + const Vector& pos + ) + { + int i; + + for( i = 0; i < num_control_points; i++ ) + { + if ( pos == *control_points[ i ].GetPosition() ) + { + loop_control_point = i; + break; + } + } + } + +int BSpline::PickControlPoint + ( + const Vector& window_point, + float pick_size + ) + + { + int i; + float closest_dist_2; + int closest_index; + float dist_2; + Vector delta; + + closest_index = -1; + closest_dist_2 = 1000000.0f; + for( i = 0; i < num_control_points; i++ ) + { + delta = window_point - *control_points[ i ].GetPosition(); + dist_2 = delta * delta; + if ( dist_2 < closest_dist_2 ) + { + closest_dist_2 = dist_2; + closest_index = i; + } + } + + if ( pick_size * pick_size >= closest_dist_2 ) + { + return closest_index; + } + else + { + return -1; + } + } + +Event EV_SplinePath_Create + ( + "SplinePath_create", + EV_DEFAULT, + NULL, + NULL, + "Creates the spline path from the target list." + ); +Event EV_SplinePath_Loop + ( + "loop", + EV_CONSOLE, + "s", + "loop_name", + "Sets the loop name." + ); +Event EV_SplinePath_Speed + ( + "speed", + EV_DEFAULT, + "f", + "speed", + "Sets the path speed." + ); +Event EV_SplinePath_SetTriggerTarget + ( + "triggertarget", + EV_DEFAULT, + "s", + "target", + "Sets the trigger target." + ); +Event EV_SplinePath_SetThread + ( + "thread", + EV_DEFAULT, + "s", + "thread", + "Sets the thread." + ); +Event EV_SplinePath_SetWatch + ( + "watch", + EV_CONSOLE, + "s", + "watchEntity", + "Sets the entity to watch at this node." + ); + +Event EV_SplinePath_SetFov + ( + "fov", + EV_CONSOLE, + "f", + "cameraFOV", + "Sets the fov at this node." + ); + +Event EV_SplinePath_SetFadeTime + ( + "fadetime", + EV_DEFAULT, + "f", + "fadeTime", + "Sets the fadetime at this node." + ); + +CLASS_DECLARATION( Entity, SplinePath, "info_splinepath" ) + { + { &EV_SplinePath_Create, CreatePath }, + { &EV_SplinePath_Loop, SetLoop }, + { &EV_SplinePath_Speed, SetSpeed }, + { &EV_SplinePath_SetTriggerTarget, SetTriggerTarget }, + { &EV_SplinePath_SetThread, SetThread }, + { &EV_SplinePath_SetWatch, SetWatch }, + { &EV_SplinePath_SetFov, SetFov }, + { &EV_SplinePath_SetFadeTime, SetFadeTime }, + { NULL, NULL } + }; + +SplinePath::SplinePath() + { + owner = this; + next = NULL; + loop = NULL; + speed = 1; + doWatch = false; + watchEnt = ""; + fov = 0; + fadeTime = -1; + + setMoveType( MOVETYPE_NONE ); + setSolidType( SOLID_NOT ); + hideModel(); + + if ( !LoadingSavegame ) + { + PostEvent( EV_SplinePath_Create, FRAMETIME ); + } + } + +SplinePath::~SplinePath() + { + // disconnect from the chain + if ( owner != this ) + { + owner->SetNext( next ); + } + else if ( next ) + { + next->SetPrev( NULL ); + next = NULL; + } + + assert( owner == this ); + assert( next == NULL ); + } + +void SplinePath::SetLoop + ( + Event *ev + ) + + { + loop_name = ev->GetString( 1 ); + } + +void SplinePath::SetSpeed + ( + Event *ev + ) + + { + speed = ev->GetFloat( 1 ); + } + +void SplinePath::SetTriggerTarget + ( + Event *ev + ) + + { + SetTriggerTarget( ev->GetString( 1 ) ); + } + +void SplinePath::SetThread + ( + Event *ev + ) + + { + SetThread( ev->GetString( 1 ) ); + } + +void SplinePath::CreatePath + ( + Event *ev + ) + + { + const char *target; + Entity *ent; + + // Make the path from the targetlist. + target = Target(); + if ( target[ 0 ] ) + { + ent = G_FindTarget( NULL, target ); + if ( ent ) + { + next = ( SplinePath * )ent; + next->owner = this; + } + else + { + gi.Error( ERR_DROP, "SplinePath::CreatePath: target %s not found\n", target ); + } + } + if ( loop_name.length() ) + { + ent = G_FindTarget( NULL, loop_name.c_str() ); + if ( ent ) + { + loop = ( SplinePath * )ent; + } + } + } + +SplinePath *SplinePath::GetNext + ( + void + ) + + { + return next; + } + +SplinePath *SplinePath::GetPrev + ( + void + ) + + { + if ( owner == this ) + { + return NULL; + } + + return owner; + } + +void SplinePath::SetNext + ( + SplinePath *node + ) + + { + if ( next ) + { + // remove ourselves from the chain + next->owner = next; + } + + next = node; + if ( next ) + { + // disconnect next from it's previous node + if ( next->owner != next ) + { + next->owner->next = NULL; + } + next->owner = this; + } + } + +void SplinePath::SetPrev + ( + SplinePath *node + ) + + { + if ( owner != this ) + { + owner->next = NULL; + } + + if ( node && ( node != this ) ) + { + // safely remove the node from its chain + if ( node->next ) + { + node->next->owner = node->next; + } + node->next = this; + owner = node; + } + else + { + owner = this; + } + } + +SplinePath *SplinePath::GetLoop + ( + void + ) + + { + return loop; + } + +void SplinePath::SetWatch + ( + const char *name + ) + + { + if ( watchEnt != name ) + { + watchEnt = name; + if ( watchEnt.length() ) + { + doWatch = true; + } + else + { + doWatch = false; + } + } + } + +void SplinePath::SetWatch + ( + Event *ev + ) + + { + SetWatch( ev->GetString( 1 ) ); + } + + +void SplinePath::NoWatch + ( + void + ) + + { + doWatch = true; + watchEnt = "none"; + } + +str SplinePath::GetWatch + ( + void + ) + + { + return watchEnt; + } + +void SplinePath::SetFov + ( + float newFov + ) + + { + fov = newFov; + } + +void SplinePath::SetFov + ( + Event *ev + ) + + { + fov = ev->GetFloat( 1 ); + } + +float SplinePath::GetFov + ( + void + ) + + { + return fov; + } + +void SplinePath::SetFadeTime + ( + float newFadeTime + ) + + { + fadeTime = newFadeTime; + } + +void SplinePath::SetFadeTime + ( + Event *ev + ) + + { + fadeTime = ev->GetFloat( 1 ); + } + +float SplinePath::GetFadeTime + ( + void + ) + + { + return fadeTime; + } diff --git a/source/source/fgame/bspline.h b/source/source/fgame/bspline.h new file mode 100644 index 0000000..5056676 --- /dev/null +++ b/source/source/fgame/bspline.h @@ -0,0 +1,617 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/bspline.h $ +// $Revision:: 9 $ +// $Author:: Steven $ +// $Date:: 7/26/00 8:37a $ +// +// Copyright (C) 1998 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source is may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/bspline.h $ +// +// 9 7/26/00 8:37a Steven +// Fixed a bad memory bug. +// +// 8 7/26/00 12:46a Markd +// fixed potential crash bug, I hope +// +// 7 7/25/00 11:32p Aldie +// Made some changes to the memory system and fixed a memory allocation bug in +// Z_TagMalloc. Also changed a lot of classes to subclass from Class. +// +// 6 5/25/00 7:52p Markd +// 2nd pass save game stuff +// +// 5 5/24/00 3:14p Markd +// first phase of save/load games +// +// 4 1/05/00 7:25p Jimdose +// made angle functions all use the same coordinate system +// AngleVectors now returns left instead of right +// no longer need to invert pitch +// +// 3 11/09/99 8:08p Markd +// revamped some functions because of changes to camera system +// +// 2 11/05/99 5:55p Markd +// Added user-interface to camera system +// +// 1 9/10/99 10:53a Jimdose +// +// 1 9/08/99 3:15p Aldie +// +// 10 9/01/99 9:05p Jimdose +// added setthread event +// +// 9 9/01/99 8:00p Jimdose +// added triggertarget event +// +// 8 9/01/99 6:15p Jimdose +// added SetThread and SetTriggerTarget +// +// DESCRIPTION: +// Uniform non-rational bspline class. +// + +#ifndef __BSPLINE_H__ +#define __BSPLINE_H__ + +#include "g_local.h" +#include "Vector.h" + +typedef enum + { + SPLINE_NORMAL, + SPLINE_LOOP, + SPLINE_CLAMP + } splinetype_t; + +class BSplineControlPoint : public Class + { + private: + float roll; + Vector position; + Vector orientation; + float speed; + + public: + BSplineControlPoint(); + BSplineControlPoint( Vector pos, Vector orient, float speed ); + BSplineControlPoint( Vector pos ); + void Clear( void ); + void Set( Vector pos ); + void Set( Vector pos, float speed ); + void Set( Vector pos, Vector orient, float speed ); + void Get( Vector& pos, Vector& orient, float& speed ); + void Get( Vector& pos ); + Vector *GetPosition( void ); + Vector *GetOrientation( void ); + float *GetRoll( void ); + float *GetSpeed( void ); + void operator=( BSplineControlPoint &point ); + virtual void Archive( Archiver &arc ); + }; + +inline void BSplineControlPoint::Archive + ( + Archiver &arc + ) + + { + arc.ArchiveVector( &position ); + arc.ArchiveVector( &orientation ); + arc.ArchiveFloat( &speed ); + arc.ArchiveFloat( &roll ); + } + +inline void BSplineControlPoint::operator= + ( + BSplineControlPoint &point + ) + + { + position = point.position; + orientation = point.orientation; + speed = point.speed; + roll = point.roll; + } + +inline BSplineControlPoint::BSplineControlPoint() + { + roll = 0; + speed = 1; + } + +inline BSplineControlPoint::BSplineControlPoint + ( + Vector pos + ) + + { + speed = 1; + position = pos; + } + +inline BSplineControlPoint::BSplineControlPoint + ( + Vector pos, + Vector orient, + float speed + ) + + { + position = pos; + orient.AngleVectors( &orientation, NULL, NULL ); + roll = orient[ ROLL ]; + if ( roll > 180 ) + { + roll -= 360; + } + if ( roll < -180 ) + { + roll += 360; + } + this->speed = speed; + } + +inline void BSplineControlPoint::Clear + ( + void + ) + + { + roll = 0; + position = "0 0 0"; + vec_zero.AngleVectors( &orientation, NULL, NULL ); + speed = 1.0f; + } + +inline void BSplineControlPoint::Set + ( + Vector pos + ) + + { + speed = 1; + position = pos; + } + +inline void BSplineControlPoint::Set + ( + Vector pos, + float pointspeed + ) + + { + speed = pointspeed; + position = pos; + } + +inline void BSplineControlPoint::Set + ( + Vector pos, + Vector orient, + float speed + ) + + { + position = pos; + orient.AngleVectors( &orientation, NULL, NULL ); + roll = orient[ ROLL ]; + if ( roll > 180 ) + { + roll -= 360; + } + if ( roll < -180 ) + { + roll += 360; + } + this->speed = speed; + } + +inline void BSplineControlPoint::Get + ( + Vector& pos + ) + { + pos = position; + } + +inline Vector *BSplineControlPoint::GetPosition + ( + void + ) + + { + return &position; + } + +inline void BSplineControlPoint::Get + ( + Vector& pos, + Vector& orient, + float& speed + ) + + { + pos = position; + orient = orientation; + speed = this->speed; + } + +inline Vector *BSplineControlPoint::GetOrientation + ( + void + ) + { + return &orientation; + } + +inline float *BSplineControlPoint::GetRoll + ( + void + ) + { + return &roll; + } + +inline float *BSplineControlPoint::GetSpeed + ( + void + ) + { + return &speed; + } + +class BSpline : public Class + { + private: + BSplineControlPoint *control_points; + int num_control_points; + int loop_control_point; + splinetype_t curvetype; + qboolean has_orientation; + + float EvalNormal( float u, Vector &pos, Vector& orient ); + float EvalLoop( float u, Vector &pos, Vector& orient ); + float EvalClamp( float u, Vector &pos, Vector& orient ); + + public: + BSpline(); + ~BSpline(); + BSpline( Vector *control_points_, int num_control_points_, splinetype_t type ); + BSpline( Vector *control_points_, Vector *control_orients_, float *control_speeds_, int num_control_points_, splinetype_t type ); + void operator=( BSpline &spline ); + void SetType( splinetype_t type ); + int GetType( void ); + void Clear( void ); + void Set( Vector *control_points_, int num_control_points_, splinetype_t type ); + void Set( Vector *control_points_, Vector *control_orients_, float *control_speeds_, int num_control_points_, splinetype_t type ); + void AppendControlPoint( const Vector& new_control_point ); + void AppendControlPoint( const Vector& new_control_point, const float& speed ); + void AppendControlPoint( const Vector& new_control_point, const Vector& new_control_orient, const float& speed ); + Vector Eval( float u ); + float Eval( float u, Vector& pos, Vector& orient ); + + void DrawControlSegments( void ); + void DrawCurve( int num_subdivisions ); + void DrawCurve( Vector offset, int num_subdivisions ); + + void SetLoopPoint( const Vector& pos ); + + float EndPoint( void ); + + // return the index of the control point picked or -1 if none. + int PickControlPoint( const Vector& window_point, float pick_size ); + + Vector *GetControlPoint( int id ); + void GetControlPoint( int id, Vector& pos, Vector& orient, float& speed ); + void SetControlPoint( int id, const Vector& new_control_point ); + void SetControlPoint( int id, const Vector& new_control_point, const Vector& new_control_orient, const float& speed ); + virtual void Archive( Archiver &arc ); + }; + +inline BSpline::BSpline() + { + has_orientation = false; + control_points = NULL; + num_control_points = 0; + loop_control_point = 0; + curvetype = SPLINE_NORMAL; + } + +inline BSpline::~BSpline() + { + if ( control_points ) + { + delete [] control_points; + control_points = NULL; + } + } + +inline BSpline::BSpline + ( + Vector *control_points_, + int num_control_points_, + splinetype_t type + ) + + { + has_orientation = false; + control_points = NULL; + num_control_points = 0; + loop_control_point = 0; + curvetype = SPLINE_NORMAL; + + Set( control_points_, num_control_points_, type ); + } + +inline BSpline::BSpline + ( + Vector *control_points_, + Vector *control_orients_, + float *control_speeds_, + int num_control_points_, + splinetype_t type + ) + + { + has_orientation = false; + control_points = NULL; + num_control_points = 0; + loop_control_point = 0; + curvetype = SPLINE_NORMAL; + + Set( control_points_, control_orients_, control_speeds_, num_control_points_, type ); + } + +inline void BSpline::operator= + ( + BSpline &spline + ) + + { + int i; + + Clear(); + num_control_points = spline.num_control_points; + loop_control_point = spline.loop_control_point; + curvetype = spline.curvetype; + has_orientation = spline.has_orientation; + + if ( num_control_points ) + { + control_points = new BSplineControlPoint[num_control_points]; + assert( control_points ); + for ( i = 0; i < num_control_points ; i++ ) + control_points[ i ] = spline.control_points[ i ]; + } + else + { + control_points = NULL; + } + } + +inline void BSpline::SetType + ( + splinetype_t type + ) + + { + curvetype = type; + } + +inline int BSpline::GetType + ( + void + ) + + { + return curvetype; + } + +inline float BSpline::EndPoint + ( + void + ) + + { + return num_control_points; + } + +inline Vector *BSpline::GetControlPoint + ( + int id + ) + + { + assert( id >= 0 ); + assert( id < num_control_points ); + if ( ( id < 0 ) && ( id >= num_control_points ) ) + { + // probably wrong, but if we're in release mode we have no recourse + id = 0; + } + + return control_points[ id ].GetPosition(); + } + +inline void BSpline::GetControlPoint + ( + int id, + Vector& pos, + Vector& orient, + float& speed + ) + + { + assert( id >= 0 ); + assert( id < num_control_points ); + if ( ( id >= 0 ) && ( id < num_control_points ) ) + { + control_points[ id ].Get( pos, orient, speed ); + } + } + +inline void BSpline::SetControlPoint + ( + int id, + const Vector& new_control_point + ) + + { + assert( id >= 0 ); + assert( id < num_control_points ); + if ( ( id >= 0 ) && ( id < num_control_points ) ) + { + control_points[ id ].Set( new_control_point ); + } + } + +inline void BSpline::SetControlPoint + ( + int id, + const Vector& new_control_point, + const Vector& new_control_orient, + const float& speed + ) + + { + assert( id >= 0 ); + assert( id < num_control_points ); + if ( ( id >= 0 ) && ( id < num_control_points ) ) + { + control_points[ id ].Set( new_control_point, new_control_orient, speed ); + } + } + +inline void BSpline::Archive + ( + Archiver &arc + ) + { + int i; + + arc.ArchiveInteger( &num_control_points ); + if ( arc.Loading() ) + { + if ( num_control_points ) + control_points = new BSplineControlPoint[ num_control_points ]; + else + control_points = NULL; + } + + arc.ArchiveInteger( &loop_control_point ); + + i = curvetype; + arc.ArchiveInteger( &i ); + curvetype = ( splinetype_t )i; + + arc.ArchiveBoolean( &has_orientation ); + for( i = 0; i < num_control_points; i++ ) + { + control_points[ i ].Archive( arc ); + } + } + +extern Event EV_SplinePath_Create; +extern Event EV_SplinePath_Loop; +extern Event EV_SplinePath_Speed; + +class SplinePath : public Entity + { + protected: + SplinePath *owner; + SplinePath *next; + SplinePath *loop; + str loop_name; + + void CreatePath( Event *ev ); + void SetLoop( Event *ev ); + void SetSpeed( Event *ev ); + void SetTriggerTarget( Event *ev ); + void SetThread( Event *ev ); + void SetFov( Event *ev ); + void SetWatch( Event *ev ); + void SetFadeTime( Event *ev ); + + public: + float speed; + float fov; + float fadeTime; + qboolean doWatch; + str watchEnt; + str triggertarget; + str thread; + + CLASS_PROTOTYPE( SplinePath ); + + SplinePath(); + ~SplinePath(); + SplinePath *GetNext( void ); + SplinePath *GetPrev( void ); + SplinePath *GetLoop( void ); + void SetFadeTime( float newFadeTime ); + void SetFov( float theFov ); + void SetWatch( const char *name ); + void SetThread( const char *name ); + void SetTriggerTarget( const char *name ); + void NoWatch( void ); + str GetWatch( void ); + float GetFadeTime( void ); + float GetFov( void ); + void SetNext( SplinePath *node ); + void SetPrev( SplinePath *node ); + virtual void Archive( Archiver &arc ); + }; + +typedef SafePtr SplinePathPtr; + +inline void SplinePath::Archive + ( + Archiver &arc + ) + + { + Entity::Archive( arc ); + + arc.ArchiveObjectPointer( ( Class ** )&owner ); + arc.ArchiveObjectPointer( ( Class ** )&next ); + arc.ArchiveObjectPointer( ( Class ** )&loop ); + arc.ArchiveString( &loop_name ); + arc.ArchiveFloat( &speed ); + arc.ArchiveFloat( &fov ); + arc.ArchiveFloat( &fadeTime ); + arc.ArchiveBoolean( &doWatch ); + arc.ArchiveString( &watchEnt ); + arc.ArchiveString( &thread ); + arc.ArchiveString( &triggertarget ); + if ( arc.Loading() ) + { + CancelEventsOfType( EV_SplinePath_Create ); + } + } + +inline void SplinePath::SetThread + ( + const char *name + ) + + { + thread = name; + } + +inline void SplinePath::SetTriggerTarget + ( + const char *name + ) + + { + triggertarget = name; + } + +#endif /* __BSPLINE_H__ */ diff --git a/source/source/fgame/bullet.cpp b/source/source/fgame/bullet.cpp new file mode 100644 index 0000000..944451a --- /dev/null +++ b/source/source/fgame/bullet.cpp @@ -0,0 +1,298 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/bullet.cpp $ +// $Revision:: 1 $ +// $Author:: Jimdose $ +// $Date:: 9/10/99 10:53a $ +// +// Copyright (C) 1997 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source is may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/bullet.cpp $ +// +// 1 9/10/99 10:53a Jimdose +// +// 1 9/08/99 3:15p Aldie +// +// 11 8/18/99 3:28p Jimdose +// added cylindrical collision detection +// +// DESCRIPTION: +// Base class for all bullet (hitscan) weapons. Includes definition for shotgun. +// + +#include "g_local.h" +#include "specialfx.h" +#include "misc.h" +#include "bullet.h" +//#include "surface.h" + +CLASS_DECLARATION( Weapon, BulletWeapon, NULL ) + { + { NULL, NULL } + }; + +BulletWeapon::BulletWeapon() + { + modelIndex( "sprites/tracer.spr" ); + modelIndex( "sprites/bullethole.spr" ); + } + +void BulletWeapon::TraceAttack + ( + Vector start, + Vector end, + int damage, + trace_t *trace, + int numricochets, + int kick, + int dflags, + int meansofdeath, + qboolean server_effects + ) + + { + Vector org; + Vector dir; + Vector endpos; + int surfflags; + int surftype; + int timeofs; + Entity *ent; + qboolean ricochet; + + if ( HitSky( trace ) ) + { + return; + } + + ricochet = false; + dir = end - start; + dir.normalize(); + + org = end - dir; + + ent = trace->ent->entity; + + if ( !trace->surface ) + { + surfflags = 0; + surftype = 0; + } + else + { + surfflags = trace->surface->flags; + surftype = SURFACETYPE_FROM_FLAGS( surfflags ); + + if ( surfflags & SURF_RICOCHET ) + ricochet = true; + } + + if ( trace->intersect.valid && ent ) + { + // + // see if the surface has ricochet turned on + // + if ( trace->intersect.surface >= 0 ) + { + int flags; + + flags = gi.Surface_Flags( ent->edict->s.modelindex, trace->intersect.surface ); + /* GAMEFIX + if ( flags & MDL_SURFACE_RICOCHET ) + { + surftype = ( flags >> 8 ) & 0xf; + ricochet = true; + } + */ + } + } + if ( ent ) + { + if ( ent->flags & FL_SPARKS ) + { + // Take care of ricochet effects on the server + if ( server_effects && !ricochet ) + { + timeofs = MAX_RICOCHETS - numricochets; + if ( timeofs > 0xf ) + { + timeofs = 0xf; + } +/* GAMEFIX + gi.WriteByte( svc_temp_entity ); + gi.WriteByte( TE_GUNSHOT ); + gi.WritePosition( org.vec3() ); + gi.WriteDir( trace->plane.normal ); + gi.WriteByte( 0 ); + gi.multicast( org.vec3(), MULTICAST_PVS ); + */ + } + G_BroadcastSound( owner, org ); + } + + if ( ent->takedamage ) + { + if ( trace->intersect.valid ) + { + // We hit a valid group so send in location based damage + ent->Damage( this, + owner, + damage, + trace->endpos, + dir, + trace->plane.normal, + kick, + dflags, + meansofdeath, + trace->intersect.surface, + -1, + trace->intersect.damage_multiplier ); + } + else + { + // We didn't hit any groups, so send in generic damage + ent->Damage( this, + owner, + damage, + trace->endpos, + dir, + trace->plane.normal, + kick, + dflags, + meansofdeath, + -1, + -1, + 1 ); + } + } + } + + if ( ricochet && ( server_effects || ( numricochets < MAX_RICOCHETS ) ) ) + { + timeofs = MAX_RICOCHETS - numricochets; + if ( timeofs > 0xf ) + { + timeofs = 0xf; + } +/* GAMEFIX + gi.WriteByte( svc_temp_entity ); + gi.WriteByte( TE_GUNSHOT ); + gi.WritePosition( org.vec3() ); + gi.WriteDir( trace->plane.normal ); + gi.WriteByte( timeofs ); + gi.multicast( org.vec3(), MULTICAST_PVS ); + */ + } + + if ( + ricochet && + numricochets && + damage + ) + { + dir += Vector( trace->plane.normal ) * 2; + endpos = org + dir * 8192; + + // + // since this is a ricochet, we don't ignore the wewapon owner this time. + // + *trace = G_FullTrace( org, vec_zero, vec_zero, endpos, 5, NULL, MASK_SHOT, false, "BulletWeapon::TraceAttack" ); + if ( trace->fraction != 1.0 ) + { + endpos = trace->endpos; + TraceAttack( org, endpos, damage * 0.8f, trace, numricochets - 1, kick, dflags, meansofdeath, true ); + } + } + } + +void BulletWeapon::FireBullets + ( + int numbullets, + Vector spread, + int mindamage, + int maxdamage, + int dflags, + int meansofdeath, + qboolean server_effects + ) + + { + Vector src; + Vector dir; + Vector end; + trace_t trace; + Vector right; + Vector up; + int i; + + assert( owner ); + if ( !owner ) + { + return; + } + + GetMuzzlePosition( &src, &dir ); + + owner->angles.AngleVectors( NULL, &right, &up ); + + angles = dir.toAngles(); + setAngles( angles ); + + for( i = 0; i < numbullets; i++ ) + { + end = src + + dir * 8192 + + right * G_CRandom() * spread.x + + up * G_CRandom() * spread.y; + + trace = G_FullTrace( src, vec_zero, vec_zero, end, 5, owner, MASK_SHOT, false, "BulletWeapon::FireBullets" ); +#if 0 + Com_Printf("Server OWNER Angles:%0.2f %0.2f %0.2f\n",owner->angles[0],owner->angles[1],owner->angles[2]); + Com_Printf("Server Bullet Angles:%0.2f %0.2f %0.2f\n",angles[0],angles[1],angles[2]); + Com_Printf("Right :%0.2f %0.2f %0.2f\n",right[0],right[1],right[2]); + Com_Printf("Up :%0.2f %0.2f %0.2f\n",up[0],up[1],up[2]); + Com_Printf("Direction :%0.2f %0.2f %0.2f\n",dir[0],dir[1],dir[2]); + Com_Printf("Endpoint :%0.2f %0.2f %0.2f\n",end[0],end[1],end[2]); + Com_Printf("Server Trace Start :%0.2f %0.2f %0.2f\n",src[0],src[1],src[2]); + Com_Printf("Server Trace End :%0.2f %0.2f %0.2f\n",trace.endpos[0],trace.endpos[1],trace.endpos[2]); + Com_Printf("\n"); +#endif + if ( trace.fraction != 1.0 ) + { + TraceAttack( src, trace.endpos, mindamage + (int)G_Random( maxdamage - mindamage + 1 ), &trace, MAX_RICOCHETS, kick, dflags, meansofdeath, server_effects ); + } + } + } + +void BulletWeapon::FireTracer( void ) + { + Entity *tracer; + Vector src,dir,end; + trace_t trace; + + GetMuzzlePosition( &src, &dir ); + end = src + dir * 8192; + trace = G_Trace( src, vec_zero, vec_zero, end, owner, MASK_SHOT, false, "BulletWeapon::FireTracer" ); + + tracer = new Entity; + + tracer->angles = dir.toAngles(); + tracer->angles[ PITCH ] = -tracer->angles[ PITCH ] + 90; + //tracer->angles[PITCH] *= -1; + + tracer->setAngles( tracer->angles ); + + tracer->setMoveType( MOVETYPE_NONE ); + tracer->setSolidType( SOLID_NOT ); + tracer->setModel( "sprites/tracer.spr" ); + tracer->setSize( "0 0 0", "0 0 0" ); + tracer->setOrigin( trace.endpos ); + tracer->edict->s.renderfx &= ~RF_FRAMELERP; + + VectorCopy( src, tracer->edict->s.origin2 ); + tracer->PostEvent(EV_Remove,FRAMETIME); + } \ No newline at end of file diff --git a/source/source/fgame/bullet.h b/source/source/fgame/bullet.h new file mode 100644 index 0000000..0b143f6 --- /dev/null +++ b/source/source/fgame/bullet.h @@ -0,0 +1,45 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/bullet.h $ +// $Revision:: 1 $ +// $Author:: Jimdose $ +// $Date:: 9/10/99 10:53a $ +// +// Copyright (C) 1997 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source is may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/bullet.h $ +// +// 1 9/10/99 10:53a Jimdose +// +// 1 9/08/99 3:15p Aldie +// +// DESCRIPTION: +// Base class for all bullet (hitscan) weapons. Includes definition for shotgun. +// + +#ifndef __BULLET_H__ +#define __BULLET_H__ + +#include "g_local.h" +#include "item.h" +#include "weapon.h" + +#define MAX_RICOCHETS 10 + +class BulletWeapon : public Weapon + { + protected: + BulletWeapon(); + virtual void TraceAttack( Vector start, Vector end, int damage, trace_t *trace, int numricochets, int kick, int dflags, int meansofdeath, qboolean server_effects ); + virtual void FireBullets( int numbullets, Vector spread, int mindamage, int maxdamage, int dflags, int meansofdeath, qboolean server_effects ); + virtual void FireTracer( void ); + + public: + CLASS_PROTOTYPE( BulletWeapon ); + }; + +#endif /* BULLET.h */ diff --git a/source/source/fgame/camera.cpp b/source/source/fgame/camera.cpp new file mode 100644 index 0000000..3f9aafc --- /dev/null +++ b/source/source/fgame/camera.cpp @@ -0,0 +1,3829 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/camera.cpp $ +// $Revision:: 55 $ +// $Author:: Markd $ +// $Date:: 7/28/00 1:34a $ +// +// Copyright (C) 1997 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source is may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/camera.cpp $ +// +// 55 7/28/00 1:34a Markd +// fixed auto_fov bug +// +// 54 7/27/00 6:31p Markd +// made useAnim's work with doors, added key ability +// +// 53 7/19/00 6:18p Markd +// fixed potential camera fov bug +// +// 52 7/10/00 11:54p Markd +// added exit level code +// +// 51 7/10/00 8:35p Markd +// added camera tracing to orbit +// +// 50 7/07/00 1:45p Aldie +// Fixed a carriage return. +// +// 49 7/04/00 2:25p Markd +// added cool cinematic for new objects +// +// 48 6/29/00 9:27a Markd +// fixed camera with multiple automatic states +// +// 47 6/28/00 12:26p Markd +// fixed scoring on automatic cameras +// +// 46 6/28/00 12:23p Markd +// Added auto_active to cameras +// +// 45 6/23/00 8:41p Markd +// made a lot of changes to different constructors for saved game support +// +// 44 6/21/00 3:22p Markd +// Fixed camera bug +// +// 43 6/21/00 1:49p Markd +// fixed camera bug +// +// 42 6/14/00 3:50p Markd +// Cleaned up more Intel Compiler warnings +// +// 41 6/09/00 7:14p Markd +// fixed additional bind bug with cameras +// +// 40 6/09/00 6:55p Markd +// fixed camera being bound to other objects +// +// 39 5/26/00 7:44p Markd +// 2nd phase save games +// +// 38 5/08/00 5:53p Markd +// changed default start and stop time for auto cameras +// +// 37 5/02/00 10:50a Markd +// fixed camera start problem +// +// 36 5/01/00 7:13p Markd +// fixed camera nodes being executed at the right time +// +// 35 4/29/00 11:45a Markd +// fixed auto camera start and stop times +// +// 34 4/19/00 2:38p Markd +// Added auto_fov support to cameras +// +// 33 4/19/00 12:54p Markd +// put in auto_starttime and auto_stoptime support into auto cameras +// +// 32 4/11/00 2:46p Markd +// Implemented Automatic camera support +// +// 31 3/16/00 11:45a Markd +// fixed a camera iniatialization bug +// +// 30 3/15/00 2:32p Markd +// made the node connects duller +// +// 29 3/15/00 2:09p Markd +// forgot to take out debugging message +// +// 27 3/15/00 2:04p Markd +// fixed up camera node system and added new debug oriented circle +// +// 26 3/13/00 7:24p Jimdose +// put in error for when START_ON is set and no target specified +// +// 25 2/03/00 3:12p Markd +// Fixed up fadetimes for watches and fov and follow +// +// 24 2/01/00 5:40p Markd +// Fixed Camera cutting issues +// +// 23 1/26/00 9:53a Markd +// Changed FOV command to an fov command +// +// 22 1/06/00 4:39p Markd +// fixed tiki file name +// +// 21 1/05/00 7:25p Jimdose +// made angle functions all use the same coordinate system +// AngleVectors now returns left instead of right +// no longer need to invert pitch +// +// 20 12/21/99 4:35p Markd +// separated camera angles into three parts and fixed sliders +// +// 19 12/10/99 12:40p Markd +// fixed thread bug in camera system +// +// 18 12/03/99 9:48a Markd +// put in immediate camera cutting so that it wouldn't look funny +// +// 17 11/15/99 6:23p Markd +// fixed some comments +// +// 16 11/15/99 12:46p Markd +// Added LerpAnglesFromCurrent +// +// 15 11/10/99 1:46p Markd +// Fixed lerping code for watch State +// +// 14 11/09/99 8:30p Markd +// fixed nodes to node and also made sure that saving paths would add that path +// to the pathList +// +// 13 11/09/99 8:06p Markd +// Did a lot of work on the camera system +// +// 12 11/05/99 5:55p Markd +// Added user-interface to camera system +// +// 11 11/04/99 10:38a Markd +// Put in AngleMod on lerped angles to prevent weird interoplation issues +// +// 10 11/04/99 10:03a Markd +// complete overhaul of the camera system +// +// 9 10/29/99 7:04p Markd +// cleaned up some camera stuff +// +// 8 10/27/99 12:19p Markd +// added smooth camera lerping +// +// 7 10/07/99 2:59p Steven +// Event formatting. +// +// 6 10/07/99 11:27a Markd +// made camera fixed size +// +// 5 9/29/99 5:18p Steven +// Event formatting. +// +// 4 9/22/99 4:47p Markd +// fixed more G_GetEntity, G_FindClass and G_GetNextEntity bugs +// +// 3 9/21/99 7:51p Markd +// Fixed a lot of entitynum_none issues +// +// 2 9/16/99 11:18a Markd +// Continuing merge of code, not functional yet but closer +// +// 1 9/10/99 10:53a Jimdose +// +// 1 9/08/99 3:15p Aldie +// +// 26 9/01/99 9:41p Markd +// fixed camera speed +// +// 25 9/01/99 9:06p Jimdose +// fixed bug in DoNodeEvent. passed thread into ExecuteScript instead of +// node->thread +// +// 24 9/01/99 6:15p Jimdose +// added setthread command to camera. Threads are now started when camera +// reaches that node. +// now use triggertarget instead of target to store the name of the entity to +// trigger when camera reaches the node +// +// 23 8/19/99 12:15p Jimdose +// made SetCamera check for NULL before calling isSubclass +// +// 22 8/18/99 3:28p Jimdose +// added cylindrical collision detection +// +// 21 7/06/99 8:33p Jimdose +// removed unused player code +// added state machine for player animation +// +// 20 6/11/99 1:23p Phook +// +// 19 6/11/99 12:58p Phook +// Changed from SINED comments to QUAKED +// +// 18 6/11/99 12:46p Phook +// EClass color changes +// +// DESCRIPTION: +// Camera. Duh. +// + +#include "g_local.h" +#include "entity.h" +#include "trigger.h" +#include "camera.h" +#include "bspline.h" +#include "player.h" +#include "camera.h" + +#define CAMERA_PATHFILE_VERSION 1 + +CameraManager CameraMan; + +void CameraMoveState::Initialize( Camera * camera ) + { + assert( camera ); + pos = camera->origin; + angles = camera->angles; + movedir = vec_zero; + followEnt = NULL; + orbitEnt = NULL; + + followingpath = false; + cameraTime = 0; + lastTime = 0; + newTime = 0; + cameraPath.Clear(); + splinePath = NULL; + currentNode = NULL; + loopNode = NULL; + } + +void CameraWatchState::Initialize( Camera * camera ) + { + assert( camera ); + watchAngles = camera->angles; + watchEnt = NULL; + watchNodes = true; + watchPath = false; + } + +void CameraState::Initialize( Camera * camera ) + { + assert( camera ); + move.Initialize( camera ); + watch.Initialize( camera ); + fov = camera->Fov(); + } + +void CameraMoveState::DoNodeEvents + ( + Camera * camera + ) + + { + SplinePath *node; + Entity *ent; + Event *event; + + assert( camera ); + + node = currentNode; + if ( node ) + { + float fadeTime; + float newFov; + + fadeTime = node->GetFadeTime(); + if ( fadeTime == -1 ) + { + fadeTime = camera->fadeTime; + } + + if ( node->doWatch ) + { + camera->Watch( node->GetWatch(), fadeTime ); + } + + newFov = node->GetFov(); + if ( newFov ) + { + camera->SetFOV( newFov, fadeTime ); + } + + if ( node->thread != "" ) + { + if ( !ExecuteThread( node->thread ) ) + { + gi.Error( ERR_DROP, "Camera could not start thread '%s' from info_splinepath '%s'\n", + node->thread.c_str(), node->targetname.c_str() ); + } + } + + if ( node->triggertarget != "" ) + { + ent = NULL; + do + { + ent = G_FindTarget( ent, node->triggertarget.c_str() ); + if ( !ent ) + { + break; + } + event = new Event( EV_Activate ); + event->AddEntity( camera ); + ent->PostEvent( event, 0 ); + } + while ( 1 ); + } + } + } + +void CameraMoveState::Evaluate + ( + Camera * camera + ) + { + Vector oldpos; + float speed_multiplier; + + assert( camera ); + + oldpos = pos; + // + // check for node events + // we explicitly skip the first node because we process that + // when we begin the follow path command + // + if ( ( lastTime != newTime ) && currentNode ) + { + if ( newTime > 1 ) + { + DoNodeEvents( camera ); + } + currentNode = currentNode->GetNext(); + if ( !currentNode ) + { + currentNode = loopNode; + } + } + lastTime = newTime; + + // + // evaluate position + // + if ( followingpath ) + { + speed_multiplier = cameraPath.Eval( cameraTime, pos, angles ); + + cameraTime += level.fixedframetime * camera->camera_speed * speed_multiplier; + + if ( orbitEnt ) + { + pos += orbitEnt->origin; + if ( camera->orbit_dotrace ) + { + trace_t trace; + Vector start, back; + + start = orbitEnt->origin; + start[ 2 ] += orbitEnt->maxs[ 2 ]; + + back = start - pos; + back.normalize(); + + trace = G_Trace( start, vec_zero, vec_zero, pos, orbitEnt, camera->follow_mask, false, "Camera::EvaluatePosition" ); + + if ( trace.fraction < 1.0f ) + { + pos = trace.endpos; + // step in a bit towards the followEng + pos += back * 16; + } + } + } + } + else + { + if ( followEnt ) + { + trace_t trace; + Vector start, end, ang, back; + + start = followEnt->origin; + start[ 2 ] += followEnt->maxs[ 2 ]; + + if ( camera->follow_yaw_fixed ) + { + ang = vec_zero; + } + else + { + if ( followEnt->isSubclassOf( Player ) ) + { + Entity * ent; + ent = followEnt; + ( ( Player * )ent )->GetPlayerView( NULL, &ang ); + } + else + { + ang = followEnt->angles; + } + } + ang.y += camera->follow_yaw; + ang.AngleVectors( &back, NULL, NULL ); + + end = start - back * camera->follow_dist; + end[ 2 ] += 24; + + trace = G_Trace( start, vec_zero, vec_zero, end, followEnt, camera->follow_mask, false, "Camera::EvaluatePosition - Orbit" ); + + pos = trace.endpos; + // step in a bit towards the followEnt + pos += back * 16; + } + } + + // + // update times for node events + // + newTime = cameraTime + 2.0f; + + if ( newTime < 0 ) + { + newTime = 0; + } + // + // set movedir + // + movedir = pos - oldpos; + } + +void CameraWatchState::Evaluate + ( + Camera * camera, + CameraMoveState * move + ) + { + assert( camera ); + assert( move ); + // + // evaluate orientation + // + if ( watchEnt ) + { + Vector watchPos; + + + watchPos.x = watchEnt->origin.x; + watchPos.y = watchEnt->origin.y; + watchPos.z = watchEnt->absmax.z; + watchPos -= camera->origin; + watchPos.normalize(); + watchAngles = watchPos.toAngles(); + } + else if ( watchNodes ) + { + watchAngles = move->angles; + } + else if ( watchPath ) + { + float length; + Vector delta; + + delta = move->movedir; + length = delta.length(); + if ( length > 0.05f ) + { + delta *= 1.0f / length; + watchAngles = delta.toAngles(); + } + } + watchAngles[ 0 ] = AngleMod( watchAngles[ 0 ] ); + watchAngles[ 1 ] = AngleMod( watchAngles[ 1 ] ); + watchAngles[ 2 ] = AngleMod( watchAngles[ 2 ] ); + } + +void CameraState::Evaluate + ( + Camera * camera + ) + { + move.Evaluate( camera ); + watch.Evaluate( camera, &move ); + } + + +Event EV_Camera_CameraThink + ( + "camera_think", + EV_DEFAULT, + NULL, + NULL, + "Called each frame to allow the camera to adjust its position." + ); +Event EV_Camera_StartMoving + ( + "start", + EV_DEFAULT, + NULL, + NULL, + "Start camera moving." + ); +Event EV_Camera_Pause + ( + "pause", + EV_DEFAULT, + NULL, + NULL, + "Pause the camera." + ); +Event EV_Camera_Continue + ( + "continue", + EV_DEFAULT, + NULL, + NULL, + "Continue the camera movement." + ); +Event EV_Camera_StopMoving + ( "stop", + EV_CONSOLE, + NULL, + NULL, + "Stop the camera movement." + ); +Event EV_Camera_SetSpeed + ( + "speed", + EV_DEFAULT, + "f", + "speed", + "Sets the camera speed." + ); +Event EV_Camera_SetFOV + ( + "fov", + EV_CONSOLE, + "fF", + "fov fadeTime", + "Sets the camera's field of view (fov).\n" + "if fadeTime is specified, camera will fade over that time\n" + "if fov is less than 3, than an auto_fov will be assumed\n" + "the value of fov will be the ratio used for keeping a watch\n" + "entity in the view at the right scale" + ); + +// +// FOLLOW EVENTS +// +Event EV_Camera_Follow + ( + "follow", + EV_DEFAULT, + "eE", + "targetEnt targetWatchEnt", + "Makes the camera follow an entity and optionally watch an entity." + ); +Event EV_Camera_SetFollowDistance + ( + "follow_distance", + EV_DEFAULT, + "f", + "distance", + "Sets the camera follow distance." + ); +Event EV_Camera_SetFollowYaw + ( + "follow_yaw", + EV_DEFAULT, + "f", + "yaw", + "Sets the yaw offset of the camera following an entity." + ); +Event EV_Camera_AbsoluteYaw + ( + "follow_yaw_absolute", + EV_DEFAULT, + NULL, + NULL, + "Makes the follow camera yaw absolute." + ); +Event EV_Camera_RelativeYaw + ( + "follow_yaw_relative", + EV_DEFAULT, + NULL, + NULL, + "Makes the follow camera yaw relative (not absolute)." + ); + +// +// ORBIT Events +// +Event EV_Camera_Orbit + ( + "orbit", + EV_DEFAULT, + "eE", + "targetEnt targetWatchEnt", + "Makes the camera orbit around an entity and optionally watch an entity." + ); +Event EV_Camera_SetOrbitHeight + ( + "orbit_height", + EV_DEFAULT, + "f", + "height", + "Sets the orbit camera's height." + ); + +// +// Watch Events +// +Event EV_Camera_Watch + ( + "watch", + EV_CONSOLE, + "eF", + "watchEnt fadeTime", + "Makes the camera watch an entity.\n" + "if fadeTime is specified, camera will fade over that time" + ); +Event EV_Camera_WatchPath + ( + "watchpath", + EV_CONSOLE, + "F", + "fadeTime", + "Makes the camera look along the path of travel.\n" + "if fadeTime is specified, camera will fade over that time" + ); +Event EV_Camera_WatchNodes + ( + "watchnode", + EV_CONSOLE, + "F", + "fadeTime", + "Makes the camera watch based on what is stored\n" + "in the camera nodes.\n" + "if fadeTime is specified, camera will fade over that time" + ); +Event EV_Camera_NoWatch + ( + "nowatch", + EV_CONSOLE, + "F", + "fadeTime", + "Stop watching an entity or looking along a path.\n" + "Camera is now static as far as orientation.\n" + "if fadeTime is specified, camera will fade over that time" + ); + +// +// Camera positioning events +// +Event EV_Camera_LookAt + ( + "lookat", + EV_DEFAULT, + "e", + "ent", + "Makes the camera look at an entity." + ); +Event EV_Camera_TurnTo + ( + "turnto", + EV_DEFAULT, + "v", + "angle", + "Makes the camera look in the specified direction." + ); +Event EV_Camera_MoveToEntity + ( + "moveto", + EV_DEFAULT, + "e", + "ent", + "Move the camera's position to that of the specified entities." + ); +Event EV_Camera_MoveToPos + ( + "movetopos", + EV_DEFAULT, + "v", + "position", + "Move the camera's position to the specified position." + ); + +// +// Camera Transitioning events +// +Event EV_Camera_FadeTime + ( + "fadetime", + EV_DEFAULT, + "f", + "fadetime", + "Sets the fade time for camera transitioning." + ); +Event EV_Camera_Cut + ( + "cut", + EV_DEFAULT, + NULL, + NULL, + "switch camera states immediately, do not transition" + ); +Event EV_Camera_SetNextCamera + ( + "nextcamera", + EV_DEFAULT, + "s", + "nextCamera", + "Sets the next camera to use." + ); + +Event EV_Camera_SetAutoState + ( + "auto_state", + EV_DEFAULT, + "sSSSSS", + "state1 state2 state3 state4 state5 state6", + "Sets the states the player needs to be in for this camera to activate." + ); + +Event EV_Camera_SetAutoRadius + ( + "auto_radius", + EV_DEFAULT, + "f", + "newRadius", + "Sets the radius of the automatic camera." + ); + +Event EV_Camera_SetAutoActive + ( + "auto_active", + EV_DEFAULT, + "b", + "newActiveState", + "Whether or not the auto camera is active." + ); + +Event EV_Camera_SetAutoStartTime + ( + "auto_starttime", + EV_DEFAULT, + "f", + "newTime", + "Sets how long it takes for the camera to be switched to." + ); + +Event EV_Camera_SetAutoStopTime + ( + "auto_stoptime", + EV_DEFAULT, + "f", + "newTime", + "Sets how long it takes for the camera switch back to the player." + ); + +Event EV_Camera_SetMaximumAutoFOV + ( + "auto_maxfov", + EV_DEFAULT, + "f", + "maxFOV", + "Sets the maximum FOV that should be used when automatically calculating FOV." + ); + +// +// general setup functions +// +Event EV_Camera_SetThread + ( + "setthread", + EV_CONSOLE, + "s", + "thread", + "Sets the thread to use." + ); +Event EV_Camera_SetThread2 + ( + "thread", + EV_DEFAULT, + "s", + "thread", + "Sets the thread to use." + ); + +Event EV_Camera_SetupCamera + ( + "_setupcamera", + EV_DEFAULT, + NULL, + NULL, + "setup the camera, post spawn." + ); + +/*****************************************************************************/ +/* func_camera (0 0.25 0.5) (-8 -8 0) (8 8 16) ORBIT START_ON AUTOMATIC NO_TRACE NO_WATCH LEVEL_EXIT + +Camera used for cinematic sequences. + +"target" points to the target to orbit or follow. If it points to a path, +the camera will follow the path. +"speed" specifies how fast to move on the path or orbit. (default 1). +"fov" specifies fov of camera, default 90. +if fov is less than 3 than an auto-fov feature is assumed. The fov will then +specify the ratio to be used to keep a watched entity zoomed in and on the screen +"follow_yaw" specifies yaw of the follow camera, default 0. +"follow_distance" the distance to follow or orbit if the target is not a path. (default 128). +"orbit_height" specifies height of camera from origin for orbiting, default 128. +"nextcamera" a link to the next camera in a chain of cameras +"thread" a thread label that will be fired when the camera is looked through +"auto_state" if specified, denotes the state the player must be in for the camera to engage +any number of states can be specified and only the first few letters need be specified as well +a state of 'pipe' would mean that any player state that started with 'pipe' would trigger this +camera +"auto_radius" the radius, in which the camera will automatically turn on (default 512) +"auto_starttime" how long it takes for the camera to be switched to (default 0.2) +"auto_stoptime" how long it takes for the camera to switch back to the player (default 0.2) +"auto_maxfov" Sets the maximum FOV that should be used when automatically calculating FOV. (default 90) + +ORBIT tells the camera to create a circular path around the object it points to. +It the camera points to a path, it will loop when it gets to the end of the path. +START_ON causes the camera to be moving as soon as it is spawned. +AUTOMATIC causes the camera to be switched to automatically when the player is within +a certain radius, if "thread" is specified, that thread will be triggered when the camers is activated +NO_TRACE when the camera is in automatic mode, it will try to trace to the player before +switching automatically, this turns off that feature +NO_WATCH if this is an automatic camera, the camera will automatically watch the player +unless this is set, camera's "score" will be affected by how close to the middle of the camera +the player is. +LEVEL_EXIT if the camera is being used, the level exit state will be set + +******************************************************************************/ + +CLASS_DECLARATION( Entity, Camera, "func_camera" ) + { + { &EV_Camera_CameraThink, CameraThink }, + { &EV_Activate, StartMoving }, + { &EV_Camera_StartMoving, StartMoving }, + { &EV_Camera_StopMoving, StopMoving }, + { &EV_Camera_Pause, Pause }, + { &EV_Camera_Continue, Continue }, + { &EV_Camera_SetSpeed, SetSpeed }, + { &EV_Camera_SetFollowDistance,SetFollowDistance }, + { &EV_Camera_SetFollowYaw, SetFollowYaw }, + { &EV_Camera_AbsoluteYaw, AbsoluteYaw }, + { &EV_Camera_RelativeYaw, RelativeYaw }, + { &EV_Camera_SetOrbitHeight, SetOrbitHeight }, + { &EV_Camera_SetFOV, SetFOV }, + { &EV_Camera_Orbit, OrbitEvent }, + { &EV_Camera_Follow, FollowEvent }, + { &EV_Camera_Watch, WatchEvent }, + { &EV_Camera_WatchPath, WatchPathEvent }, + { &EV_Camera_WatchNodes, WatchNodesEvent }, + { &EV_Camera_NoWatch, NoWatchEvent }, + { &EV_Camera_LookAt, LookAt }, + { &EV_Camera_TurnTo, TurnTo }, + { &EV_Camera_MoveToEntity, MoveToEntity }, + { &EV_Camera_MoveToPos, MoveToPos }, + { &EV_Camera_Cut, Cut }, + { &EV_Camera_FadeTime, FadeTime }, + { &EV_Camera_SetNextCamera, SetNextCamera }, + { &EV_Camera_SetThread, SetThread }, + { &EV_Camera_SetThread2, SetThread }, + { &EV_Camera_SetupCamera, SetupCamera }, + { &EV_SetAngles, SetAnglesEvent }, + { &EV_Camera_SetAutoState, SetAutoStateEvent }, + { &EV_Camera_SetAutoRadius, SetAutoRadiusEvent }, + { &EV_Camera_SetAutoStartTime, SetAutoStartTimeEvent }, + { &EV_Camera_SetAutoStopTime, SetAutoStopTimeEvent }, + { &EV_Camera_SetMaximumAutoFOV, SetMaximumAutoFOVEvent }, + { &EV_Camera_SetAutoActive, SetAutoActiveEvent }, + + { NULL, NULL } + }; + +Camera::Camera() + { + Vector ang; + + camera_fov = 90; + camera_speed = 1; + orbit_height = 128; + orbit_dotrace = qtrue; + follow_yaw = 0; + follow_yaw_fixed = false; + follow_dist = 128; + follow_mask = MASK_SOLID; + auto_fov = 0; + automatic_maxFOV = 90; + + watchTime = 0; + followTime = 0; + fovTime = 0; + + fadeTime = 2.0f; + + setSolidType( SOLID_NOT ); + setMoveType( MOVETYPE_NONE ); + + showcamera = sv_showcameras->integer; + if ( showcamera ) + { + setModel( "func_camera.tik" ); + showModel(); + } + else + { + hideModel(); + } + + automatic_active = qtrue; + automatic_radius = 512; + automatic_states.ClearObjectList(); + automatic_startTime = 0.7f; + automatic_stopTime = 0.7f; + + if ( !LoadingSavegame ) + { + PostEvent( EV_Camera_SetupCamera, EV_POSTSPAWN ); + } + } + +void Camera::SetupCamera + ( + Event *ev + ) + + { + currentstate.Initialize( this ); + newstate.Initialize( this ); + + if ( spawnflags & START_ON ) + { + PostEvent( EV_Camera_StartMoving, 0 ); + } + if ( spawnflags & AUTOMATIC ) + { + level.AddAutomaticCamera( this ); + } + } + +qboolean Camera::IsAutomatic + ( + void + ) + { + return ( spawnflags & AUTOMATIC ); + } + +qboolean Camera::IsLevelExit + ( + void + ) + { + return ( spawnflags & LEVEL_EXIT ); + } + +float Camera::CalculateScore + ( + Entity * player, + str state + ) + { + int i; + float range; + float score; + qboolean found; + + if ( !automatic_active ) + { + return 10; + } + + range = Vector( player->origin - origin ).length() / automatic_radius; + // bias the range so that we don't immediately jump out of the camera if we are out of range + range -= 0.1f; + + score = range; + + // + // early exit if our score exceeds 1 + // + if ( score > 1.0f ) + return score; + + // find out if we match a state + found = qfalse; + for( i = 1; i <= automatic_states.NumObjects(); i++ ) + { + str *auto_state; + + auto_state = &automatic_states.ObjectAt( i ); + if ( !state.icmpn( state, auto_state->c_str(), auto_state->length() ) ) + { + found = qtrue; + break; + } + } + + // if we are comparing states and we haven't found a valid one... + if ( automatic_states.NumObjects() && !found ) + { + // if we aren't in the right state, push our score out significantly + score += 2.0f; + return score; + } + + // perform a trace to the player if necessary + if ( !( spawnflags & NO_TRACE ) && !( spawnflags & NO_WATCH ) ) + { + trace_t trace; + + trace = G_Trace( origin, vec_zero, vec_zero, player->centroid, player, follow_mask, false, "Camera::CalculateScore" ); + if ( trace.startsolid || trace.allsolid || trace.fraction < 1.0f ) + { + // if we are blocked, push our score out, but not too much since this may be a temporary thing + if ( trace.startsolid || trace.allsolid ) + { + score += 2.0f; + return score; + } + else + { + score += 1.0f - trace.fraction; + } + } + } + + // perform a dot product test for no watch cameras + if ( spawnflags & NO_WATCH ) + { + trace_t trace; + float limit; + float threshold; + float dot; + Vector dir; + + dir = player->centroid - origin; + dir.normalize(); + dot = dir * orientation[ 0 ]; + + threshold = cos( DEG2RAD( ( camera_fov * 0.25f ) ) ); + if ( dot <= threshold ) + { + limit = cos( DEG2RAD( ( camera_fov * 0.45f ) ) ); + if ( dot <= limit ) + { + // we are outside the viewing cone + score += 2.0f; + return score; + } + else + { + // our score is a scale between the two values + score += ( threshold - dot ) / ( limit ); + } + } + + trace = G_Trace( origin, vec_zero, vec_zero, player->origin, player, follow_mask, false, "Camera::CalculateScore" ); + if ( trace.startsolid || trace.allsolid || trace.fraction < 1.0f ) + { + // if we are blocked, push our score out, but not too much since this may be a temporary thing + if ( trace.startsolid || trace.allsolid ) + { + score += 2.0f; + return score; + } + else + { + score += 1.0f - trace.fraction; + } + } + } + + return score; + } + +float Camera::AutomaticStart + ( + Entity * player + ) + { + if ( !( spawnflags & NO_WATCH ) && player ) + { + Watch( player, 0 ); + Cut( NULL ); + } + + if ( thread.length() ) + { + ExecuteThread( thread ); + } + + return automatic_startTime; + } + +float Camera::AutomaticStop + ( + Entity * player + ) + { + Stop(); + return automatic_stopTime; + } + +void Camera::UpdateStates + ( + void + ) + + { + if ( followTime && watchTime ) + { + newstate.Evaluate( this ); + } + else if ( watchTime ) + { + newstate.watch.Evaluate( this, ¤tstate.move ); + } + else if ( followTime ) + { + newstate.move.Evaluate( this ); + } + currentstate.Evaluate( this ); + } + + +Vector Camera::CalculatePosition + ( + void + ) + + { + int i; + float t; + Vector pos; + + // + // calcualte position + // + if ( followTime ) + { + t = followTime - level.time; + // + // are we still fading? + // + if ( t <= 0 ) + { + // + // if not zero out the fade + // + t = 0; + currentstate.move = newstate.move; + newstate.move.Initialize( this ); + followTime = 0; + pos = currentstate.move.pos; + } + else + { + // + // if we are lerp over followFadeTime + // + t = ( followFadeTime - t ) / followFadeTime; + + for ( i = 0; i < 3; i++ ) + { + pos[ i ] = currentstate.move.pos[ i ] + ( t * ( newstate.move.pos[ i ] - currentstate.move.pos[ i ] ) ); + } + } + } + else + { + pos = currentstate.move.pos; + } + + return pos; + } + + +Vector Camera::CalculateOrientation + ( + void + ) + + { + int i; + float t; + Vector ang; + + // + // calculate orientation + // + if ( watchTime ) + { + t = watchTime - level.time; + // + // are we still fading? + // + if ( t <= 0 ) + { + // + // if not zero out the fade + // + t = 0; + currentstate.watch = newstate.watch; + newstate.watch.Initialize( this ); + watchTime = 0; + ang = currentstate.watch.watchAngles; + } + else + { + t = ( watchFadeTime - t ) / watchFadeTime; + + for ( i=0; i<3; i++ ) + { + ang[ i ] = LerpAngleFromCurrent + ( + currentstate.watch.watchAngles[ i ], + newstate.watch.watchAngles[ i ], + this->angles[ i ], + t + ); + } + /* + warning("", "%.2f a x%.0f y%.0f z%.0f c x%.0f y%.0f z%.0f n x%.0f y%.0f z%.0f\n", + t, + ang[ 0 ], + ang[ 1 ], + ang[ 2 ], + currentstate.watch.watchAngles[ 0 ], + currentstate.watch.watchAngles[ 1 ], + currentstate.watch.watchAngles[ 2 ], + newstate.watch.watchAngles[ 0 ], + newstate.watch.watchAngles[ 1 ], + newstate.watch.watchAngles[ 2 ] + ); + */ + } + } + else + { + ang = currentstate.watch.watchAngles; + } + + return ang; + } + +float Camera::CalculateFov + ( + void + ) + + { + float fov; + float t; + + // + // calculate fov + // + // check if we have an auto_fov + if ( auto_fov > 0 ) + { + if ( currentstate.watch.watchEnt ) + { + float distance; + float size; + float new_fov; + Entity * ent; + + ent = currentstate.watch.watchEnt; + size = ent->maxs[ 2 ] - ent->mins[ 2 ]; + size = ent->edict->radius / 2; + // cap the size + if ( size < 16 ) + size = 16; + distance = Vector( ent->centroid - origin ).length(); + new_fov = RAD2DEG( 2.0f * atan2( size, distance * auto_fov ) ); + if ( new_fov > automatic_maxFOV ) + new_fov = automatic_maxFOV; + else if ( new_fov < 5 ) + new_fov = 5; + return new_fov; + } + else + { + return 90; + } + } + // if we get here, we don't have an auto_fov, or we have an invalid watch target + if ( fovTime ) + { + t = fovTime - level.time; + // + // are we still fading? + // + if ( t <= 0 ) + { + // + // if not zero out the fade + // + t = 0; + currentstate.fov = newstate.fov; + fovTime = 0; + fov = currentstate.fov; + } + else + { + // + // if we are lerp over fovFadeTime + // + t = ( fovFadeTime - t ) / fovFadeTime; + fov = currentstate.fov + ( t * ( newstate.fov - currentstate.fov ) ); + } + } + else + { + fov = currentstate.fov; + } + + return fov; + } + +void Camera::CameraThink + ( + Event *ev + ) + + { + UpdateStates(); + + setOrigin( CalculatePosition() ); + setAngles( CalculateOrientation() ); + camera_fov = CalculateFov(); + + // + // debug info + // + if ( sv_showcameras->integer != showcamera ) + { + showcamera = sv_showcameras->integer; + if ( showcamera ) + { + setModel( "func_camera.tik" ); + showModel(); + } + else + { + hideModel(); + } + } + + if ( sv_showcameras->integer != showcamera ) + { + showcamera = sv_showcameras->integer; + if ( showcamera ) + { + setModel( "func_camera.tik" ); + showModel(); + } + else + { + hideModel(); + } + } + if ( showcamera && currentstate.move.followingpath ) + { + G_Color3f( 1, 1, 0 ); + if ( currentstate.move.orbitEnt ) + { + currentstate.move.cameraPath.DrawCurve( currentstate.move.orbitEnt->origin, 10 ); + } + else + { + currentstate.move.cameraPath.DrawCurve( 10 ); + } + } + + CancelEventsOfType( EV_Camera_CameraThink ); + PostEvent( EV_Camera_CameraThink, FRAMETIME ); + } + +void Camera::LookAt + ( + Event *ev + ) + + { + Vector pos, delta; + Entity * ent; + + ent = ev->GetEntity( 1 ); + + if ( !ent ) + return; + + pos.x = ent->origin.x; + pos.y = ent->origin.y; + pos.z = ent->absmax.z; + delta = pos - origin; + delta.normalize(); + + currentstate.watch.watchAngles = delta.toAngles(); + setAngles( currentstate.watch.watchAngles ); + } + +void Camera::TurnTo + ( + Event *ev + ) + + { + currentstate.watch.watchAngles = ev->GetVector( 1 ); + setAngles( currentstate.watch.watchAngles ); + } + +void Camera::MoveToEntity + ( + Event *ev + ) + + { + Entity * ent; + + ent = ev->GetEntity( 1 ); + if ( ent ) + currentstate.move.pos = ent->origin; + setOrigin( currentstate.move.pos ); + } + +void Camera::MoveToPos + ( + Event *ev + ) + + { + currentstate.move.pos = ev->GetVector( 1 ); + setOrigin( currentstate.move.pos ); + } + +void Camera::Stop + ( + void + ) + + { + if ( followTime ) + { + currentstate.move = newstate.move; + newstate.move.Initialize( this ); + } + if ( watchTime ) + { + currentstate.watch = newstate.watch; + newstate.watch.Initialize( this ); + } + CancelEventsOfType( EV_Camera_CameraThink ); + + watchTime = 0; + followTime = 0; + } + +void Camera::CreateOrbit + ( + Vector pos, + float radius, + Vector &forward, + Vector &left + ) + + { + newstate.move.cameraPath.Clear(); + newstate.move.cameraPath.SetType( SPLINE_LOOP ); + + newstate.move.cameraPath.AppendControlPoint( pos + radius * forward ); + newstate.move.cameraPath.AppendControlPoint( pos + radius * left ); + newstate.move.cameraPath.AppendControlPoint( pos - radius * forward ); + newstate.move.cameraPath.AppendControlPoint( pos - radius * left ); + } + +void Camera::CreatePath + ( + SplinePath *path, + splinetype_t type + ) + + { + SplinePath *node; + SplinePath *loop; + + newstate.move.cameraPath.Clear(); + newstate.move.cameraPath.SetType( type ); + + newstate.move.splinePath = path; + newstate.move.currentNode = path; + newstate.move.loopNode = NULL; + + node = path; + while( node != NULL ) + { + newstate.move.cameraPath.AppendControlPoint( node->origin, node->angles, node->speed ); + loop = node->GetLoop(); + if ( loop && ( type == SPLINE_LOOP ) ) + { + newstate.move.loopNode = loop; + newstate.move.cameraPath.SetLoopPoint( loop->origin ); + } + node = node->GetNext(); + + if ( node == path ) + { + break; + } + } + + if ( ( type == SPLINE_LOOP ) && ( !newstate.move.loopNode ) ) + { + newstate.move.loopNode = path; + } + } + +void Camera::FollowPath + ( + SplinePath *path, + qboolean loop, + Entity * watch + ) + + { + // make sure we process any setup events before continuing + ProcessPendingEvents(); + + Stop(); + if ( loop ) + { + CreatePath( path, SPLINE_LOOP ); + } + else + { + CreatePath( path, SPLINE_CLAMP ); + } + + newstate.move.cameraTime = -2; + newstate.move.lastTime = 0; + newstate.move.newTime = 0; + newstate.move.currentNode = path; + // evaluate the first node events + newstate.move.DoNodeEvents( this ); + + if ( watch ) + { + newstate.watch.watchEnt = watch; + } + else + { + Watch( newstate.move.currentNode->GetWatch(), newstate.move.currentNode->GetFadeTime() ); + } + + followFadeTime = fadeTime; + watchFadeTime = fadeTime; + + newstate.move.followingpath = true; + followTime = level.time + followFadeTime; + watchTime = level.time + watchFadeTime; + + PostEvent( EV_Camera_CameraThink, FRAMETIME ); + } + +void Camera::Orbit + ( + Entity *ent, + float dist, + Entity *watch, + float yaw_offset, + qboolean dotrace + ) + + { + Vector ang, forward, left; + + // make sure we process any setup events before continuing + ProcessPendingEvents(); + + Stop(); + + if ( watch ) + { + ang = watch->angles; + ang.y += yaw_offset; + } + else + { + ang = vec_zero; + ang.y += yaw_offset; + } + ang.AngleVectors( &forward, &left, NULL ); + + orbit_dotrace = dotrace; + + CreateOrbit( Vector( 0, 0, orbit_height ), dist, forward, left ); + newstate.move.cameraTime = -2; + newstate.move.lastTime = 0; + newstate.move.newTime = 0; + + newstate.move.orbitEnt = ent; + + followFadeTime = fadeTime; + watchFadeTime = fadeTime; + + newstate.move.followingpath = true; + followTime = level.time + followFadeTime; + watchTime = level.time + watchFadeTime; + newstate.move.currentNode = NULL; + + if ( watch ) + { + newstate.watch.watchEnt = watch; + } + else + { + newstate.watch.watchEnt = ent; + } + + PostEvent( EV_Camera_CameraThink, FRAMETIME ); + } + +void Camera::FollowEntity + ( + Entity *ent, + float dist, + int mask, + Entity *watch + ) + + { + // make sure we process any setup events before continuing + ProcessPendingEvents(); + + assert( ent ); + + Stop(); + + if ( ent ) + { + newstate.move.followEnt = ent; + newstate.move.followingpath = false; + + followFadeTime = fadeTime; + watchFadeTime = fadeTime; + + newstate.move.cameraTime = -2; + newstate.move.lastTime = 0; + newstate.move.newTime = 0; + newstate.move.currentNode = NULL; + + followTime = level.time + followFadeTime; + watchTime = level.time + watchFadeTime; + if ( watch ) + { + newstate.watch.watchEnt = watch; + } + else + { + newstate.watch.watchEnt = ent; + } + follow_dist = dist; + follow_mask = mask; + PostEvent( EV_Camera_CameraThink, 0 ); + } + } + +void Camera::StartMoving + ( + Event *ev + ) + + { + Entity *targetEnt; + Entity *targetWatchEnt; + Entity *ent; + SplinePath *path; + + if ( ev->NumArgs() > 0 ) + { + targetEnt = ev->GetEntity( 1 ); + } + else + { + targetEnt = NULL; + } + + if ( ev->NumArgs() > 1 ) + { + targetWatchEnt = ev->GetEntity( 2 ); + } + else + { + targetWatchEnt = NULL; + } + + if ( ( spawnflags & START_ON ) && ( !Q_stricmp( Target(), "" ) ) ) + { + gi.Error( ERR_DROP, "Camera '%s' with START_ON selected, but no target specified.", TargetName() ); + } + + if ( !targetEnt ) + { + ent = G_FindTarget( NULL, Target() ); + if ( !ent ) + { + // + // we took this out just because of too many warnings, oh well + //warning("StartMoving", "Can't find target for camera\n" ); + // + // I put it back in as an error. Fuck em! Yeeeeeha! + // + gi.Error( ERR_DROP, "Can't find target '%s' for camera\n", Target() ); + return; + } + } + else + { + ent = targetEnt; + } + + if ( ent->isSubclassOf( SplinePath ) ) + { + path = ( SplinePath * )ent; + FollowPath( path, spawnflags & ORBIT, targetWatchEnt ); + } + else + { + if ( spawnflags & ORBIT ) + { + Orbit( ent, follow_dist, targetWatchEnt ); + } + else + { + FollowEntity( ent, follow_dist, follow_mask, targetWatchEnt ); + } + } + } + +void Camera::SetAutoStateEvent + ( + Event *ev + ) + + { + int i; + + for( i = 1; i <= ev->NumArgs(); i++ ) + { + char *buffer; + char com_token[ MAX_QPATH ]; + char com_buffer[MAX_STRING_CHARS]; + + strcpy( com_buffer, ev->GetString( i ) ); + buffer = com_buffer; + // get the rest of the line + while( 1 ) + { + strcpy( com_token, COM_ParseExt( &buffer, qfalse ) ); + if (!com_token[0]) + break; + + automatic_states.AddUniqueObject( str( com_token ) ); + } + } + } + +void Camera::SetMaximumAutoFOVEvent + ( + Event *ev + ) + + { + automatic_maxFOV = ev->GetFloat( 1 ); + } + +void Camera::SetAutoRadiusEvent + ( + Event *ev + ) + + { + automatic_radius = ev->GetFloat( 1 ); + } + +void Camera::SetAutoActiveEvent + ( + Event *ev + ) + + { + automatic_active = ev->GetBoolean( 1 ); + } + +void Camera::SetAutoStartTimeEvent + ( + Event *ev + ) + + { + automatic_startTime = ev->GetFloat( 1 ); + } + +void Camera::SetAutoStopTimeEvent + ( + Event *ev + ) + + { + automatic_stopTime = ev->GetFloat( 1 ); + } + + +void Camera::StopMoving + ( + Event *ev + ) + + { + Stop(); + } + +void Camera::Pause + ( + Event *ev + ) + + { + CancelEventsOfType( EV_Camera_CameraThink ); + } + +void Camera::Continue + ( + Event *ev + ) + + { + CancelEventsOfType( EV_Camera_CameraThink ); + PostEvent( EV_Camera_CameraThink, 0 ); + } + +void Camera::SetAnglesEvent + ( + Event *ev + ) + + { + Vector ang; + + ang = ev->GetVector( 1 ); + setAngles( ang ); + } + +void Camera::SetSpeed + ( + Event *ev + ) + + { + camera_speed = ev->GetFloat( 1 ); + } + +void Camera::SetFollowDistance + ( + Event *ev + ) + + { + follow_dist = ev->GetFloat( 1 ); + } + +void Camera::SetOrbitHeight + ( + float height + ) + + { + orbit_height = height; + } + +void Camera::SetOrbitHeight + ( + Event *ev + ) + + { + orbit_height = ev->GetFloat( 1 ); + } + +void Camera::SetFollowYaw + ( + Event *ev + ) + + { + follow_yaw = ev->GetFloat( 1 ); + } + +void Camera::AbsoluteYaw + ( + Event *ev + ) + + { + follow_yaw_fixed = true; + } + +void Camera::RelativeYaw + ( + Event *ev + ) + + { + follow_yaw_fixed = false; + } + +void Camera::SetNextCamera + ( + Event *ev + ) + + { + nextCamera = ev->GetString( 1 ); + } + +void Camera::Cut + ( + Event *ev + ) + { + int j; + + if ( followTime ) + { + currentstate.move = newstate.move; + newstate.move.Initialize( this ); + followTime = 0; + } + if ( watchTime ) + { + currentstate.watch = newstate.watch; + newstate.watch.Initialize( this ); + watchTime = 0; + } + if ( fovTime ) + { + currentstate.fov = newstate.fov; + newstate.fov = camera_fov; + fovTime = 0; + } + CancelEventsOfType( EV_Camera_CameraThink ); + ProcessEvent( EV_Camera_CameraThink ); + + // + // let any clients know that this camera has just cut + // + for( j = 0; j < game.maxclients; j++ ) + { + gentity_t *other; + Player *client; + + other = &g_entities[ j ]; + if ( other->inuse && other->client ) + { + client = ( Player * )other->entity; + client->CameraCut( this ); + } + } + } + +void Camera::FadeTime + ( + Event *ev + ) + + { + fadeTime = ev->GetFloat( 1 ); + } + +void Camera::OrbitEvent + ( + Event *ev + ) + + { + Entity *ent; + + spawnflags |= ORBIT; + ent = ev->GetEntity( 1 ); + if ( ent ) + { + Event * event; + + event = new Event( EV_Camera_StartMoving ); + event->AddEntity( ent ); + if ( ev->NumArgs() > 1 ) + { + event->AddEntity( ev->GetEntity( 2 ) ); + } + Stop(); + ProcessEvent( event ); + } + } + +void Camera::FollowEvent + ( + Event *ev + ) + + { + Entity *ent; + + spawnflags &= ~ORBIT; + ent = ev->GetEntity( 1 ); + if ( ent ) + { + Event * event; + + event = new Event( EV_Camera_StartMoving ); + event->AddEntity( ent ); + if ( ev->NumArgs() > 1 ) + { + event->AddEntity( ev->GetEntity( 2 ) ); + } + Stop(); + ProcessEvent( event ); + } + } + +void Camera::SetFOV + ( + Event *ev + ) + + { + float time; + + if ( ev->NumArgs() > 1 ) + { + time = ev->GetFloat( 2 ); + } + else + { + time = fadeTime; + } + + SetFOV( ev->GetFloat( 1 ), time ); + } + +void Camera::WatchEvent + ( + Event *ev + ) + + { + float time; + + if ( ev->NumArgs() > 1 ) + { + time = ev->GetFloat( 2 ); + } + else + { + time = fadeTime; + } + + Watch( ev->GetString( 1 ), time ); + } + +Entity * GetWatchEntity + ( + str watch + ) + + { + const char *name; + Entity * ent; + + // + // if empty just return + // + if ( watch == "" ) + { + return NULL; + } + + // + // ignore all the reserved words + // + if ( + ( watch == "path" ) || + ( watch == "none" ) || + ( watch == "node" ) + ) + { + return NULL; + } + + name = watch.c_str(); + + if ( name[ 0 ] == '*' ) + { + if ( !IsNumeric( &name[ 1 ] ) ) + { + gi.DPrintf( "GetWatchEntity :: Expecting a numeric value but found '%s'.", &name[ 1 ] ); + return NULL; + } + else + { + ent = G_GetEntity( atoi( &name[ 1 ] ) ); + if ( !ent ) + { + gi.DPrintf( "GetWatchEntity :: Entity with targetname of '%s' not found", &name[ 1 ] ); + return NULL; + } + } + } + else if ( name[ 0 ] == '$' ) + { + ent = G_FindTarget( NULL, &name[ 1 ] ); + if ( !ent ) + { + gi.DPrintf( "GetWatchEntity :: Entity with targetname of '%s' not found", &name[ 1 ] ); + return NULL; + } + } + else + { + gi.DPrintf( "GetWatchEntity :: Entity with targetname of '%s' not found", name ); + return NULL; + } + + return ent; + } + +void Camera::Watch + ( + str watch, + float time + ) + + { + // make sure we process any setup events before continuing + ProcessPendingEvents(); + + // + // if empty just return + // + if ( watch == "" ) + return; + + // + // clear out the watch variables + // + watchFadeTime = time; + newstate.watch.watchPath = false; + newstate.watch.watchNodes = false; + newstate.watch.watchEnt = NULL; + watchTime = level.time + watchFadeTime; + // + // really a watchpath command + // + if ( watch == "path" ) + { + newstate.watch.watchPath = true; + } + // + // really a watchnodes command + // + else if ( watch == "node" ) + { + newstate.watch.watchNodes = true; + } + // + // really a watchnodes command + // + else if ( watch == "none" ) + { + // intentionally blank + } + // + // just a normal watch command + // + else + { + Entity * ent = GetWatchEntity( watch ); + newstate.watch.watchEnt = ent; + } + } + +void Camera::Watch + ( + Entity * ent, + float time + ) + + { + // + // clear out the watch variables + // + watchFadeTime = time; + newstate.watch.watchPath = false; + newstate.watch.watchNodes = false; + watchTime = level.time + watchFadeTime; + newstate.watch.watchEnt = ent; + } + + +void Camera::SetFOV + ( + float fov, + float time + ) + + { + // if it is less than 3, then we are setting an auto_fov state + if ( fov < 3 ) + { + auto_fov = fov; + } + else + { + // if we are explicitly setting the fov, turn the auto_fov off + auto_fov = 0; + + fovFadeTime = time; + fovTime = level.time + fovFadeTime; + currentstate.fov = newstate.fov; + newstate.fov = fov; + } + } + +void Camera::WatchPathEvent + ( + Event *ev + ) + + { + if ( ev->NumArgs() > 1 ) + { + watchFadeTime = ev->GetFloat( 2 ); + } + else + { + watchFadeTime = fadeTime; + } + + watchTime = level.time + watchFadeTime; + newstate.watch.watchEnt = NULL; + newstate.watch.watchNodes = false; + newstate.watch.watchPath = true; + } + +void Camera::WatchNodesEvent + ( + Event *ev + ) + + { + if ( ev->NumArgs() > 1 ) + { + watchFadeTime = ev->GetFloat( 2 ); + } + else + { + watchFadeTime = fadeTime; + } + watchTime = level.time + watchFadeTime; + newstate.watch.watchEnt = NULL; + newstate.watch.watchPath = false; + newstate.watch.watchNodes = true; + } + +void Camera::NoWatchEvent + ( + Event *ev + ) + + { + if ( ev->NumArgs() > 1 ) + { + watchFadeTime = ev->GetFloat( 2 ); + } + else + { + watchFadeTime = fadeTime; + } + watchTime = level.time + watchFadeTime; + newstate.watch.watchEnt = NULL; + newstate.watch.watchPath = false; + newstate.watch.watchNodes = false; + } + +void SetCamera + ( + Entity *ent, + float switchTime + ) + + { + int j; + gentity_t *other; + Camera *cam; + Player *client; + + if ( ent && !ent->isSubclassOf( Camera ) ) + { + return; + } + + cam = ( Camera * )ent; + for( j = 0; j < game.maxclients; j++ ) + { + other = &g_entities[ j ]; + if ( other->inuse && other->client ) + { + client = ( Player * )other->entity; + client->SetCamera( cam, switchTime ); + } + } + } + +str &Camera::NextCamera + ( + void + ) + + { + return nextCamera; + } + +void Camera::SetThread + ( + Event *ev + ) + + { + thread = ev->GetString( 1 ); + } + +str &Camera::Thread + ( + void + ) + + { + return thread; + } + +float Camera::Fov + ( + void + ) + + { + return camera_fov; + } + +void Camera::Reset + ( + Vector org, + Vector ang + ) + + { + setOrigin( org ); + setAngles( ang ); + currentstate.Initialize( this ); + newstate.Initialize( this ); + } + +void Camera::bind + ( + Entity *master, + qboolean use_my_angles + ) + + { + Entity::bind( master, use_my_angles ); + + currentstate.move.pos = localorigin; + } + +void Camera::unbind + ( + void + ) + + { + Entity::unbind(); + + currentstate.move.pos = origin; + } + + +/****************************************************************************** + + Camera Manager + +******************************************************************************/ + +Event EV_CameraManager_NewPath + ( + "new", + EV_CONSOLE, + NULL, + NULL, + "Starts a new path." + ); +Event EV_CameraManager_SetPath + ( + "setpath", + EV_CONSOLE, + "e", + "path", + "Sets the new path." + ); +Event EV_CameraManager_SetTargetName + ( + "settargetname", + EV_CONSOLE, + "s", + "targetname", + "Set the targetname." + ); +Event EV_CameraManager_SetTarget + ( + "settarget", + EV_CONSOLE, + "s", + "target", + "Set the trigger target." + ); +Event EV_CameraManager_AddPoint + ( + "add", + EV_CONSOLE, + NULL, + NULL, + "Add a new point to the camera path where the player is standing." + ); +Event EV_CameraManager_DeletePoint + ( + "delete", + EV_CONSOLE, + NULL, + NULL, + "Delete the current path node." + ); +Event EV_CameraManager_MovePlayer + ( + "moveplayer", + EV_CONSOLE, + NULL, + NULL, + "Move the player to the current path node position." + ); +Event EV_CameraManager_ReplacePoint + ( + "replace", + EV_CONSOLE, + NULL, + NULL, + "Replace the current path node position/angle with the player's." + ); +Event EV_CameraManager_NextPoint + ( + "next", + EV_CONSOLE, + NULL, + NULL, + "Go to the next path node." + ); +Event EV_CameraManager_PreviousPoint + ( + "prev", + EV_CONSOLE, + NULL, + NULL, + "Go to the previous path node." + ); +Event EV_CameraManager_ShowPath + ( + "show", + EV_CONSOLE, + "E", + "path", + "Shows the specified path." + ); +Event EV_CameraManager_ShowingPath + ( + "_showing_path", + EV_CONSOLE, + NULL, + NULL, + "Internal event for showing the path." + ); +Event EV_CameraManager_HidePath + ( + "hide", + EV_CONSOLE, + NULL, + NULL, + "Hides the paths." + ); +Event EV_CameraManager_PlayPath + ( + "play", + EV_CONSOLE, + "E", + "path", + "Play the current path or the specified one once." + ); +Event EV_CameraManager_LoopPath + ( + "loop", + EV_CONSOLE, + "E", + "path", + "Loop the current path or the specified one." + ); +Event EV_CameraManager_StopPlayback + ( + "stop", + EV_CONSOLE, + NULL, + NULL, + "Stop the camera playing path." + ); +Event EV_CameraManager_Watch + ( + "watch", + EV_CONSOLE, + "s", + "watch", + "Set the current path node to watch something." + ); +Event EV_CameraManager_NoWatch + ( + "nowatch", + EV_CONSOLE, + NULL, + NULL, + "Set the current path node to watch nothing." + ); +Event EV_CameraManager_Fov + ( + "setfov", + EV_CONSOLE, + "s", + "newFOV", + "Set the fov at the current path node." + ); +Event EV_CameraManager_FadeTime + ( + "setfadetime", + EV_CONSOLE, + "f", + "newFadeTime", + "Set the fadetime of the current path node." + ); +Event EV_CameraManager_Speed + ( + "setspeed", + EV_CONSOLE, + "f", + "speed", + "Set the speed of the camera at the current path node." + ); +Event EV_CameraManager_Save + ( + "save", + EV_CONSOLE, + "s", + "filename", + "Saves the camera path." + ); +Event EV_CameraManager_Load + ( + "load", + EV_CONSOLE, + "s", + "filename", + "Loads a camera path." + ); +Event EV_CameraManager_SaveMap + ( + "savemap", + EV_CONSOLE, + "s", + "filename", + "Saves the camera path to a map file." + ); +Event EV_CameraManager_SetThread + ( + "setthread", + EV_CONSOLE, + "s", + "thread", + "Sets the thread for the current path node." + ); +Event EV_CameraManager_UpdateInput + ( + "updateinput", + EV_CONSOLE, + NULL, + NULL, + "Updates the current node with user interface values." + ); + +Event EV_CameraManager_NextPath + ( + "nextpath", + EV_CONSOLE, + NULL, + NULL, + "Go to the next path." + ); +Event EV_CameraManager_PreviousPath + ( + "prevpath", + EV_CONSOLE, + NULL, + NULL, + "Go to the previous path." + ); + +Event EV_CameraManager_RenamePath + ( + "renamepath", + EV_CONSOLE, + "s", + "newName", + "Rename the path to the new name." + ); + +CLASS_DECLARATION( Listener, CameraManager, NULL ) + { + { &EV_CameraManager_NewPath, NewPath }, + { &EV_CameraManager_SetPath, SetPath }, + { &EV_CameraManager_SetTargetName, SetTargetName }, + { &EV_CameraManager_SetTarget, SetTarget }, + { &EV_CameraManager_SetThread, SetThread }, + { &EV_CameraManager_SetPath, SetPath }, + { &EV_CameraManager_AddPoint, AddPoint }, + { &EV_CameraManager_ReplacePoint, ReplacePoint }, + { &EV_CameraManager_DeletePoint, DeletePoint }, + { &EV_CameraManager_MovePlayer, MovePlayer }, + { &EV_CameraManager_NextPoint, NextPoint }, + { &EV_CameraManager_PreviousPoint, PreviousPoint }, + { &EV_CameraManager_ShowPath, ShowPath }, + { &EV_CameraManager_ShowingPath, ShowingPath }, + { &EV_CameraManager_HidePath, HidePath }, + { &EV_CameraManager_PlayPath, PlayPath }, + { &EV_CameraManager_LoopPath, LoopPath }, + { &EV_CameraManager_StopPlayback, StopPlayback }, + { &EV_CameraManager_Watch, Watch }, + { &EV_CameraManager_NoWatch, NoWatch }, + { &EV_CameraManager_Fov, Fov }, + { &EV_CameraManager_FadeTime, FadeTime }, + { &EV_CameraManager_Speed, Speed }, + { &EV_CameraManager_Save, Save }, + { &EV_CameraManager_Load, Load }, + { &EV_CameraManager_SaveMap, SaveMap }, + { &EV_CameraManager_UpdateInput, UpdateEvent }, + { &EV_CameraManager_NextPath, NextPath }, + { &EV_CameraManager_PreviousPath, PreviousPath }, + { &EV_CameraManager_RenamePath, RenamePath }, + { NULL, NULL } + }; + +Player *CameraManager_GetPlayer + ( + void + ) + + { + assert( g_entities[ 0 ].entity && g_entities[ 0 ].entity->isSubclassOf( Player ) ); + if ( !g_entities[ 0 ].entity || !( g_entities[ 0 ].entity->isSubclassOf( Player ) ) ) + { + gi.Printf( "No player found.\n" ); + return NULL; + } + + return ( Player * )g_entities[ 0 ].entity; + } + +CameraManager::CameraManager() + { + pathList.ClearObjectList(); + path = NULL; + current = NULL; + cameraPath_dirty = qtrue; + speed = 1; + watch = 0; + cam = NULL; + } + +void CameraManager::UpdateUI + ( + void + ) + { + int num; + SplinePath *next; + float temp; + + // + // set path name + // + gi.cvar_set( "cam_filename", pathName ); + if ( current ) + { + + gi.cvar_set( "cam_origin", va( "%.2f %.2f %.2f", current->origin[ 0 ], current->origin[ 1 ], current->origin[ 2 ] ) ); + gi.cvar_set( "cam_angles_yaw", va( "%.1f", current->angles[ YAW ] ) ); + gi.cvar_set( "cam_angles_pitch", va( "%.1f", current->angles[ PITCH ] ) ); + gi.cvar_set( "cam_angles_roll", va( "%.1f", current->angles[ ROLL ] ) ); + gi.cvar_set( "cam_thread", current->thread.c_str() ); + gi.cvar_set( "cam_target", current->triggertarget.c_str() ); + gi.cvar_set( "cam_watch", current->watchEnt.c_str() ); + temp = current->GetFov(); + if ( temp ) + { + gi.cvar_set( "cam_fov", va( "%.1f", temp ) ); + } + else + { + gi.cvar_set( "cam_fov", "Default" ); + } + temp = current->GetFadeTime(); + if ( temp != -1 ) + { + gi.cvar_set( "cam_fadetime", va( "%.2f", temp ) ); + } + else + { + gi.cvar_set( "cam_fadetime", "Default" ); + } + gi.cvar_set( "cam_speed", va( "%.1f", current->speed ) ); + if ( EventPending( EV_CameraManager_ShowingPath ) ) + { + gi.cvar_set( "cam_hiddenstate", "visible" ); + } + else + { + gi.cvar_set( "cam_hiddenstate", "hidden" ); + } + + // + // set node num + // + num = 0; + next = path; + while ( next && ( next != current ) ) + { + next = next->GetNext(); + num++; + } + gi.cvar_set( "cam_nodenum", va( "%d", num ) ); + } + } + +void CameraManager::UpdateEvent + ( + Event *ev + ) + { + Vector tempvec; + cvar_t * cvar; + + if ( !current ) + { + return; + } + + // get origin + cvar = gi.cvar( "cam_origin", "", 0 ); + sscanf( cvar->string, "%f %f %f", &tempvec[ 0 ], &tempvec[ 1 ], &tempvec[ 2 ] ); + current->setOrigin( tempvec ); + + // get angles yaw + cvar = gi.cvar( "cam_angles_yaw", "", 0 ); + current->angles[ YAW ] = cvar->value; + + // get angles pitch + cvar = gi.cvar( "cam_angles_pitch", "", 0 ); + current->angles[ PITCH ] = cvar->value; + + // get angles roll + cvar = gi.cvar( "cam_angles_roll", "", 0 ); + current->angles[ ROLL ] = cvar->value; + + current->setAngles( current->angles ); + + // get thread + cvar = gi.cvar( "cam_thread", "", 0 ); + current->SetThread( cvar->string ); + + // get target + cvar = gi.cvar( "cam_target", "", 0 ); + current->SetTriggerTarget( cvar->string ); + + // get watch + cvar = gi.cvar( "cam_watch", "", 0 ); + current->SetWatch( cvar->string ); + + // get fov + cvar = gi.cvar( "cam_fov", "", 0 ); + current->SetFov( cvar->value ); + + // get fadetime + cvar = gi.cvar( "cam_fadetime", "", 0 ); + current->SetFadeTime( cvar->value ); + + // get speed + cvar = gi.cvar( "cam_speed", "", 0 ); + current->speed = cvar->value; + } + +void CameraManager::SetPathName + ( + str name + ) + + { + pathName = name; + UpdateUI(); + } + +void CameraManager::NewPath + ( + Event *ev + ) + + { + if ( path ) + { + cameraPath_dirty = qtrue; + path = NULL; + current = NULL; + } + SetPathName( "untitled" ); + ShowPath(); + } + +void CameraManager::RenamePath + ( + Event *ev + ) + + { + str name; + + if ( !ev->NumArgs() ) + { + cvar_t * cvar; + + // + // get the path name from the cvar + // + cvar = gi.cvar( "cam_filename", "", 0 ); + if ( cvar->string[ 0 ] ) + { + name = cvar->string; + } + else + { + ev->Error( "Usage: cam renamepath [pathname]" ); + return; + } + } + else + { + name = ev->GetString( 1 ); + } + + if ( pathList.ObjectInList( name ) ) + { + // remove the old name + pathList.RemoveObject( name ); + } + SetPathName( name ); + pathList.AddUniqueObject( name ); + } + +void CameraManager::SetPath + ( + str pathName + ) + + { + Entity * ent; + SplinePath *node; + + ent = G_FindTarget( NULL, pathName ); + + if ( !ent ) + { + warning( "SetPath", "Could not find path named '%s'.", pathName.c_str() ); + return; + } + + if ( !ent->isSubclassOf( SplinePath ) ) + { + warning( "SetPath", "'%s' is not a camera path.", pathName.c_str() ); + return; + } + node = ( SplinePath * )ent; + + SetPathName( pathName ); + cameraPath_dirty = qtrue; + path = node; + current = node; + UpdateUI(); + } + +void CameraManager::SetPath + ( + Event *ev + ) + + { + if ( !ev->NumArgs() ) + { + ev->Error( "Usage: cam setpath [pathname]" ); + return; + } + + SetPath( ev->GetString( 1 ) ); + } + +void CameraManager::SetTargetName + ( + Event *ev + ) + + { + if ( ev->NumArgs() != 1 ) + { + ev->Error( "Usage: cam targetname [name]" ); + return; + } + + if ( !path ) + { + ev->Error( "Camera path not set." ); + return; + } + + path->SetTargetName( ev->GetString( 1 ) ); + UpdateUI(); + } + +void CameraManager::SetTarget + ( + Event *ev + ) + + { + if ( ev->NumArgs() != 1 ) + { + ev->Error( "Usage: cam target [name]" ); + return; + } + + if ( !current ) + { + ev->Error( "Camera path not set." ); + return; + } + + current->SetTriggerTarget( ev->GetString( 1 ) ); + UpdateUI(); + } + +void CameraManager::SetThread + ( + Event *ev + ) + + { + if ( ev->NumArgs() != 1 ) + { + ev->Error( "Usage: cam thread [name]" ); + return; + } + + if ( !current ) + { + ev->Error( "Camera path not set." ); + return; + } + + current->SetThread( ev->GetString( 1 ) ); + UpdateUI(); + } + +void CameraManager::AddPoint + ( + Event *ev + ) + + { + Player *player; + SplinePath *prev; + SplinePath *next; + Vector ang; + Vector pos; + + player = CameraManager_GetPlayer(); + if ( player ) + { + prev = current; + if ( current ) + { + next = current->GetNext(); + } + else + { + next = NULL; + } + + player->GetPlayerView( &pos, &ang ); + + current = new SplinePath; + current->setOrigin( pos ); + current->setAngles( ang ); + current->speed = speed; + current->SetPrev( prev ); + current->SetNext( next ); + + if ( !path ) + { + path = current; + } + + ShowPath(); + } + cameraPath_dirty = qtrue; + UpdateUI(); + } + +void CameraManager::ReplacePoint + ( + Event *ev + ) + + { + Player *player; + Vector ang; + Vector pos; + + player = CameraManager_GetPlayer(); + if ( current && player ) + { + player->GetPlayerView( &pos, &ang ); + + current->setOrigin( pos ); + current->setAngles( ang ); + current->speed = speed; + } + cameraPath_dirty = qtrue; + UpdateUI(); + } + +void CameraManager::DeletePoint + ( + Event *ev + ) + + { + SplinePath *node; + + if ( current ) + { + node = current->GetNext(); + if ( !node ) + { + node = current->GetPrev(); + } + + if ( ( SplinePath * )path == ( SplinePath * )current ) + { + path = current->GetNext(); + } + + delete current; + current = node; + } + cameraPath_dirty = qtrue; + UpdateUI(); + } + +void CameraManager::MovePlayer + ( + Event *ev + ) + + { + Player *player; + Vector pos; + + player = CameraManager_GetPlayer(); + if ( current && player ) + { + player->GetPlayerView( &pos, NULL ); + + player->setOrigin( current->origin - pos + player->origin ); + player->SetViewAngles( current->angles ); + player->SetFov( current->fov ); + } + } + +void CameraManager::NextPoint + ( + Event *ev + ) + + { + SplinePath *next; + + if ( current ) + { + next = current->GetNext(); + if ( next ) + { + current = next; + } + } + UpdateUI(); + } + +void CameraManager::PreviousPoint + ( + Event *ev + ) + + { + SplinePath *prev; + + if ( current ) + { + prev = current->GetPrev(); + if ( prev ) + { + current = prev; + } + } + UpdateUI(); + } + +void CameraManager::NextPath + ( + Event *ev + ) + + { + int index; + + // + // find current path in container of paths + // + index = pathList.IndexOfObject( pathName ); + if ( index < pathList.NumObjects() ) + index++; + + if ( index > 0 ) + { + SetPath( pathList.ObjectAt( index ) ); + UpdateUI(); + } + } + +void CameraManager::PreviousPath + ( + Event *ev + ) + + { + int index; + + // + // find current path in container of paths + // + index = pathList.IndexOfObject( pathName ); + if ( index > 1 ) + index--; + + if ( index > 0 ) + { + SetPath( pathList.ObjectAt( index ) ); + UpdateUI(); + } + } + +void CameraManager::ShowingPath + ( + Event *ev + ) + + { + int count; + SplinePath *node; + SplinePath *prev; + Vector mins( -8, -8, -8 ); + Vector maxs( 8, 8, 8 ); + + prev = NULL; + for( node = path; node != NULL; node = node->GetNext() ) + { + if ( prev ) + { + G_LineStipple( 4, ( unsigned short )( 0xF0F0F0F0 >> ( 7 - ( level.framenum & 7 ) ) ) ); + G_DebugLine( prev->origin, node->origin, 0.4, 0.4, 0.4, 0.1 ); + G_LineStipple( 1, 0xffff ); + } + + if ( current == node ) + { + G_DrawDebugNumber( node->origin + Vector( 0, 0, 20 ), node->speed, 0.5, 0, 1, 0, 1 ); + if ( current->GetFov() ) + G_DrawDebugNumber( node->origin + Vector( 0, 0, 30 ), node->GetFov(), 0.5, 0, 0, 1, 0 ); + G_DebugBBox( node->origin, mins, maxs, 1, 1, 0, 1 ); + } + else + { + G_DebugBBox( node->origin, mins, maxs, 1, 0, 0, 1 ); + } + + // + // draw watch + // + if ( node->doWatch ) + { + Entity *watchEnt; + Vector ang; + Vector delta; + Vector left; + Vector up; + Vector endpoint; + + watchEnt = GetWatchEntity( node->GetWatch() ); + if ( watchEnt ) + { + delta.x = watchEnt->origin.x; + delta.y = watchEnt->origin.y; + delta.z = watchEnt->absmax.z; + delta -= node->origin; + delta.normalize(); + ang = delta.toAngles(); + ang.AngleVectors( NULL, &left, &up ); + + G_LineWidth( 1 ); + endpoint = node->origin + delta * 48; + G_DebugLine( node->origin, endpoint, 0.5, 1, 1, 1 ); + G_DebugLine( endpoint, endpoint + (left * 8) - (delta * 8), 0.5, 1, 1, 1 ); + G_DebugLine( endpoint, endpoint - (left * 8) - (delta * 8), 0.5, 1, 1, 1 ); + G_DebugLine( endpoint, endpoint - (up * 8) - (delta * 8), 0.5, 1, 1, 1 ); + G_DebugLine( endpoint, endpoint + (up * 8) - (delta * 8), 0.5, 1, 1, 1 ); + } + } + + G_LineWidth( 3 ); + G_DebugLine( node->origin, node->origin + Vector( node->orientation[ 0 ] ) * 16, 1, 0, 0, 1 ); + G_DebugLine( node->origin, node->origin + Vector( node->orientation[ 1 ] ) * 16, 0, 1, 0, 1 ); + G_DebugLine( node->origin, node->origin + Vector( node->orientation[ 2 ] ) * 16, 0, 0, 1, 1 ); + G_LineWidth( 1 ); + + prev = node; + } + + if ( cameraPath_dirty ) + { + cameraPath_dirty = qfalse; + cameraPath.Clear(); + cameraPath.SetType( SPLINE_CLAMP ); + + node = path; + while( node != NULL ) + { + cameraPath.AppendControlPoint( node->origin, node->angles, node->speed ); + node = node->GetNext(); + + if ( node == path ) + { + break; + } + } + } + + // draw the curve itself + G_Color3f( 1, 1, 0 ); + cameraPath.DrawCurve( 10 ); + + // draw all the nodes + for( node = path, count = -1; node != NULL; node = node->GetNext(), count++ ) + { + Vector dir, angles; + + dir = cameraPath.Eval( ( float )count - 0.9f ) - cameraPath.Eval( count - 1 ); + angles = dir.toAngles(); + if ( node->doWatch || node->GetFov() || ( node->thread != "" ) || ( node->triggertarget != "" ) ) + { + G_DebugOrientedCircle( cameraPath.Eval( count - 1 ), 5, 0, 1, 1, 1, angles ); + } + else + { + G_DebugOrientedCircle( cameraPath.Eval( count - 1 ), 2, 0, 0, 1, 0.2, angles ); + } + // if we are the first node, we need to skip the count so that we properly go to the next node + if ( count == -1 ) + { + count = 0; + } + } + + + PostEvent( EV_CameraManager_ShowingPath, FRAMETIME ); + } + +void CameraManager::ShowPath + ( + void + ) + + { + CancelEventsOfType( EV_CameraManager_ShowingPath ); + PostEvent( EV_CameraManager_ShowingPath, FRAMETIME ); + UpdateUI(); + } + +void CameraManager::ShowPath + ( + Event *ev + ) + + { + if ( ev->NumArgs() ) + { + SetPath( ev->GetString( 1 ) ); + } + ShowPath(); + } + +void CameraManager::HidePath + ( + Event *ev + ) + + { + CancelEventsOfType( EV_CameraManager_ShowingPath ); + UpdateUI(); + } + +void CameraManager::StopPlayback + ( + Event *ev + ) + + { + if ( cam ) + { + cam->Stop(); + SetCamera( NULL, 0 ); + } + } + +void CameraManager::PlayPath + ( + Event *ev + ) + + { + if ( cam ) + { + SetCamera( NULL, 0 ); + } + + if ( ev->NumArgs() ) + { + SetPath( ev->GetString( 1 ) ); + } + + if ( path ) + { + if ( !cam ) + { + cam = new Camera; + cam->SetTargetName( "_loadedcamera" ); + cam->ProcessPendingEvents(); + } + + cam->Reset( path->origin, path->angles ); + cam->FollowPath( path, false, NULL ); + cam->Cut( NULL ); + SetCamera( cam, 0 ); + } + } + +void CameraManager::LoopPath + ( + Event *ev + ) + + { + if ( cam ) + { + SetCamera( NULL, 0 ); + } + + if ( ev->NumArgs() ) + { + SetPath( ev->GetString( 1 ) ); + } + + if ( path ) + { + if ( !cam ) + { + cam = new Camera; + cam->SetTargetName( "_loadedcamera" ); + cam->ProcessPendingEvents(); + } + + cam->Reset( path->origin, path->angles ); + cam->FollowPath( path, true, NULL ); + cam->Cut( NULL ); + SetCamera( cam, 0 ); + } + } + +void CameraManager::Watch + ( + Event *ev + ) + + { + if ( current ) + { + current->SetWatch( ev->GetString( 1 ) ); + } + UpdateUI(); + } + +void CameraManager::NoWatch + ( + Event *ev + ) + + { + if ( current ) + { + current->NoWatch(); + } + UpdateUI(); + } + +void CameraManager::Fov + ( + Event *ev + ) + + { + if ( current ) + { + current->SetFov( ev->GetFloat( 1 ) ); + } + UpdateUI(); + } + +void CameraManager::FadeTime + ( + Event *ev + ) + + { + if ( current ) + { + current->SetFadeTime( ev->GetFloat( 1 ) ); + } + UpdateUI(); + } + + +void CameraManager::Speed + ( + Event *ev + ) + + { + speed = ev->GetFloat( 1 ); + if ( current ) + { + current->speed = speed; + } + cameraPath_dirty = qtrue; + UpdateUI(); + } + +void CameraManager::SavePath + ( + str pathName + ) + { + SplinePath *node; + str buf; + str filename; + int num; + int index; + + num = 0; + for( node = path; node != NULL; node = node->GetNext() ) + { + num++; + } + + if ( num == 0 ) + { + warning( "CameraManager::SavePath", "Can't save. No points in path." ); + return; + } + + filename = "cams/"; + filename += pathName; + filename += ".cam"; + + path->SetTargetName( pathName ); + + gi.Printf( "Saving camera path to '%s'...\n", filename.c_str() ); + + buf = ""; + buf += va( "//\n" ); + buf += va( "// Camera Path \"%s\", %d Nodes.\n", pathName.c_str(), num ); + buf += va( "//\n" ); + + index = 0; + for( node = path; node != NULL; node = node->GetNext() ) + { + // + // start off the spawn command + // + buf += "spawn SplinePath"; + // + // set the targetname + // + if ( !index ) + { + buf += va( " targetname %s", pathName.c_str() ); + } + else + { + buf += va( " targetname camnode_%s_%d", pathName.c_str(), index ); + } + // + // set the target + // + if ( index < ( num - 1 ) ) + { + buf += va( " target camnode_%s_%d", pathName.c_str(), index + 1 ); + } + // + // set the trigger target + // + if ( node->triggertarget != "" ) + { + buf += va( " triggertarget %s", node->triggertarget.c_str() ); + } + // + // set the thread + // + if ( node->thread != "" ) + { + buf += va( " thread %s", node->thread.c_str() ); + } + // + // set the origin + // + buf += va( " origin \"%.2f %.2f %.2f\"", node->origin.x, node->origin.y, node->origin.z ); + // + // set the angles + // + buf += va( " angles \"%.1f %.1f %.1f\"", AngleMod( node->angles.x ), AngleMod( node->angles.y ), AngleMod( node->angles.z ) ); + // + // set the speed + // + buf += va( " speed %.1f", node->speed ); + // + // set the watch + // + if ( node->doWatch && node->watchEnt != "" ) + { + buf += va( " watch %s", node->watchEnt.c_str() ); + } + // + // set the fov + // + if ( node->GetFov() ) + { + buf += va( " fov %.1f", node->GetFov() ); + } + // + // set the fadetime + // + if ( node->GetFadeTime() ) + { + buf += va( " fadetime %.1f", node->GetFadeTime() ); + } + + buf += "\n"; + index++; + } + buf += "end\n"; + + gi.FS_WriteFile( filename.c_str(), buf.c_str(), buf.length() + 1 ); + gi.Printf( "done.\n" ); + } + +void CameraManager::Save + ( + Event *ev + ) + + { + str filename; + str name; + + if ( ev->NumArgs() != 1 ) + { + cvar_t * cvar; + + // + // get the path name from the cvar + // + cvar = gi.cvar( "cam_filename", "", 0 ); + if ( cvar->string[ 0 ] ) + { + name = cvar->string; + } + else + { + ev->Error( "Usage: cam save [filename]" ); + return; + } + } + else + { + name = ev->GetString( 1 ); + } + SavePath( name ); + pathList.AddUniqueObject( name ); + } + +void CameraManager::Load + ( + Event *ev + ) + + { + ScriptThread * thread; + qboolean show; + str filename; + str name; + + if ( ev->NumArgs() != 1 ) + { + cvar_t * cvar; + + // + // get the path name from the cvar + // + cvar = gi.cvar( "cam_filename", "", 0 ); + if ( cvar->string[ 0 ] ) + { + show = true; + name = cvar->string; + } + else + { + ev->Error( "Usage: cam load [filename]" ); + return; + } + } + else + { + show = false; + name = ev->GetString( 1 ); + } + + if ( pathList.ObjectInList( name ) && show ) + { + gi.Printf( "Camera path '%s' already loaded...\n", name.c_str() ); + return; + } + + filename = "cams/"; + filename += name; + filename += ".cam"; + + gi.Printf( "Loading camera path from '%s'...", filename.c_str() ); + + thread = Director.CreateThread( filename, LEVEL_SCRIPT, NULL ); + if ( thread ) + { + // start right away + thread->StartImmediately(); + pathList.AddUniqueObject( name ); + if ( show ) + { + Event * ev; + + ev = new Event( EV_CameraManager_SetPath ); + ev->AddString( name ); + PostEvent( ev, 0 ); + ShowPath(); + } + gi.Printf( "done.\n" ); + } + else + { + gi.Printf( "failed.\n" ); + } + } + + +void CameraManager::SaveMap + ( + Event *ev + ) + + { + SplinePath *node; + str buf; + str filename; + int num; + int index; + + if ( ev->NumArgs() != 1 ) + { + ev->Error( "Usage: cam savemap [filename]" ); + return; + } + + num = 0; + for( node = path; node != NULL; node = node->GetNext() ) + { + num++; + } + + if ( num == 0 ) + { + ev->Error( "Can't save. No points in path." ); + return; + } + + filename = "cams/"; + filename += ev->GetString( 1 ); + filename += ".map"; + + if ( !path->targetname.length() ) + { + path->SetTargetName( ev->GetString( 1 ) ); + gi.Printf( "Targetname set to '%s'\n", path->targetname.c_str() ); + } + + gi.Printf( "Saving camera path to map '%s'...\n", filename.c_str() ); + + buf = ""; + index = 0; + for( node = path; node != NULL; node = node->GetNext() ) + { + buf += va( "// pathnode %d\n", index ); + buf += "{\n"; + buf += va( "\"classname\" \"info_splinepath\"\n" ); + if ( index < ( num - 1 ) ) + { + buf += va( "\"target\" \"camnode_%s_%d\"\n", ev->GetString( 1 ), index + 1 ); + } + if ( !index ) + { + buf += va( "\"targetname\" \"%s\"\n", ev->GetString( 1 ) ); + } + else + { + buf += va( "\"targetname\" \"camnode_%s_%d\"\n", ev->GetString( 1 ), index ); + } + if ( node->triggertarget != "" ) + { + buf += va( "\"triggertarget\" \"%s\"\n", node->triggertarget.c_str() ); + } + if ( node->thread != "" ) + { + buf += va( "\"thread\" \"%s\"\n", node->thread.c_str() ); + } + buf += va( "\"origin\" \"%d %d %d\"\n", ( int )node->origin.x, ( int )node->origin.y, ( int )node->origin.z ); + buf += va( "\"angles\" \"%d %d %d\"\n", ( int )AngleMod( node->angles.x ), ( int )AngleMod( node->angles.y ), ( int )AngleMod( node->angles.z ) ); + buf += va( "\"speed\" \"%.3f\"\n", node->speed ); + buf += "}\n"; + index++; + } + + gi.FS_WriteFile( filename.c_str(), buf.c_str(), buf.length() + 1 ); + gi.Printf( "done.\n" ); + } + diff --git a/source/source/fgame/camera.h b/source/source/fgame/camera.h new file mode 100644 index 0000000..fa04d9e --- /dev/null +++ b/source/source/fgame/camera.h @@ -0,0 +1,520 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/camera.h $ +// $Revision:: 21 $ +// $Author:: Aldie $ +// $Date:: 7/25/00 11:32p $ +// +// Copyright (C) 1997 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source is may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/camera.h $ +// +// 21 7/25/00 11:32p Aldie +// Made some changes to the memory system and fixed a memory allocation bug in +// Z_TagMalloc. Also changed a lot of classes to subclass from Class. +// +// 20 7/10/00 11:54p Markd +// added exit level code +// +// 19 7/10/00 8:35p Markd +// added camera tracing to orbit +// +// 18 7/04/00 2:25p Markd +// added cool cinematic for new objects +// +// 17 6/28/00 12:23p Markd +// Added auto_active to cameras +// +// 16 6/09/00 6:55p Markd +// fixed camera being bound to other objects +// +// 15 5/26/00 7:44p Markd +// 2nd phase save games +// +// 14 5/25/00 7:52p Markd +// 2nd pass save game stuff +// +// 13 5/24/00 3:14p Markd +// first phase of save/load games +// +// 12 4/19/00 2:38p Markd +// Added auto_fov support to cameras +// +// 11 4/19/00 12:54p Markd +// put in auto_starttime and auto_stoptime support into auto cameras +// +// 10 4/11/00 2:46p Markd +// Implemented Automatic camera support +// +// 9 3/16/00 11:45a Markd +// fixed a camera iniatialization bug +// +// 8 3/15/00 2:04p Markd +// fixed up camera node system and added new debug oriented circle +// +// 7 2/03/00 3:12p Markd +// Fixed up fadetimes for watches and fov and follow +// +// 6 11/09/99 8:07p Markd +// Did a lot of work on the camera system +// +// 5 11/05/99 5:55p Markd +// Added user-interface to camera system +// +// 4 11/04/99 10:03a Markd +// complete overhaul of the camera system +// +// 3 10/29/99 7:04p Markd +// cleaned up some camera stuff +// +// 2 10/27/99 12:19p Markd +// added smooth camera lerping +// +// 1 9/10/99 10:53a Jimdose +// +// 1 9/08/99 3:15p Aldie +// +// 10 9/01/99 6:16p Jimdose +// added SetThread +// +// 9 7/06/99 8:33p Jimdose +// removed unused player code +// added state machine for player animation +// +// DESCRIPTION: +// Camera. Duh. +// + +#ifndef __CAMERA_H__ +#define __CAMERA_H__ + +#include "g_local.h" +#include "entity.h" +#include "bspline.h" +#include "container.h" + +#define CAMERA_SWITCHTIME 0.5f + +#define ORBIT ( 1 << 0 ) +#define START_ON ( 1 << 1 ) +#define AUTOMATIC ( 1 << 2 ) +#define NO_TRACE ( 1 << 3 ) +#define NO_WATCH ( 1 << 4 ) +#define LEVEL_EXIT ( 1 << 5 ) + + +extern Event EV_Camera_CameraThink; +extern Event EV_Camera_StartMoving; +extern Event EV_Camera_Pause; +extern Event EV_Camera_Continue; +extern Event EV_Camera_StopMoving; +extern Event EV_Camera_SetSpeed; +extern Event EV_Camera_SetFollowDistance; +extern Event EV_Camera_SetOrbitHeight; +extern Event EV_Camera_SetYaw; +extern Event EV_Camera_AbsoluteYaw; +extern Event EV_Camera_RelativeYaw; +extern Event EV_Camera_SetFOV; +extern Event EV_Camera_Orbit; +extern Event EV_Camera_Follow; +extern Event EV_Camera_Watch; +extern Event EV_Camera_WatchPath; +extern Event EV_Camera_LookAt; +extern Event EV_Camera_TurnTo; +extern Event EV_Camera_MoveToEntity; +extern Event EV_Camera_MoveToPos; +extern Event EV_Camera_NoWatch; +extern Event EV_Camera_FadeTime; +extern Event EV_Camera_Cut; + +class Camera; + +class CameraMoveState : public Class + { + public: + Vector pos; + Vector movedir; // direction of travel + Vector angles; // angles from spline camera + + BSpline cameraPath; + SplinePathPtr splinePath; + SplinePathPtr currentNode; + SplinePathPtr loopNode; + + float cameraTime; + int lastTime; + int newTime; + + qboolean followingpath; + EntityPtr followEnt; + EntityPtr orbitEnt; + + void operator=( CameraMoveState &newstate ); + void Evaluate( Camera * camera ); + void Initialize( Camera * camera ); + void DoNodeEvents( Camera * camera ); + virtual void Archive( Archiver &arc ); + }; + +inline void CameraMoveState::operator= + ( + CameraMoveState &newstate + ) + + { + movedir = newstate.movedir; + pos = newstate.pos; + angles = newstate.angles; + + cameraPath = newstate.cameraPath; + splinePath = newstate.splinePath; + currentNode = newstate.currentNode; + loopNode = newstate.loopNode; + + cameraTime = newstate.cameraTime; + lastTime = newstate.lastTime; + newTime = newstate.newTime; + + followEnt = newstate.followEnt; + orbitEnt = newstate.orbitEnt; + + followingpath = newstate.followingpath; + } + +inline void CameraMoveState::Archive + ( + Archiver &arc + ) + { + arc.ArchiveVector( &movedir ); + arc.ArchiveVector( &pos ); + arc.ArchiveVector( &angles ); + + cameraPath.Archive( arc ); + + arc.ArchiveSafePointer( &splinePath ); + arc.ArchiveSafePointer( ¤tNode ); + arc.ArchiveSafePointer( &loopNode ); + + arc.ArchiveFloat( &cameraTime ); + arc.ArchiveInteger( &lastTime ); + arc.ArchiveInteger( &newTime ); + + arc.ArchiveSafePointer( &followEnt ); + arc.ArchiveSafePointer( &orbitEnt ); + + arc.ArchiveBoolean( &followingpath ); + } + +class CameraWatchState : public Class + { + public: + Vector watchAngles; + + EntityPtr watchEnt; + qboolean watchNodes; + qboolean watchPath; + + void Evaluate( Camera * camera, CameraMoveState * move ); + void Initialize( Camera * camera ); + virtual void Archive( Archiver &arc ); + }; + +inline void CameraWatchState::Archive + ( + Archiver &arc + ) + { + arc.ArchiveVector( &watchAngles ); + arc.ArchiveSafePointer( &watchEnt ); + arc.ArchiveBoolean( &watchNodes ); + arc.ArchiveBoolean( &watchPath ); + } + +class CameraState : public Class + { + public: + CameraMoveState move; + CameraWatchState watch; + float fov; + + void Evaluate( Camera * camera ); + void Initialize( Camera * camera ); + virtual void Archive( Archiver &arc ); + }; + +inline void CameraState::Archive + ( + Archiver &arc + ) + { + move.Archive( arc ); + watch.Archive( arc ); + arc.ArchiveFloat( &fov ); + } + +class Camera : public Entity + { + private: + friend class CameraState; + friend class CameraWatchState; + friend class CameraMoveState; + // + // follow parameters + // + float follow_yaw; + qboolean follow_yaw_fixed; + float follow_dist; + int follow_mask; + + // camera speed + float camera_speed; + // current camera fov + float camera_fov; + // orbit height + float orbit_height; + // orbit_dotrace + qboolean orbit_dotrace; + // whether or not auto calculate fov, a non-zero value means yes + float auto_fov; + + // automatic variables + float automatic_startTime; + float automatic_stopTime; + float automatic_radius; + float automatic_maxFOV; + qboolean automatic_active; + Container automatic_states; + + protected: + CameraState currentstate; + CameraState newstate; + + float watchTime; // if non-zero, camera view is transitioning + float followTime; // if non-zero, camera position is tranisitioning + float fovTime; // if non-zero, fov is being lerped + + float fadeTime; // time to transition over + float fovFadeTime; // time for fov transition + float followFadeTime; // time for fov transition + float watchFadeTime; // time for fov transition + + str nextCamera; + str thread; + + qboolean showcamera; + + void SetupCamera( Event *ev ); + void CameraThink( Event *ev ); + void CreateOrbit( Vector pos, float radius, Vector &forward, Vector &left ); + void CreatePath( SplinePath *path, splinetype_t type ); + void UpdateStates( void ); + Vector CalculatePosition( void ); + Vector CalculateOrientation( void ); + float CalculateFov( void ); + virtual void bind( Entity *master, qboolean use_my_angles = false ); + virtual void unbind( void ); + + public: + CLASS_PROTOTYPE( Camera ); + + Camera(); + void Stop( void ); + void FollowPath( SplinePath *path, qboolean loop, Entity *watch ); + void Orbit( Entity *ent, float dist, Entity *watch, float yaw_offset = 0, qboolean dotrace = qtrue ); + void FollowEntity( Entity *ent, float dist, int mask, Entity *watch = NULL ); + void Watch( str watch, float time ); + void Watch( Entity *ent, float time ); + void SetFOV( float fov, float time ); + + void StartMoving( Event *ev ); + void StopMoving( Event *ev ); + void Pause( Event *ev ); + void Continue( Event *ev ); + void SetAnglesEvent( Event *ev ); + void SetSpeed( Event *ev ); + void SetFollowDistance( Event *ev ); + void SetOrbitHeight( float height ); + void SetOrbitHeight( Event *ev ); + void SetFollowYaw( Event *ev ); + void AbsoluteYaw( Event *ev ); + void RelativeYaw( Event *ev ); + void SetFOV( Event *ev ); + void OrbitEvent( Event *ev ); + void FollowEvent( Event *ev ); + void WatchEvent( Event *ev ); + void WatchPathEvent( Event *ev ); + void WatchNodesEvent( Event *ev ); + void NoWatchEvent( Event *ev ); + void LookAt( Event *ev ); + void MoveToEntity( Event *ev ); + void MoveToPos( Event *ev ); + void Cut( Event *ev ); + void FadeTime( Event *ev ); + void TurnTo( Event *ev ); + void SetNextCamera( Event *ev ); + void SetThread( Event *ev ); + float CalculateScore( Entity * player, str state ); + float AutomaticStart( Entity * player ); + float AutomaticStop( Entity * player ); + qboolean IsAutomatic( void ); + qboolean IsLevelExit( void ); + void SetAutoStateEvent( Event * ev ); + void SetAutoRadiusEvent( Event * ev ); + void SetAutoStartTimeEvent( Event * ev ); + void SetAutoStopTimeEvent( Event * ev ); + void SetMaximumAutoFOVEvent( Event * ev ); + void SetAutoActiveEvent( Event * ev ); + + str &NextCamera( void ); + str &Thread( void ); + float Fov( void ); + + void Reset( Vector org, Vector ang ); + + virtual void Archive( Archiver &arc ); + }; + +inline void Camera::Archive + ( + Archiver &arc + ) + { + Entity::Archive( arc ); + + arc.ArchiveFloat( &follow_yaw ); + arc.ArchiveBoolean( &follow_yaw_fixed ); + arc.ArchiveFloat( &follow_dist ); + arc.ArchiveInteger( &follow_mask ); + + arc.ArchiveFloat( &camera_speed ); + arc.ArchiveFloat( &camera_fov ); + arc.ArchiveFloat( &orbit_height ); + arc.ArchiveBoolean( &orbit_dotrace ); + arc.ArchiveFloat( &auto_fov ); + + arc.ArchiveFloat( &automatic_startTime ); + arc.ArchiveFloat( &automatic_stopTime ); + arc.ArchiveFloat( &automatic_radius ); + arc.ArchiveFloat( &automatic_maxFOV ); + arc.ArchiveBoolean( &automatic_active ); + + automatic_states.Archive( arc ); + + // currentstate + currentstate.Archive( arc ); + // newstate + newstate.Archive( arc ); + + arc.ArchiveFloat( &watchTime ); + arc.ArchiveFloat( &followTime ); + arc.ArchiveFloat( &fovTime ); + arc.ArchiveFloat( &fadeTime ); + arc.ArchiveFloat( &fovFadeTime ); + arc.ArchiveFloat( &followFadeTime ); + arc.ArchiveFloat( &watchFadeTime ); + + arc.ArchiveString( &nextCamera ); + arc.ArchiveString( &thread ); + + arc.ArchiveBoolean( &showcamera ); + + if ( arc.Loading() ) + { + if ( spawnflags & AUTOMATIC ) + { + level.AddAutomaticCamera( this ); + } + } + } + +void SetCamera( Entity *ent, float switchTime ); +Entity * GetWatchEntity( str watch ); + +typedef SafePtr CameraPtr; + +class CameraManager : public Listener + { + protected: + Container pathList; + BSpline cameraPath; + SplinePathPtr path; + SplinePathPtr current; + float speed; + int watch; + str pathName; + CameraPtr cam; + qboolean cameraPath_dirty; + + void NewPath( Event *ev ); + void SetPath( Event *ev ); + void SetTargetName( Event *ev ); + void SetTarget( Event *ev ); + void SetThread( Event *ev ); + void AddPoint( Event *ev ); + void ReplacePoint( Event *ev ); + void DeletePoint( Event *ev ); + void MovePlayer( Event *ev ); + void NextPoint( Event *ev ); + void PreviousPoint( Event *ev ); + void ShowingPath( Event *ev ); + void ShowPath( Event *ev ); + void HidePath( Event *ev ); + void StopPlayback( Event *ev ); + void PlayPath( Event *ev ); + void LoopPath( Event *ev ); + void Watch( Event *ev ); + void NoWatch( Event *ev ); + void Fov( Event *ev ); + void FadeTime( Event *ev ); + void Speed( Event *ev ); + void Save( Event *ev ); + void Load( Event *ev ); + void SaveMap( Event *ev ); + void UpdateEvent( Event *ev ); + void NextPath( Event *ev ); + void PreviousPath( Event *ev ); + void RenamePath( Event *ev ); + + void ShowPath( void ); + void UpdateUI( void ); + void SetPathName( str name ); + void SavePath( str pathName ); + + public: + CLASS_PROTOTYPE( CameraManager ); + + CameraManager(); + void SetPath( str pathName ); + virtual void Archive( Archiver &arc ); + }; + +inline void CameraManager::Archive + ( + Archiver &arc + ) + + { + Listener::Archive( arc ); + + pathList.Archive( arc ); + + // no need to archive the cameraPath + arc.ArchiveSafePointer( &path ); + arc.ArchiveSafePointer( ¤t ); + arc.ArchiveFloat( &speed ); + arc.ArchiveInteger( &watch ); + arc.ArchiveString( &pathName ); + arc.ArchiveSafePointer( &cam ); + + // make sure the cameraPath gets rebuilt + cameraPath_dirty = qtrue; + } + +extern CameraManager CameraMan; + +#endif /* camera.h */ diff --git a/source/source/fgame/characterstate.cpp b/source/source/fgame/characterstate.cpp new file mode 100644 index 0000000..621699a --- /dev/null +++ b/source/source/fgame/characterstate.cpp @@ -0,0 +1,1324 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/characterstate.cpp $ +// $Revision:: 34 $ +// $Date:: 7/25/00 11:32p $ +// +// Copyright (C) 1999 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source is may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/characterstate.cpp $ +// +// 34 7/25/00 11:32p Aldie +// Made some changes to the memory system and fixed a memory allocation bug in +// Z_TagMalloc. Also changed a lot of classes to subclass from Class. +// +// 33 7/21/00 1:14a Markd +// fixed fakeplayer again +// +// 32 7/13/00 9:18p Markd +// added behind_nopitch camera type +// +// 31 7/05/00 3:22p Markd +// Added movecontrol_gotcoolobject +// +// 30 6/28/00 3:56p Markd +// added additional camera views +// +// 29 6/28/00 3:12p Steven +// Added CacheStatemap. +// +// 28 6/17/00 3:48p Aldie +// +// 27 6/14/00 3:50p Markd +// Cleaned up more Intel Compiler warnings +// +// 26 6/10/00 1:50p Steven +// Added statemap caching. +// +// 25 6/08/00 9:54a Markd +// added camera behind_fixed +// +// 24 6/04/00 6:52p Markd +// Added camera support to TouchAnim's cleaned up player camera interface +// +// 23 4/29/00 11:28a Markd +// removed old rope code, cleaned up rope interface +// +// 22 4/08/00 3:55p Steven +// Made it so any parameter that has spaces in it addes quotes around the token +// in readCommands. +// +// 21 4/07/00 2:05p Markd +// added MOVETYPE_PIPEHANG +// +// 20 4/07/00 1:53p Aldie +// Fix for process commands on state changes +// +// 19 3/31/00 3:18p Markd +// Added Movetype USEOBJECT +// +// 18 2/25/00 7:27p Markd +// Added useanim_numloop support and fixed useanim_orientation +// +// 17 2/24/00 4:16p Jimdose +// added MOVECONTROL_CROUCH +// +// 16 2/24/00 3:25p Jimdose +// made parsing of cameratype and movetype to be table based +// added check for valid class when parsing behavior. +// +// 15 2/22/00 4:55p Steven +// A small fix to make sure entry and exit commands can take the parameter "" +// and process it correctly. +// +// 14 2/22/00 1:56p Jimdose +// added MOVECONTROL_PUSH +// +// 13 2/17/00 12:00p Aldie +// Added command processing to state system with the addition of entrycommands +// and exitcommands. +// +// 12 2/14/00 5:44p Jimdose +// added MOVECONTROL_LEGS +// changed calls to Q_stricmp to Str::icmp +// +// 11 2/09/00 3:53p Steven +// Made it so the CHANCE conditional doesn't get merged with others. +// +// 10 2/08/00 11:34a Steven +// Added picking up of Shgliek. +// +// 9 2/08/00 12:17a Jimdose +// made rope grabbing controlled by state system +// +// 8 1/28/00 6:21p Jimdose +// added rope movecontrol types +// +// 7 1/22/00 4:05p Jimdose +// added MOVECONTROL_PIPECRAWL and MOVECONTROL_STEPUP +// +// 6 1/17/00 10:20p Jimdose +// Rewrote state system initialization. Made conditionals defined with array. +// Made Evaluate functions early exit +// +// 5 12/14/18 2:43p Jimdose +// added monkeybar movetype +// +// 4 12/10/99 6:10p Jimdose +// added MOVECONTROL_WALLHUG +// +// 3 9/20/99 6:58p Steven +// Cleanup +// +// 2 9/13/99 3:30p Jimdose +// merge +// +// 1 9/10/99 10:53a Jimdose +// +// 1 9/08/99 3:15p Aldie +// +// 16 9/02/99 3:25p Steven +// Reset next times when changing states. +// +// 15 8/31/99 5:47p Jimdose +// fixed bug with frame number conditions +// +// 14 8/28/99 5:22p Steven +// Added a wait time between each conditional check (defaults to 0). +// +// 13 8/16/99 10:30a Steven +// Added a time command to the state machine for AI use. +// +// 12 8/11/99 8:57p Jimdose +// fixed isStatic +// +// 11 8/11/99 7:27p Jimdose +// added hanging movetype +// +// 10 8/10/99 4:44p Steven +// Fixed a bug when getting condition parameters. +// +// 9 8/10/99 4:24p Aldie +// Added parmlist to conditional parameters +// +// 8 8/10/99 3:18p Steven +// Fixed a bug when getting the behavior arguement. +// +// 7 8/10/99 2:45p Steven +// Added parms to state checks and behavior commands from state machine. +// +// 6 8/10/99 10:49a Jimdose +// added MOVECONTROL_ABSOLUTE +// +// 5 8/06/99 6:53p Jimdose +// added ConditionalAnimationFrame +// +// 4 8/05/99 9:14a Steven +// New AI stuff. +// +// 3 7/06/99 8:33p Jimdose +// removed unused player code +// added state machine for player animation +// +// 2 7/01/99 12:25a Jimdose +// debugged code +// +// 1 6/30/99 7:25p Jimdose +// Created file +// +// DESCRIPTION: +// + +#include "characterstate.h" +#include "animate.h" +#include "scriptmaster.h" + +static const char *MoveControl_Names[] = + { + "user", // MOVECONTROL_USER + "legs", // MOVECONTROL_LEGS + "anim", // MOVECONTROL_ANIM + "absolute", // MOVECONTROL_ABSOLUTE + "hanging", // MOVECONTROL_HANGING + "wallhug", // MOVECONTROL_WALLHUG + "monkeybars", // MOVECONTROL_MONKEYBARS + "pipecrawl", // MOVECONTROL_PIPECRAWL + "pipehang", // MOVECONTROL_PIPEHANG + "stepup", // MOVECONTROL_STEPUP + "rope_grab", // MOVECONTROL_ROPE_GRAB + "rope_release", // MOVECONTROL_ROPE_RELEASE + "rope_move", // MOVECONTROL_ROPE_MOVE + "pickupenemy", // MOVECONTROL_PICKUPENEMY + "push", // MOVECONTROL_PUSH + "climbwall", // MOVECONTROL_CLIMBWALL + "useanim", // MOVECONTROL_USEANIM + "crouch", // MOVECONTROL_CROUCH + "loopuseanim", // MOVECONTROL_LOOPUSEANIM + "useobject", // MOVECONTROL_USEOBJECT + "coolobject", // MOVECONTROL_COOLOBJECT + "fakeplayer", // MOVECONTROL_FAKEPLAYER + NULL + }; + +static const char *Camera_Names[] = + { + "topdown", // CAMERA_TOPDOWN + "behind", // CAMERA_BEHIND + "front", // CAMERA_FRONT + "side", // CAMERA_SIDE + "behind_fixed", // CAMERA_BEHIND_FIXED + "side_left", // CAMERA_SIDE_LEFT + "side_right", // CAMERA_SIDE_RIGHT + "behind_nopitch", // CAMERA_BEHIND_NOPITCH + NULL + }; + +Conditional::Conditional + ( + Condition &cond + ) : condition( cond ) + + { + result = false; + previous_result = false; + checked = false; + } + +Expression::Expression() + { + } + +Expression::Expression + ( + Expression &exp + ) + + { + int i; + + value = exp.value; + + for( i = 1; i <= exp.conditions.NumObjects(); i++ ) + { + conditions.AddObject( exp.conditions.ObjectAt( i ) ); + } + } + +Expression::Expression + ( + Script &script, + State &state + ) + + { + str token; + condition_t condition; + int start; + + value = script.GetToken( true ); + + if ( !script.TokenAvailable( false ) || Q_stricmp( script.GetToken( false ), ":" ) ) + { + gi.Error( ERR_DROP, "%s: Expecting ':' on line %d.\n", script.Filename(), script.GetLineNumber() ); + } + + while( script.TokenAvailable( false ) ) + { + token = script.GetToken( true ); + + switch( token[ 0 ] ) + { + case '!' : + condition.test = TC_ISFALSE; + start = 1; + break; + + case '+' : + condition.test = TC_EDGETRUE; + start = 1; + break; + + case '-' : + condition.test = TC_EDGEFALSE; + start = 1; + break; + + default : + condition.test = TC_ISTRUE; + start = 0; + } + + if ( token.length() <= start ) + { + gi.Error( ERR_DROP, "%s: Illegal syntax '%s' on line %d.\n", script.Filename(), &token, script.GetLineNumber() ); + condition.condition_index = 0; + continue; + } + + condition.condition_index = state.addCondition( &token[ start ], script ); + if ( !condition.condition_index ) + { + gi.Error( ERR_DROP, "%s: Unknown condition '%s' on line %d.\n", script.Filename(), &token[ start ], script.GetLineNumber() ); + } + + conditions.AddObject( condition ); + } + } + +bool Expression::getResult + ( + State &state, + Entity &ent, + Container *sent_conditionals + ) + + { + int i; + condition_t *cond; + Conditional *conditional; + + for( i = 1; i <= conditions.NumObjects(); i++ ) + { + cond = &conditions.ObjectAt( i ); + conditional = sent_conditionals->ObjectAt( cond->condition_index ); + + if ( !conditional || !conditional->getResult( cond->test, ent ) ) + { + return false; + } + } + + return true; + } + +void State::readNextState + ( + Script &script + ) + + { + nextState = script.GetToken( false ); + } + +void State::readMoveType + ( + Script &script + ) + + { + str token; + const char **name; + int i; + + token = script.GetToken( false ); + + for( i = 0, name = MoveControl_Names; *name != NULL; name++, i++ ) + { + if ( !token.icmp( *name ) ) + { + break; + } + } + + if ( *name == NULL ) + { + gi.Error( ERR_DROP, "%s: Unknown movetype '%s' on line %d.\n", script.Filename(), token.c_str(), script.GetLineNumber() ); + } + else + { + movetype = ( movecontrol_t )i; + } + } + +qboolean State::setCameraType + ( + str ctype + ) + + { + const char **name; + int i; + + for( i = 0, name = Camera_Names; *name != NULL; name++, i++ ) + { + if ( !ctype.icmp( *name ) ) + { + cameratype = ( cameratype_t )i; + return qtrue; + } + } + return qfalse; + } + + +void State::readCamera + ( + Script &script + ) + + { + str token; + + token = script.GetToken( false ); + + if ( !setCameraType( token ) ) + { + gi.Error( ERR_DROP, "%s: Unknown camera type '%s' on line %d.\n", script.Filename(), token.c_str(), script.GetLineNumber() ); + } + } + +void State::readLegs + ( + Script &script + ) + + { + str token; + + if ( !script.TokenAvailable( true ) || Q_stricmp( script.GetToken( true ), "{" ) ) + { + gi.Error( ERR_DROP, "%s: Expecting '{' on line %d.\n", script.Filename(), script.GetLineNumber() ); + } + + while( script.TokenAvailable( true ) ) + { + token = script.GetToken( true ); + if ( !Q_stricmp( token.c_str(), "}" ) ) + { + break; + } + + script.UnGetToken(); + legAnims.AddObject( Expression( script, *this ) ); + } + } + +void State::readTorso + ( + Script &script + ) + + { + str token; + + if ( !script.TokenAvailable( true ) || Q_stricmp( script.GetToken( true ), "{" ) ) + { + gi.Error( ERR_DROP, "%s: Expecting '{' on line %d.\n", script.Filename(), script.GetLineNumber() ); + } + + while( script.TokenAvailable( true ) ) + { + token = script.GetToken( true ); + if ( !Q_stricmp( token.c_str(), "}" ) ) + { + break; + } + + script.UnGetToken(); + torsoAnims.AddObject( Expression( script, *this ) ); + } + } + +void State::readBehavior + ( + Script &script + ) + + { + str token; + + if ( !script.TokenAvailable( true ) ) + { + gi.Error( ERR_DROP, "%s: Expecting behavior name on line %d.\n", script.Filename(), script.GetLineNumber() ); + } + + behaviorName = script.GetToken( true ); + if ( !getClass( behaviorName ) ) + { + gi.Error( ERR_DROP, "%s: Unknown behavior '%s' on line %d.\n", script.Filename(), behaviorName.c_str(), script.GetLineNumber() ); + } + + // Read in the behavior arguments if there are any + + while ( script.TokenAvailable( false ) && script.AtString( false ) ) + { + token = script.GetToken( false ); + addBehaviorParm( token ); + } + } + +void State::readTime + ( + Script &script + ) + + { + str token; + + + if ( script.TokenAvailable( false ) && script.AtString( false ) ) + { + token = script.GetToken( false ); + minTime = atof( token.c_str() ); + } + + if ( script.TokenAvailable( false ) && script.AtString( false ) ) + { + token = script.GetToken( false ); + maxTime = atof( token.c_str() ); + } + else + { + maxTime = minTime; + } + } + +void State::readStates + ( + Script &script + ) + + { + str token; + + if ( !script.TokenAvailable( true ) || Q_stricmp( script.GetToken( true ), "{" ) ) + { + gi.Error( ERR_DROP, "%s: Expecting '{' on line %d.\n", script.Filename(), script.GetLineNumber() ); + } + + while( script.TokenAvailable( true ) ) + { + token = script.GetToken( true ); + if ( !Q_stricmp( token.c_str(), "}" ) ) + { + break; + } + + script.UnGetToken(); + states.AddObject( Expression( script, *this ) ); + } + } + +void State::ParseAndProcessCommand + ( + str command, + Entity *target + ) + + { + int argc; + const char *argv[ MAX_COMMANDS ]; + char args[ MAX_COMMANDS ][ MAXTOKEN ]; + Script script; + Event *event; + + script.Parse( command, command.length(), "CommandString" ); + + argc = 0; + while( script.TokenAvailable( false ) ) + { + if ( argc >= MAX_COMMANDS ) + { + gi.DPrintf( "State:ParseAndProcessCommand : Line exceeds %d command limit", MAX_COMMANDS ); + script.SkipToEOL(); + break; + } + strcpy( args[ argc ], script.GetToken( false ) ); + argv[ argc ] = args[ argc ]; + argc++; + } + + assert( argc > 0 ); + + if ( argc <= 0 ) + return; + + event = new Event( args[0] ); + event->AddTokens( argc - 1, &argv[ 1 ] ); + target->ProcessEvent( event ); + } + +void State::ProcessEntryCommands + ( + Entity *target + ) + + { + int i,count; + str command; + + assert( target ); + if ( !target ) + { + return; + } + + count = entryCommands.NumObjects(); + for( i = 1; i <= count; i++ ) + { + ParseAndProcessCommand( entryCommands.ObjectAt( i ), target ); + } + } + +void State::ProcessExitCommands + ( + Entity *target + ) + + { + int i,count; + str command; + + assert( target ); + if ( !target ) + { + return; + } + + count = exitCommands.NumObjects(); + for( i = 1; i <= count; i++ ) + { + ParseAndProcessCommand( exitCommands.ObjectAt( i ), target ); + } + } + +void State::readCommands + ( + Script &script, + Container &container + ) + + { + str token; + str command; + + if ( !script.TokenAvailable( true ) || Q_stricmp( script.GetToken( true ), "{" ) ) + { + gi.Error( ERR_DROP, "%s: Expecting '{' on line %d.\n", script.Filename(), script.GetLineNumber() ); + } + + while( script.TokenAvailable( true ) ) + { + while( script.TokenAvailable( false ) ) + { + token = script.GetToken( true ); + if ( !Q_stricmp( token.c_str(), "}" ) ) + { + goto out; + } + if ( token.length() ) + { + if ( strstr( token.c_str(), " " ) == NULL ) + { + command.append( token ); + } + else + { + command.append( "\"" ); + command.append( token ); + command.append( "\"" ); + } + } + else + { + command.append( "\"\"" ); + } + + command.append( " " ); + } + container.AddObject( command ); + command = ""; + } +out: + return; + } + +State *State::Evaluate + ( + Entity &ent, + Container *sent_conditionals + ) + + { + int i; + Expression *exp; + State *state; + int index; + + for( i = 1; i <= condition_indexes.NumObjects(); i++ ) + { + index = condition_indexes.ObjectAt( i ); + sent_conditionals->ObjectAt( index )->clearCheck(); + //conditions.ObjectAt( i )->clearCheck(); + } + + for( i = 1; i <= states.NumObjects(); i++ ) + { + exp = &states.ObjectAt( i ); + if ( exp->getResult( *this, ent, sent_conditionals ) ) + { + state = statemap.FindState( exp->getValue() ); + return state; + } + } + + return this; + } + +const char *State::getLegAnim + ( + Entity &ent, + Container *sent_conditionals + ) + + { + int i; + Expression *exp; + int index; + + for( i = 1; i <= condition_indexes.NumObjects(); i++ ) + { + index = condition_indexes.ObjectAt( i ); + sent_conditionals->ObjectAt( index )->clearCheck(); + //conditions.ObjectAt( i )->clearCheck(); + } + + for( i = 1; i <= legAnims.NumObjects(); i++ ) + { + exp = &legAnims.ObjectAt( i ); + if ( exp->getResult( *this, ent, sent_conditionals ) ) + { + return exp->getValue(); + } + } + + return ""; + } + +const char *State::getTorsoAnim + ( + Entity &ent, + Container *sent_conditionals + ) + + { + int i; + Expression *exp; + int index; + + for( i = 1; i <= condition_indexes.NumObjects(); i++ ) + { + index = condition_indexes.ObjectAt( i ); + sent_conditionals->ObjectAt( index )->clearCheck(); + } + + for( i = 1; i <= torsoAnims.NumObjects(); i++ ) + { + exp = &torsoAnims.ObjectAt( i ); + if ( exp->getResult( *this, ent, sent_conditionals ) ) + { + return exp->getValue(); + } + } + + return ""; + } + +const char *State::getBehaviorName + ( + void + ) + + { + return behaviorName.c_str(); + } + +float State::getMinTime + ( + void + ) + + { + return minTime; + } + +float State::getMaxTime + ( + void + ) + + { + return maxTime; + } + +int State::addCondition + ( + const char *name, + Script &script + ) + + { + Conditional *condition; + Condition *cond; + int index; + + str token; + + condition = NULL; + cond = statemap.getCondition( name ); + if ( !cond ) + { + return NULL; + } + + condition = new Conditional( *cond ); + + // Get the paramaters + while ( script.TokenAvailable( false ) && script.AtString( false ) ) + { + token = script.GetToken( false ); + condition->addParm( token ); + } + + // only add a new conditional if a similar on doesn't exist + index = statemap.findConditional( condition ); + + if ( index ) + { + // delete the one we just made + delete condition; + } + else + { + index = statemap.addConditional( condition ); + } + + condition_indexes.AddUniqueObject( index ); + + return index; + } + +void State::CheckStates + ( + void + ) + + { + const char *value; + int i; + + if ( !statemap.FindState( nextState.c_str() ) ) + { + gi.Error( ERR_DROP, "Unknown next state '%s' referenced in state '%s'.\n", nextState.c_str(), getName() ); + } + + for( i = 1; i <= states.NumObjects(); i++ ) + { + value = states.ObjectAt( i ).getValue(); + if ( !statemap.FindState( value ) ) + { + gi.Error( ERR_DROP, "Unknown state '%s' referenced in state '%s'.\n", value, getName() ); + } + } + } + +void State::GetLegAnims + ( + Container *c + ) + + { + int i,j; + qboolean addobj = true; + + for ( i=1; i<=legAnims.NumObjects(); i++ ) + { + const char *value = legAnims.ObjectAt( i ).getValue(); + addobj = true; + + // Check to see if it's already in there + for ( j=1; j<=c->NumObjects(); j++ ) + { + if ( !stricmp( c->ObjectAt( j ), value ) ) + { + addobj = false; + break; + } + } + if ( addobj ) + c->AddObject( value ); + } + } + +void State::GetTorsoAnims + ( + Container *c + ) + + { + int i,j; + qboolean addobj = true; + + for ( i=1; i<=torsoAnims.NumObjects(); i++ ) + { + const char *value = torsoAnims.ObjectAt( i ).getValue(); + addobj = true; + + // Check to see if it's already in there + for ( j=1; j<=c->NumObjects(); j++ ) + { + if ( !stricmp( c->ObjectAt( j ), value ) ) + { + addobj = false; + break; + } + } + if ( addobj ) + c->AddObject( value ); + } + } + +State::State + ( + const char *statename, + Script &script, + StateMap &map + ) : statemap( map ) + + { + str cmd; + + name = statename; + nextState = statename; + movetype = DEFAULT_MOVETYPE; + cameratype = DEFAULT_CAMERA; + behaviorName = "idle"; + + minTime = -1.0; + maxTime = -1.0; + + if ( !script.TokenAvailable( true ) || Q_stricmp( script.GetToken( true ), "{" ) ) + { + gi.Error( ERR_DROP, "%s: Expecting '{' on line %d.\n", script.Filename(), script.GetLineNumber() ); + } + + while( script.TokenAvailable( true ) ) + { + cmd = script.GetToken( true ); + if ( !cmd.icmp( "nextstate" ) ) + { + readNextState( script ); + } + else if ( !cmd.icmp( "movetype" ) ) + { + readMoveType( script ); + } + else if ( !cmd.icmp( "camera" ) ) + { + readCamera( script ); + } + else if ( !cmd.icmp( "legs" ) ) + { + readLegs( script ); + } + else if ( !cmd.icmp( "torso" ) ) + { + readTorso( script ); + } + else if ( !cmd.icmp( "behavior" ) ) + { + readBehavior( script ); + } + else if ( !cmd.icmp( "time" ) ) + { + readTime( script ); + } + else if ( !cmd.icmp( "states" ) ) + { + readStates( script ); + } + else if ( !cmd.icmp( "entrycommands" ) ) + { + readCommands( script, entryCommands ); + } + else if ( !cmd.icmp( "exitcommands" ) ) + { + readCommands( script, exitCommands ); + } + else if ( !cmd.icmp( "}" ) ) + { + break; + } + else + { + gi.Error( ERR_DROP, "%s: Unknown command '%s' on line %d.\n", script.Filename(), cmd.c_str(), script.GetLineNumber() ); + } + } + } + +StateMap::StateMap + ( + const char *file_name, + Condition *conditions, + Container *conditionals + ) + + { + str cmd; + str statename; + Script script; + State *state; + int i; + + assert( file_name ); + + filename = file_name; + + this->current_conditions = conditions; + + this->current_conditionals = conditionals; + + script.LoadFile( filename ); + + while( script.TokenAvailable( true ) ) + { + cmd = script.GetToken( true ); + if ( !cmd.icmp( "state" ) ) + { + statename = script.GetToken( false ); + if ( FindState( statename.c_str() ) ) + { + gi.Error( ERR_DROP, "%s: Duplicate definition of state '%s' on line %d.\n", filename, statename.c_str(), script.GetLineNumber() ); + } + + // parse the state even if we already have it defined + state = new State( statename.c_str(), script, *this ); + stateList.AddObject( state ); + } + else + { + gi.Error( ERR_DROP, "%s: Unknown command '%s' on line %d.\n", script.Filename(), cmd.c_str(), script.GetLineNumber() ); + } + } + + // Have all the states check themselves to see if they reference any non-existant states. + for( i = 1; i <= stateList.NumObjects(); i++ ) + { + stateList.ObjectAt( i )->CheckStates(); + } + } + +StateMap::~StateMap() + { + int i,num; + + num = stateList.NumObjects(); + for( i=num; i>0; i-- ) + { + delete stateList.ObjectAt( i ); + } + stateList.FreeObjectList(); + } + +Condition *StateMap::getCondition + ( + const char *name + ) + + { + Condition *c; + + if ( current_conditions ) + { + for( c = current_conditions; c->name; c++ ) + { + if ( !strcmp( c->name, name ) ) + { + return c; + } + } + } + + return NULL; + } + +int StateMap::findConditional + ( + Conditional *condition + ) + + { + int i; + int j; + Conditional *c; + bool found; + + + // Check for the one special case where we don't want to merge the conditionals + + if ( strcmp( condition->getName(), "CHANCE" ) == 0 ) + return NULL; + + for( i = 1; i <= current_conditionals->NumObjects(); i++ ) + { + c = current_conditionals->ObjectAt( i ); + if ( ( c->getName() == condition->getName() ) && ( c->numParms() == condition->numParms() ) ) + { + found = true; + for( j = 1; j <= c->numParms(); j++ ) + { + if ( strcmp( c->getParm( j ), condition->getParm( j ) ) ) + { + found = false; + break; + } + } + + if ( found ) + { + return i; + } + } + } + + return 0; + } + +int StateMap::addConditional + ( + Conditional *condition + ) + + { + int index; + index = current_conditionals->AddObject( condition ); + + return index; + } + +Conditional *StateMap::getConditional + ( + const char *name + ) + + { + int i; + Conditional *c; + Condition *condition; + + for( i = 1; i <= current_conditionals->NumObjects(); i++ ) + { + c = current_conditionals->ObjectAt( i ); + if ( !strcmp( c->getName(), name ) ) + { + return c; + } + } + + condition = getCondition( name ); + + c = new Conditional( *condition ); + current_conditionals->AddObject( c ); + + return c; + } + +State *StateMap::FindState + ( + const char *name + ) + + { + int i; + + for( i = 1; i <= stateList.NumObjects(); i++ ) + { + if ( !strcmp( stateList.ObjectAt( i )->getName(), name ) ) + { + return stateList.ObjectAt( i ); + } + } + + return NULL; + } + +// Caching statemaps + +struct cached_statemap_t + { + StateMap *statemap; + Container *conditionals; + }; + +Container cached_statemaps; + +StateMap *GetStatemap + ( + str filename, + Condition *conditions, + Container *conditionals, + qboolean reload, + qboolean cache_only + ) + + { + int i; + int j; + cached_statemap_t *cache = NULL; + cached_statemap_t new_cache; + qboolean found = false; + Conditional *new_conditional; + Conditional *old_conditional; + Condition *cond; + + for( i = 1 ; i <= cached_statemaps.NumObjects() ; i++ ) + { + cache = &cached_statemaps.ObjectAt( i ); + + if ( strcmp( cache->statemap->Filename(), filename.c_str() ) == 0 ) + { + found = true; + break; + } + } + + if ( found && reload ) + { + delete cache->statemap; + delete cache->conditionals; + + cache->conditionals = new Container; + cache->statemap = new StateMap( filename, conditions, cache->conditionals ); + } + + if ( !found ) + { + new_cache.conditionals = new Container; + new_cache.statemap = new StateMap( filename, conditions, new_cache.conditionals ); + + cached_statemaps.AddObject( new_cache ); + + cache = &new_cache; + } + + // Copy conditionals over + + if ( !cache_only ) + { + for( i = 1 ; i <= cache->conditionals->NumObjects() ; i++ ) + { + old_conditional = cache->conditionals->ObjectAt( i ); + + cond = cache->statemap->getCondition( old_conditional->condition.name ); + + new_conditional = new Conditional( *cond ); + + for( j = 1 ; j <= old_conditional->parmList.NumObjects() ; j++ ) + { + new_conditional->parmList.AddObject( old_conditional->parmList.ObjectAt( j ) ); + } + + conditionals->AddObject( new_conditional ); + } + } + + return cache->statemap; + } + +void CacheStatemap + ( + str filename, + Condition *conditions + ) + + { + GetStatemap( filename, conditions, NULL, false, true ); + } + +void StateMap::GetAllAnims + ( + Container *c + ) + + { + int i; + + for( i = 1; i <= stateList.NumObjects(); i++ ) + { + stateList.ObjectAt( i )->GetLegAnims( c ); + stateList.ObjectAt( i )->GetTorsoAnims( c ); + } + } + +void ClearCachedStatemaps + ( + void + ) + + { + int i,j,num2; + cached_statemap_t *cache; + + num2 = cached_statemaps.NumObjects(); + + for( i=num2 ; i>0; i-- ) + { + cache = &cached_statemaps.ObjectAt( i ); + + delete cache->statemap; + + int num = cache->conditionals->NumObjects(); + for ( j=num; j>0; j-- ) + { + Conditional *cond = cache->conditionals->ObjectAt( j ); + delete cond; + } + delete cache->conditionals; + } + + cached_statemaps.FreeObjectList(); + } \ No newline at end of file diff --git a/source/source/fgame/characterstate.h b/source/source/fgame/characterstate.h new file mode 100644 index 0000000..5955352 --- /dev/null +++ b/source/source/fgame/characterstate.h @@ -0,0 +1,543 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/characterstate.h $ +// $Revision:: 29 $ +// $Date:: 7/25/00 11:32p $ +// +// Copyright (C) 1999 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source is may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/characterstate.h $ +// +// 29 7/25/00 11:32p Aldie +// Made some changes to the memory system and fixed a memory allocation bug in +// Z_TagMalloc. Also changed a lot of classes to subclass from Class. +// +// 28 7/21/00 1:14a Markd +// fixed fakeplayer again +// +// 27 7/13/00 9:18p Markd +// added behind_nopitch camera type +// +// 26 7/05/00 3:22p Markd +// Added movecontrol_gotcoolobject +// +// 25 6/28/00 3:56p Markd +// added additional camera views +// +// 24 6/28/00 3:12p Steven +// Added CacheStatemap. +// +// 23 6/17/00 3:48p Aldie +// +// 22 6/10/00 1:50p Steven +// Added statemap caching. +// +// 21 6/08/00 9:55a Markd +// added camera_type behind_fixed +// +// 20 6/04/00 6:52p Markd +// Added camera support to TouchAnim's cleaned up player camera interface +// +// 19 4/29/00 11:28a Markd +// removed old rope code, cleaned up rope interface +// +// 18 4/07/00 2:05p Markd +// added MOVETYPE_PIPEHANG +// +// 17 3/31/00 3:18p Markd +// Added Movetype USEOBJECT +// +// 16 2/25/00 7:27p Markd +// Added useanim_numloop support and fixed useanim_orientation +// +// 15 2/24/00 4:16p Jimdose +// added MOVECONTROL_CROUCH +// +// 14 2/24/00 3:25p Jimdose +// made parsing of cameratype and movetype to be table based +// added check for valid class when parsing behavior. +// +// 13 2/22/00 1:56p Jimdose +// added MOVECONTROL_PUSH +// +// 12 2/17/00 12:00p Aldie +// Added command processing to state system with the addition of entrycommands +// and exitcommands. +// +// 11 2/14/00 5:37p Jimdose +// added MOVECONTROL_LEGS +// +// 10 2/08/00 11:34a Steven +// Added picking up of Shgliek. +// +// 9 2/08/00 12:17a Jimdose +// made rope grabbing controlled by state system +// +// 8 1/28/00 6:21p Jimdose +// added rope movecontrol types +// +// 7 1/22/00 4:05p Jimdose +// added MOVECONTROL_PIPECRAWL and MOVECONTROL_STEPUP +// +// 6 1/17/00 10:20p Jimdose +// Rewrote state system initialization. Made conditionals defined with array. +// Made Evaluate functions early exit +// +// 5 1/15/00 4:13p Markd +// Changed MOVETYPE_ABSOLUTE to have collision and no user input of the angles +// +// 4 12/14/18 2:43p Jimdose +// added monkeybar movetype +// +// 3 12/10/99 6:10p Jimdose +// added MOVECONTROL_WALLHUG +// +// 2 9/20/99 6:58p Steven +// Cleanup +// +// 1 9/10/99 10:53a Jimdose +// +// 1 9/08/99 3:15p Aldie +// +// 15 9/02/99 3:26p Steven +// Reset next times when changing states. +// +// 14 8/31/99 5:48p Jimdose +// fixed bug with frame number conditions +// +// 13 8/30/99 11:06a Steven +// Fixed a bug with the new timing stuff. +// +// 12 8/28/99 5:23p Steven +// Added a wait time between each conditional check (defaults to 0). +// +// 11 8/17/99 4:51p Jimdose +// got rid of default parameter on getParm +// added error checking to getParm +// +// 10 8/16/99 10:31a Steven +// Added a time command to the state machine for AI use and moved +// ConditionalParameter back into Conditional. +// +// 9 8/11/99 7:27p Jimdose +// added MOVECONTROL_HANGING +// +// 8 8/10/99 4:23p Aldie +// Added parmlist to conditional parameters +// +// 7 8/10/99 2:45p Steven +// Added parms to state checks and behavior commands from state machine. +// +// 6 8/10/99 10:48a Jimdose +// added MOVECONTROL_ABSOLUTE +// +// 5 8/06/99 6:53p Jimdose +// added ConditionalAnimationFrame +// +// 4 8/05/99 9:16a Steven +// New AI stuff. +// +// 3 7/06/99 8:33p Jimdose +// removed unused player code +// added state machine for player animation +// +// 2 7/01/99 12:25a Jimdose +// debugged code +// +// 1 6/30/99 7:25p Jimdose +// Created file +// +// DESCRIPTION: +// + +#ifndef __CHARACTERSTATE_H__ +#define __CHARACTERSTATE_H__ + +#include "g_local.h" +#include "script.h" + +enum testcondition_t + { + TC_ISTRUE, // no prefix + TC_ISFALSE, // ! + TC_EDGETRUE, // + + TC_EDGEFALSE // - + }; + +enum movecontrol_t + { + MOVECONTROL_USER, // Quake style + MOVECONTROL_LEGS, // Quake style, legs state system active + MOVECONTROL_ANIM, // move based on animation, with full collision testing + MOVECONTROL_ABSOLUTE, // move based on animation, with full collision testing but no turning + MOVECONTROL_HANGING, // move based on animation, with full collision testing, hanging + MOVECONTROL_WALLHUG, // move based on animation, with full collision testing, hanging + MOVECONTROL_MONKEYBARS, // move based on animation, with full collision testing, monkey bars + MOVECONTROL_PIPECRAWL, // move based on animation, with full collision testing, crawling on pipe + MOVECONTROL_PIPEHANG, // move based on animation, with full collision testing, hanging from pipe + MOVECONTROL_STEPUP, + MOVECONTROL_ROPE_GRAB, + MOVECONTROL_ROPE_RELEASE, + MOVECONTROL_ROPE_MOVE, + MOVECONTROL_PICKUPENEMY, + MOVECONTROL_PUSH, + MOVECONTROL_CLIMBWALL, + MOVECONTROL_USEANIM, + MOVECONTROL_CROUCH, + MOVECONTROL_LOOPUSEANIM, + MOVECONTROL_USEOBJECT, + MOVECONTROL_COOLOBJECT, + MOVECONTROL_FAKEPLAYER + }; + +enum cameratype_t + { + CAMERA_TOPDOWN, + CAMERA_BEHIND, + CAMERA_FRONT, + CAMERA_SIDE, + CAMERA_BEHIND_FIXED, + CAMERA_SIDE_LEFT, + CAMERA_SIDE_RIGHT, + CAMERA_BEHIND_NOPITCH + }; + +#define DEFAULT_MOVETYPE MOVECONTROL_LEGS +#define DEFAULT_CAMERA CAMERA_BEHIND + +class Conditional; + +template< class Type > +struct Condition + { + const char *name; + qboolean ( Type::*func )( Conditional &condition ); + }; + +class Conditional : public Class + { + private : + qboolean result; + qboolean previous_result; + bool checked; + + public : + Condition condition; + Container parmList; + + bool getResult( testcondition_t test, Entity &ent ); + const char *getName( void ); + + Conditional( Condition &condition ); + + const char *getParm( int number ); + void addParm( str parm ); + int numParms( void ); + void clearCheck( void ); + }; + +inline void Conditional::addParm + ( + str parm + ) + + { + parmList.AddObject( parm ); + } + +inline const char *Conditional::getParm + ( + int number + ) + + { + if ( ( number < 1 ) || ( number > parmList.NumObjects() ) ) + { + gi.Error( ERR_DROP, "Parm #%d out of range on %s condition\n", number, condition.name ); + } + return parmList.ObjectAt( number ).c_str(); + } + +inline int Conditional::numParms + ( + void + ) + + { + return parmList.NumObjects(); + } + +inline void Conditional::clearCheck + ( + void + ) + + { + checked = false; + } + +inline const char *Conditional::getName + ( + void + ) + + { + return condition.name; + } + +inline bool Conditional::getResult + ( + testcondition_t test, + Entity &ent + ) + + { + if ( condition.func && !checked ) + { + checked = true; + previous_result = result; + + result = ( ent.*condition.func )( *this ); + } + + switch( test ) + { + case TC_ISFALSE : + return !result; + break; + + case TC_EDGETRUE : + return result && !previous_result; + break; + + case TC_EDGEFALSE : + return !result && previous_result; + break; + + case TC_ISTRUE : + default : + return result != qfalse; + } + } + +class State; +class StateMap; + +class Expression : public Class + { + private : + struct condition_t + { + testcondition_t test; + int condition_index; + }; + + str value; + Container conditions; + + public : + Expression(); + Expression( Expression &exp ); + Expression( Script &script, State &state ); + + void operator=( Expression &exp ); + + bool getResult( State &state, Entity &ent, Container *sent_conditionals ); + const char *getValue( void ); + }; + +inline void Expression::operator= + ( + Expression &exp + ) + + { + int i; + + value = exp.value; + + conditions.FreeObjectList(); + for( i = 1; i <= exp.conditions.NumObjects(); i++ ) + { + conditions.AddObject( exp.conditions.ObjectAt( i ) ); + } + } + +inline const char *Expression::getValue + ( + void + ) + + { + return value.c_str(); + } + +class State : public Class + { + private : + Container condition_indexes; + + StateMap &statemap; + + str name; + + str nextState; + movecontrol_t movetype; + cameratype_t cameratype; + + str behaviorName; + Container behaviorParmList; + + float minTime; + float maxTime; + + Container legAnims; + Container torsoAnims; + + Container states; + Container entryCommands; + Container exitCommands; + + void readNextState( Script &script ); + void readMoveType( Script &script ); + void readCamera( Script &script ); + void readLegs( Script &script ); + void readTorso( Script &script ); + void readBehavior( Script &script ); + void readTime( Script &script ); + void readStates( Script &script ); + void readCommands( Script &script, Container &container ); + + void ParseAndProcessCommand( str command, Entity *target ); + + public : + State( const char *name, Script &script, StateMap &map ); + + State *Evaluate( Entity &ent, Container *ent_conditionals ); + int addCondition( const char *name, Script &script ); + void CheckStates( void ); + + const char *getName( void ); + + const char *getLegAnim( Entity &ent, Container *sent_conditionals ); + const char *getTorsoAnim( Entity &ent, Container *sent_conditionals ); + const char *getBehaviorName( void ); + State *getNextState( void ); + movecontrol_t getMoveType( void ); + cameratype_t getCameraType( void ); + qboolean setCameraType( str ctype ); + + const char *getBehaviorParm( int number=1 ); + void addBehaviorParm( str parm ); + int numBehaviorParms( void ); + + float getMinTime( void ); + float getMaxTime( void ); + void ProcessEntryCommands( Entity *target ); + void ProcessExitCommands( Entity *target ); + void GetLegAnims( Container *c ); + void GetTorsoAnims( Container *c ); + }; + +inline void State::addBehaviorParm + ( + str parm + ) + + { + behaviorParmList.AddObject( parm ); + } + +inline const char *State::getBehaviorParm + ( + int number + ) + + { + return behaviorParmList.ObjectAt( number ).c_str(); + } + +inline int State::numBehaviorParms + ( + void + ) + + { + return behaviorParmList.NumObjects(); + } + +class StateMap : public Class + { + private : + Container stateList; + Condition *current_conditions; + Container *current_conditionals; + str filename; + + public : + StateMap( const char *filename, Condition *conditions, Container *conditionals ); + ~StateMap(); + + Condition *getCondition( const char *name ); + int findConditional( Conditional *condition ); + int addConditional( Conditional *condition ); + Conditional *getConditional( const char *name ); + void GetAllAnims( Container *c ); + State *FindState( const char *name ); + const char *Filename(); + }; + +inline const char *StateMap::Filename + ( + void + ) + + { + return filename.c_str(); + } + +inline const char *State::getName + ( + void + ) + + { + return name.c_str(); + } + +inline State *State::getNextState + ( + void + ) + + { + return statemap.FindState( nextState.c_str() ); + } + +inline movecontrol_t State::getMoveType + ( + void + ) + + { + return movetype; + } + +inline cameratype_t State::getCameraType + ( + void + ) + + { + return cameratype; + } + +void ClearCachedStatemaps( void ); +StateMap *GetStatemap( str filename, Condition *conditions, Container *conditionals, qboolean reload, qboolean cache_only = false ); +void CacheStatemap( str filename, Condition *conditions ); + +#endif /* !__CHARACTERSTATE_H__ */ diff --git a/source/source/fgame/class.cpp b/source/source/fgame/class.cpp new file mode 100644 index 0000000..c5c278d --- /dev/null +++ b/source/source/fgame/class.cpp @@ -0,0 +1,1035 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/cgame/class.cpp $ +// $Revision:: 17 $ +// $Author:: Aldie $ +// $Date:: 8/10/00 6:34p $ +// +// Copyright (C) 1997 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source is may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/cgame/class.cpp $ +// +// 17 8/10/00 6:34p Aldie +// Added a shutdown method +// +// 16 7/26/00 1:07p Steven +// Made it so in classes new function NULL is returned if we try to allocate 0 +// bytes. +// +// 15 7/07/00 6:57p Markd +// changed default debug printf when starting up event system +// +// 14 5/24/00 3:14p Markd +// first phase of save/load games +// +// 13 4/29/00 3:50p Markd +// added some convenience classes and printed out classID when appropriate +// +// 12 4/29/00 3:26p Markd +// fleshed out the rest of the event/class documentation +// +// 11 4/29/00 11:38a Markd +// changed formatting for dump all classes +// +// 10 4/26/00 7:55p Markd +// Added more documentation code into various systems +// +// 9 4/12/00 6:19p Aldie +// Fixed formatting +// +// 8 3/04/00 11:45a Markd +// Added malloc and free for cgame and client +// +// 7 2/26/00 3:27p Markd +// pre-initialized all memory with known bad value +// +// 6 2/04/00 11:20a Markd +// Added memory leak test code to new and delete operators +// +// 5 1/10/00 5:34p Markd +// Changed Allocation routines for fgame to use the gi.Malloc and gi.Free +// instead of the in game heap +// +// 4 12/15/99 11:45a Markd +// made Event's Classes and also freed up safe pointers at the appropriate +// times +// +// 3 10/05/99 2:03p Markd +// Added warning about files being in multiple projects +// +// 2 9/28/99 4:26p Markd +// merged listener, class and vector between 3 projects +// +// 1 9/10/99 10:53a Jimdose +// +// 1 9/08/99 3:15p Aldie +// +// DESCRIPTION: +// Base class that all classes that are used in conjunction with Sin should +// be based off of. Class gives run-time type information about any class +// derived from it. This is really handy when you have a pointer to an object +// that you need to know if it supports certain behaviour. +// +// WARNING: This file is shared between fgame, cgame and possibly the user interface. +// It is instanced in each one of these directories because of the way that SourceSafe works. +// + +#include +#include +#include + +#if defined( GAME_DLL ) + +#include "g_local.h" + +#elif defined ( CGAME_DLL ) + +#include "cg_local.h" +#include "listener.h" +#include "../qcommon/qcommon.h" + +#else + +#include "listener.h" +#include "../qcommon/qcommon.h" + +#endif + +#include "class.h" +#include "linklist.h" + +int totalmemallocated = 0; +int numclassesallocated = 0; + +static ClassDef *classlist = NULL; + + +ClassDef::ClassDef() + { + this->classname = NULL; + this->classID = NULL; + this->superclass = NULL; + this->responses = NULL, + this->numEvents = 0; + this->responseLookup = NULL; + this->newInstance = NULL; + this->classSize = 0; + this->super = NULL; + this->prev = this; + this->next = this; + } + +ClassDef::ClassDef + ( + const char *classname, + const char *classID, + const char *superclass, + ResponseDef *responses, + void *( *newInstance )( void ), + int classSize + ) + + { + ClassDef *node; + + if ( classlist == NULL ) + { + classlist = new ClassDef; + } + + this->classname = classname; + this->classID = classID; + this->superclass = superclass; + this->responses = responses; + this->numEvents = 0; + this->responseLookup = NULL; + this->newInstance = newInstance; + this->classSize = classSize; + this->super = getClass( superclass ); + + // It's not uncommon for classes to not have a class id, so just set it + // to an empty string so that we're not checking for it all the time. + if ( !classID ) + { + this->classID = ""; + } + + // Check if any subclasses were initialized before their superclass + for( node = classlist->next; node != classlist; node = node->next ) + { + if ( ( node->super == NULL ) && ( !Q_stricmp( node->superclass, this->classname ) ) && + ( Q_stricmp( node->classname, "Class" ) ) ) + { + node->super = this; + } + } + + // Add to front of list + LL_Add( classlist, this, prev, next ); + } + +void ClassDef::Shutdown + ( + void + ) + + { + if ( responseLookup ) + { + delete[] responseLookup; + responseLookup = NULL; + } + } + +ClassDef::~ClassDef() + { + ClassDef *node; + + if ( classlist != this ) + { + LL_Remove( this, prev, next ); + + // Check if any subclasses were initialized before their superclass + for( node = classlist->next; node != classlist; node = node->next ) + { + if ( node->super == this ) + { + node->super = NULL; + } + } + } + else + { + // If the head of the list is deleted before the list is cleared, then we may have problems + assert( this->next == this->prev ); + } + + if ( responseLookup ) + { + delete[] responseLookup; + responseLookup = NULL; + } + } + +void ClassDef::BuildResponseList + ( + void + ) + + { + ClassDef *c; + ResponseDef *r; + int ev; + int i; + qboolean *set; + int num; + + if ( responseLookup ) + { + delete[] responseLookup; + responseLookup = NULL; + } + + num = Event::NumEventCommands(); + responseLookup = ( Response ** )new char[ sizeof( Response * ) * num ]; + memset( responseLookup, 0, sizeof( Response * ) * num ); + + set = new qboolean[ num ]; + memset( set, 0, sizeof( qboolean ) * num ); + + this->numEvents = num; + + for( c = this; c != NULL; c = c->super ) + { + r = c->responses; + if ( r ) + { + for( i = 0; r[ i ].event != NULL; i++ ) + { + ev = ( int )*r[ i ].event; + if ( !set[ ev ] ) + { + set[ ev ] = true; + if ( r[ i ].response ) + { + responseLookup[ ev ] = &r[ i ].response; + } + else + { + responseLookup[ ev ] = NULL; + } + } + } + } + } + + delete[] set; + } + +void BuildEventResponses + ( + void + ) + + { + ClassDef *c; + int amount; + int numclasses; + + amount = 0; + numclasses = 0; + for( c = classlist->next; c != classlist; c = c->next ) + { + c->BuildResponseList(); + + amount += c->numEvents * sizeof( Response * ); + numclasses++; + } + + CLASS_DPrintf( "\n------------------\nEvent system initialized: " + "%d classes %d events %d total memory in response list\n\n", + numclasses, Event::NumEventCommands(), amount ); + } + +ClassDef *getClassForID + ( + const char *name + ) + + { + ClassDef *c; + + for( c = classlist->next; c != classlist; c = c->next ) + { + if ( c->classID && !Q_stricmp( c->classID, name ) ) + { + return c; + } + } + + return NULL; + } + +ClassDef *getClass + ( + const char *name + ) + + { + ClassDef *c; + + for( c = classlist->next; c != classlist; c = c->next ) + { + if ( !Q_stricmp( c->classname, name ) ) + { + return c; + } + } + + return NULL; + } + +ClassDef *getClassList + ( + void + ) + + { + return classlist; + } + +void listAllClasses + ( + void + ) + + { + ClassDef *c; + + for( c = classlist->next; c != classlist; c = c->next ) + { + CLASS_DPrintf( "%s\n", c->classname ); + } + } + +void listInheritanceOrder + ( + const char *classname + ) + + { + ClassDef *cls; + ClassDef *c; + + cls = getClass( classname ); + if ( !cls ) + { + CLASS_DPrintf( "Unknown class: %s\n", classname ); + return; + } + for( c = cls; c != NULL; c = c->super ) + { + CLASS_DPrintf( "%s\n", c->classname ); + } + } + +qboolean checkInheritance + ( + ClassDef *superclass, + ClassDef *subclass + ) + + { + ClassDef *c; + + for( c = subclass; c != NULL; c = c->super ) + { + if ( c == superclass ) + { + return true; + } + } + return false; + } + +qboolean checkInheritance + ( + ClassDef *superclass, + const char *subclass + ) + + { + ClassDef *c; + + c = getClass( subclass ); + if ( c == NULL ) + { + CLASS_DPrintf( "Unknown class: %s\n", subclass ); + return false; + } + return checkInheritance( superclass, c ); + } + +qboolean checkInheritance + ( + const char *superclass, + const char *subclass + ) + + { + ClassDef *c1; + ClassDef *c2; + + c1 = getClass( superclass ); + c2 = getClass( subclass ); + if ( c1 == NULL ) + { + CLASS_DPrintf( "Unknown class: %s\n", superclass ); + return false; + } + if ( c2 == NULL ) + { + CLASS_DPrintf( "Unknown class: %s\n", subclass ); + return false; + } + return checkInheritance( c1, c2 ); + } + +void CLASS_Print( FILE *class_file, const char *fmt, ... ) + { + va_list argptr; + char text[ 1024 ]; + + va_start( argptr, fmt ); + vsprintf( text, fmt, argptr ); + va_end( argptr ); + + if ( class_file ) + fprintf( class_file, text ); + else + CLASS_DPrintf( text ); + } + + +CLASS_DECLARATION( NULL, Class, NULL ) + { + { NULL, NULL } + }; + +#ifdef NDEBUG + +void * Class::operator new( size_t s ) + { + int *p; + + if ( s == 0 ) + return NULL; + + s += sizeof( int ); +#if defined( GAME_DLL ) + p = ( int * )gi.Malloc( s ); +#elif defined( CGAME_DLL ) + p = ( int * )cgi.Malloc( s ); +#else + p = ( int * )Z_TagMalloc( s, TAG_CLIENT ); +#endif + *p = s; + totalmemallocated += s; + numclassesallocated++; + return p + 1; + } + +void Class::operator delete( void *ptr ) + { + int *p; + + p = ( ( int * )ptr ) - 1; + totalmemallocated -= *p; + numclassesallocated--; +#if defined( GAME_DLL ) + gi.Free( p ); +#elif defined( CGAME_DLL ) + cgi.Free( p ); +#else + Z_Free( p ); +#endif + } + +#else + +#ifdef MEMORY_LEAK_TEST +int classindex = 0; +#endif + +void * Class::operator new( size_t s ) + { + int *p; + + s += sizeof( int ) * 3; +#if defined( GAME_DLL ) + p = ( int * )gi.Malloc( s ); +#elif defined( CGAME_DLL ) + p = ( int * )cgi.Malloc( s ); +#else + p = ( int * )Z_TagMalloc( s, TAG_CLIENT ); +#endif + // set memory to a known wrong number + memset( p, 0xaa, s ); +#ifdef MEMORY_LEAK_TEST + p[ 0 ] = classindex++; +#else + p[ 0 ] = 0x12348765; +#endif + *( int * )( ((byte *)p) + s - sizeof( int ) ) = 0x56784321; + p[ 1 ] = s; + totalmemallocated += s; + numclassesallocated++; + return p + 2; + } + +void Class::operator delete( void *ptr ) + { + int *p; + + p = ( ( int * )ptr ) - 2; +#ifndef MEMORY_LEAK_TEST + assert( p[ 0 ] == 0x12348765 ); +#endif + assert( *( int * )( ((byte *)p) + p[ 1 ] - sizeof( int ) ) == 0x56784321 ); + + totalmemallocated -= p[ 1 ]; + numclassesallocated--; +#if defined( GAME_DLL ) + gi.Free( p ); +#elif defined( CGAME_DLL ) + cgi.Free( p ); +#else + Z_Free( p ); +#endif + } + +#endif + +void DisplayMemoryUsage + ( + void + ) + + { + CLASS_Printf( "Classes %-5d Class memory used: %d\n", numclassesallocated, totalmemallocated ); + } + +Class::Class() + { + SafePtrList = NULL; + } + +Class::~Class() + { + ClearSafePointers(); + } + +#ifdef GAME_DLL + +void Class::Archive + ( + Archiver &arc + ) + + { + } + +#endif + +void Class::ClearSafePointers( void ) + { + while( SafePtrList != NULL ) + { + SafePtrList->Clear(); + } + } + + +void Class::warning + ( + const char *function, + const char *fmt, + ... + ) + + { + va_list argptr; + char text[ 1024 ]; + + va_start( argptr, fmt ); + vsprintf( text, fmt, argptr ); + va_end( argptr ); + + if ( getClassID() ) + { + CLASS_DPrintf( "%s::%s : %s\n", getClassID(), function, text ); + } + else + { + CLASS_DPrintf( "%s::%s : %s\n", getClassname(), function, text ); + } + } + +void Class::error + ( + const char *function, + const char *fmt, + ... + ) + + { + va_list argptr; + char text[ 1024 ]; + + va_start( argptr, fmt ); + vsprintf( text, fmt, argptr ); + va_end( argptr ); + + if ( getClassID() ) + { + CLASS_Error( ERR_DROP, "%s::%s : %s\n", getClassID(), function, text ); + } + else + { + CLASS_Error( ERR_DROP, "%s::%s : %s\n", getClassname(), function, text ); + } + } + +qboolean Class::inheritsFrom + ( + const char *name + ) + + { + ClassDef *c; + + c = getClass( name ); + if ( c == NULL ) + { + CLASS_DPrintf( "Unknown class: %s\n", name ); + return false; + } + return checkInheritance( c, classinfo() ); + } + +qboolean Class::isInheritedBy + ( + const char *name + ) + + { + ClassDef *c; + + c = getClass( name ); + if ( c == NULL ) + { + CLASS_DPrintf( "Unknown class: %s\n", name ); + return false; + } + return checkInheritance( classinfo(), c ); + } + +const char *Class::getClassname + ( + void + ) + + { + ClassDef *cls; + + cls = classinfo(); + return cls->classname; + } + +const char *Class::getClassID + ( + void + ) + + { + ClassDef *cls; + + cls = classinfo(); + return cls->classID; + } + +const char *Class::getSuperclass + ( + void + ) + + { + ClassDef *cls; + + cls = classinfo(); + return cls->superclass; + } + +void *Class::newInstance + ( + void + ) + + { + ClassDef *cls; + + cls = classinfo(); + return cls->newInstance(); + } + +#define MAX_INHERITANCE 64 +void ClassEvents + ( + const char *classname, + qboolean print_to_disk + ) + + { + ClassDef *c; + ResponseDef *r; + int ev; + int i, j; + qboolean *set; + int num, orderNum; + Event **events; + byte *order; + FILE *class_file; + str classNames[ MAX_INHERITANCE ]; + str class_filename; + + c = getClass( classname ); + if ( !c ) + { + CLASS_DPrintf( "Unknown class: %s\n", classname ); + return; + } + + class_file = NULL; + + if ( print_to_disk ) + { + class_filename = str ( classname ) + ".txt"; + class_file = fopen( class_filename.c_str(), "w" ); + if ( class_file == NULL ) + return; + } + + num = Event::NumEventCommands(); + + set = new qboolean[ num ]; + memset( set, 0, sizeof( qboolean ) * num ); + + events = new Event *[ num ]; + memset( events, 0, sizeof( Event * ) * num ); + + order = new byte[ num ]; + memset( order, 0, sizeof( byte ) * num ); + + orderNum = 0; + for( ; c != NULL; c = c->super ) + { + if ( orderNum < MAX_INHERITANCE ) + { + classNames[ orderNum ] = c->classname; + } + r = c->responses; + if ( r ) + { + for( i = 0; r[ i ].event != NULL; i++ ) + { + ev = ( int )*r[ i ].event; + if ( !set[ ev ] ) + { + set[ ev ] = true; + + if ( r[ i ].response ) + { + events[ ev ] = r[ i ].event; + order[ ev ] = orderNum; + } + } + } + } + orderNum++; + } + + CLASS_Print( class_file, "********************************************************\n" ); + CLASS_Print( class_file, "********************************************************\n" ); + CLASS_Print( class_file, "* All Events For Class: %s\n", classname ); + CLASS_Print( class_file, "********************************************************\n" ); + CLASS_Print( class_file, "********************************************************\n\n" ); + + for( j = orderNum - 1; j >= 0; j-- ) + { + CLASS_Print( class_file, "\n********************************************************\n" ); + CLASS_Print( class_file, "* Class: %s\n", classNames[ j ].c_str() ); + CLASS_Print( class_file, "********************************************************\n\n" ); + for( i = 1; i < num; i++ ) + { + int index; + + index = Event::MapSortedEventIndex( i ); + if ( events[ index ] && ( order[ index ] == j ) ) + { + Event::PrintEventDocumentation( events[ index ], class_file ); + } + } + } + + if ( class_file != NULL ) + { + CLASS_DPrintf( "Printed class info to file %s\n", class_filename.c_str() ); + fclose( class_file ); + } + + delete[] events; + delete[] order; + delete[] set; + } + +static int dump_numclasses; +static int dump_numevents; +void DumpClass + ( + FILE * class_file, + const char * className + ) + + { + ClassDef *c; + ResponseDef *r; + int ev; + int i; + int num; + Event **events; + + c = getClass( className ); + if ( !c ) + { + return; + } + + num = Event::NumEventCommands(); + + events = new Event *[ num ]; + memset( events, 0, sizeof( Event * ) * num ); + + // gather event responses for this class + r = c->responses; + if ( r ) + { + for( i = 0; r[ i ].event != NULL; i++ ) + { + ev = ( int )*r[ i ].event; + if ( r[ i ].response ) + { + events[ ev ] = r[ i ].event; + } + } + } + + CLASS_Print( class_file, "\n"); + if ( c->classID[ 0 ] ) + { + CLASS_Print( class_file, "

%s (%s)", c->classname, c->classname, c->classID ); + } + else + { + CLASS_Print( class_file, "

%s", c->classname, c->classname ); + } + + // print out lineage + for( c = c->super; c != NULL; c = c->super ) + { + CLASS_Print( class_file, " -> %s", c->classname, c->classname ); + } + CLASS_Print( class_file, "

\n"); + + dump_numclasses++; + + CLASS_Print( class_file, "
\n"); + for( i = 1; i < num; i++ ) + { + int index; + + index = Event::MapSortedEventIndex( i ); + if ( events[ index ] ) + { + Event::PrintEventDocumentation( events[ index ], class_file, qtrue ); + dump_numevents++; + } + } + CLASS_Print( class_file, "
\n"); + delete[] events; + } + + +#define MAX_CLASSES 1024 +void DumpAllClasses + ( + void + ) + + { + int i, j, num, smallest; + ClassDef *c; + FILE * class_file; + str class_filename; + str class_title; + str classes[ MAX_CLASSES ]; + +#if defined( GAME_DLL ) + class_filename = "g_allclasses.html"; + class_title = "Game Module"; +#elif defined( CGAME_DLL ) + class_filename = "cg_allclasses.html"; + class_title = "Client Game Module"; +#else + class_filename = "cl_allclasses.html"; + class_title = "Client Module"; +#endif + + class_file = fopen( class_filename.c_str(), "w" ); + if ( class_file == NULL ) + return; + + // construct the HTML header for the document + CLASS_Print( class_file, "\n"); + CLASS_Print( class_file, "\n"); + CLASS_Print( class_file, "%s Classes\n", class_title.c_str() ); + CLASS_Print( class_file, "\n"); + CLASS_Print( class_file, "\n"); + CLASS_Print( class_file, "

\n"); + CLASS_Print( class_file, "
%s Classes
\n", class_title.c_str() ); + CLASS_Print( class_file, "

\n"); +#if defined( GAME_DLL ) + // + // print out some commonly used classnames + // + CLASS_Print( class_file, "

" ); + CLASS_Print( class_file, "Actor, " ); + CLASS_Print( class_file, "Animate, " ); + CLASS_Print( class_file, "Entity, " ); + CLASS_Print( class_file, "ScriptSlave, " ); + CLASS_Print( class_file, "ScriptThread, " ); + CLASS_Print( class_file, "Sentient, " ); + CLASS_Print( class_file, "Trigger, " ); + CLASS_Print( class_file, "World" ); + CLASS_Print( class_file, "

" ); +#endif + + dump_numclasses = 0; + dump_numevents = 0; + + // get all the classes + num = 0; + for( c = classlist->next; c != classlist; c = c->next ) + { + if ( num < MAX_CLASSES ) + { + classes[ num++ ] = c->classname; + } + } + + // go through and process each class from smallest to greatest + for( i = 0; i < num; i++ ) + { + smallest = -1; + for( j = 0; j < num; j++ ) + { + if ( classes[ j ].length() > 1 ) + { + if ( smallest >= 0 ) + { + if ( classes[ j ].icmp( classes[ smallest ] ) < 0 ) + { + smallest = j; + } + } + else + { + smallest = j; + } + } + } + DumpClass( class_file, classes[ smallest ] ); + // delete the name from the list + classes[ smallest ] = ""; + } + + if ( class_file != NULL ) + { + CLASS_Print( class_file, "

\n"); + CLASS_Print( class_file, "%d %s Classes.
%d %s Events.\n", dump_numclasses, class_title.c_str(), dump_numevents, class_title.c_str() ); + CLASS_Print( class_file, "

\n"); + CLASS_Print( class_file, "\n"); + CLASS_Print( class_file, "\n"); + CLASS_DPrintf( "Dumped all classes to file %s\n", class_filename.c_str() ); + fclose( class_file ); + } + + } + + +void ShutdownClasses + ( + void + ) + + { + ClassDef *c; + + for( c = classlist->next; c != classlist; c = c->next ) + { + c->Shutdown(); + } + } diff --git a/source/source/fgame/class.h b/source/source/fgame/class.h new file mode 100644 index 0000000..71f3171 --- /dev/null +++ b/source/source/fgame/class.h @@ -0,0 +1,511 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/client/class.h $ +// $Revision:: 13 $ +// $Author:: Aldie $ +// $Date:: 8/10/00 9:27p $ +// +// Copyright (C) 1997 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source is may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/client/class.h $ +// +// 13 8/10/00 9:27p Aldie +// Fixing memory leaks +// +// 12 8/10/00 6:34p Aldie +// Added a shutdown method +// +// 11 6/14/00 12:14p Markd +// more intel compiler bug fixes +// +// 10 6/14/00 11:18a Markd +// cleaned up code using Intel compiler +// +// 9 5/26/00 7:44p Markd +// 2nd phase save games +// +// 8 5/25/00 4:28p Markd +// fixed up archive functions +// +// 7 5/24/00 3:14p Markd +// first phase of save/load games +// +// 6 4/26/00 7:55p Markd +// Added more documentation code into various systems +// +// 5 3/16/00 10:50a Markd +// Fixed some bad syntax in headers that exhibited itself in non-visualc +// compilers +// +// 4 12/15/99 11:45a Markd +// made Event's Classes and also freed up safe pointers at the appropriate +// times +// +// 3 10/05/99 2:03p Markd +// Added warning about files being in multiple projects +// +// 2 9/28/99 4:26p Markd +// merged listener, class and vector between 3 projects +// +// 1 9/10/99 10:53a Jimdose +// +// 1 9/08/99 3:15p Aldie +// +// 6 8/27/99 3:31p Markd +// externed totalmemallocated +// +// DESCRIPTION: +// Base class that all classes that are used in conjunction with Sin should +// be based off of. Class gives run-time type information about any class +// derived from it. This is really handy when you have a pointer to an object +// that you need to know if it supports certain behaviour. +// +// WARNING: This file is shared between fgame, cgame and possibly the user interface. +// It is instanced in each one of these directories because of the way that SourceSafe works. +// + +#ifndef __CLASS_H__ +#define __CLASS_H__ + +#if defined( GAME_DLL ) +// +// game dll specific defines +// +#include "g_local.h" +#include "linklist.h" + +#define CLASS_DPrintf gi.DPrintf +#define CLASS_Printf gi.Printf +#define CLASS_Error gi.Error + +class Archiver; + +#elif defined ( CGAME_DLL ) +// +// cgame dll specific defines +// +#include "../fgame/q_shared.h" +#include "linklist.h" + +#define CLASS_DPrintf cgi.DPrintf +#define CLASS_Printf cgi.Printf +#define CLASS_Error cgi.Error + +#else + +// +// client specific defines +// +#include "../fgame/q_shared.h" +#include "linklist.h" + +#define CLASS_DPrintf Com_DPrintf +#define CLASS_Printf Com_Printf +#define CLASS_Error Com_Error +#endif + +class Class; +class Event; + +typedef void ( Class::*Response )( Event *event ); + +template< class Type > +struct ResponseDef + { + Event *event; + void ( Type::*response )( Event *event ); + }; + +/*********************************************************************** + + ClassDef + +***********************************************************************/ + +class ClassDef + { + public: + const char *classname; + const char *classID; + const char *superclass; + void *( *newInstance )( void ); + int classSize; + ResponseDef *responses; + int numEvents; + Response **responseLookup; + ClassDef *super; + ClassDef *next; + ClassDef *prev; + + ClassDef(); + ~ClassDef(); + ClassDef( const char *classname, const char *classID, const char *superclass, + ResponseDef *responses, void *( *newInstance )( void ), int classSize ); + void BuildResponseList( void ); + void Shutdown( void ); + }; + +/*********************************************************************** + + SafePtr + +***********************************************************************/ + +class SafePtrBase; + +class Class; + +class SafePtrBase + { + private: + void AddReference( Class *ptr ); + void RemoveReference( Class *ptr ); + + protected: + SafePtrBase *prevSafePtr; + SafePtrBase *nextSafePtr; + Class *ptr; + + public: + SafePtrBase(); + virtual ~SafePtrBase(); + void InitSafePtr( Class *newptr ); + Class *Pointer( void ); + void Clear( void ); + }; + +/*********************************************************************** + + Class + +***********************************************************************/ + +#define CLASS_DECLARATION( nameofsuperclass, nameofclass, classid ) \ + ClassDef nameofclass::ClassInfo \ + ( \ + #nameofclass, classid, #nameofsuperclass, \ + ( ResponseDef * )nameofclass::Responses, \ + nameofclass::_newInstance, sizeof( nameofclass ) \ + ); \ + void *nameofclass::_newInstance( void ) \ + { \ + return new nameofclass; \ + } \ + ClassDef *nameofclass::classinfo( void ) \ + { \ + return &( nameofclass::ClassInfo ); \ + } \ + ResponseDef nameofclass::Responses[] = + +#define CLASS_PROTOTYPE( nameofclass ) \ + public: \ + static ClassDef ClassInfo; \ + static void *_newInstance( void ); \ + virtual ClassDef *classinfo( void ); \ + static ResponseDef Responses[] + +class Class + { + private: + SafePtrBase *SafePtrList; + friend class SafePtrBase; + + protected: + void ClearSafePointers( void ); + + public: + CLASS_PROTOTYPE( Class ); + void * operator new( size_t ); + void operator delete( void * ); + + Class(); + virtual ~Class(); + void warning( const char *function, const char *fmt, ... ); + void error( const char *function, const char *fmt, ... ); + qboolean inheritsFrom( ClassDef *c ); + qboolean inheritsFrom( const char *name ); + qboolean isInheritedBy( const char *name ); + qboolean isInheritedBy( ClassDef *c ); + const char *getClassname( void ); + const char *getClassID( void ); + const char *getSuperclass( void ); + void *newInstance( void ); + +#ifdef GAME_DLL + virtual void Archive( Archiver &arc ); +#endif + }; + +void BuildEventResponses( void ); +ClassDef *getClassForID( const char *name ); +ClassDef *getClass( const char *name ); +ClassDef *getClassList( void ); +void listAllClasses( void ); +void listInheritanceOrder( const char *classname ); +qboolean checkInheritance( ClassDef *superclass, ClassDef *subclass ); +qboolean checkInheritance( ClassDef *superclass, const char *subclass ); +qboolean checkInheritance( const char *superclass, const char *subclass ); +void DisplayMemoryUsage( void ); +void ClassEvents( const char *classname, qboolean dump = qfalse ); +void DumpAllClasses( void ); + +inline qboolean Class::inheritsFrom + ( + ClassDef *c + ) + + { + return checkInheritance( c, classinfo() ); + } + +inline qboolean Class::isInheritedBy + ( + ClassDef *c + ) + + { + return checkInheritance( classinfo(), c ); + } + +// The lack of a space between the ")" and "inheritsFrom" is intentional. +// It allows the macro to compile like a function call. However, this +// may cause problems in some compilers (like gcc), so we may have to +// change this to work like a normal macro with the object passed in +// as a parameter to the macro. +#define isSubclassOf( classname )inheritsFrom( &classname::ClassInfo ) +#define isSuperclassOf( classname )isInheritedBy( &classname::ClassInfo ) + +/*********************************************************************** + + SafePtr + +***********************************************************************/ + +inline void SafePtrBase::AddReference + ( + Class *ptr + ) + + { + if ( !ptr->SafePtrList ) + { + ptr->SafePtrList = this; + LL_Reset( this, nextSafePtr, prevSafePtr ); + } + else + { + LL_Add( ptr->SafePtrList, this, nextSafePtr, prevSafePtr ); + } + } + +inline void SafePtrBase::RemoveReference + ( + Class *ptr + ) + + { + if ( ptr->SafePtrList == this ) + { + if ( ptr->SafePtrList->nextSafePtr == this ) + { + ptr->SafePtrList = NULL; + } + else + { + ptr->SafePtrList = nextSafePtr; + LL_Remove( this, nextSafePtr, prevSafePtr ); + } + } + else + { + LL_Remove( this, nextSafePtr, prevSafePtr ); + } + } + +inline void SafePtrBase::Clear + ( + void + ) + + { + if ( ptr ) + { + RemoveReference( ptr ); + ptr = NULL; + } + } + +inline SafePtrBase::SafePtrBase() + { + prevSafePtr = NULL; + nextSafePtr = NULL; + ptr = NULL; + } + +inline SafePtrBase::~SafePtrBase() + { + Clear(); + } + +inline Class * SafePtrBase::Pointer + ( + void + ) + + { + return ptr; + } + +inline void SafePtrBase::InitSafePtr + ( + Class *newptr + ) + + { + if ( ptr != newptr ) + { + if ( ptr ) + { + RemoveReference( ptr ); + } + + ptr = newptr; + if ( ptr == NULL ) + { + return; + } + + AddReference( ptr ); + } + } + +template +class SafePtr : public SafePtrBase + { + public: + SafePtr( T* objptr = 0 ); + SafePtr( const SafePtr& obj ); + + SafePtr& operator=( const SafePtr& obj ); + SafePtr& operator=( T * const obj ); + + friend int operator==( SafePtr a, T *b ); + friend int operator!=( SafePtr a, T *b ); + friend int operator==( T *a, SafePtr b ); + friend int operator!=( T *a, SafePtr b ); + + operator T*() const; + T* operator->() const; + T& operator*() const; + }; + +template +inline SafePtr::SafePtr( T* objptr ) + { + InitSafePtr( objptr ); + } + +template +inline SafePtr::SafePtr( const SafePtr& obj ) + { + InitSafePtr( obj.ptr ); + } + +template +inline SafePtr& SafePtr::operator=( const SafePtr& obj ) + { + InitSafePtr( obj.ptr ); + return *this; + } + +template +inline SafePtr& SafePtr::operator=( T * const obj ) + { + InitSafePtr( obj ); + return *this; + } + +template +inline int operator== + ( + SafePtr a, + T* b + ) + + { + return a.ptr == b; + } + +template +inline int operator!= + ( + SafePtr a, + T* b + ) + + { + return a.ptr != b; + } + +template +inline int operator== + ( + T* a, + SafePtr b + ) + + { + return a == b.ptr; + } + +template +inline int operator!= + ( + T* a, + SafePtr b + ) + + { + return a != b.ptr; + } + +template +inline SafePtr::operator T*() const + { + return ( T * )ptr; + } + +template +inline T* SafePtr::operator->() const + { + return ( T * )ptr; + } + +template +inline T& SafePtr::operator*() const + { + return *( T * )ptr; + } + +typedef SafePtr ClassPtr; + +#ifdef GAME_DLL +#include "archive.h" +#endif + +// used by listener for event allocation +extern int totalmemallocated; + +#ifndef GAME_DLL +extern "C" + { + // interface functions + void ShutdownClasses( void ); + } +#endif + +#endif /* class.h */ diff --git a/source/source/fgame/clusterbomb.cpp b/source/source/fgame/clusterbomb.cpp new file mode 100644 index 0000000..a35aa07 --- /dev/null +++ b/source/source/fgame/clusterbomb.cpp @@ -0,0 +1,143 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/clusterbomb.cpp $ +// $Revision:: 5 $ +// $Author:: Steven $ +// $Date:: 6/29/00 2:03p $ +// +// Copyright (C) 1998 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/clusterbomb.cpp $ +// +// 5 6/29/00 2:03p Steven +// Improved cluster bombs a little. +// +// 4 6/23/00 8:41p Markd +// made a lot of changes to different constructors for saved game support +// +// 3 6/08/00 6:26p Aldie +// Put in the explode anim +// +// 2 6/07/00 4:16p Aldie +// Added clusterbombs, heatseeking, and drunk +// +// DESCRIPTION: +// Clusterbomb + +#include "clusterbomb.h" + +Event EV_ClusterBomb_Think + ( + "_think", + EV_DEFAULT, + NULL, + NULL, + "Clusterbomb think function" + ); +Event EV_ClusterBomb_ClusterModel + ( + "clustermodel", + EV_DEFAULT, + "s", + "modelname", + "The model of the bombs that are spawned when the main bomb explodes" + ); +Event EV_ClusterBomb_ClusterCount + ( + "clustercount", + EV_DEFAULT, + "i", + "count", + "The number of clusters to spawn" + ); + +CLASS_DECLARATION( Projectile, ClusterBomb, NULL ) + { + { &EV_ClusterBomb_Think, Think }, + { &EV_ClusterBomb_ClusterCount, ClusterCount }, + { &EV_ClusterBomb_ClusterModel, ClusterModel }, + { NULL, NULL } + }; + +ClusterBomb::ClusterBomb + ( + ) + + { + if ( LoadingSavegame ) + { + return; + } + + m_clustercount = 5; + // Make the clusterbomb think each frame + PostEvent( EV_ClusterBomb_Think, level.frametime ); + } + +void ClusterBomb::Think + ( + Event *ev + ) + + { + CancelEventsOfType( EV_ClusterBomb_Think ); + PostEvent( EV_ClusterBomb_Think, level.frametime ); + + // Explode if we start moving down + if ( velocity.z < 0 ) + { + Explode( NULL ); + } + } + +void ClusterBomb::ClusterModel + ( + Event *ev + ) + + { + m_clustermodel = ev->GetString( 1 ); + } + +void ClusterBomb::ClusterCount + ( + Event *ev + ) + + { + m_clustercount = ev->GetInteger( 1 ); + } + +void ClusterBomb::Explode + ( + Event *ev + ) + + { + int i; + Vector dir; + + CancelEventsOfType( EV_ClusterBomb_Think ); + + // Spawn clusters from the point of explosion + for ( i=0; iorigin, dir, this, m_clustermodel, 1.0, velocity.length() ); + } + + velocity = Vector( 0,0,0 ); + setMoveType( MOVETYPE_NONE ); + RandomAnimate( "explode" ); + + PostEvent( EV_Remove, 1 ); + } diff --git a/source/source/fgame/clusterbomb.h b/source/source/fgame/clusterbomb.h new file mode 100644 index 0000000..191ebb0 --- /dev/null +++ b/source/source/fgame/clusterbomb.h @@ -0,0 +1,63 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/clusterbomb.h $ +// $Revision:: 4 $ +// $Author:: Aldie $ +// $Date:: 7/14/00 10:42a $ +// +// Copyright (C) 1998 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/clusterbomb.h $ +// +// 4 7/14/00 10:42a Aldie +// Added archive function +// +// 3 6/14/00 3:50p Markd +// Cleaned up more Intel Compiler warnings +// +// 2 6/07/00 4:16p Aldie +// Added clusterbombs, heatseeking, and drunk +// +// DESCRIPTION: +// Clusterbomb + +#ifndef __CLUSTERBOMB_H__ +#define __CLUSTERBOMB_H__ + +#include "weapon.h" +#include "weaputils.h" + +class ClusterBomb : public Projectile + { + private: + str m_clustermodel; + int m_clustercount; + + public: + CLASS_PROTOTYPE( ClusterBomb ); + + ClusterBomb(); + void Explode( Event *ev ); + void Think( Event *ev ); + void ClusterModel( Event *ev ); + void ClusterCount( Event *ev ); + + virtual void Archive( Archiver &arc ); + }; + +inline void ClusterBomb::Archive + ( + Archiver &arc + ) + { + Projectile::Archive( arc ); + + arc.ArchiveInteger( &m_clustercount ); + arc.ArchiveString( &m_clustermodel ); + } + +#endif // __CLUSTERBOMB_H__ diff --git a/source/source/fgame/container.cpp b/source/source/fgame/container.cpp new file mode 100644 index 0000000..1cd829d --- /dev/null +++ b/source/source/fgame/container.cpp @@ -0,0 +1,243 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/cgame/container.cpp $ +// $Revision:: 2 $ +// $Author:: Markd $ +// $Date:: 10/05/99 2:03p $ +// +// Copyright (C) 1997 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source is may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/cgame/container.cpp $ +// +// 2 10/05/99 2:03p Markd +// Added warning about files being in multiple projects +// +// 1 9/10/99 10:53a Jimdose +// +// 1 9/08/99 3:15p Aldie +// +// DESCRIPTION: +// Base class for a dynamic array. Allows adding, removing, index of, +// and finding of entries with specified value. Originally created for +// cataloging entities, but pointers to objects that may be removed at +// any time are bad to keep around, so only entity numbers should be +// used in the future. +// +// WARNING: This file is shared between fgame, cgame and possibly the user interface. +// It is instanced in each one of these directories because of the way that SourceSafe works. +// + +#if 0 + +#include "g_local.h" +#include "class.h" +#include "container.h" + +template< class Type > +Container::Container() + { + objlist = NULL; + FreeObjectList(); + } + +template< class Type > +Container::~Container() + { + FreeObjectList(); + } + +template< class Type > +void Container::FreeObjectList + ( + void + ) + + { + if ( objlist ) + { + delete objlist; + } + objlist = NULL; + numobjects = 0; + maxobjects = 0; + } + +template< class Type > +void Container::ClearObjectList + ( + void + ) + + { + if ( objlist ) + { + memset( objlist, 0, maxobjects * sizeof( Type ) ); + } + numobjects = 0; + } + +template< class Type > +int Container::NumObjects + ( + void + ) + + { + return numobjects; + } + +template< class Type > +void Container::Resize + ( + int maxelements + ) + + { + Type *temp; + + if ( !objlist ) + { + maxobjects = maxelements; + objlist = new Type[ maxobjects ]; + memset( objlist, 0, maxobjects * sizeof( Type ) ); + } + else + { + temp = objlist; + maxobjects = maxelements; + if ( maxobjects < numobjects ) + { + maxobjects = numobjects; + } + + objlist = new Type[ maxobjects ]; + memset( objlist, 0, maxobjects * sizeof( Type ) ); + memcpy( objlist, temp, numobjects * sizeof( Type ) ); + delete temp; + } + } + +template< class Type > +void Container::AddObject + ( + Type obj + ) + + { + Type *temp; + + if ( !objlist ) + { + Resize( 10 ); + } + + if ( numobjects == maxobjects ) + { + Resize( maxobjects * 2 ); + } + + objlist[ numobjects++ ] = obj; + } + +template< class Type > +int Container::IndexOfObject + ( + Type obj + ) + + { + int i; + + for( i = 0; i < numobjects; i++ ) + { + if ( objlist[ i ] == obj ) + { + return i + 1; + } + } + + return 0; + } + +template< class Type > +qboolean Container::ObjectInList + ( + Type obj + ) + + { + if ( !IndexOfObject( obj ) ) + { + return false; + } + + return true; + } + +template< class Type > +Type Container::ObjectAt + ( + int index + ) + + { + if ( ( index <= 0 ) || ( index > numobjects ) ) + { + gi.DPrintf( "Container::ObjectAt : index out of range" ); + return 0; + } + + return objlist[ index - 1 ]; + } + +template< class Type > +void Container::RemoveObjectAt + ( + int index + ) + + { + int i; + + if ( !objlist ) + { + gi.DPrintf( "Container::RemoveObjectAt : Empty list" ); + return; + } + + if ( ( index <= 0 ) || ( index > numobjects ) ) + { + gi.DPrintf( "Container::RemoveObjectAt : index out of range" ); + return; + } + + i = index - 1; + memcpy( &objlist[ i ], &objlist[ i + 1 ], ( numobjects - 1 - i ) * sizeof( Type ) ); + memset( &objlist[ numobjects - 1 ], 0, sizeof( Type ) ); + numobjects--; + } + +template< class Type > +void Container::RemoveObject + ( + Type obj + ) + + { + int index; + + index = IndexOfObject( obj ); + if ( !index ) + { + gi.DPrintf( "Container::RemoveObject : Object not in list" ); + return; + } + + RemoveObjectAt( index ); + } + +#endif \ No newline at end of file diff --git a/source/source/fgame/container.h b/source/source/fgame/container.h new file mode 100644 index 0000000..8cc7518 --- /dev/null +++ b/source/source/fgame/container.h @@ -0,0 +1,538 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/container.h $ +// $Revision:: 9 $ +// $Author:: Steven $ +// $Date:: 7/26/00 1:08p $ +// +// Copyright (C) 1997 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source is may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/container.h $ +// +// 9 7/26/00 1:08p Steven +// In ClearObjectList make sure we don't have 0 maxelements when creating a new +// array. +// +// 8 7/25/00 2:32p Aldie +// Undo checkout for new operator +// +// 7 7/25/00 2:18p Aldie +// changed the new operator for containers +// +// 6 5/26/00 7:44p Markd +// 2nd phase save games +// +// 5 1/06/00 11:18p Jimdose +// put sort back in +// +// 4 1/06/00 11:08p Jimdose +// cleaning up unused code +// +// 3 10/05/99 2:03p Markd +// Added warning about files being in multiple projects +// +// 2 9/28/99 4:26p Markd +// merged listener, class and vector between 3 projects +// +// 1 9/10/99 10:53a Jimdose +// +// 1 9/08/99 3:15p Aldie +// +// DESCRIPTION: +// Base class for a dynamic array. Allows adding, removing, index of, +// and finding of entries with specified value. NOTE: indices in container +// are 1 based, not 0. This means that loops must check from 1 up to and including +// NumObjects() (ei. for( i = 1; i <= list.NumObjects(); i++ ) ). +// +// FIXME: Someday make this 0 based and update all code to match. +// +// WARNING: This file is shared between fgame, cgame and possibly the user interface. +// It is instanced in each one of these directories because of the way that SourceSafe works. +// + +#ifndef __CONTAINER_H__ +#define __CONTAINER_H__ + +#if defined( GAME_DLL ) +// +// game dll specific defines +// +#include "g_local.h" + +#define CONTAINER_Error gi.Error +#define CONTAINER_DPrintf gi.DPrintf + +#elif defined ( CGAME_DLL ) +// +// cgame dll specific defines +// +#define CONTAINER_Error cgi.Error +#define CONTAINER_DPrintf cgi.DPrintf + +#else + +// +// client specific defines +// +#define CONTAINER_Error Com_Error +#define CONTAINER_DPrintf Com_DPrintf +#endif + +#include + +class Archiver; +template< class Type > +class Container + { + private: + Type *objlist; + int numobjects; + int maxobjects; + + public: + Container(); + ~Container(); + + void FreeObjectList( void ); + void ClearObjectList( void ); + int NumObjects( void ); + void Resize( int maxelements ); + void SetObjectAt( int index, Type& obj ); + int AddObject( Type& obj ); + int AddUniqueObject( Type& obj ); + void AddObjectAt( int index, Type& obj ); + int IndexOfObject( Type& obj ); + qboolean ObjectInList( Type& obj ); + Type& ObjectAt( int index ); + Type *AddressOfObjectAt( int index ); + void RemoveObjectAt( int index ); + void RemoveObject( Type& obj ); + void Sort( int ( __cdecl *compare )( const void *elem1, const void *elem2 ) ); +#if defined( GAME_DLL ) + void Archive( Archiver &arc ); +#endif + }; + +template< class Type > +Container::Container() + { + objlist = NULL; + FreeObjectList(); + } + +template< class Type > +Container::~Container() + { + FreeObjectList(); + } + +template< class Type > +void Container::FreeObjectList + ( + void + ) + + { + if ( objlist ) + { + delete[] objlist; + } + objlist = NULL; + numobjects = 0; + maxobjects = 0; + } + +template< class Type > +void Container::ClearObjectList + ( + void + ) + + { + // only delete the list if we have objects in it + if ( objlist && numobjects ) + { + delete[] objlist; + + if ( maxobjects == 0 ) + { + objlist = NULL; + return; + } + + objlist = new Type[ maxobjects ]; + numobjects = 0; + } + } + +template< class Type > +int Container::NumObjects + ( + void + ) + + { + return numobjects; + } + +template< class Type > +void Container::Resize + ( + int maxelements + ) + + { + Type *temp; + int i; + + assert( maxelements >= 0 ); + + if ( maxelements <= 0 ) + { + FreeObjectList(); + return; + } + + if ( !objlist ) + { + maxobjects = maxelements; + objlist = new Type[ maxobjects ]; + } + else + { + temp = objlist; + maxobjects = maxelements; + if ( maxobjects < numobjects ) + { + maxobjects = numobjects; + } + + objlist = new Type[ maxobjects ]; + for( i = 0; i < numobjects; i++ ) + { + objlist[ i ] = temp[ i ]; + } + delete[] temp; + } + } + +template< class Type > +void Container::SetObjectAt + ( + int index, + Type& obj + ) + + { + if ( ( index <= 0 ) || ( index > numobjects ) ) + { + CONTAINER_Error( ERR_DROP, "Container::SetObjectAt : index out of range" ); + } + + objlist[ index - 1 ] = obj; + } + +template< class Type > +int Container::AddObject + ( + Type& obj + ) + + { + if ( !objlist ) + { + Resize( 10 ); + } + + if ( numobjects == maxobjects ) + { + Resize( maxobjects * 2 ); + } + + objlist[ numobjects ] = obj; + numobjects++; + + return numobjects; + } + +template< class Type > +int Container::AddUniqueObject + ( + Type& obj + ) + + { + int index; + + index = IndexOfObject( obj ); + if ( !index ) + index = AddObject( obj ); + return index; + } + +template< class Type > +void Container::AddObjectAt + ( + int index, + Type& obj + ) + + { + // + // this should only be used when reconstructing a list that has to be identical to the original + // + if ( index > maxobjects ) + { + Resize( index ); + } + if ( index > numobjects ) + { + numobjects = index; + } + SetObjectAt( index, obj ); + } + +template< class Type > +int Container::IndexOfObject + ( + Type& obj + ) + + { + int i; + + for( i = 0; i < numobjects; i++ ) + { + if ( objlist[ i ] == obj ) + { + return i + 1; + } + } + + return 0; + } + +template< class Type > +qboolean Container::ObjectInList + ( + Type& obj + ) + + { + if ( !IndexOfObject( obj ) ) + { + return false; + } + + return true; + } + +template< class Type > +Type& Container::ObjectAt + ( + int index + ) + + { + if ( ( index <= 0 ) || ( index > numobjects ) ) + { + CONTAINER_Error( ERR_DROP, "Container::ObjectAt : index out of range" ); + } + + return objlist[ index - 1 ]; + } + +template< class Type > +Type * Container::AddressOfObjectAt + ( + int index + ) + + { + // + // this should only be used when reconstructing a list that has to be identical to the original + // + if ( index > maxobjects ) + { + CONTAINER_Error( ERR_DROP, "Container::AddressOfObjectAt : index is greater than maxobjects" ); + } + if ( index > numobjects ) + { + numobjects = index; + } + return &objlist[ index - 1 ]; + } + +template< class Type > +void Container::RemoveObjectAt + ( + int index + ) + + { + int i; + + if ( !objlist ) + { + CONTAINER_DPrintf( "Container::RemoveObjectAt : Empty list\n" ); + return; + } + + if ( ( index <= 0 ) || ( index > numobjects ) ) + { + CONTAINER_Error( ERR_DROP, "Container::RemoveObjectAt : index out of range" ); + return; + } + + i = index - 1; + numobjects--; + for( i = index - 1; i < numobjects; i++ ) + { + objlist[ i ] = objlist[ i + 1 ]; + } + } + +template< class Type > +void Container::RemoveObject + ( + Type& obj + ) + + { + int index; + + index = IndexOfObject( obj ); + if ( !index ) + { + CONTAINER_DPrintf( "Container::RemoveObject : Object not in list\n" ); + return; + } + + RemoveObjectAt( index ); + } + +template< class Type > +void Container::Sort + ( + int ( __cdecl *compare )( const void *elem1, const void *elem2 ) + ) + + { + if ( !objlist ) + { + CONTAINER_DPrintf( "Container::Sort : Empty list\n" ); + return; + } + + qsort( ( void * )objlist, ( size_t )numobjects, sizeof( Type ), compare ); + } + +#if 0 +#if defined( GAME_DLL ) + +#include "str.h" +void Container::Archive + ( + Archiver &arc + ) + { + int i, num; + + if ( arc.Loading() ) + { + ClearObjectList(); + arc.ArchiveInteger( &num ); + Resize( num ); + } + else + { + num = numobjects; + arc.ArchiveInteger( &num ); + } + for( i = 1; i <= num; i++ ) + { + arc.ArchiveString( AddressOfObjectAt( i ) ); + } + } + +#include "vector.h" +void Container::Archive + ( + Archiver &arc + ) + { + int i, num; + + if ( arc.Loading() ) + { + ClearObjectList(); + arc.ArchiveInteger( &num ); + Resize( num ); + } + else + { + num = numobjects; + arc.ArchiveInteger( &num ); + } + for( i = 1; i <= num; i++ ) + { + arc.ArchiveVector( AddressOfObjectAt( i ) ); + } + } + +void Container::Archive + ( + Archiver &arc + ) + { + int i, num; + + if ( arc.Loading() ) + { + ClearObjectList(); + arc.ArchiveInteger( &num ); + Resize( num ); + } + else + { + num = numobjects; + arc.ArchiveInteger( &num ); + } + for( i = 1; i <= num; i++ ) + { + arc.ArchiveInteger( AddressOfObjectAt( i ) ); + } + } + +void Container::Archive + ( + Archiver &arc + ) + { + int i, num; + + if ( arc.Loading() ) + { + ClearObjectList(); + arc.ArchiveInteger( &num ); + Resize( num ); + } + else + { + num = numobjects; + arc.ArchiveInteger( &num ); + } + for( i = 1; i <= num; i++ ) + { + arc.ArchiveFloat( AddressOfObjectAt( i ) ); + } + } + +#endif +#endif + +#endif /* container.h */ diff --git a/source/source/fgame/crossbow.cpp b/source/source/fgame/crossbow.cpp new file mode 100644 index 0000000..4689952 --- /dev/null +++ b/source/source/fgame/crossbow.cpp @@ -0,0 +1,93 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/crossbow.cpp $ +// $Revision:: 3 $ +// $Author:: Aldie $ +// $Date:: 4/08/00 2:49p $ +// +// Copyright (C) 1998 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/crossbow.cpp $ +// +// 3 4/08/00 2:49p Aldie +// New crossbow bolt implementation +// +// 2 4/08/00 11:53a Aldie +// First version +// +// DESCRIPTION: +// Crossbow projectile + +#include "crossbow.h" +#include "decals.h" + +CLASS_DECLARATION( Projectile, CrossbowProjectile, NULL ) + { + { NULL, NULL } + }; + +CrossbowProjectile::CrossbowProjectile + ( + ) + + { + } + +void CrossbowProjectile::DoDecal + ( + void + ) + + { + float scale=1; + + if ( charge_fraction < 0.3 ) + { + scale = .3; + } + else if ( charge_fraction > 0.6 ) + { + scale = 1.5; + } + + if ( impactmarkshader.length() ) + { + Decal *decal = new Decal; + decal->setShader( impactmarkshader ); + decal->setOrigin( level.impact_trace.endpos ); + decal->setDirection( level.impact_trace.plane.normal ); + decal->setOrientation( impactmarkorientation ); + decal->setRadius( impactmarkradius * scale ); + } + } + +void CrossbowProjectile::Explode + ( + Event *ev + ) + + { + Entity *owner; + + // Get the owner of this projectile + owner = G_GetEntity( this->owner ); + + // If the owner's not here, make the world the owner + if ( !owner ) + owner = world; + + // When a crossbow bolt explodes, depending on the charge time it may explode + if ( explosionmodel.length() && charge_fraction > 0.3 ) + { + if ( charge_fraction > 0.6 ) + ExplosionAttack( origin, owner, explosionmodel, Vector( 0,0,0 ), NULL, 1.5 ); + else + ExplosionAttack( origin, owner, explosionmodel, Vector( 0,0,0 ), NULL ); + } + + PostEvent( EV_Remove, 0 ); + } diff --git a/source/source/fgame/crossbow.h b/source/source/fgame/crossbow.h new file mode 100644 index 0000000..b61f2df --- /dev/null +++ b/source/source/fgame/crossbow.h @@ -0,0 +1,46 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/crossbow.h $ +// $Revision:: 4 $ +// $Author:: Markd $ +// $Date:: 6/14/00 3:50p $ +// +// Copyright (C) 1998 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/crossbow.h $ +// +// 4 6/14/00 3:50p Markd +// Cleaned up more Intel Compiler warnings +// +// 3 4/08/00 2:49p Aldie +// New crossbow bolt implementation +// +// 2 4/08/00 11:53a Aldie +// First version +// +// DESCRIPTION: +// Crossbow projectile + +#ifndef __CROSSBOW_H__ +#define __CROSSBOW_H__ + +#include "weapon.h" +#include "weaputils.h" + +class CrossbowProjectile : public Projectile + { + public: + CLASS_PROTOTYPE( CrossbowProjectile ); + + CrossbowProjectile(); + void Explode( Event *ev ); + void DoDecal( void ); + + }; + +#endif // __CROSSBOW_H__ + diff --git a/source/source/fgame/deadbody.cpp b/source/source/fgame/deadbody.cpp new file mode 100644 index 0000000..3765fcb --- /dev/null +++ b/source/source/fgame/deadbody.cpp @@ -0,0 +1,112 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/deadbody.cpp $ +// $Revision:: 4 $ +// $Author:: Jimdose $ +// $Date:: 12/17/99 6:35p $ +// +// Copyright (C) 1998 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source is may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/deadbody.cpp $ +// +// 4 12/17/99 6:35p Jimdose +// changed spawnarg code +// added Level class for spawning and map control +// got rid of unused or superflous variables +// changed setjmp/longjmp calls to try/throw/catch exception handling +// +// 3 9/16/99 11:18a Markd +// Continuing merge of code, not functional yet but closer +// +// 2 9/13/99 4:22p Jimdose +// merge +// +// 1 9/10/99 10:53a Jimdose +// +// 1 9/08/99 3:15p Aldie +// +// DESCRIPTION: +// Dead body + +#include "deadbody.h" +#include "gibs.h" + +CLASS_DECLARATION( Sentient, Deadbody, "deadbody" ) + { + { &EV_Gib, GibEvent }, + { NULL, NULL } + }; + +void Deadbody::GibEvent + ( + Event *ev + ) + + { + takedamage = DAMAGE_NO; + + if ( sv_gibs->integer && !parentmode->integer ) + { + setSolidType( SOLID_NOT ); + hideModel(); + + CreateGibs( this, health, 1.0f, 3 ); + } + } + +void CopyToBodyQueue + ( + gentity_t *ent + ) + + { + gentity_t *body; + + // grab a body from the queue and cycle to the next one + body = &g_entities[ ( int )maxclients->integer + level.body_queue ]; + level.body_queue = ( level.body_queue + 1 ) % BODY_QUEUE_SIZE; + + gi.unlinkentity( ent ); + gi.unlinkentity( body ); + + body->s = ent->s; + body->s.number = body - g_entities; + body->svflags = ent->svflags; + body->solid = ent->solid; + body->clipmask = ent->clipmask; + body->ownerNum = ent->ownerNum; + body->entity->movetype = ent->entity->movetype; + body->entity->takedamage = DAMAGE_YES; + body->entity->deadflag = DEAD_DEAD; + body->s.renderfx &= ~RF_DONTDRAW; + body->entity->setOrigin( ent->entity->origin ); + body->entity->setSize(ent->mins,ent->maxs); + body->entity->link(); +// body->entity->SetGravityAxis( ent->entity->gravaxis ); + } + +void InitializeBodyQueue + ( + void + ) + + { + int i; + Deadbody *body; + + if ( !LoadingSavegame && deathmatch->integer ) + { + level.body_queue = 0; + for ( i=0; iedict->ownerNum = ENTITYNUM_NONE; + body->edict->s.skinNum = -1; + body->flags |= (FL_DIE_GIBS|FL_BLOOD); + } + } + } \ No newline at end of file diff --git a/source/source/fgame/deadbody.h b/source/source/fgame/deadbody.h new file mode 100644 index 0000000..283b272 --- /dev/null +++ b/source/source/fgame/deadbody.h @@ -0,0 +1,42 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/deadbody.h $ +// $Revision:: 1 $ +// $Author:: Jimdose $ +// $Date:: 9/10/99 10:53a $ +// +// Copyright (C) 1998 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source is may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/deadbody.h $ +// +// 1 9/10/99 10:53a Jimdose +// +// 1 9/08/99 3:15p Aldie +// +// DESCRIPTION: +// Dead body + +#ifndef __DEADBODY_H__ +#define __DEADBODY_H__ + +#include "g_local.h" +#include "sentient.h" + +#define BODY_QUEUE_SIZE 4 + +void InitializeBodyQueue( void ); +void CopyToBodyQueue( gentity_t *ent ); + +class Deadbody : public Sentient + { + public: + CLASS_PROTOTYPE( Deadbody ); + + virtual void GibEvent( Event *ev ); + }; + +#endif /* deadbody.h */ \ No newline at end of file diff --git a/source/source/fgame/debuglines.cpp b/source/source/fgame/debuglines.cpp new file mode 100644 index 0000000..4f9d0bb --- /dev/null +++ b/source/source/fgame/debuglines.cpp @@ -0,0 +1,793 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/debuglines.cpp $ +// $Revision:: 8 $ +// $Date:: 3/15/00 2:04p $ +// +// Copyright (C) 1999 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source is may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/debuglines.cpp $ +// +// 8 3/15/00 2:04p Markd +// fixed up camera node system and added new debug oriented circle +// +// 7 3/03/00 4:17p Markd +// Fixed bug in highlight facet +// +// 6 3/02/00 6:04p Markd +// Added Debug Arrow and DebugHighlightFacet +// +// 5 2/09/00 9:54a Markd +// Made debuglines be malloced from the normal heap rather than the game heap +// so that they don't interfere with the game's memory footprint. +// +// 4 1/22/00 12:42p Jimdose +// got rid of calls to vec3() +// +// 3 1/10/00 5:27p Markd +// Added DeallocDebugLines +// +// 2 1/06/00 11:08p Jimdose +// cleaning up unused code +// +// DESCRIPTION: +// + +#include "debuglines.h" + +#define NUM_CIRCLE_SEGMENTS 24 + +debugline_t *DebugLines = NULL; +Vector currentVertex( 0, 0, 0 ); +Vector vertColor( 1, 1, 1 ); +float vertAlpha = 1; +float vertexIndex = 0; +float linewidth = 1; +unsigned short lineStippleFactor = 1; +unsigned short linePattern = 0xffff; + +void G_InitDebugLines + ( + void + ) + + { + *gi.DebugLines = DebugLines; + *gi.numDebugLines = 0; + + currentVertex = vec_zero; + vertColor = Vector( 1, 1, 1 ); + vertAlpha = 1; + vertexIndex = 0; + + linewidth = 1; + lineStippleFactor = 1; + linePattern = 0xffff; + } + +void G_AllocDebugLines + ( + void + ) + + { + // we do a malloc here so that we don't interfere with the game's memory footprint + DebugLines = ( debugline_t * )malloc( ( int )g_numdebuglines->integer * sizeof( debugline_t ) ); + + G_InitDebugLines(); + } + +void G_DeAllocDebugLines + ( + void + ) + + { + if ( DebugLines ) + { + // we do a free here, because we used malloc above + free( DebugLines ); + DebugLines = NULL; + *gi.DebugLines = DebugLines; + *gi.numDebugLines = 0; + } + } + +void G_DebugLine + ( + Vector start, + Vector end, + float r, + float g, + float b, + float alpha + ) + + { + debugline_t *line; + + if ( !g_numdebuglines ) + { + return; + } + + if ( *gi.numDebugLines >= g_numdebuglines->integer ) + { + gi.DPrintf( "G_DebugLine: Exceeded MAX_DEBUG_LINES\n" ); + return; + } + + line = &DebugLines[ *gi.numDebugLines ]; + ( *gi.numDebugLines )++; + + VectorCopy( start, line->start ); + VectorCopy( end, line->end ); + VectorSet( line->color, r, g, b ); + line->alpha = alpha; + + line->width = linewidth; + line->factor = lineStippleFactor; + line->pattern = linePattern; + } + +void G_LineStipple + ( + int factor, + unsigned short pattern + ) + + { + lineStippleFactor = factor; + linePattern = pattern; + } + +void G_LineWidth + ( + float width + ) + + { + linewidth = width; + } + +void G_Color3f + ( + float r, + float g, + float b + ) + + { + vertColor = Vector( r, g, b ); + } + +void G_Color3v + ( + Vector color + ) + + { + vertColor = color; + } + +void G_Color4f + ( + float r, + float g, + float b, + float alpha + ) + + { + vertColor = Vector( r, g, b ); + vertAlpha = alpha; + } + +void G_Color3vf + ( + Vector color, + float alpha + ) + + { + vertColor = color; + vertAlpha = alpha; + } + +void G_BeginLine + ( + void + ) + + { + currentVertex = vec_zero; + vertexIndex = 0; + } + +void G_Vertex + ( + Vector v + ) + + { + vertexIndex++; + if ( vertexIndex > 1 ) + { + G_DebugLine( currentVertex, v, vertColor[ 0 ], vertColor[ 1 ], vertColor[ 2 ], vertAlpha ); + } + currentVertex = v; + } + +void G_EndLine + ( + void + ) + + { + currentVertex = vec_zero; + vertexIndex = 0; + } + +void G_DebugBBox + ( + Vector org, + Vector mins, + Vector maxs, + float r, + float g, + float b, + float alpha + ) + { + int i; + Vector points[8]; + + /* + ** compute a full bounding box + */ + for ( i = 0; i < 8; i++ ) + { + Vector tmp; + + if ( i & 1 ) + tmp[0] = org[0] + mins[0]; + else + tmp[0] = org[0] + maxs[0]; + + if ( i & 2 ) + tmp[1] = org[1] + mins[1]; + else + tmp[1] = org[1] + maxs[1]; + + if ( i & 4 ) + tmp[2] = org[2] + mins[2]; + else + tmp[2] = org[2] + maxs[2]; + + points[i] = tmp; + } + + G_Color4f( r, g, b, alpha ); + + G_BeginLine(); + G_Vertex( points[0] ); + G_Vertex( points[1] ); + G_Vertex( points[3] ); + G_Vertex( points[2] ); + G_Vertex( points[0] ); + G_EndLine(); + + G_BeginLine(); + G_Vertex( points[4] ); + G_Vertex( points[5] ); + G_Vertex( points[7] ); + G_Vertex( points[6] ); + G_Vertex( points[4] ); + G_EndLine(); + + for ( i = 0; i < 4; i++ ) + { + G_BeginLine(); + G_Vertex( points[i] ); + G_Vertex( points[4 + i] ); + G_EndLine(); + } + } + +// +// LED style digits +// +// ****1*** +// * * 8 == / +// 6 *4 +// * * * +// ****2*** +// * * * +// 7 *--8 5 9 +// ** * **10 +// ****3*** 12** +// 11 + +static int Numbers[ 12 ][ 8 ] = + { + { 1, 3, 4, 5, 6, 7, 0, 0 }, // 0 + { 4, 5, 0, 0, 0, 0, 0, 0 }, // 1 + { 1, 4, 2, 7, 3, 0, 0, 0 }, // 2 + { 1, 4, 2, 5, 3, 0, 0, 0 }, // 3 + { 6, 4, 2, 5, 0, 0, 0, 0 }, // 4 + { 1, 6, 2, 5, 3, 0, 0, 0 }, // 5 + { 1, 6, 2, 5, 7, 3, 0, 0 }, // 6 + { 1, 8, 0, 0, 0, 0, 0, 0 }, // 7 + { 1, 2, 3, 4, 5, 6, 7, 0 }, // 8 + { 1, 6, 4, 2, 5, 3, 0, 0 }, // 9 + { 9, 10, 11, 12, 0, 0, 0, 0 }, // . + { 2, 0, 0, 0, 0, 0, 0, 0 }, // - + }; + +static float Lines[ 13 ][ 4 ] = + { + { 0, 0, 0, 0 }, // Unused + { -4, 8, 4, 8 }, // 1 + { -4, 4, 4, 4 }, // 2 + { -4, 0, 4, 0 }, // 3 + { 4, 8, 4, 4 }, // 4 + { 4, 4, 4, 0 }, // 5 + { -4, 8, -4, 4 }, // 6 + { -4, 4, -4, 0 }, // 7 + { 4, 8, -4, 0 }, // 8 + + { -1, 2, 1, 2 }, // 9 + { 1, 2, 1, 0 }, // 10 + { -1, 0, 1, 0 }, // 11 + { -1, 0, -1, 2 }, // 12 + }; + +void G_DrawDebugNumber + ( + Vector org, + float number, + float scale, + float r, + float g, + float b, + int precision + ) + + { + int i; + int j; + int l; + int num; + Vector up; + Vector left; + Vector pos; + Vector start; + Vector ang; + str text; + Vector delta; + char format[ 20 ]; + + // only draw entity numbers within a certain radius + delta = Vector( g_entities[ 0 ].s.origin ) - org; + if ( ( delta * delta ) > ( 1000 * 1000 ) ) + { + return; + } + + G_Color4f( r, g, b, 1.0 ); + + ang = game.clients[ 0 ].ps.viewangles; + ang.AngleVectors( NULL, &left, &up ); + + up *= scale; + left *= scale; + + if ( precision > 0 ) + { + sprintf( format, "%%.%df", precision ); + text = va( format, number ); + } + else + { + text = va( "%d", ( int )number ); + } + + start = org + ( text.length() - 1 ) * 5 * left; + + for( i = 0; i < text.length(); i++ ) + { + if ( text[ i ] == '.' ) + { + num = 10; + } + else if ( text[ i ] == '-' ) + { + num = 11; + } + else + { + num = text[ i ] - '0'; + } + + for( j = 0; j < 8; j++ ) + { + l = Numbers[ num ][ j ]; + if ( l == 0 ) + { + break; + } + + G_BeginLine(); + + pos = start - Lines[ l ][ 0 ] * left + Lines[ l ][ 1 ] * up; + G_Vertex( pos ); + + pos = start - Lines[ l ][ 2 ] * left + Lines[ l ][ 3 ] * up; + G_Vertex( pos ); + + G_EndLine(); + } + + start -= 10 * left; + } + } + +void G_DebugCircle + ( + Vector org, + float radius, + float r, + float g, + float b, + float alpha, + qboolean horizontal + ) + { + int i; + float ang; + Vector angles; + Vector forward; + Vector left; + Vector pos; + Vector delta; + + // only draw circles within a certain radius + delta = Vector( g_entities[ 0 ].s.origin ) - org; + if ( ( delta * delta ) > ( ( 1000 + radius ) * ( 1000 + radius ) ) ) + { + return; + } + + G_Color4f( r, g, b, alpha ); + + if ( horizontal ) + { + forward = "1 0 0"; + left = "0 -1 0"; + } + else + { + angles = game.clients[ 0 ].ps.viewangles; + angles.AngleVectors( NULL, &left, &forward ); + } + + G_BeginLine(); + for( i = 0; i <= NUM_CIRCLE_SEGMENTS; i++ ) + { + ang = DEG2RAD( i * 360 / NUM_CIRCLE_SEGMENTS ); + pos = org + ( sin( ang ) * radius * forward ) - ( cos( ang ) * radius * left ); + G_Vertex( pos ); + } + G_EndLine(); + } + +void G_DebugOrientedCircle + ( + Vector org, + float radius, + float r, + float g, + float b, + float alpha, + Vector angles + ) + { + int i; + float ang; + Vector forward; + Vector left; + Vector pos; + Vector delta; + + // only draw circles within a certain radius + delta = Vector( g_entities[ 0 ].s.origin ) - org; + if ( ( delta * delta ) > ( ( 1000 + radius ) * ( 1000 + radius ) ) ) + { + return; + } + + G_Color4f( r, g, b, alpha ); + + angles.AngleVectors( NULL, &left, &forward ); + + G_BeginLine(); + for( i = 0; i <= NUM_CIRCLE_SEGMENTS; i++ ) + { + ang = DEG2RAD( i * 360 / NUM_CIRCLE_SEGMENTS ); + pos = org + ( sin( ang ) * radius * forward ) - ( cos( ang ) * radius * left ); + G_Vertex( pos ); + } + G_EndLine(); + + // + // Draw the cross sign + // + G_BeginLine(); + ang = DEG2RAD( 45 * 360 / NUM_CIRCLE_SEGMENTS ); + pos = org + ( sin( ang ) * radius * forward ) - ( cos( ang ) * radius * left ); + G_Vertex( pos ); + ang = DEG2RAD( 225 * 360 / NUM_CIRCLE_SEGMENTS ); + pos = org + ( sin( ang ) * radius * forward ) - ( cos( ang ) * radius * left ); + G_Vertex( pos ); + + G_BeginLine(); + ang = DEG2RAD( 315 * 360 / NUM_CIRCLE_SEGMENTS ); + pos = org + ( sin( ang ) * radius * forward ) - ( cos( ang ) * radius * left ); + G_Vertex( pos ); + ang = DEG2RAD( 135 * 360 / NUM_CIRCLE_SEGMENTS ); + pos = org + ( sin( ang ) * radius * forward ) - ( cos( ang ) * radius * left ); + G_Vertex( pos ); + } + +void G_DebugPyramid + ( + Vector org, + float radius, + float r, + float g, + float b, + float alpha + ) + { + Vector delta; + Vector points[ 4 ]; + + // only draw pyramids within a certain radius + delta = Vector( g_entities[ 0 ].s.origin ) - org; + if ( ( delta * delta ) > ( ( 1000 + radius ) * ( 1000 + radius ) ) ) + { + return; + } + + G_Color4f( r, g, b, alpha ); + + points[ 0 ] = org; + points[ 0 ].z += radius; + + points[ 1 ] = org; + points[ 1 ].z -= radius; + points[ 2 ] = points[ 1 ]; + points[ 3 ] = points[ 1 ]; + + points[ 1 ].x += cos( DEG2RAD( 0 ) ) * radius; + points[ 1 ].y += sin( DEG2RAD( 0 ) ) * radius; + points[ 2 ].x += cos( DEG2RAD( 120 ) ) * radius; + points[ 2 ].y += sin( DEG2RAD( 120 ) ) * radius; + points[ 3 ].x += cos( DEG2RAD( 240 ) ) * radius; + points[ 3 ].y += sin( DEG2RAD( 240 ) ) * radius; + + G_BeginLine(); + G_Vertex( points[ 0 ] ); + G_Vertex( points[ 1 ] ); + G_Vertex( points[ 2 ] ); + G_Vertex( points[ 0 ] ); + G_EndLine(); + + G_BeginLine(); + G_Vertex( points[ 0 ] ); + G_Vertex( points[ 2 ] ); + G_Vertex( points[ 3 ] ); + G_Vertex( points[ 0 ] ); + G_EndLine(); + + G_BeginLine(); + G_Vertex( points[ 0 ] ); + G_Vertex( points[ 3 ] ); + G_Vertex( points[ 1 ] ); + G_Vertex( points[ 0 ] ); + G_EndLine(); + + G_BeginLine(); + G_Vertex( points[ 1 ] ); + G_Vertex( points[ 2 ] ); + G_Vertex( points[ 3 ] ); + G_Vertex( points[ 1 ] ); + G_EndLine(); + } + +void G_DrawCoordSystem + ( + Vector pos, + Vector forward, + Vector right, + Vector up, + int length + ) + + { + if ( g_showaxis->integer ) + { + G_DebugLine( pos, pos + forward * length, 1,0,0,1 ); + G_DebugLine( pos, pos + right * length, 0,1,0,1 ); + G_DebugLine( pos, pos + up * length, 0,0,1,1 ); + } + } + +void G_DrawCSystem + ( + void + ) + + { + Vector pos; + Vector ang; + Vector f; + Vector l; + Vector u; + Vector v; + + pos.x = csys_posx->value; + pos.y = csys_posy->value; + pos.z = csys_posz->value; + + ang.x = csys_x->value; + ang.y = csys_y->value; + ang.z = csys_z->value; + + ang.AngleVectors( &f, &l, &u ); + + G_DebugLine( pos, pos + f * 48, 1.0, 0, 0, 1 ); + G_DebugLine( pos, pos - l * 48, 0, 1.0, 0, 1 ); + G_DebugLine( pos, pos + u * 48, 0, 0, 1.0, 1 ); + } + +void G_DebugArrow + ( + Vector org, + Vector dir, + float length, + float r, + float g, + float b, + float alpha + ) + { + Vector right; + Vector up; + Vector startpoint; + Vector endpoint; + + PerpendicularVector( right, dir ); + up.CrossProduct( right, dir ); + + startpoint = org; + + endpoint = startpoint + dir * length; + length /= 6; + G_DebugLine( startpoint, endpoint, r, g, b, alpha ); + G_DebugLine( endpoint, endpoint - (right * length) - (dir * length), r, g, b, alpha ); + G_DebugLine( endpoint, endpoint + (right * length) - (dir * length), r, g, b, alpha ); + G_DebugLine( endpoint, endpoint - (up * length) - (dir * length), r, g, b, alpha ); + G_DebugLine( endpoint, endpoint + (up * length) - (dir * length), r, g, b, alpha ); + } + +void G_DebugHighlightFacet + ( + Vector org, + Vector mins, + Vector maxs, + facet_t facet, + float r, + float g, + float b, + float alpha + ) + { + int i; + Vector points[8]; + + /* + ** compute a full bounding box + */ + for ( i = 0; i < 8; i++ ) + { + Vector tmp; + + if ( i & 1 ) + tmp[0] = org[0] + mins[0]; + else + tmp[0] = org[0] + maxs[0]; + + if ( i & 2 ) + tmp[1] = org[1] + mins[1]; + else + tmp[1] = org[1] + maxs[1]; + + if ( i & 4 ) + tmp[2] = org[2] + mins[2]; + else + tmp[2] = org[2] + maxs[2]; + + points[i] = tmp; + } + + G_Color4f( r, g, b, alpha ); + + switch( facet ) + { + case north: + G_BeginLine(); + G_Vertex( points[0] ); + G_Vertex( points[5] ); + G_EndLine(); + G_BeginLine(); + G_Vertex( points[1] ); + G_Vertex( points[4] ); + G_EndLine(); + break; + case south: + G_BeginLine(); + G_Vertex( points[2] ); + G_Vertex( points[7] ); + G_EndLine(); + G_BeginLine(); + G_Vertex( points[3] ); + G_Vertex( points[6] ); + G_EndLine(); + break; + case east: + G_BeginLine(); + G_Vertex( points[0] ); + G_Vertex( points[6] ); + G_EndLine(); + G_BeginLine(); + G_Vertex( points[4] ); + G_Vertex( points[2] ); + G_EndLine(); + break; + case west: + G_BeginLine(); + G_Vertex( points[1] ); + G_Vertex( points[7] ); + G_EndLine(); + G_BeginLine(); + G_Vertex( points[5] ); + G_Vertex( points[3] ); + G_EndLine(); + break; + case up: + G_BeginLine(); + G_Vertex( points[0] ); + G_Vertex( points[3] ); + G_EndLine(); + G_BeginLine(); + G_Vertex( points[1] ); + G_Vertex( points[2] ); + G_EndLine(); + break; + case down: + G_BeginLine(); + G_Vertex( points[4] ); + G_Vertex( points[7] ); + G_EndLine(); + G_BeginLine(); + G_Vertex( points[5] ); + G_Vertex( points[6] ); + G_EndLine(); + break; + } + } diff --git a/source/source/fgame/debuglines.h b/source/source/fgame/debuglines.h new file mode 100644 index 0000000..7bcf429 --- /dev/null +++ b/source/source/fgame/debuglines.h @@ -0,0 +1,64 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/debuglines.h $ +// $Revision:: 4 $ +// $Date:: 3/15/00 2:04p $ +// +// Copyright (C) 1999 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source is may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/debuglines.h $ +// +// 4 3/15/00 2:04p Markd +// fixed up camera node system and added new debug oriented circle +// +// 3 3/02/00 6:04p Markd +// Added Debug Arrow and DebugHighlightFacet +// +// 2 1/06/00 11:08p Jimdose +// cleaning up unused code +// +// DESCRIPTION: +// + +#ifndef __DEBUGLINES_H__ +#define __DEBUGLINES_H__ + +#include "g_local.h" + +void G_InitDebugLines( void ); +void G_DebugLine( Vector start, Vector end, float r, float g, float b, float alpha ); +void G_LineStipple( int factor, unsigned short pattern ); +void G_LineWidth( float width ); +void G_Color3f( float r, float g, float b ); +void G_Color3v( Vector color ); +void G_Color4f( float r, float g, float b, float alpha ); +void G_Color3vf( Vector color, float alpha ); +void G_BeginLine( void ); +void G_Vertex( Vector v ); +void G_EndLine( void ); +void G_DebugBBox( Vector org, Vector mins, Vector maxs, float r, float g, float b, float alpha ); +void G_DrawDebugNumber( Vector org, float number, float scale, float r, float g, float b, int precision = 0 ); +void G_DebugCircle( Vector org, float radius, float r, float g, float b, float alpha, qboolean horizontal = false ); +void G_DebugOrientedCircle( Vector org, float radius, float r, float g, float b, float alpha, Vector angles ); +void G_DebugPyramid( Vector org, float radius, float r, float g, float b, float alpha ); +void G_DrawCoordSystem( Vector pos, Vector f, Vector r, Vector u, int len ); +void G_DebugArrow( Vector org, Vector dir, float length, float r, float g, float b, float alpha ); +void G_DrawCSystem( void ); + +typedef enum + { + north, + south, + east, + west, + up, + down + } facet_t; + +void G_DebugHighlightFacet( Vector org, Vector mins, Vector maxs, facet_t facet, float r, float g, float b, float alpha ); + +#endif /* !__DEBUGLINES_H__ */ diff --git a/source/source/fgame/decals.cpp b/source/source/fgame/decals.cpp new file mode 100644 index 0000000..6598cff --- /dev/null +++ b/source/source/fgame/decals.cpp @@ -0,0 +1,94 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/decals.cpp $ +// $Revision:: 4 $ +// $Author:: Markd $ +// $Date:: 6/23/00 11:49a $ +// +// Copyright (C) 1998 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/decals.cpp $ +// +// 4 6/23/00 11:49a Markd +// fixed various imagindexes and saved games +// +// 3 6/14/00 3:50p Markd +// Cleaned up more Intel Compiler warnings +// +// 2 1/29/00 2:48p Aldie +// Added impact mark functionality and Decal class +// +// DESCRIPTION: +// Decal entities + +#include "decals.h" + + +CLASS_DECLARATION( Entity, Decal, NULL ) + { + { NULL, NULL } + }; + +Decal::Decal + ( + ) + + { + edict->s.eType = ET_DECAL; + edict->s.modelindex = 1; // must be non-zero + PostEvent( EV_Remove, FRAMETIME ); + } + +void Decal::setDirection + ( + Vector dir + ) + + { + edict->s.surfaces[0] = DirToByte( dir ); + } + +void Decal::setShader + ( + str decal_shader + ) + + { + str temp_shader; + + shader = decal_shader; + edict->s.tag_num = gi.imageindex( shader.c_str() ); + + temp_shader = shader + ".spr"; + CacheResource( temp_shader, this ); + } + +void Decal::setOrientation + ( + str deg + ) + + { + Vector ang; + + if ( !deg.icmp( "random" ) ) + ang[2] = random() * 360; + else + ang[2] = atof( deg ); + + setAngles( ang ); + } + +void Decal::setRadius + ( + float rad + ) + + { + edict->s.scale = rad; + } + diff --git a/source/source/fgame/decals.h b/source/source/fgame/decals.h new file mode 100644 index 0000000..dd296ff --- /dev/null +++ b/source/source/fgame/decals.h @@ -0,0 +1,63 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/decals.h $ +// $Revision:: 4 $ +// $Author:: Markd $ +// $Date:: 6/23/00 11:49a $ +// +// Copyright (C) 1998 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/decals.h $ +// +// 4 6/23/00 11:49a Markd +// fixed various imagindexes and saved games +// +// 3 6/14/00 3:50p Markd +// Cleaned up more Intel Compiler warnings +// +// 2 1/29/00 2:48p Aldie +// Added impact mark functionality and Decal class +// +// DESCRIPTION: +// Decal entities + +#ifndef __DECAL_H__ +#define __DECAL_H__ + +#include "g_local.h" + +class Decal : public Entity + { + private: + str shader; + + public: + CLASS_PROTOTYPE( Decal ); + + Decal(); + void setDirection( Vector dir ); + void setShader( str shader ); + void setOrientation( str deg ); + void setRadius( float rad ); + virtual void Archive( Archiver &arc ); + }; + +inline void Decal::Archive + ( + Archiver &arc + ) + { + Entity::Archive( arc ); + + arc.ArchiveString( &shader ); + if ( arc.Loading() ) + { + setShader( shader ); + } + } + +#endif // __DECAL_H__ diff --git a/source/source/fgame/doors.cpp b/source/source/fgame/doors.cpp new file mode 100644 index 0000000..a51cc12 --- /dev/null +++ b/source/source/fgame/doors.cpp @@ -0,0 +1,1768 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/doors.cpp $ +// $Revision:: 27 $ +// $Author:: Markd $ +// $Date:: 7/27/00 5:39p $ +// +// Copyright (C) 1997 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source is may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/doors.cpp $ +// +// 27 7/27/00 5:39p Markd +// put in doorcompletelyclosed +// +// 25 7/18/00 3:29p Markd +// added better caching for sounds in general +// +// 24 7/18/00 3:03p Markd +// fixed error message +// +// 23 7/17/00 4:43p Steven +// Made doors play locked sound when player uses them if they are locked and +// automatic. +// +// 22 7/15/00 3:00p Steven +// fixed door locked sound playing constantly when it is an auto open door +// +// 21 7/11/00 7:07p Steven +// Made it so actors don't cause door locked sounds and removed a center print. +// +// 20 7/03/00 6:59p Steven +// Setup default locked door sound. +// +// 19 7/01/00 1:25p Markd +// fixed door bug with area portals +// +// 18 6/23/00 8:41p Markd +// made a lot of changes to different constructors for saved game support +// +// 17 6/14/00 3:50p Markd +// Cleaned up more Intel Compiler warnings +// +// 16 6/05/00 11:16a Markd +// fixed doors getting blocked by entities and crashing the game +// +// 15 6/01/00 3:18p Markd +// rewrote giveItem and item management in sentient +// +// 14 3/27/00 4:15p Markd +// updated script_door documentation +// +// 13 1/25/00 10:02a Steven +// Made doors automatically open for actors. +// +// 12 1/15/00 3:57p Markd +// Eliminated multiple "angle" events and replaced them with EV_SetAngle +// +// 11 1/14/00 5:06p Markd +// Removed surface num, tri_num and damage_multiplier from multiple functions +// and events +// +// 10 1/12/00 6:16p Jimdose +// made EV_SlidingDoor_Setup use EV_HIDE +// +// 9 1/06/00 11:08p Jimdose +// cleaning up unused code +// +// 8 12/11/99 6:44p Markd +// second run-through of q3a merge, got the entire project to build without +// errors or warnings +// +// 7 10/14/99 5:08p Markd +// removed a lot of G_GetMoveDir calls from the initialization code +// +// 6 10/13/99 5:03p Markd +// Fixed door bug where multiple linked doors where all adjusting the portal +// state +// +// 5 10/07/99 2:59p Steven +// Event formatting. +// +// 4 9/29/99 5:18p Steven +// Event formatting. +// +// 3 9/22/99 4:47p Markd +// fixed more G_GetEntity, G_FindClass and G_GetNextEntity bugs +// +// 2 9/21/99 7:51p Markd +// Fixed a lot of entitynum_none issues +// +// 1 9/10/99 10:53a Jimdose +// +// 1 9/08/99 3:15p Aldie +// +// 22 8/28/99 11:42a Steven +// Removed global from sound function calls. +// +// 21 8/25/99 12:42p Markd +// Fixed some minor and major scripting bugs +// +// 20 7/08/99 4:28p Markd +// Removed obsolete QUAKED functions +// +// 19 6/11/99 2:20p Phook +// Renamed a few entities +// +// 18 6/11/99 1:23p Phook +// +// 17 6/11/99 12:58p Phook +// Changed from SINED comments to QUAKED +// +// 16 6/11/99 12:46p Phook +// EClass color changes +// +// DESCRIPTION: +// Doors are environment objects that rotate open when activated by triggers +// or when used by the player. +// + +#include "g_local.h" +#include "entity.h" +#include "trigger.h" +#include "mover.h" +#include "doors.h" +#include "sentient.h" +#include "scriptmaster.h" +#include "item.h" +#include "actor.h" +#include "player.h" +#include "g_utils.h" + +Event EV_Door_StopSound + ( + "sound_stop", + EV_DEFAULT, + "s", + "sound_stop", + "Sets the sound to use when the door stops." + ); +Event EV_Door_MoveSound + ( + "sound_move", + EV_DEFAULT, + "s", + "sound_move", + "Sets the sound to use when the door moves." + ); +Event EV_Door_MessageSound + ( + "sound_message", + EV_DEFAULT, + "s", + "sound_message", + "Sets the sound to use when the door displays a message." + ); +Event EV_Door_LockedSound + ( + "sound_locked", + EV_DEFAULT, + "s", + "sound_locked", + "Sets the sound to use when the door is locked." + ); +Event EV_Door_SetWait + ( + "wait", + EV_DEFAULT, + "f", + "wait", + "Sets the amount of time to wait before automatically shutting." + ); +Event EV_Door_SetDmg + ( + "dmg", + EV_DEFAULT, + "i", + "damage", + "Sets the amount of damage the door will do to entities that get stuck in it." + ); +Event EV_Door_TriggerFieldTouched + ( + "door_triggerfield", + EV_DEFAULT, + "e", + "other", + "Is called when a doors trigger field is touched." + ); +Event EV_Door_TryOpen + ( + "tryToOpen", + EV_DEFAULT, + "e", + "other", + "Tries to open the door." + ); +Event EV_Door_Close + ( + "close", + EV_DEFAULT, + NULL, + NULL, + "Closes the door." + ); +Event EV_Door_Open + ( + "open", + EV_DEFAULT, + "e", + "other", + "Opens the door." + ); +Event EV_Door_DoClose + ( + "doclose", + EV_DEFAULT, + NULL, + NULL, + "Closes the door (special doors)." + ); +Event EV_Door_DoOpen + ( + "doopen", + EV_DEFAULT, + "e", + "other", + "Opens the door (special doors)." + ); +Event EV_Door_CloseEnd + ( + "doorclosed", + EV_DEFAULT, + NULL, + NULL, + "Called when the door finishes closing." + ); +Event EV_Door_OpenEnd + ( + "dooropened", + EV_DEFAULT, + NULL, + NULL, + "Called when the door finishes opening." + ); +Event EV_Door_Fire + ( + "toggledoor", + EV_DEFAULT, + "e", + "other", + "Toggles the state of the door (open/close)." + ); +Event EV_Door_Link + ( + "linkdoor", + EV_DEFAULT, + NULL, + NULL, + "Link doors together." + ); +Event EV_Door_SetTime + ( + "time", + EV_DEFAULT, + "f", + "traveltime", + "Sets the time it takes for the door to open an close." + ); +Event EV_Door_Lock + ( + "lock", + EV_DEFAULT, + NULL, + NULL, + "Lock the door." + ); +Event EV_Door_Unlock + ( + "unlock", + EV_DEFAULT, + NULL, + NULL, + "Unlock the door." + ); + +#define DOOR_START_OPEN 1 +#define DOOR_OPEN_DIRECTION 2 +#define DOOR_DONT_LINK 4 +#define DOOR_TOGGLE 32 +#define DOOR_AUTO_OPEN 64 +#define DOOR_TARGETED 128 + +#define STATE_OPEN 1 +#define STATE_OPENING 2 +#define STATE_CLOSING 3 +#define STATE_CLOSED 4 + +/* + +Doors are similar to buttons, but can spawn a fat trigger field around them +to open without a touch, and they link together to form simultanious +double/quad doors. + +Door.master is the master door. If there is only one door, it points to itself. +If multiple doors, all will point to a single one. + +Door.enemy chains from the master door through all doors linked in the chain. + +*/ + +CLASS_DECLARATION( ScriptSlave, Door, "NormalDoor" ) + { + { &EV_Door_StopSound, SetStopSound }, + { &EV_Door_MoveSound, SetMoveSound }, + { &EV_Door_MessageSound, SetMessageSound }, + { &EV_Door_LockedSound, SetLockedSound }, + { &EV_Door_SetWait, SetWait }, + { &EV_Door_SetDmg, SetDmg }, + { &EV_Door_TriggerFieldTouched, FieldTouched }, + { &EV_Trigger_Effect, TryOpen }, + { &EV_Activate, TryOpen }, + { &EV_Door_TryOpen, TryOpen }, + { &EV_Door_Close, Close }, + { &EV_Door_Open, Open }, + { &EV_Door_CloseEnd, CloseEnd }, + { &EV_Door_OpenEnd, OpenEnd }, + { &EV_Door_Fire, DoorFire }, + { &EV_Door_Link, LinkDoors }, + { &EV_Door_SetTime, SetTime }, + { &EV_Use, DoorUse }, + { &EV_Killed, DoorFire }, + { &EV_Blocked, DoorBlocked }, + { &EV_Door_Lock, LockDoor }, + { &EV_Door_Unlock, UnlockDoor }, + { &EV_SetAngle, SetDir }, + { &EV_Touch, NULL }, + { NULL, NULL } + }; + +Door::Door() + { + float t; + const char *text; + + if ( LoadingSavegame ) + { + return; + } + + nextdoor = 0; + trigger = 0; + locked = false; + master = this; + lastblocktime = 0; + diropened = 0; + + dir = G_GetMovedir( 0 ); + t = dir[ 0 ]; + dir[ 0 ] = -dir[ 1 ]; + dir[ 1 ] = t; + + showModel(); + + text = gi.GlobalAlias_FindRandom( "door_stop" ); + if ( text ) + { + SetStopSound( text ); + } + + text = gi.GlobalAlias_FindRandom( "door_moving" ); + if ( text ) + { + SetMoveSound( text ); + } + + text = gi.GlobalAlias_FindRandom( "snd_locked" ); + if ( text ) + { + SetLockedSound( text ); + } + + traveltime = 0.3; + speed = 1.0f / traveltime; + + wait = ( spawnflags & DOOR_TOGGLE ) ? 0 : 3; + dmg = 0; + + setSize( mins, maxs ); + + setOrigin( localorigin ); + + // DOOR_START_OPEN is to allow an entity to be lighted in the closed position + // but spawn in the open position + if ( spawnflags & DOOR_START_OPEN ) + { + state = STATE_OPEN; + PostEvent( EV_Door_Open, EV_POSTSPAWN ); + } + else + { + state = STATE_CLOSED; + } + previous_state = state; + + if ( health ) + { + takedamage = DAMAGE_YES; + } + + // LinkDoors can't be done until all of the doors have been spawned, so + // the sizes can be detected properly. + nextdoor = 0; + PostEvent( EV_Door_Link, EV_LINKDOORS ); + + // Default to work with monsters and players + respondto = TRIGGER_PLAYERS | TRIGGER_MONSTERS; + if ( spawnflags & 8 ) + { + respondto &= ~TRIGGER_PLAYERS; + } + if ( spawnflags & 16 ) + { + respondto &= ~TRIGGER_MONSTERS; + } + + next_locked_time = 0; + } + +void Door::SetDir + ( + Event *ev + ) + + { + float t; + float angle; + + angle = ev->GetFloat( 1 ); + dir = G_GetMovedir( angle ); + t = dir[ 0 ]; + dir[ 0 ] = -dir[ 1 ]; + dir[ 1 ] = t; + } + +void Door::SetStopSound + ( + str sound + ) + + { + sound_stop = sound; + if ( sound_stop.length() > 1 ) + { + CacheResource( sound_stop.c_str(), this ); + } + } + +void Door::SetMoveSound + ( + str sound + ) + + { + sound_move = sound; + if ( sound_move.length() > 1 ) + { + CacheResource( sound_move.c_str(), this ); + } + } + +void Door::SetMessageSound + ( + str sound + ) + + { + sound_message = sound; + if ( sound_message.length() > 1 ) + { + CacheResource( sound_message.c_str(), this ); + } + } + +void Door::SetLockedSound + ( + str sound + ) + + { + sound_locked = sound; + if ( sound_locked.length() > 1 ) + { + CacheResource( sound_locked.c_str(), this ); + } + } + +void Door::SetStopSound + ( + Event *ev + ) + + { + SetStopSound( ev->GetString( 1 ) ); + } + +void Door::SetMoveSound + ( + Event *ev + ) + + { + SetMoveSound( ev->GetString( 1 ) ); + } + +void Door::SetMessageSound + ( + Event *ev + ) + + { + SetMessageSound( ev->GetString( 1 ) ); + } + +void Door::SetLockedSound + ( + Event *ev + ) + + { + SetLockedSound( ev->GetString( 1 ) ); + } + +void Door::SetWait + ( + Event *ev + ) + + { + wait = ev->GetFloat( 1 ); + } + +void Door::SetDmg + ( + Event *ev + ) + + { + dmg = ev->GetInteger( 1 ); + } + +qboolean Door::isOpen + ( + void + ) + + { + return ( state == STATE_OPEN ); + } + +qboolean Door::isCompletelyClosed + ( + void + ) + + { + return ( state == STATE_CLOSED ); + } + +void Door::OpenEnd + ( + Event *ev + ) + + { + if ( sound_stop.length() > 1 ) + { + BroadcastSound(); + Sound( sound_stop, CHAN_VOICE ); + } + else + { + StopSound( CHAN_VOICE ); + } + + previous_state = state; + state = STATE_OPEN; + if ( spawnflags & DOOR_TOGGLE ) + { + // don't close automatically + return; + } + + if ( ( wait > 0 ) && ( master == this ) ) + { + PostEvent( EV_Door_Close, wait ); + } + } + +void Door::CloseEnd + ( + Event *ev + ) + + { + if ( sound_stop.length() > 1 ) + { + BroadcastSound(); + Sound( sound_stop, CHAN_VOICE ); + } + else + { + StopSound( CHAN_VOICE ); + } + + if ( master == this ) + { + gi.AdjustAreaPortalState( this->edict, false ); + } + + previous_state = state; + state = STATE_CLOSED; + } + +void Door::Close + ( + Event *ev + ) + + { + Door *door; + + CancelEventsOfType( EV_Door_Close ); + + previous_state = state; + state = STATE_CLOSING; + + ProcessEvent( EV_Door_DoClose ); + + if ( sound_move.length() > 1 ) + { + BroadcastSound(); + Sound( sound_move, CHAN_VOICE ); + } + if ( master == this ) + { + if ( max_health ) + { + takedamage = DAMAGE_YES; + health = max_health; + } + + // trigger all paired doors + door = ( Door * )G_GetEntity( nextdoor ); + assert( door->isSubclassOf( Door ) ); + while( door && ( door != this ) ) + { + door->ProcessEvent( EV_Door_Close ); + door = ( Door * )G_GetEntity( door->nextdoor ); + assert( door->isSubclassOf( Door ) ); + } + } + } + +void Door::Open + ( + Event *ev + ) + + { + Door *door; + Event *e; + Entity *other; + + if ( ev->NumArgs() < 1 ) + { + ev->Error( "No entity specified to open door. Door may open the wrong way." ); + other = world; + } + else + { + other = ev->GetEntity( 1 ); + } + + if ( state == STATE_OPENING ) + { + // already going up + return; + } + + if ( state == STATE_OPEN ) + { + // reset top wait time + if ( wait > 0 ) + { + CancelEventsOfType( EV_Door_Close ); + PostEvent( EV_Door_Close, wait ); + } + return; + } + + previous_state = state; + state = STATE_OPENING; + + e = new Event( EV_Door_DoOpen ); + e->AddEntity( other ); + ProcessEvent( e ); + + if ( sound_move.length() > 1 ) + { + BroadcastSound(); + Sound( sound_move, CHAN_VOICE ); + } + if ( master == this ) + { + // trigger all paired doors + door = ( Door * )G_GetEntity( nextdoor ); + assert( door->isSubclassOf( Door ) ); + while( door && ( door != this ) ) + { + e = new Event( EV_Door_Open ); + e->AddEntity( other ); + door->ProcessEvent( e ); + door = ( Door * )G_GetEntity( door->nextdoor ); + assert( door->isSubclassOf( Door ) ); + } + + if ( previous_state == STATE_CLOSED ) + { + gi.AdjustAreaPortalState( this->edict, true ); + } + } + } + +void Door::DoorUse + ( + Event *ev + ) + + { + Entity *other; + qboolean respond; + Event *e; + + other = ev->GetEntity( 1 ); + + respond = ( ( ( respondto & TRIGGER_PLAYERS ) && other->isClient() ) || + ( ( respondto & TRIGGER_MONSTERS ) && other->isSubclassOf( Actor ) ) ); + + if ( !respond ) + { + return; + } + + // only allow use when not triggerd by other events + if ( health || ( spawnflags & ( DOOR_AUTO_OPEN | DOOR_TARGETED ) ) ) + { + if ( other->isSubclassOf( Sentient ) && ( state == STATE_CLOSED ) ) + { + if ( health ) + { + gi.SendServerCommand( NULL, "print \"This door is jammed.\"" ); + } + else if ( spawnflags & DOOR_TARGETED ) + { + Sound( "door_triggered", CHAN_VOICE ); + } + } + + if ( spawnflags & DOOR_AUTO_OPEN && locked && other->isSubclassOf( Player ) && sound_locked.length() ) + { + other->Sound( sound_locked, CHAN_VOICE ); + } + + return; + } + + assert( master ); + if ( !master ) + { + // bulletproofing + master = this; + } + + if ( master->state == STATE_CLOSED ) + { + e = new Event( EV_Door_TryOpen ); + e->AddEntity( other ); + master->ProcessEvent( e ); + } + else if ( master->state == STATE_OPEN ) + { + e = new Event( EV_Door_Close ); + e->AddEntity( other ); + master->ProcessEvent( e ); + } + } + +void Door::DoorFire + ( + Event *ev + ) + + { + Event *e; + Entity *other; + + other = ev->GetEntity( 1 ); + + assert( master == this ); + if ( master != this ) + { + gi.Error( ERR_DROP, "DoorFire: master != self" ); + } + + // no more messages + SetMessage( NULL ); + + // reset health in case we were damage triggered + health = max_health; + + // will be reset upon return + takedamage = DAMAGE_NO; + + if ( ( spawnflags & ( DOOR_TOGGLE | DOOR_START_OPEN ) ) && ( state == STATE_OPENING || state == STATE_OPEN ) ) + { + spawnflags &= ~DOOR_START_OPEN; + ProcessEvent( EV_Door_Close ); + } + else + { + e = new Event( EV_Door_Open ); + e->AddEntity( other ); + ProcessEvent( e ); + } + } + +void Door::DoorBlocked + ( + Event *ev + ) + + { + Event *e; + Entity *other; + + assert( master ); + if ( ( master ) && ( master != this ) ) + { + master->ProcessEvent( new Event( ev ) ); + return; + } + + if ( lastblocktime > level.time ) + { + return; + } + + lastblocktime = level.time + 0.3; + + other = ev->GetEntity( 1 ); + + if ( dmg ) + { + other->Damage( this, this, (int)dmg, origin, vec_zero, vec_zero, 0, 0, MOD_CRUSH ); + } + + // + // if we killed him, lets keep on going + // + if ( other->deadflag ) + { + return; + } + + if ( state == STATE_OPENING || state == STATE_OPEN ) + { + spawnflags &= ~DOOR_START_OPEN; + ProcessEvent( EV_Door_Close ); + } + else + { + e = new Event( EV_Door_Open ); + e->AddEntity( other ); + ProcessEvent( e ); + } + } + +void Door::FieldTouched + ( + Event *ev + ) + + { + Entity *other; + + other = ev->GetEntity( 1 ); + + if ( !other ) + return; + + if ( ( state != STATE_OPEN ) && !( spawnflags & DOOR_AUTO_OPEN ) && !other->isSubclassOf( Actor ) ) + return; + + TryOpen( ev ); + } + +qboolean Door::CanBeOpenedBy + ( + Entity *ent + ) + + { + assert( master ); + if ( ( master ) && ( master != this ) ) + { + return master->CanBeOpenedBy( ent ); + } + + if ( !locked && !key.length() ) + { + return true; + } + + if ( ent && ent->isSubclassOf( Sentient ) && ( ( Sentient * )ent )->HasItem( key.c_str() ) ) + { + return true; + } + + return false; + } + +void Door::TryOpen + ( + Event *ev + ) + + { + Entity *other; + Event *event; + + //FIXME + // hack so that doors aren't triggered by guys when game starts. + // have to fix delay that guys go through before setting up their threads + if ( level.time < 0.4 ) + { + return; + } + + other = ev->GetEntity( 1 ); + + assert( master ); + if ( master && ( this != master ) ) + { + event = new Event( EV_Door_TryOpen ); + event->AddEntity( other ); + master->ProcessEvent( event ); + return; + } + + if ( !other || other->deadflag ) + { + return; + } + + if ( locked ) + { + if ( next_locked_time <= level.time ) + { + if ( sound_locked.length() > 1 && !other->isSubclassOf( Actor ) ) + { + other->Sound( sound_locked, CHAN_VOICE ); + } + else if ( other->isSubclassOf( Player ) ) + { + other->Sound( "snd_locked", CHAN_VOICE ); + // gi.centerprintf ( other->edict, "This door is locked." ); + } + } + + // Always increment next locked time + + next_locked_time = level.time + 0.5; + + // locked doors don't open for anyone + return; + } + + if ( !CanBeOpenedBy( other ) ) + { + Item *item; + ClassDef *cls; + + if ( other->isClient() ) + { + cls = getClass( key.c_str() ); + if ( !cls ) + { + gi.DPrintf( "No item named '%s'\n", key.c_str() ); + return; + } + item = ( Item * )cls->newInstance(); + item->CancelEventsOfType( EV_Item_DropToFloor ); + item->CancelEventsOfType( EV_Remove ); + item->ProcessPendingEvents(); + gi.centerprintf ( other->edict, "You need the %s", item->getName() ); + delete item; + } + return; + } + + // once we're opened by an item, we no longer need that item to open the door + key = ""; + + if ( Message().length() ) + { + gi.centerprintf( other->edict, Message().c_str() ); + Sound( sound_message, CHAN_VOICE ); + } + + event = new Event( EV_Door_Fire ); + event->AddEntity( other ); + ProcessEvent( event ); + } + +void Door::SpawnTriggerField + ( + Vector fmins, + Vector fmaxs + ) + + { + TouchField *trig; + Vector min; + Vector max; + + min = fmins - "60 60 8"; + max = fmaxs + "60 60 8"; + + trig = new TouchField; + trig->Setup( this, EV_Door_TriggerFieldTouched, min, max, respondto ); + + trigger = trig->entnum; + } + +qboolean Door::DoorTouches + ( + Door *e1 + ) + + { + if ( e1->absmin.x > absmax.x ) + { + return false; + } + if ( e1->absmin.y > absmax.y ) + { + return false; + } + if ( e1->absmin.z > absmax.z ) + { + return false; + } + if ( e1->absmax.x < absmin.x ) + { + return false; + } + if ( e1->absmax.y < absmin.y ) + { + return false; + } + if ( e1->absmax.z < absmin.z ) + { + return false; + } + + return true; + } + +void Door::LinkDoors + ( + Event *ev + ) + + { + Entity *entptr; + Door *ent; + Door *next; + Vector cmins; + Vector cmaxs; + int i; + + setSolidType( SOLID_BSP ); + setMoveType( MOVETYPE_PUSH ); + + if ( nextdoor ) + { + // already linked by another door + return; + } + + // master doors own themselves + master = this; + + if ( spawnflags & DOOR_DONT_LINK ) + { + // don't want to link this door + nextdoor = entnum; + return; + } + + cmins = absmin; + cmaxs = absmax; + + ent = this; + for( entptr = this; entptr; entptr = G_FindClass( entptr, getClassID() ) ) + { + next = ( Door * )entptr; + if ( !ent->DoorTouches( next ) ) + { + continue; + } + + if ( next->nextdoor ) + { + error( "cross connected doors. Targetname = %s entity %d\n", TargetName(), entnum ); + } + + ent->nextdoor = next->entnum; + ent = next; + + for( i = 0; i < 3; i++ ) + { + if ( ent->absmin[ i ] < cmins[ i ] ) + { + cmins[ i ] = ent->absmin[ i ]; + } + if ( ent->absmax[ i ] > cmaxs[ i ] ) + { + cmaxs[ i ] = ent->absmax[ i ]; + } + } + + // set master door + ent->master = this; + + if ( ent->health ) + { + health = ent->health; + } + + if ( ent->Targeted() ) + { + if ( !Targeted() ) + { + SetTargetName( ent->TargetName() ); + } + else if ( strcmp( TargetName(), ent->TargetName() ) ) + { + // not a critical error, but let them know about it. + gi.DPrintf( "cross connected doors\n" ); + + ent->SetTargetName( TargetName() ); + } + } + + if ( ent->Message().length() ) + { + if ( Message().length() && !strcmp( Message().c_str(), ent->Message().c_str() ) ) + { + // not a critical error, but let them know about it. + gi.DPrintf( "Different messages on linked doors. Targetname = %s", TargetName() ); + } + + // only master should have a message + SetMessage( ent->Message().c_str() ); + ent->SetMessage( NULL ); + } + } + + // make the chain a loop + ent->nextdoor = entnum; + + // open up any portals we control + if ( spawnflags & DOOR_START_OPEN ) + { + gi.AdjustAreaPortalState( this->edict, true ); + } + + // shootable or targeted doors don't need a trigger + if ( health || ( spawnflags & DOOR_TARGETED ) ) + { + // Don't let the player trigger the door + return; + } + + // Don't spawn trigger field when set to toggle + if ( !( spawnflags & DOOR_TOGGLE ) ) + { + SpawnTriggerField( cmins, cmaxs ); + } + } + +void Door::SetTime + ( + Event *ev + ) + + { + traveltime = ev->GetFloat( 1 ); + if ( traveltime < FRAMETIME ) + { + traveltime = FRAMETIME; + } + + speed = 1.0f / traveltime; + } + +void Door::LockDoor + ( + Event *ev + ) + + { + locked = true; + } + +void Door::UnlockDoor + ( + Event *ev + ) + + { + locked = false; + } + +/*****************************************************************************/ +/*QUAKED func_rotatingdoor (0 0.25 0.5) ? START_OPEN OPEN_DIRECTION DOOR_DONT_LINK NOT_PLAYERS NOT_MONSTERS TOGGLE AUTO_OPEN TARGETED +if two doors touch, they are assumed to be connected and operate as a unit. + +TOGGLE causes the door to wait in both the start and end states for a trigger event. +DOOR_DONT_LINK is for when you have two doors that are touching but you want to operate independently. + +START_OPEN causes the door to move to its destination when spawned, and operate in reverse. It is used to temporarily or permanently close off an area when triggered (not usefull for touch or takedamage doors). +OPEN_DIRECTION indicates which direction to open when START_OPEN is set. +AUTO_OPEN causes the door to open when a player is near instead of waiting for the player to use the door. +TARGETED door is only operational from triggers or script + +"message" is printed when the door is touched if it is a trigger door and it hasn't been fired yet +"openangle" how wide to open the door +"angle" determines the opening direction. point toward the middle of the door (away from the hinge) +"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 +"time" move time (0.3 default) +"wait" wait before returning (3 default, -1 = never return) +"dmg" damage to inflict when blocked (0 default) +"key" The item needed to open this door (default nothing) + +"sound_stop" Specify the sound that plays when the door stops moving (default global door_stop) +"sound_move" Specify the sound that plays when the door opens or closes (default global door_moving) +"sound_message" Specify the sound that plays when the door displays a message +"sound_locked" Specify the sound that plays when the door is locked + +******************************************************************************/ + +Event EV_RotatingDoor_OpenAngle + ( + "openangle", + EV_DEFAULT, + "f", + "open_angle", + "Sets the open angle of the door." + ); + +CLASS_DECLARATION( Door, RotatingDoor, "func_rotatingdoor" ) + { + { &EV_Door_DoClose, DoClose }, + { &EV_Door_DoOpen, DoOpen }, + { &EV_RotatingDoor_OpenAngle, OpenAngle }, + { NULL, NULL } + }; + +void RotatingDoor::DoOpen + ( + Event *ev + ) + + { + Vector ang; + + if ( previous_state == STATE_CLOSED ) + { + if ( ev->NumArgs() > 0 ) + { + Entity *other; + Vector p; + + other = ev->GetEntity( 1 ); + p = other->origin - origin; + p.z = 0; + diropened = dir * p; + } + else + { + diropened = 0 - init_door_direction; + } + } + + if ( diropened < 0 ) + { + ang = startangle + Vector( 0, angle, 0 ); + } + else + { + ang = startangle - Vector( 0, angle, 0 ); + } + + MoveTo( origin, ang, fabs( speed*angle ), EV_Door_OpenEnd ); + } + +void RotatingDoor::DoClose + ( + Event *ev + ) + + { + MoveTo( origin, startangle, fabs( speed*angle ), EV_Door_CloseEnd ); + } + +void RotatingDoor::OpenAngle + ( + Event *ev + ) + + { + angle = ev->GetFloat( 1 ); + } + +RotatingDoor::RotatingDoor() + { + if ( LoadingSavegame ) + { + return; + } + startangle = angles; + + angle = 90; + + init_door_direction = (spawnflags & DOOR_OPEN_DIRECTION); + } + +/*****************************************************************************/ +/*QUAKED func_door (0 0.25 0.5) ? START_OPEN x DOOR_DONT_LINK NOT_PLAYERS NOT_MONSTERS TOGGLE AUTO_OPEN TARGETED +if two doors touch, they are assumed to be connected and operate as a unit. + +TOGGLE causes the door to wait in both the start and end states for a trigger event. +DOOR_DONT_LINK is for when you have two doors that are touching but you want to operate independently. + +START_OPEN causes the door to move to its destination when spawned, and operate in reverse. It is used to temporarily or permanently close off an area when triggered (not usefull for touch or takedamage doors). +OPEN_DIRECTION indicates which direction to open when START_OPEN is set. +AUTO_OPEN causes the door to open when a player is near instead of waiting for the player to use the door. +TARGETED door is only operational from triggers or script + +"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. point toward the middle of the door (away from the hinge) +"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" move speed (100 default) +"time" move time (1/speed default, overides speed) +"wait" wait before returning (3 default, -1 = never return) +"lip" lip remaining at end of move (8 default) +"dmg" damage to inflict when blocked (0 default) +"key" The item needed to open this door (default nothing) + +"sound_stop" Specify the sound that plays when the door stops moving (default global door_stop) +"sound_move" Specify the sound that plays when the door opens or closes (default global door_moving) +"sound_message" Specify the sound that plays when the door displays a message +"sound_locked" Specify the sound that plays when the door is locked + +******************************************************************************/ + +Event EV_SlidingDoor_Setup + ( + "setup", + EV_HIDE, + NULL, + NULL, + "Sets up the sliding door." + ); +Event EV_SlidingDoor_SetLip + ( + "lip", + EV_DEFAULT, + "f", + "lip", + "Sets the lip of the sliding door." + ); +Event EV_SlidingDoor_SetSpeed + ( + "speed", + EV_DEFAULT, + "f", + "speed", + "Sets the speed of the sliding door." + ); + +CLASS_DECLARATION( Door, SlidingDoor, "func_door" ) + { + { &EV_Door_DoClose, DoClose }, + { &EV_Door_DoOpen, DoOpen }, + { &EV_SlidingDoor_Setup, Setup }, + { &EV_SlidingDoor_SetLip, SetLip }, + { &EV_SlidingDoor_SetSpeed, SetSpeed }, + { &EV_SetAngle, SetMoveDir }, + { NULL, NULL } + }; + +void SlidingDoor::SetMoveDir + ( + Event *ev + ) + + { + float t; + float angle; + + angle = ev->GetFloat( 1 ); + movedir = G_GetMovedir( angle ); + dir = movedir; + t = dir[ 0 ]; + dir[ 0 ] = -dir[ 1 ]; + dir[ 1 ] = t; + } + +void SlidingDoor::DoOpen + ( + Event *ev + ) + + { + MoveTo( pos2, angles, speed*totalmove, EV_Door_OpenEnd ); + } + +void SlidingDoor::DoClose + ( + Event *ev + ) + + { + MoveTo( pos1, angles, speed*totalmove, EV_Door_CloseEnd ); + } + +void SlidingDoor::SetLip + ( + Event *ev + ) + + { + lip = ev->GetFloat( 1 ); + CancelEventsOfType( EV_SlidingDoor_Setup ); + PostEvent( EV_SlidingDoor_Setup, EV_POSTSPAWN ); + } + +void SlidingDoor::SetSpeed + ( + Event *ev + ) + + { + basespeed = ev->GetFloat( 1 ); + CancelEventsOfType( EV_SlidingDoor_Setup ); + PostEvent( EV_SlidingDoor_Setup, EV_POSTSPAWN ); + } + +void SlidingDoor::Setup + ( + Event *ev + ) + + { + totalmove = fabs( movedir * size ) - lip; + pos1 = origin; + pos2 = pos1 + movedir * totalmove; + + if ( basespeed ) + { + speed = basespeed / totalmove; + } + } + +SlidingDoor::SlidingDoor() + { + if ( LoadingSavegame ) + { + return; + } + lip = 8; + basespeed = 0; + movedir = G_GetMovedir( 0 ); + + PostEvent( EV_SlidingDoor_Setup, EV_POSTSPAWN ); + } + +/*****************************************************************************/ +/*QUAKED script_door (0 0.5 1) ? START_OPEN x DOOR_DONT_LINK NOT_PLAYERS NOT_MONSTERS TOGGLE AUTO_OPEN TARGETED +if two doors touch, they are assumed to be connected and operate as a unit. + +TOGGLE causes the door to wait in both the start and end states for a trigger event. +DOOR_DONT_LINK is for when you have two doors that are touching but you want to operate independently. + +START_OPEN causes the door to move to its destination when spawned, and operate in reverse. It is used to temporarily or permanently close off an area when triggered (not usefull for touch or takedamage doors). +OPEN_DIRECTION indicates which direction to open when START_OPEN is set. +AUTO_OPEN causes the door to open when a player is near instead of waiting for the player to use the door. +TARGETED door is only operational from triggers or script + +"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. point toward the middle of the door (away from the hinge) +"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" move speed (100 default) +"time" move time (1/speed default, overides speed) +"wait" wait before returning (3 default, -1 = never return) +"dmg" damage to inflict when blocked (0 default) +"key" The item needed to open this door (default nothing) +"initthread" code to execute to setup the door (optional) +"openthread" code to execute when opening the door (required) + The openthread should send the "dooropened" event to the door, when it is completely open +"closethread" code to execute when closing the door (required) + The closethread should send the "doorclosed" event to the door, when it is completely closed + +"sound_stop" Specify the sound that plays when the door stops moving (default global door_stop) +"sound_move" Specify the sound that plays when the door opens or closes (default global door_moving) +"sound_message" Specify the sound that plays when the door displays a message +"sound_locked" Specify the sound that plays when the door is locked + +******************************************************************************/ + +Event EV_ScriptDoor_DoInit + ( + "doinit", + EV_DEFAULT, + NULL, + NULL, + "Sets up the script door." + ); +Event EV_ScriptDoor_SetOpenThread + ( + "openthread", + EV_DEFAULT, + "s", + "openthread", + "Set the thread to run when the door is opened (required)." + ); +Event EV_ScriptDoor_SetCloseThread + ( + "closethread", + EV_DEFAULT, + "s", + "closethread", + "Set the thread to run when the door is closed (required)." + ); +Event EV_ScriptDoor_SetInitThread + ( + "initthread", + EV_DEFAULT, + "s", + "initthread", + "Set the thread to run when the door is initialized (optional)." + ); + +CLASS_DECLARATION( Door, ScriptDoor, "script_door" ) + { + { &EV_ScriptDoor_DoInit, DoInit }, + { &EV_Door_DoClose, DoClose }, + { &EV_Door_DoOpen, DoOpen }, + { &EV_ScriptDoor_SetInitThread, SetInitThread }, + { &EV_ScriptDoor_SetOpenThread, SetOpenThread }, + { &EV_ScriptDoor_SetCloseThread, SetCloseThread }, + { &EV_SetAngle, SetMoveDir }, + { NULL, NULL } + }; + +void ScriptDoor::SetMoveDir + ( + Event *ev + ) + + { + float t; + float angle; + + angle = ev->GetFloat( 1 ); + movedir = G_GetMovedir( angle ); + dir = movedir; + t = dir[ 0 ]; + dir[ 0 ] = -dir[ 1 ]; + dir[ 1 ] = t; + } + +void ScriptDoor::SetOpenThread + ( + Event *ev + ) + { + openthreadname = ev->GetString( 1 ); + } + +void ScriptDoor::SetCloseThread + ( + Event *ev + ) + { + closethreadname = ev->GetString( 1 ); + } + +void ScriptDoor::DoInit + ( + Event *ev + ) + { + const char * label = NULL; + GameScript * s; + const char * tname; + + startorigin = origin; + doorsize = fabs( movedir * size ); + + // + // see if we have an openthread + // + if ( !openthreadname.length() ) + { + warning( "ScriptDoor", "No openthread defined for door at %.2f %.2f %.2f", origin[0], origin[1], origin[2] ); + } + + // + // see if we have an closethread + // + if ( !closethreadname.length() ) + { + warning( "ScriptDoor", "No closethread defined for door at %.2f %.2f %.2f", origin[0], origin[1], origin[2] ); + } + + s = ScriptLib.GetScript( ScriptLib.GetGameScript() ); + if ( !s ) + { + warning( "DoInit", "Null game script" ); + return; + } + + if ( initthreadname.length() ) + label = initthreadname.c_str(); + + doorthread = Director.CreateThread( s, label, MODEL_SCRIPT ); + if ( !doorthread ) + { + warning( "DoInit", "Could not allocate thread." ); + return; + } + doorthread->Vars()->SetVariable( "self", this ); + tname = TargetName(); + if ( tname && tname[ 0 ] ) + { + str name; + name = "$" + str( tname ); + doorthread->Vars()->SetVariable( "targetname", name.c_str() ); + } + doorthread->Vars()->SetVariable( "startorigin", startorigin ); + doorthread->Vars()->SetVariable( "startangles", startangle ); + doorthread->Vars()->SetVariable( "movedir", movedir ); + doorthread->Vars()->SetVariable( "doorsize", doorsize ); + if ( initthreadname.length() ) + { + // start right away + doorthread->StartImmediately(); + } + } + +void ScriptDoor::DoOpen + ( + Event *ev + ) + + { + if ( !doorthread ) + { + warning( "DoOpen", "No Thread allocated." ); + return; + } + else + { + if ( !doorthread->Goto( openthreadname.c_str() ) ) + { + warning( "DoOpen", "Could not goto %s", openthreadname.c_str() ); + return; + } + } + + if ( previous_state == STATE_CLOSED ) + { + diropened = 0; + if ( ev->NumArgs() > 0 ) + { + Entity *other; + Vector p; + + other = ev->GetEntity( 1 ); + p = other->origin - origin; + p.z = 0; + diropened = dir * p; + } + } + doorthread->Vars()->SetVariable( "origin", origin ); + doorthread->Vars()->SetVariable( "opendot", diropened ); + doorthread->Start( 0 ); + } + +void ScriptDoor::DoClose + ( + Event *ev + ) + { + if ( !doorthread ) + { + warning( "DoClose", "No Thread allocated." ); + return; + } + else + { + if ( !doorthread->Goto( closethreadname.c_str() ) ) + { + warning( "DoOpen", "Could not goto %s", closethreadname.c_str() ); + } + } + doorthread->Vars()->SetVariable( "origin", origin ); + doorthread->Start( 0 ); + } + +void ScriptDoor::SetInitThread + ( + Event *ev + ) + + { + initthreadname = ev->GetString( 1 ); + } + +ScriptDoor::ScriptDoor() + { + if ( LoadingSavegame ) + { + return; + } + startangle = angles; + + // + // clear out the sounds if necessary + // scripted doors typically have their own sounds + // + sound_stop = ""; + sound_move = ""; + + movedir = G_GetMovedir( 0 ); + + PostEvent( EV_ScriptDoor_DoInit, EV_POSTSPAWN ); + } diff --git a/source/source/fgame/doors.h b/source/source/fgame/doors.h new file mode 100644 index 0000000..1f65a36 --- /dev/null +++ b/source/source/fgame/doors.h @@ -0,0 +1,266 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/doors.h $ +// $Revision:: 7 $ +// $Author:: Markd $ +// $Date:: 7/27/00 5:39p $ +// +// Copyright (C) 1997 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source is may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/doors.h $ +// +// 7 7/27/00 5:39p Markd +// put in doorcompletelyclosed +// +// 6 7/15/00 3:00p Steven +// fixed door locked sound playing constantly when it is an auto open door +// +// 5 6/23/00 8:41p Markd +// made a lot of changes to different constructors for saved game support +// +// 4 5/25/00 7:52p Markd +// 2nd pass save game stuff +// +// 3 5/24/00 3:14p Markd +// first phase of save/load games +// +// 2 10/14/99 5:08p Markd +// removed a lot of G_GetMoveDir calls from the initialization code +// +// 1 9/10/99 10:53a Jimdose +// +// 1 9/08/99 3:15p Aldie +// +// DESCRIPTION: +// Doors are environment objects that slide open when activated by triggers +// or when used by the player. +// + +#ifndef __DOORS_H__ +#define __DOORS_H__ + +#include "g_local.h" +#include "entity.h" +#include "trigger.h" +#include "scriptslave.h" + +extern Event EV_Door_TryOpen; +extern Event EV_Door_GoDown; +extern Event EV_Door_GoUp; +extern Event EV_Door_HitBottom; +extern Event EV_Door_HitTop; +extern Event EV_Door_Fire; +extern Event EV_Door_Link; +extern Event EV_Door_SetSpeed; +extern Event EV_Door_Lock; +extern Event EV_Door_Unlock; + +class Door; + +typedef SafePtr DoorPtr; + +class Door : public ScriptSlave + { + protected: + str sound_stop; + str sound_move; + str sound_message; + str sound_locked; + float lastblocktime; + float angle; + Vector dir; + float diropened; + int state; + int previous_state; + int trigger; + int nextdoor; + DoorPtr master; + float next_locked_time; + + void SetDir( Event *ev ); + void OpenEnd( Event *ev ); + void CloseEnd( Event *ev ); + void Close( Event *ev ); + void Open( Event *ev ); + void DoorUse( Event *ev ); + void DoorFire( Event *ev ); + void DoorBlocked( Event *ev ); + void FieldTouched( Event *ev ); + void TryOpen( Event *ev ); + void SpawnTriggerField( Vector fmins, Vector fmaxs ); + qboolean DoorTouches( Door *e1 ); + void LinkDoors( Event *ev ); + void SetTime( Event *ev ); + void LockDoor( Event *ev ); + void UnlockDoor( Event *ev ); + void SetStopSound( str sound ); + void SetStopSound( Event *ev ); + void SetMoveSound( str sound ); + void SetMoveSound( Event *ev ); + void SetMessageSound( str sound ); + void SetMessageSound( Event *ev ); + void SetLockedSound( str sound ); + void SetLockedSound( Event *ev ); + void SetWait( Event *ev ); + void SetDmg( Event *ev ); + + public: + CLASS_PROTOTYPE( Door ); + + qboolean locked; + + Door(); + qboolean isOpen( void ); + qboolean isCompletelyClosed( void ); + qboolean CanBeOpenedBy( Entity *ent ); + virtual void Archive( Archiver &arc ); + }; + +inline void Door::Archive + ( + Archiver &arc + ) + { + ScriptSlave::Archive( arc ); + + arc.ArchiveString( &sound_stop ); + arc.ArchiveString( &sound_move ); + arc.ArchiveString( &sound_message ); + arc.ArchiveString( &sound_locked ); + if ( arc.Loading() ) + { + SetStopSound( sound_stop ); + SetMoveSound( sound_move ); + SetMessageSound( sound_message ); + SetLockedSound( sound_locked ); + } + arc.ArchiveFloat( &lastblocktime ); + arc.ArchiveFloat( &angle ); + arc.ArchiveVector( &dir ); + arc.ArchiveFloat( &diropened ); + arc.ArchiveInteger( &state ); + arc.ArchiveInteger( &previous_state ); + arc.ArchiveInteger( &trigger ); + arc.ArchiveInteger( &nextdoor ); + arc.ArchiveSafePointer( &master ); + arc.ArchiveBoolean( &locked ); + arc.ArchiveFloat( &next_locked_time ); + } + +class RotatingDoor : public Door + { + protected: + float angle; + Vector startangle; + int init_door_direction; + + public: + CLASS_PROTOTYPE( RotatingDoor ); + + void DoOpen( Event *ev ); + void DoClose( Event *ev ); + void OpenAngle( Event *ev ); + virtual void Archive( Archiver &arc ); + + RotatingDoor(); + }; + +inline void RotatingDoor::Archive + ( + Archiver &arc + ) + { + Door::Archive( arc ); + + arc.ArchiveFloat( &angle ); + arc.ArchiveVector( &startangle ); + arc.ArchiveInteger( &init_door_direction ); + } + +class SlidingDoor : public Door + { + protected: + float totalmove; + float lip; + Vector pos1; + Vector pos2; + float basespeed; + Vector movedir; + + public: + CLASS_PROTOTYPE( SlidingDoor ); + + void SetMoveDir( Event *ev ); + void Setup( Event *ev ); + void SetLip( Event *ev ); + void SetSpeed( Event *ev ); + void DoOpen( Event *ev ); + void DoClose( Event *ev ); + virtual void Archive( Archiver &arc ); + + SlidingDoor(); + }; + +inline void SlidingDoor::Archive + ( + Archiver &arc + ) + { + Door::Archive( arc ); + + arc.ArchiveFloat( &totalmove ); + arc.ArchiveFloat( &lip ); + arc.ArchiveVector( &pos1 ); + arc.ArchiveVector( &pos2 ); + arc.ArchiveVector( &movedir ); + arc.ArchiveFloat( &basespeed ); + } + +class ScriptDoor : public Door + { + protected: + ThreadPtr doorthread; + str initthreadname; + str openthreadname; + str closethreadname; + float doorsize; + Vector startangle; + Vector startorigin; + Vector movedir; + + public: + CLASS_PROTOTYPE( ScriptDoor ); + + void SetMoveDir( Event *ev ); + void DoInit( Event *ev ); + void DoOpen( Event *ev ); + void DoClose( Event *ev ); + void SetOpenThread( Event *ev ); + void SetCloseThread( Event *ev ); + void SetInitThread( Event *ev ); + virtual void Archive( Archiver &arc ); + ScriptDoor(); + }; + +inline void ScriptDoor::Archive + ( + Archiver &arc + ) + { + Door::Archive( arc ); + + arc.ArchiveSafePointer( &doorthread ); + arc.ArchiveString( &initthreadname ); + arc.ArchiveString( &openthreadname ); + arc.ArchiveString( &closethreadname ); + arc.ArchiveFloat( &doorsize ); + arc.ArchiveVector( &startangle ); + arc.ArchiveVector( &startorigin ); + arc.ArchiveVector( &movedir ); + } + +#endif /* doors.h */ diff --git a/source/source/fgame/earthquake.cpp b/source/source/fgame/earthquake.cpp new file mode 100644 index 0000000..c91e481 --- /dev/null +++ b/source/source/fgame/earthquake.cpp @@ -0,0 +1,258 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/earthquake.cpp $ +// $Revision:: 9 $ +// $Author:: Markd $ +// $Date:: 7/18/00 3:29p $ +// +// Copyright (C) 1997 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source is may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/earthquake.cpp $ +// +// 9 7/18/00 3:29p Markd +// added better caching for sounds in general +// +// 8 6/23/00 8:41p Markd +// made a lot of changes to different constructors for saved game support +// +// 7 6/14/00 3:50p Markd +// Cleaned up more Intel Compiler warnings +// +// 6 4/30/00 2:46p Markd +// fixed earthquake screwups +// +// 5 3/21/00 5:05p Markd +// improved earthquakes a lot with a visual effect +// +// 4 12/11/99 6:44p Markd +// second run-through of q3a merge, got the entire project to build without +// errors or warnings +// +// 3 11/02/99 5:45p Steven +// Added level wide sound stuff. +// +// 2 9/29/99 5:18p Steven +// Event formatting. +// +// 1 9/10/99 10:53a Jimdose +// +// 1 9/08/99 3:15p Aldie +// +// 13 8/28/99 11:43a Steven +// Removed global from sound function calls. +// +// 12 6/11/99 1:23p Phook +// +// 11 6/11/99 12:58p Phook +// Changed from SINED comments to QUAKED +// +// 10 6/11/99 12:46p Phook +// EClass color changes +// +// DESCRIPTION: +// Earthquake trigger causes a localized earthquake when triggered. +// The earthquake effect is visible to the user as the shaking of his screen. +// +#include "earthquake.h" + +#define EARTHQUAKE_NO_RAMPUP ( 1 << 0 ) +#define EARTHQUAKE_NO_RAMPDOWN ( 1 << 1 ) +/*****************************************************************************/ +/*QUAKED func_earthquake (0 0.25 0.5) (-8 -8 -8) (8 8 8) NO_RAMPUP NO_RAMPDOWN + Causes an earthquake +"duration" is the duration of the earthquake. Default is 0.8 seconds. +"magnitude" severity of the quake. Default 1.0 +******************************************************************************/ + +Event EV_Earthquake_Deactivate + ( + "earthquake_deactivate", + EV_DEFAULT, + NULL, + NULL, + "Stops the earthquake." + ); +Event EV_Earthquake_SetDuration + ( + "duration", + EV_DEFAULT, + "f", + "duration", + "Sets the duration of the earthquake." + ); + +Event EV_Earthquake_SetMagnitude + ( + "magnitude", + EV_DEFAULT, + "f", + "theMagnitude", + "Sets the magnitude of the earthquake." + ); + +Event EV_Earthquake_Think + ( + "_earthquake_think", + EV_DEFAULT, + NULL, + NULL, + "think function for the earthquake." + ); + +CLASS_DECLARATION( Trigger, Earthquake, "func_earthquake" ) + { + { &EV_Touch, NULL }, + { &EV_Trigger_Effect, Activate }, + { &EV_Earthquake_Deactivate, Deactivate }, + { &EV_Earthquake_SetDuration, SetDuration }, + { &EV_Earthquake_SetMagnitude, SetMagnitude }, + { &EV_Earthquake_Think, ThinkEvent }, + { NULL, NULL } + }; + +Earthquake::Earthquake + ( + void + ) + + { + // cache in the quake sound + CacheResource( "snd_earthquake", this ); + + if ( LoadingSavegame ) + { + return; + } + + duration = 0.8f; + magnitude = 1.0f; + quakeactive = false; + + // make sure it gets sent to the client + edict->svflags &= ~SVF_NOCLIENT; + } + +void Earthquake::SetDuration + ( + Event *ev + ) + + { + duration = ev->GetFloat( 1 ); + } + +void Earthquake::SetMagnitude + ( + Event *ev + ) + + { + magnitude = ev->GetFloat( 1 ); + } + +void Earthquake::Activate + ( + Event *ev + ) + + { + float newtime; + + starttime = level.time; + newtime = duration + level.time; + if ( newtime > level.earthquake ) + { + level.earthquake = newtime; + level.earthquake_magnitude = magnitude; + } + quakeactive = true; + LoopSound( "snd_earthquake", DEFAULT_VOL, LEVEL_WIDE_MIN_DIST ); + + PostEvent( EV_Earthquake_Deactivate,duration); + PostEvent( EV_Earthquake_Think, 0 ); + } + +void Earthquake::ThinkEvent + ( + Event *ev + ) + + { + float timedelta; + + if ( !quakeactive ) + { + return; + } + + timedelta = level.time - starttime; + + // we are in the first half of the earthquake + if ( timedelta < ( duration * 0.5f ) ) + { + if ( !( spawnflags & EARTHQUAKE_NO_RAMPUP ) ) + { + float rampuptime; + + rampuptime = starttime + ( duration * 0.33f ); + if ( level.time < rampuptime ) + { + float scale; + + scale = ( timedelta ) / ( duration * 0.33f ); + level.earthquake_magnitude = magnitude * scale; + edict->s.loopSoundVolume = scale; + } + else + { + level.earthquake_magnitude = magnitude; + edict->s.loopSoundVolume = 1.0f; + } + } + } + // we are in the second half of the earthquake + else + { + if ( !( spawnflags & EARTHQUAKE_NO_RAMPDOWN ) ) + { + float rampdowntime; + + rampdowntime = starttime + ( duration * 0.66f ); + if ( level.time > rampdowntime ) + { + float scale; + + scale = 1.0f - ( ( level.time - rampdowntime ) / ( duration * 0.33f ) ); + level.earthquake_magnitude = magnitude * scale; + edict->s.loopSoundVolume = scale; + } + else + { + level.earthquake_magnitude = magnitude; + edict->s.loopSoundVolume = 1.0f; + } + } + } + + CancelEventsOfType( EV_Earthquake_Think ); + PostEvent( EV_Earthquake_Think, FRAMETIME ); + } + + +void Earthquake::Deactivate + ( + Event *ev + ) + + { + quakeactive = false; + level.earthquake = 0; + level.earthquake_magnitude = 0; + StopLoopSound(); + // make sure to stop thinking + CancelEventsOfType( EV_Earthquake_Think ); + } diff --git a/source/source/fgame/earthquake.h b/source/source/fgame/earthquake.h new file mode 100644 index 0000000..12f9a52 --- /dev/null +++ b/source/source/fgame/earthquake.h @@ -0,0 +1,82 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/earthquake.h $ +// $Revision:: 6 $ +// $Author:: Markd $ +// $Date:: 6/14/00 3:50p $ +// +// Copyright (C) 1997 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source is may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/earthquake.h $ +// +// 6 6/14/00 3:50p Markd +// Cleaned up more Intel Compiler warnings +// +// 5 6/14/00 2:17p Markd +// fixed compiler warnings for Intel Compiler +// +// 4 5/25/00 7:52p Markd +// 2nd pass save game stuff +// +// 3 5/24/00 3:14p Markd +// first phase of save/load games +// +// 2 3/21/00 5:05p Markd +// improved earthquakes a lot with a visual effect +// +// 1 9/10/99 10:53a Jimdose +// +// 1 9/08/99 3:15p Aldie +// +// DESCRIPTION: +// Earthquake trigger causes a localized earthquake when triggered. +// The earthquake effect is visible to the user as the shaking of his screen. +// + +#ifndef __EARTHQUAKE_H__ +#define __EARTHQUAKE_H__ + +#include "g_local.h" +#include "trigger.h" + +#define EARTHQUAKE_STRENGTH 50 + +class Earthquake : public Trigger + { + protected: + float starttime; + qboolean quakeactive; + float magnitude; + float duration; + + public: + CLASS_PROTOTYPE( Earthquake ); + + Earthquake(); + void Activate( Event *ev ); + void Deactivate( Event *ev ); + void SetDuration( Event *ev ); + void SetMagnitude( Event *ev ); + void ThinkEvent( Event *ev ); + qboolean EarthquakeActive() { return quakeactive; }; + virtual void Archive( Archiver &arc ); + }; + +inline void Earthquake::Archive + ( + Archiver &arc + ) + { + Trigger::Archive( arc ); + + arc.ArchiveFloat( &starttime ); + arc.ArchiveBoolean( &quakeactive ); + arc.ArchiveFloat( &magnitude ); + arc.ArchiveFloat( &duration ); + } + +#endif /* Earthquake.h */ diff --git a/source/source/fgame/edenwater.cpp b/source/source/fgame/edenwater.cpp new file mode 100644 index 0000000..801e577 --- /dev/null +++ b/source/source/fgame/edenwater.cpp @@ -0,0 +1,106 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/edenwater.cpp $ +// $Revision:: 12 $ +// $Author:: Markd $ +// $Date:: 7/14/00 11:45p $ +// +// Copyright (C) 1998 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/edenwater.cpp $ +// +// 12 7/14/00 11:45p Markd +// Added ambient sounds to func_supllywater +// +// 11 7/11/00 11:13a Markd +// Took space out of EdenWater item name +// +// 10 7/01/00 4:10p Markd +// fixed edenwater pickup stuff +// +// 9 6/27/00 5:59p Markd +// got rid of unused variable +// +// 8 6/27/00 5:45p Steven +// Made it so water is not picked up if player already has 100. +// +// 7 4/06/00 3:47p Markd +// added blue shift to water pickup +// +// 6 4/06/00 11:44a Aldie +// Fix for water so it's not put into the player's inventory +// +// 5 1/26/00 3:33p Aldie +// Change Amount to getAmount. Added some 'listinventory' command. Added give +// all cheat to execute the script in global/giveall.txt +// +// 4 1/25/00 4:11p Aldie +// Fix the amount to use the internal variable +// +// 3 1/18/00 3:27p Aldie +// Changed startamount to 1 +// +// 2 1/18/00 3:11p Aldie +// First version of edenwater +// +// DESCRIPTION: +// Eden water pickupable item + +#include "edenwater.h" +#include "player.h" + +CLASS_DECLARATION( Item, EdenWater, "item_edenwater" ) + { + { &EV_Item_Pickup, PickupEdenWater }, + { NULL, NULL } + }; + +EdenWater::EdenWater + ( + ) + + { + setName( "EdenWater" ); + setAmount( 1 ); + } + +void EdenWater::PickupEdenWater + ( + Event *ev + ) + + { + Player *player; + Entity *other; + str realname; + + other = ev->GetEntity( 1 ); + + if ( !other || !other->isSubclassOf( Player ) ) + { + return; + } + + player = ( Player * )other; + + if ( player->GetWaterPower() >= 100 ) + return; + + player->SetWaterPower( player->GetWaterPower() + this->amount ); + + realname = GetRandomAlias( "snd_pickup" ); + if ( realname.length() > 1 ) + player->Sound( realname, CHAN_ITEM ); + + PostEvent( EV_Remove, 0 ); + + // fire off any pickup_thread's + if ( pickup_thread.length() ) + { + ExecuteThread( pickup_thread ); + } + } diff --git a/source/source/fgame/edenwater.h b/source/source/fgame/edenwater.h new file mode 100644 index 0000000..1bb2f9c --- /dev/null +++ b/source/source/fgame/edenwater.h @@ -0,0 +1,40 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/edenwater.h $ +// $Revision:: 2 $ +// $Author:: Aldie $ +// $Date:: 1/18/00 3:11p $ +// +// Copyright (C) 1998 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/edenwater.h $ +// +// 2 1/18/00 3:11p Aldie +// First version of edenwater +// +// DESCRIPTION: +// EdenWater header file + + +#ifndef __EDENWATER_H__ +#define __EDENWATER_H__ + +#include "g_local.h" +#include "item.h" +#include "sentient.h" +#include "item.h" + +class EdenWater : public Item + { + public: + CLASS_PROTOTYPE( EdenWater ); + + EdenWater(); + virtual void PickupEdenWater( Event *ev ); + }; + +#endif /* edenwater.h */ diff --git a/source/source/fgame/entity.cpp b/source/source/fgame/entity.cpp new file mode 100644 index 0000000..a105d4a --- /dev/null +++ b/source/source/fgame/entity.cpp @@ -0,0 +1,5211 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/entity.cpp $ +// $Revision:: 130 $ +// $Author:: Markd $ +// $Date:: 8/09/00 1:51p $ +// +// Copyright (C) 1997 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source is may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/entity.cpp $ +// +// 130 8/09/00 1:51p Markd +// bullet proofed detachallchildren fix +// +// 129 8/08/00 3:00p Aldie +// Fix for detachallchildren +// +// 128 29.07.00 10:51p Jimdose +// added radius2 to gentity_t +// +// 127 7/26/00 6:18p Aldie +// Fix for detachallchildren +// +// 126 7/24/00 10:38a Markd +// fixed solid bsp bug +// +// 125 7/23/00 1:47p Aldie +// Added detach all children command +// +// 124 7/19/00 9:52p Aldie +// Put ET_EVENTS back in. They will get sent over once, and should get +// processed once on the client. +// +// 123 7/17/00 5:09p Markd +// added sendonce flag to svflags +// +// 122 7/11/00 8:55p Aldie +// Added in an autoaim flag +// +// 121 7/10/00 11:54p Markd +// added exit level code +// +// 120 6/30/00 3:08p Markd +// fixed rise animation issues +// +// 119 6/30/00 10:45a Markd +// added MOVETYPE_STATIONARY and revamped some physics +// +// 118 6/27/00 5:45p Steven +// Changed HurtEvent to come from the centroid instead of the origin. +// +// 117 6/26/00 5:50p Markd +// re-did some renderfx commands, fixed anti-sb juice stuff +// +// 116 6/26/00 2:41p Markd +// put in more world protection for targetname +// +// 115 6/26/00 2:39p Markd +// made sure that world would not be re-targeted +// +// 114 6/24/00 7:39p Aldie +// Fixed attachmodel event to handle a failed attach return value and delete +// the object that was created. +// +// 113 6/19/00 5:55p Aldie +// Added support for invisible models that are lit only by negative intensity +// lights +// +// 112 6/14/00 3:50p Markd +// Cleaned up more Intel Compiler warnings +// +// 111 6/10/00 2:39p Markd +// fixed typo in event documentation +// +// 110 6/10/00 1:41p Markd +// Added scriptshader alias for shader +// +// 109 6/09/00 2:25p Steven +// Work to get bound entites to always get sent over if the entity they are +// bound to is. +// +// 108 6/08/00 8:34p Markd +// fixed localorigin problem +// +// 107 6/07/00 5:36p Markd +// fixed radius calcualtion for BSP objects +// +// 106 6/05/00 2:22p Markd +// fixed viewspawn issue +// +// 105 6/04/00 3:48p Markd +// Added precise shadows to certain characters +// +// 104 6/03/00 5:45p Markd +// fixed some more savegame issues +// +// 103 6/03/00 5:23p Markd +// fixed bug in saved games, made items have playersolid as their default +// clipmask +// +// 102 6/01/00 2:01p Steven +// Made it so you can turn look at me stuff on and off. +// +// 101 5/31/00 5:33p Steven +// Added look at me stuff. +// +// 100 5/31/00 10:24a Markd +// changed LoadingServer to LoadingSavegame +// +// 99 5/29/00 1:16p Markd +// 3rd round of saved games +// +// 98 5/24/00 6:05p Markd +// Fixed bug where MAX_MAP_BOUNDS was being used instead of MAP_SIZE +// +// 97 5/10/00 10:31a Steven +// Added com_blood stuff. +// +// 96 5/07/00 5:00p Markd +// Fixed ProcessInitCommands bug +// +// 95 5/05/00 2:15p Steven +// Only removed an attached model if the model names match if a model name is +// passed in. +// +// 94 5/04/00 2:21p Markd +// Added godmode support to flags +// +// 93 4/20/00 5:44p Steven +// Added offset to attachmodel. +// +// 92 4/20/00 9:23a Markd +// Fixed CanDamage function to be more forgiving for bmodels +// +// 91 4/19/00 5:48p Markd +// put in world targetname bulletproofing +// +// 90 4/15/00 5:43p Steven +// Made damage fractioanl again. +// +// 89 4/15/00 5:18p Aldie +// Added stun events and fixed yet another bug with Ammo and AutoPutaway +// +// 88 4/15/00 1:30p Steven +// Made it so the direction in HurtEvent is normalized. +// +// 87 4/14/00 1:40p Steven +// Added direction to hurt. +// +// 86 4/13/00 4:58p Steven +// Changed the string name of an event so that it didn't conflict with another +// one in actor. +// +// 85 4/13/00 3:45p Aldie +// Added more flashbang support. Added damage_type to entities used to specify +// what type of damage they take. +// +// 84 4/11/00 5:43p Steven +// Sinking into ground work. +// +// 83 4/10/00 6:49p Steven +// Added bind_use_my_angles so that a bound entity could use its angles for +// its local offset or its bindmaster. +// +// 82 4/10/00 11:57a Steven +// Moved process init commands to happen before EV_POSTSPAWN. +// +// 81 4/05/00 3:54p Markd +// made lightRadius work with settings from the editor +// +// 80 4/01/00 3:55p Markd +// Added FL_TOUCH_TRIGGERS support +// +// 79 3/31/00 6:23p Markd +// fixed usage of local orientation copy when edict->s.mat would work fine +// +// 78 3/31/00 6:07p Markd +// fixed matrix/orientation bug in entity +// +// 77 3/28/00 10:05a Steven +// Fixed one of the event documentations. +// +// 76 3/23/00 10:44a Markd +// fixed fade command, it wasn't setting the final alpha value +// +// 75 3/21/00 5:06p Markd +// added vehicle support +// +// 74 3/20/00 3:01p Markd +// added more functionality to falling rock +// +// 73 3/17/00 12:29p Steven +// Added means of death parameter to HurtEvent. +// +// 72 3/15/00 4:09p Aldie +// Fixed a bug with using weapons, and added some ability to force a state in +// the player +// +// 71 3/14/00 5:08p Aldie +// Fixed event mismatch +// +// 70 3/14/00 4:56p Aldie +// Added new script damage command +// +// 69 3/04/00 5:05p Steven +// Added a skipent to CanDamage and made Explosion pass in an owner to +// ExplosionAttack. +// +// 68 3/04/00 11:48a Markd +// Added light style support +// +// 67 3/01/00 10:58a Jimdose +// added TriggerEvent +// +// 66 2/21/00 4:39p Markd +// Added fade command to entity +// +// 65 2/21/00 3:33p Steven +// Added a GetControllerAngles function. +// +// 64 2/18/00 6:41p Markd +// Added crossblend support to surfaces +// +// 63 2/18/00 6:21p Aldie +// Added yet another parm to attachmodel... we need to find a better way to fix +// that. +// +// 62 2/17/00 8:07p Aldie +// Put in a fix for fading models +// +// 61 2/17/00 6:33p Aldie +// Added even more parms to attachmodel +// +// 60 2/07/00 3:59p Steven +// Fixed dead monsters not always falling to the ground. +// +// 59 2/03/00 7:01p Jimdose +// made all hardcoded map bounds use MAX_MAP_BOUNDS +// +// 58 1/31/00 3:56p Aldie +// working on the auto aim / tracking code +// +// 57 1/29/00 5:27p Steven +// Fixed children not using entity numbers correctly (weren't using +// ENTITYNUM_NONE). +// +// 56 1/27/00 12:15p Markd +// added fullbright support and minlight support to all lighting functions +// +// 55 1/27/00 11:35a Markd +// Fixed solid/notsolid client side entities +// +// 54 1/22/00 2:54p Markd +// fixed sprite problem where sprites were incorrectly set to ET_MODELANIM +// instead of ET_SPRITE +// +// 53 1/22/00 1:43p Markd +// Fixed attached entity bug +// +// 52 1/22/00 12:42p Jimdose +// got rid of calls to vec3() +// +// 51 1/20/00 7:05p Jimdose +// removed angmod +// +// 50 1/19/00 9:01p Steven +// Added fade support to the attachmodel command. +// +// 49 1/19/00 7:59p Markd +// Rewrote Surface Model Event and also added changeoutfit command to player +// +// 48 1/19/00 7:09p Steven +// Added a removeattachedmodel event. +// +// 47 1/15/00 3:57p Markd +// Eliminated multiple "angle" events and replaced them with EV_SetAngle +// +// 46 1/14/00 5:06p Markd +// Removed surface num, tri_num and damage_multiplier from multiple functions +// and events +// +// 45 1/13/00 7:08p Steven +// Made a SetControllerAngles event so I could post them in the future. +// +// 44 1/12/00 6:17p Jimdose +// fixed spawnflags--added spawnflags to level +// +// 43 1/10/00 6:17p Jimdose +// more code cleanup +// +// 42 1/06/00 7:00p Steven +// Made it so the surface command would recognize * notation. +// +// 41 1/05/00 7:25p Jimdose +// made angle functions all use the same coordinate system +// AngleVectors now returns left instead of right +// no longer need to invert pitch +// +// 40 12/20/99 11:41a Markd +// Fixed a music trigger issue +// +// 39 12/17/99 8:26p Jimdose +// got rid of unused vars and functions +// +// 38 12/17/99 6:35p Jimdose +// changed spawnarg code +// added Level class for spawning and map control +// got rid of unused or superflous variables +// changed setjmp/longjmp calls to try/throw/catch exception handling +// +// 37 12/14/18 2:42p Jimdose +// moved blood_model to Sentient +// +// 36 12/02/99 6:57p Jimdose +// removed classname variable from Entity +// +// 35 11/12/99 6:52p Markd +// fixed up sound manager saving and loading +// +// 34 11/02/99 6:12p Steven +// Always send original position of sound even if attached to entity. +// +// 33 11/02/99 5:44p Steven +// Added level wide sound stuff. +// +// 32 11/01/99 4:00p Jimdose +// added SetControllerAngles and SetControllerTag +// +// 31 10/28/99 6:07p Steven +// Added a use_angles flag and an offset to the entity attach stuff. +// +// 30 10/25/99 6:39p Markd +// removed size and other unused variables, added radius and centroid to both +// server and game code +// +// 29 10/22/99 11:02a Markd +// fixed fadein command again! +// +// 28 10/21/99 5:24p Aldie +// Removed scaling from fade +// +// 27 10/21/99 2:19p Markd +// Changed range to use ..., fixed fadein and fadeout some more +// +// 26 10/21/99 1:55p Markd +// added more functionality to fadein and fadeout +// +// 25 10/21/99 10:57a Markd +// Added fade in and fixed suppresion of _events. +// +// 24 10/19/99 7:52p Markd +// Removed three part model system +// +// 23 10/14/99 11:05a Aldie +// Make attached models Animate instead of Entity +// +// 22 10/11/99 3:10p Steven +// Event documentation cleanup. +// +// 21 10/08/99 2:12p Markd +// Made entities default to ET_GENERAL, ET_MODELANIm if tiki and ET_SPRITE if +// sprite +// +// 20 10/07/99 12:45p Aldie +// initialized the owner num to the ENTITYNUM_NONE +// +// 19 10/06/99 7:25p Markd +// removed TIMESTAMP, time and fixed make_static bug +// +// 18 10/03/99 4:38p Markd +// Fixed ?Out command +// +// 17 10/02/99 6:51p Markd +// Put in backend work for event documentation and fixed a lot of event +// documentation bugs +// +// 16 10/01/99 4:52p Markd +// Made Warning level 4 work on all projects +// +// 15 10/01/99 2:42p Markd +// moved all the binding code back into Entity from Mover +// +// 14 9/30/99 4:38p Aldie +// Fix for sprites +// +// 13 9/29/99 7:43p Markd +// Made items behave better when dropping to floor +// +// 12 9/28/99 10:06a Markd +// somehow forgot to checkin some changes +// +// 11 9/28/99 9:51a Markd +// fixed default flags +// +// 10 9/27/99 5:44p Markd +// began documentation and cleanup phase after merge +// +// 9 9/20/99 11:43a Markd +// added currentOrigin and currentAngles support to setOrigin and setAngles +// +// 8 9/17/99 5:32p Jimdose +// added TR_LERP +// +// 7 9/17/99 4:54p Aldie +// Fix for parent +// +// 6 9/16/99 7:43p Jimdose +// added check for NULL child in destructor +// +// 5 9/16/99 4:47p Jimdose +// removed SpawnParticles +// +// 4 9/16/99 3:18p Markd +// fixed some entity number screwups +// +// 3 9/16/99 11:18a Markd +// Continuing merge of code, not functional yet but closer +// +// 2 9/13/99 3:27p Aldie +// code merge +// +// 1 9/10/99 10:53a Jimdose +// +// 1 9/08/99 3:15p Aldie +// +// 74 9/02/99 7:43p Markd +// Cached blood model +// +// 73 9/02/99 5:41p Markd +// made CacheResource utility functions changed code every where else +// +// 72 9/02/99 4:35p Markd +// Added Color Offset support for sentients +// +// 71 9/02/99 3:06p Markd +// Fixed speakers, precaching of models and appending "models" and +// automatically caching in projectiles. +// +// 70 9/02/99 2:33p Markd +// Added cache ability to entities +// +// 69 9/02/99 10:49a Steven +// Added a life parameter to the attachmodel command. +// +// 68 9/01/99 6:46p Markd +// made attached models MOVETYPE_NONE +// +// 67 9/01/99 12:02p Steven +// Added blood spurts. +// +// 66 8/31/99 2:44p Steven +// Added a detach_at_death flag to models and fixed explosion origins. +// +// 65 8/30/99 3:25p Steven +// Added an event to kill all of an entities attachments. +// +// 64 8/30/99 2:36p Steven +// Added support for aliases, volume, and minimum distance for loop sounds. +// +// 63 8/28/99 7:46p Markd +// added broadcast to any entity that is a portal sky origin +// +// 62 8/28/99 11:43a Steven +// Removed global from sound function calls. +// +// 61 8/25/99 9:01p Markd +// working on RF_ stuff and local color for entities on client +// +// 60 8/24/99 11:51a Aldie +// Added viewlensflare command +// +// 59 8/24/99 11:26a Steven +// Reworked sound stuff to use global alias, then tiki alias, and then the +// literal. +// +// 58 8/19/99 6:59p Markd +// removed the old tiki_cmd structure, now tiki_cmd_t is passed into the tiki +// functions +// +// 57 8/18/99 3:28p Jimdose +// added cylindrical collision detection +// +// 56 8/17/99 4:49p Markd +// Fixed offset shader effect +// +// 55 8/09/99 11:44a Markd +// Added timestamps for translation and rotation +// +// 54 8/09/99 11:36a Steven +// Explosions can now be based off of tags now instead of just the entities +// origin. +// +// 53 8/06/99 8:00p Markd +// Added shader modifiable from script +// +// 52 8/06/99 3:35p Markd +// Cleaned up cgame, added shader commands and shader manipulation support +// +// 51 7/30/99 6:45p Aldie +// Added explosion command +// +// 50 7/30/99 4:49p Steven +// Added a stationary command to entities and a gas explode flag. +// +// 49 7/23/99 3:27p Aldie +// +// 48 7/08/99 4:58p Markd +// Added scale ability to attachmodel events +// +// 47 7/06/99 8:33p Jimdose +// removed unused player code +// added state machine for player animation +// +// 46 6/16/99 3:52p Aldie +// Make sure sprites entity type get set properly +// +// DESCRIPTION: +// Base class for all enities that are controlled by Sin. If you have any +// object that should be called on a periodic basis and it is not an entity, +// then you have to have an dummy entity that calls it. +// +// An entity in Sin is any object that is not part of the world. Any non-world +// object that is visible in Sin is an entity, although it is not required that +// all entities be visible to the player. Some objects are basically just virtual +// constructs that act as an instigator of certain actions, for example, some +// triggers are invisible and cannot be touched, but when activated by other +// objects can cause things to happen. +// +// All entities are capable of receiving messages from Sin or from other entities. +// Messages received by an entity may be ignored, passed on to their superclass, +// or acted upon by the entity itself. The programmer must decide on the proper +// action for the entity to take to any message. There will be many messages +// that are completely irrelevant to an entity and should be ignored. Some messages +// may require certain states to exist and if they are received by an entity when +// it these states don't exist may indicate a logic error on the part of the +// programmer or map designer and should be reported as warnings (if the problem is +// not severe enough for the game to be halted) or as errors (if the problem should +// not be ignored at any cost). +// + +#include "entity.h" +#include "worldspawn.h" +#include "scriptmaster.h" +#include "sentient.h" +#include "misc.h" +#include "specialfx.h" +#include "object.h" +#include "player.h" +#include "weaputils.h" +#include "soundman.h" +#include "../qcommon/qfiles.h" + +// Player events +Event EV_ClientMove + ( + "client_move", + EV_DEFAULT, + NULL, + NULL, + "The movement packet from the client is processed by this event." + ); +Event EV_ClientEndFrame + ( + "client_endframe", + EV_DEFAULT, + NULL, + NULL, + "Called at the end of each frame for each client." + ); + +// Generic entity events +Event EV_Classname + ( + "classname" , + EV_DEFAULT, + "s", + "nameOfClass", + "Determines what class to use for this entity,\n" + "this is pre-processed from the BSP at the start\n" + "of the level." + ); +Event EV_SpawnFlags + ( + "spawnflags", + EV_DEFAULT, + "i", + "flags", + "spawnflags from the BSP, these are set inside the editor" + ); +Event EV_SetTeam + ( + "team", + EV_DEFAULT, + "s", + "moveTeam", + "used to make multiple entities move together." + ); +Event EV_Trigger + ( + "trigger", + EV_DEFAULT, + "s", + "name", + "Trigger the specified target or entity." + ); +Event EV_Activate + ( + "doActivate", + EV_DEFAULT, + "e", + "activatingEntity", + "General trigger event for all entities" + ); +Event EV_Use + ( + "doUse", + EV_DEFAULT, + "e", + "activatingEntity", + "sent to entity when it is used by another entity" + ); + +Event EV_FadeNoRemove + ( + "fade", + EV_DEFAULT, + "F[0,]F[0,1]", + "fadetime target_alpha", + "Fade the entity's alpha, reducing it by 0.03\n" + "every FRAMETIME, until it has faded out, does not remove the entity" + ); + +Event EV_FadeOut + ( + "_fadeout", + EV_DEFAULT, + NULL, + NULL, + "Fade the entity's alpha and scale out, reducing it by 0.03\n" + "every FRAMETIME, until it has faded out, removes the entity\n" + "Once the entity has been completely faded, the entity is removed." + ); + +Event EV_Fade + ( + "fadeout", + EV_DEFAULT, + "F[0,]F[0,1]", + "fadetime target_alpha", + "Fade the entity's alpha and scale out, reducing it by 0.03\n" + "every FRAMETIME, until it has faded out. If fadetime or\n" + "target_alpha are defined, they will override the defaults.\n" + "Once the entity has been completely faded, the entity is removed." + ); +Event EV_FadeIn + ( + "fadein", + EV_DEFAULT, + "F[0,]F[0,1]", + "fadetime target_alpha", + "Fade the entity's alpha and scale in, increasing it by 0.03\n" + "every FRAMETIME, until it has faded completely in to 1.0.\n" + "If fadetime or target_alpha are defined, they will override\n" + "the default values." + ); + Event EV_Killed + ( + "killed", + EV_DEFAULT, + "eiei", + "attacker damage inflictor meansofdeath", + "event which is sent to an entity once it as been killed" + ); +Event EV_GotKill + ( + "gotkill" , + EV_DEFAULT, + "eieib", + "victim damage inflictor meansofdeath gib", + "event sent to attacker when an entity dies" + ); +Event EV_Pain + ( + "pain", + EV_DEFAULT, + "iei", + "damage attacker meansofdeath", + "used to inflict pain to an entity" + ); +Event EV_Damage + ( + "_damage", + EV_DEFAULT, + "ieevvviii", + "damage inflictor attacker position direction normal knockback damageflags meansofdeath", + "general damage event used by all entities" + ); +Event EV_Stun + ( + "_stun", + EV_DEFAULT, + "f", + "time", + "Stun this entity for the specified time" + ); +Event EV_Kill + ( + "kill", + EV_CONSOLE, + NULL, + NULL, + "console based command to kill yourself if stuck." + ); +Event EV_Gib + ( + "gib", + EV_DEFAULT, + "iIFS", + "number power scale gibmodel", + "causes entity to spawn a number of gibs" + ); +Event EV_Hurt + ( + "hurt", + EV_DEFAULT, + "iSV", + "damage means_of_death direction", + "Inflicts damage if the entity is damageable. If the number of damage\n" + "points specified in the command argument is greater or equal than the\n" + "entity's current health, it will be killed or destroyed." + ); + +Event EV_TakeDamage + ( + "takedamage", + EV_DEFAULT, + NULL, + NULL, + "makes entity take damage." + ); +Event EV_NoDamage + ( + "nodamage", + EV_DEFAULT, + NULL, + NULL, + "entity does not take damage." + ); + +Event EV_Stationary + ( + "stationary", + EV_DEFAULT, + NULL, + NULL, + "entity does not move, causes no physics to be run on it." + ); + +// Physics events +Event EV_MoveDone + ( + "movedone", + EV_DEFAULT, + "e", + "finishedEntity", + "Sent to commanding thread when done with move ." + ); +Event EV_Touch + ( + "doTouch", + EV_DEFAULT, + "e", + "touchingEntity", + "sent to entity when touched." + ); +Event EV_Blocked + ( + "doBlocked", + EV_DEFAULT, + "e", + "obstacle", + "sent to entity when blocked." + ); +Event EV_UseBoundingBox + ( + "usebbox", + EV_DEFAULT, + NULL, + NULL, + "do not perform perfect collision, use bounding box instead." + ); +Event EV_Gravity + ( + "gravity", + EV_DEFAULT, + "f", + "gravityValue", + "Change the gravity on this entity" + ); +Event EV_Stop + ( + "stopped", + EV_DEFAULT, + NULL, + NULL, + "sent when entity has stopped bouncing for MOVETYPE_TOSS." + ); + +Event EV_ProcessInitCommands + ( + "processinit", + EV_DEFAULT, + "i", + "modelIndex", + "process the init section of this entity, this is an internal command,\n" + "it is not meant to be called from script." + ); +Event EV_Attach + ( + "attach", + EV_DEFAULT, + "esI", + "parent tagname use_angles", + "attach this entity to the parent's legs tag called tagname" + ); +Event EV_AttachModel + ( + "attachmodel", + EV_DEFAULT, + "ssFSBFFFFV", + "modelname tagname scale targetname detach_at_death removetime fadeintime fadeoutdelay fadetime offset", + "attach a entity with modelname to this entity to tag called tagname.\n" + "scale - scale of attached entities\n" + "targetname - targetname for attached entities\n" + "detach_at_death - when entity dies, should this model be detached.\n" + "removetime - when the entity should be removed, if not specified, never.\n" + "fadeintime - time to fade the model in over.\n" + "fadeoutdelay - time to wait until we fade the attached model out\n" + "fadeoutspeed - time the model fades out over\n" + "offset - vector offset for the model from the specified tag" + ); +Event EV_RemoveAttachedModel + ( + "removeattachedmodel", + EV_DEFAULT, + "s", + "tagname", + "Removes the model attached to this entity at the specified tag." + ); +Event EV_Detach + ( + "detach", + EV_DEFAULT, + NULL, + NULL, + "detach this entity from its parent." + ); + +// script stuff +Event EV_Model + ( + "model", + EV_DEFAULT, + "e", + "modelName", + "set the model to modelName." + ); +Event EV_Hide + ( + "hide", + EV_DEFAULT, + NULL, + NULL, + "hide the entity, opposite of show." + ); +Event EV_Show + ( + "show", + EV_DEFAULT, + NULL, + NULL, + "show the entity, opposite of hide." + ); +Event EV_BecomeSolid + ( + "solid", + EV_DEFAULT, + NULL, + NULL, + "make solid." + ); +Event EV_BecomeNonSolid + ( + "notsolid", + EV_DEFAULT, + NULL, + NULL, + "make non-solid." + ); +Event EV_Ghost + ( + "ghost", + EV_DEFAULT, + NULL, + NULL, + "make non-solid but still send to client regardless of hide status." + ); +Event EV_TouchTriggers + ( + "touchtriggers", + EV_DEFAULT, + NULL, + NULL, + "this entity should touch triggers." + ); + + +Event EV_Sound + ( + "playsound", + EV_DEFAULT, + "sIFS", + "soundName channel volume min_distance", + "play a sound coming from this entity.\n" + "default channel, CHAN_BODY." + ); +Event EV_StopSound + ( + "stopsound", + EV_DEFAULT, + "I", + "channel", + "stop the current sound on the specified channel.\n" + "default channel, CHAN_BODY." + ); +Event EV_Bind + ( + "bind", + EV_DEFAULT, + "e", + "parent", + "bind this entity to the specified entity." + ); +Event EV_Unbind + ( + "unbind", + EV_DEFAULT, + NULL, + NULL, + "unbind this entity." + ); +Event EV_JoinTeam + ( + "joinTeam", + EV_DEFAULT, + "e", + "teamMember", + "join a bind team." + ); +Event EV_QuitTeam + ( + "quitTeam", + EV_DEFAULT, + NULL, + NULL, + "quit the current bind team" + ); +Event EV_SetHealth + ( + "health", + EV_CHEAT, + "i", + "newHealth", + "set the health of the entity to newHealth" + ); +Event EV_SetScale + ( + "scale", + EV_DEFAULT, + "f", + "newScale", + "set the scale of the entity" + ); +Event EV_SetSize + ( + "setsize", + EV_DEFAULT, + "vv", + "mins maxs", + "Set the bounding box of the entity to mins and maxs." + ); +Event EV_SetMins + ( + "_setmins", + EV_DEFAULT, + "v", + "mins", + "Set the mins of the bounding box of the entity to mins." + ); +Event EV_SetMaxs + ( + "_setmaxs", + EV_DEFAULT, + "v", + "maxs", + "Set the maxs of the bounding box of the entity to maxs." + ); +Event EV_SetAlpha + ( + "alpha", + EV_DEFAULT, + "f", + "newAlpha", + "Set the alpha of the entity to alpha." + ); +Event EV_SetOrigin + ( + "origin", + EV_DEFAULT, + "v", + "newOrigin", + "Set the origin of the entity to newOrigin." + ); +Event EV_SetTargetName + ( + "targetname", + EV_DEFAULT, + "s", + "targetName", + "set the targetname of the entity to targetName." + ); +Event EV_SetTarget + ( + "target", + EV_DEFAULT, + "s", + "targetname_to_target", + "target another entity with targetname_to_target." + ); +Event EV_SetKillTarget + ( + "killtarget", + EV_DEFAULT, + "s", + "targetName", + "when dying kill entities with this targetName." + ); +Event EV_SetAngles + ( + "angles", + EV_DEFAULT, + "v[0,360][0,360][0,360]", + "newAngles", + "set the angles of the entity to newAngles." + ); +Event EV_SetAngle + ( + "angle", + EV_DEFAULT, + "f", + "newAngle", + "set the angles of the entity using just one value.\n" + "Sets the yaw of the entity or an up and down\n" + "direction if newAngle is [0-359] or -1 or -2" + ); +Event EV_RegisterAlias + ( + "alias", + EV_CACHE, + "ssSSSSSS", + "alias realname parameter1 parameter2 parameter3 parameter4 parameter5 paramater6", + "create an alias for the given realname\n" + "Valid parameters are as follows:\n" + "global - all instances act as one\n" + "stop - once used, don't use again\n" + "timeout [seconds] - once used wait [seconds] until using again\n" + "maxuse [times] - can only be used [times] times.\n" + "weight [weight] - random weighting" + ); +Event EV_RegisterAliasAndCache + ( + "aliascache", + EV_CACHE, + "ssSSSSSS", + "alias realname parameter1 parameter2 parameter3 parameter4 parameter5 paramater6", + "create an alias for the given realname and cache the resource\n" + "Valid parameters are as follows:\n" + "global - all instances act as one\n" + "stop - once used, don't use again\n" + "timeout [seconds] - once used wait [seconds] until using again\n" + "maxuse [times] - can only be used [times] times.\n" + "weight [weight] - random weighting" + ); +Event EV_Cache + ( + "cache", + EV_CACHE, + "s", + "resourceName", + "pre-cache the given resource." + ); +Event EV_SetMass + ( + "mass", + EV_DEFAULT, + "f", + "massAmount", + "set the mass of this entity." + ); + +Event EV_LoopSound + ( + "loopsound", + EV_DEFAULT, + "sFS", + "soundName volume minimum_distance", + "play a looped-sound with a certain volume and minimum_distance\n" + "which is attached to the current entity." + ); +Event EV_StopLoopSound + ( + "stoploopsound", + EV_DEFAULT, + NULL, + NULL, + "Stop the looped-sound on this entity." + ); + +Event EV_SurfaceModelEvent + ( + "surface", + EV_DEFAULT, + "sSSSSSS", + "surfaceName parameter1 parameter2 parameter3 parameter4 parameter5 parameter6", + "change a legs surface parameter for the given surface.\n" + "+ sets the flag, - clears the flag\n" + "Valid surface commands are:\n" + "skin1 - set the skin1 offset bit\n" + "skin2 - set the skin2 offset bit\n" + "nodraw - don't draw this surface" + ); +// AI sound events +Event EV_BroadcastSound + ( + "soundevent", + EV_DEFAULT, + "F", + "soundRadius", + "Let the AI know that this entity made a sound,\n" + "radius determines how far the sound reaches." + ); +Event EV_HeardSound + ( + "heardsound", + EV_DEFAULT, + "ev", + "noisyEntity noisyLocation", + "sent to entities when another makes a sound, not for script use\n" + ); + +// Conditionals +Event EV_IfSkill + ( + "ifskill", + EV_DEFAULT, + "isSSSSS", + "skillLevel command argument1 argument2 argument3 argument4 argument5", + "if the current skill level is skillLevel than execute command" + ); + +// Lighting +Event EV_SetLight + ( + "light", + EV_DEFAULT, + "ffff", + "red green blue radius", + "Create a dynmaic light on this entity." + ); + +Event EV_LightOn + ( + "lightOn", + EV_DEFAULT, + NULL, + NULL, + "Turn the configured dynmaic light on this entity on." + ); +Event EV_LightOff + ( + "lightOff", + EV_DEFAULT, + NULL, + NULL, + "Turn the configured dynamic light on this entity off." + ); +Event EV_LightStyle + ( + "lightStyle", + EV_DEFAULT, + "i", + "lightStyleIndex", + "What light style to use for this dynamic light on this entity." + ); +Event EV_LightRed + ( + "lightRed", + EV_DEFAULT, + "f", + "red", + "Set the red component of the dynmaic light on this entity." + ); +Event EV_LightGreen + ( + "lightGreen", + EV_DEFAULT, + "f", + "red", + "Set the red component of the dynmaic light on this entity." + ); +Event EV_LightBlue + ( + "lightBlue", + EV_DEFAULT, + "f", + "red", + "Set the red component of the dynmaic light on this entity." + ); +Event EV_LightRadius + ( + "lightRadius", + EV_DEFAULT, + "f", + "red", + "Set the red component of the dynmaic light on this entity." + ); + +// Entity flag specific +Event EV_EntityFlags + ( + "flags", + EV_DEFAULT, + "SSSSSS", + "parameter1 parameter2 parameter3 parameter4 parameter5 parameter6", + "Change the current entity flags.\n" + "Valid flags are as follows:\n" + "+ sets a flag, - clears a flag\n" + "blood - should it bleed\n" + "explode - should it explode when dead\n" + "die_gibs - should it spawn gibs when dead\n" + "god - makes the entity invincible\n" + ); +Event EV_EntityRenderEffects + ( + "rendereffects", + EV_DEFAULT, + "SSSSSS", + "parameter1 parameter2 parameter3 parameter4 parameter5 parameter6", + "Change the current render effects flags.\n" + "Valid flags are as follows:\n" + "+ sets a flag, - clears a flag\n" + "dontdraw - send the entity to the client, but don't draw\n" + "betterlighting - do sphere based vertex lighting on the entity\n" + "lensflare - add a lens glow to the entity at its origin\n" + "viewlensflare - add a view dependent lens glow to the entity at its origin\n" + "lightoffset - use the dynamic color values as a light offset to the model\n" + "skyorigin - this entity is the portal sky origin\n" + "minlight - this entity always has some lighting on it\n" + "fullbright - this entity is always fully lit\n" + "additivedynamiclight - the dynamic light should have an additive effect\n" + "lightstyledynamiclight - the dynamic light uses a light style, use the\n" + "'lightstyle' command to set the index of the light style to be used" + ); +Event EV_EntityEffects + ( + "effects", + EV_DEFAULT, + "SSSSSS", + "parameter1 parameter2 parameter3 parameter4 parameter5 parameter6", + "Change the current entity effects flags.\n" + "Valid flags are as follows:\n" + "+ sets a flag, - clears a flag\n" + "antisbjuice - anti sucknblow juice" + "everyframe - process commands every time entity is rendered" + ); +Event EV_EntitySVFlags + ( + "svflags", + EV_DEFAULT, + "SSSSSS", + "parameter1 parameter2 parameter3 parameter4 parameter5 parameter6", + "Change the current server flags.\n" + "Valid flags are as follows:\n" + "+ sets a flag, - clears a flag\n" + "broadcast - always send this entity to the client" + ); + +// Special Effects +Event EV_Censor + ( + "censor", + EV_DEFAULT, + NULL, + NULL, + "used to ban certain contact when in parentmode\n" + ); +Event EV_Explosion + ( + "explosionattack", + EV_DEFAULT, + "sS", + "explosionModel tagName", + "Spawn an explosion optionally from a specific tag" + ); + +Event EV_ShaderEvent + ( + "shader", + EV_DEFAULT, + "sfF", + "shaderCommand argument1 argument2", + "change a specific shader parameter for the entity.\n" + "Valid shader commands are:\n" + "translation [trans_x] [trans_y] - change the texture translation\n" + "offset [offset_x] [offset_y] - change the texture offset\n" + "rotation [rot_speed] - change the texture rotation speed\n" + "frame [frame_num] - change the animated texture frame\n" + "wavebase [base] - change the base parameter of the wave function\n" + "waveamp [amp] - change the amp parameter of the wave function\n" + "wavebase [phase] - change the phase parameter of the wave function\n" + "wavefreq [freq] - change the frequency parameter of the wave function\n" + ); + +Event EV_ScriptShaderEvent + ( + "scriptshader", + EV_DEFAULT, + "sfF", + "shaderCommand argument1 argument2", + "alias for shader command, change a specific shader parameter for the entity.\n" + "Valid shader commands are:\n" + "translation [trans_x] [trans_y] - change the texture translation\n" + "offset [offset_x] [offset_y] - change the texture offset\n" + "rotation [rot_speed] - change the texture rotation speed\n" + "frame [frame_num] - change the animated texture frame\n" + "wavebase [base] - change the base parameter of the wave function\n" + "waveamp [amp] - change the amp parameter of the wave function\n" + "wavebase [phase] - change the phase parameter of the wave function\n" + "wavefreq [freq] - change the frequency parameter of the wave function\n" + ); + +Event EV_KillAttach + ( + "killattach", + EV_DEFAULT, + NULL, + NULL, + "kill all the attached entities." + ); +Event EV_DropToFloor + ( + "droptofloor", + EV_DEFAULT, + "F", + "maxRange", + "drops the entity to the ground, if maxRange is not specified 8192 is used." + ); +Event EV_AddToSoundManager + ( + "_addtosoundmanager", + EV_DEFAULT, + NULL, + NULL, + "adds the current entity to the sound manager." + ); +Event EV_SetControllerAngles + ( + "setcontrollerangles", + EV_DEFAULT, + "iv", + "num angles", + "Sets the control angles for the specified bone." + ); +Event EV_DeathSinkStart + ( + "deathsinkstart", + EV_DEFAULT, + NULL, + NULL, + "Makes the entity sink into the ground and then get removed (this starts it)." + ); +Event EV_DeathSink + ( + "deathsinkeachframe", + EV_DEFAULT, + NULL, + NULL, + "Makes the entity sink into the ground and then get removed (this gets called each frame)." + ); +Event EV_DamageType + ( + "damage_type", + EV_DEFAULT, + "s", + "meansofdeathstring", + "Set the type of damage that this entity can take" + ); +Event EV_LookAtMe + ( + "lookatme", + EV_DEFAULT, + NULL, + NULL, + "Makes the player look at this object if close." + ); +Event EV_DetachAllChildren + ( + "detachallchildren", + EV_DEFAULT, + NULL, + NULL, + "Detach all the children from the entity." + ); + +CLASS_DECLARATION( Listener, Entity, NULL ) + { + { &EV_Damage, DamageEvent }, + { &EV_DamageType, DamageType }, + { &EV_Kill, Kill }, + { &EV_FadeNoRemove, FadeNoRemove }, + { &EV_FadeOut, FadeOut }, + { &EV_FadeIn, FadeIn }, + { &EV_Fade, Fade }, + { &EV_Hide, EventHideModel }, + { &EV_Show, EventShowModel }, + { &EV_BecomeSolid, BecomeSolid }, + { &EV_BecomeNonSolid, BecomeNonSolid }, + { &EV_Ghost, Ghost }, + { &EV_TouchTriggers, TouchTriggersEvent }, + { &EV_Sound, Sound }, + { &EV_StopSound, StopSound }, + { &EV_SetHealth, SetHealth }, + { &EV_SetSize, SetSize }, + { &EV_SetMins, SetMins }, + { &EV_SetMaxs, SetMaxs }, + { &EV_SetScale, SetScale }, + { &EV_SetAlpha, SetAlpha }, + { &EV_SetOrigin, SetOrigin }, + { &EV_SetTargetName, SetTargetName }, + { &EV_SetTarget, SetTarget }, + { &EV_SetKillTarget, SetKillTarget }, + { &EV_SetAngles, SetAngles }, + { &EV_SetAngle, SetAngleEvent }, + { &EV_SetMass, SetMassEvent }, + { &EV_RegisterAlias, RegisterAlias }, + { &EV_RegisterAliasAndCache, RegisterAliasAndCache }, + { &EV_Cache, Cache }, + { &EV_LoopSound, LoopSound }, + { &EV_StopLoopSound, StopLoopSound }, + { &EV_Model, SetModelEvent }, + { &EV_SetLight, SetLight }, + { &EV_LightOn, LightOn }, + { &EV_LightOff, LightOff }, + { &EV_LightRed, LightRed }, + { &EV_LightGreen, LightGreen }, + { &EV_LightBlue, LightBlue }, + { &EV_LightRadius, LightRadius }, + { &EV_LightStyle, LightStyle }, + { &EV_EntityFlags, Flags }, + { &EV_EntityEffects, Effects }, + { &EV_EntitySVFlags, SVFlags }, + { &EV_EntityRenderEffects, RenderEffects }, + { &EV_BroadcastSound, BroadcastSound }, + { &EV_SurfaceModelEvent, SurfaceModelEvent }, + { &EV_ProcessInitCommands, ProcessInitCommandsEvent }, + { &EV_Attach, AttachEvent }, + { &EV_AttachModel, AttachModelEvent }, + { &EV_RemoveAttachedModel, RemoveAttachedModelEvent }, + { &EV_Detach, DetachEvent }, + { &EV_TakeDamage, TakeDamageEvent }, + { &EV_NoDamage, NoDamageEvent }, + { &EV_Gravity, Gravity }, + { &EV_UseBoundingBox, UseBoundingBoxEvent }, + { &EV_Hurt, HurtEvent }, + { &EV_IfSkill, IfSkillEvent }, + { &EV_Classname, ClassnameEvent }, + { &EV_SpawnFlags, SpawnFlagsEvent }, + { &EV_SetTeam, SetTeamEvent }, + { &EV_Trigger, TriggerEvent }, + { &EV_Censor, Censor }, + { &EV_Stationary, StationaryEvent }, + { &EV_Explosion, Explosion }, + { &EV_ShaderEvent, Shader }, + { &EV_ScriptShaderEvent, Shader }, + { &EV_KillAttach, KillAttach }, + { &EV_DropToFloor, DropToFloorEvent }, + { &EV_Bind, BindEvent }, + { &EV_Unbind, EventUnbind }, + { &EV_JoinTeam, JoinTeam }, + { &EV_QuitTeam, EventQuitTeam }, + { &EV_AddToSoundManager, AddToSoundManager }, + { &EV_SetControllerAngles, SetControllerAngles }, + { &EV_DeathSinkStart, DeathSinkStart }, + { &EV_DeathSink, DeathSink }, + { &EV_LookAtMe, LookAtMe }, + { &EV_DetachAllChildren, DetachAllChildren }, + { NULL, NULL } + }; + +Entity::Entity() + { + int i; + + edict = level.AllocEdict( this ); + client = edict->client; + entnum = edict->s.number; + + // spawning variables + spawnflags = level.spawnflags; + level.spawnflags = 0; + + // rendering variables + setAlpha( 1.0f ); + setScale( 1.0f ); + + // physics variables + move_time = 0; + total_delta = "0 0 0"; + mass = 0; + gravity = 1.0; + groundentity = NULL; + groundcontents = 0; + velocity = vec_zero; + avelocity = vec_zero; + edict->clipmask = MASK_SOLID; + + // team variables + teamchain = NULL; + teammaster = NULL; + + // bind variables + bindmaster = NULL; + edict->s.bindparent = ENTITYNUM_NONE; + + // this is an generic entity + edict->s.eType = ET_GENERAL; + + setContents( 0 ); + + edict->s.parent = ENTITYNUM_NONE; + edict->s.pos.trType = TR_LERP; + edict->ownerNum = ENTITYNUM_NONE; + + // model binding variables + numchildren = 0; + + for( i = 0 ; i < MAX_MODEL_CHILDREN ; i++ ) + children[i] = ENTITYNUM_NONE; + + setOrigin( vec_zero ); + origin.copyTo( edict->s.origin2 ); + + setAngles( vec_zero ); + + setMoveType( MOVETYPE_NONE ); + setSolidType( SOLID_NOT ); + + // Character state + health = 0; + max_health = 0; + deadflag = DEAD_NO; + flags = 0; + + // underwater variables + watertype = 0; + waterlevel = 0; + + // Pain and damage variables + takedamage = DAMAGE_NO; + enemy = NULL; + pain_finished = 0; + damage_debounce_time = 0; + damage_type = -1; + + detach_at_death = qtrue; + + // Surface variables + numsurfaces = 0; + + // Light variables + lightRadius = 0; + + look_at_me = false; + } + +Entity::~Entity() + { + Container bindlist; + Entity *ent; + int num; + int i; + + // unbind any entities that are bound to me + // can't unbind within this loop, so make an array + // and unbind them outside of it. + num = 0; + for( ent = teamchain; ent; ent = ent->teamchain ) + { + if ( ent->bindmaster == this ) + { + bindlist.AddObject( ent ); + } + } + + num = bindlist.NumObjects(); + for( i = 1; i <= num; i++ ) + { + bindlist.ObjectAt( i )->unbind(); + } + + bindlist.FreeObjectList(); + + unbind(); + quitTeam(); + + detach(); + + // + // go through and set our children + // + num = numchildren; + for( i = 0; ( i < MAX_MODEL_CHILDREN ) && num; i++ ) + { + if ( children[ i ] == ENTITYNUM_NONE ) + { + continue; + } + ent = G_GetEntity( children[ i ] ); + if ( ent ) + { + ent->PostEvent( EV_Remove, 0 ); + } + num--; + } + + if ( targetname.length() && world ) + { + world->RemoveTargetEntity( targetname, this ); + } + + level.FreeEdict( edict ); + } + +void Entity::SetEntNum + ( + int num + ) + + { + if ( edict ) + { + level.FreeEdict( edict ); + } + + level.spawn_entnum = num; + level.AllocEdict( this ); + client = edict->client; + entnum = edict->s.number; + } + +void Entity::ClassnameEvent + ( + Event *ev + ) + + { + strncpy( edict->entname, ev->GetString( 1 ), sizeof( edict->entname ) - 1 ); + } + +void Entity::SpawnFlagsEvent + ( + Event *ev + ) + + { + // spawning variables + spawnflags = ev->GetInteger( 1 ); + if ( spawnflags & SPAWNFLAG_DETAIL ) + { + edict->s.renderfx |= RF_DETAIL; + } + } + +void Entity::SetTarget + ( + const char *text + ) + + { + if ( text ) + { + target = text; + } + else + { + target = ""; + } + } + +void Entity::SetTargetName + ( + const char *text + ) + + { + if ( targetname.length() && world ) + { + world->RemoveTargetEntity( targetname, this ); + } + + if ( text ) + { + if ( text[ 0 ] == '$' ) + text++; + targetname = text; + } + else + { + targetname = ""; + } + + if ( targetname.length() && world ) + { + // + // make sure we don't re-targetname the world entity + // + if ( + ( this != world ) || + ( targetname == str( "world" ) ) + ) + { + world->AddTargetEntity( targetname, this ); + } + else + { + // this is bad + assert( 0 ); + gi.DPrintf( "world was re-targeted with targetname %s\n", targetname.c_str() ); + targetname = "world"; + } + + } + } + +void Entity::SetKillTarget + ( + const char *text + ) + + { + if ( text ) + { + killtarget = text; + } + else + { + killtarget = ""; + } + } + +void Entity::setModel + ( + const char *mdl + ) + + { + str temp; + + if ( LoadingSavegame && ( this == world ) ) + { + // don't set model on the world + return; + } + + if ( !mdl ) + { + mdl = ""; + } + + // Prepend 'models/' to make things easier + temp = ""; + if ( ( strlen( mdl ) > 0 ) && !strchr( mdl, '*' ) && strnicmp( "models/", mdl, 7 ) && !strstr( mdl, ".spr" ) ) + { + temp = "models/"; + } + temp += mdl; + + // we use a temp string so that if model was passed into here, we don't + // accidentally free up the string that we're using in the process. + model = temp; + + gi.setmodel( edict, model.c_str() ); + + if ( gi.IsModel( edict->s.modelindex ) ) + { + Event *ev; + + numsurfaces = gi.NumSurfaces( edict->s.modelindex ); + + if ( !LoadingSavegame ) + { + CancelEventsOfType( EV_ProcessInitCommands ); + + ev = new Event( EV_ProcessInitCommands ); + ev->AddInteger( edict->s.modelindex ); + PostEvent( ev, EV_PROCESS_INIT ); + } + else + { + ProcessInitCommands( edict->s.modelindex, qtrue ); + } + } + else if ( strstr( mdl, ".spr" ) ) + { + edict->s.eType = ET_SPRITE; + } + + // Sanity check to see if we're expecting a B-Model + assert( !( ( edict->solid == SOLID_BSP ) && !edict->s.modelindex ) ); + if ( ( edict->solid == SOLID_BSP ) && !edict->s.modelindex ) + { + const char *name; + + name = getClassID(); + if ( !name ) + { + name = getClassname(); + } + gi.DPrintf( "%s with SOLID_BSP and no model - '%s'(%d)\n", name, targetname.c_str(), entnum ); + + // Make it non-solid so that the collision code doesn't kick us out. + setSolidType( SOLID_NOT ); + } + + mins = edict->mins; + maxs = edict->maxs; + size = maxs - mins; + edict->radius = size.length() * 0.5f; + edict->radius2 = edict->radius * edict->radius; + + // + // see if we have a mins and maxs set for this model + // + //FIXME + //We only did this on startup, but with the spawnargs as events it would have to + //be here. Do we still need this? It may cause strange effects. + if ( gi.IsModel( edict->s.modelindex ) && !mins.length() && !maxs.length() ) + { + vec3_t tempmins, tempmaxs; + gi.CalculateBounds( edict->s.modelindex, edict->s.scale, tempmins, tempmaxs ); + setSize( tempmins, tempmaxs ); + } + } + +void Entity::ProcessInitCommands + ( + int index, + qboolean cache + ) + + { + tiki_cmd_t cmds; + + if ( LoadingSavegame && !cache ) + { + // Don't process init commands when loading a savegame since + // it will cause items to be added to inventories unnecessarily. + // All variables affected by the init commands will be set + // by the unarchive functions. + // + // we do want to process the cache commands though regardless + return; + } + + if ( gi.InitCommands( index, &cmds ) ) + { + int i, j, savedindex; + Event *event; + + // because the model has not necessarily been spawned yet, we need to set + // this entity to have this index so that precaches go where they are supposed + // to, this should have no bad effects, since we are only doing it in the + // cache phase of spawning + if ( index != edict->s.modelindex ) + { + savedindex = edict->s.modelindex; + edict->s.modelindex = index; + } + else + { + savedindex = -1; + } + for( i = 0; i < cmds.num_cmds; i++ ) + { + event = new Event( cmds.cmds[ i ].args[ 0 ] ); + if ( !cache || ( event->GetFlags() & EV_CACHE ) ) + { + for( j = 1; j < cmds.cmds[ i ].num_args; j++ ) + { + event->AddToken( cmds.cmds[ i ].args[ j ] ); + } + ProcessEvent( event ); + } + else + { + delete event; + } + } + // restore the modelindex, see above + if ( savedindex != -1 ) + { + edict->s.modelindex = savedindex; + } + } + } + +void Entity::ProcessInitCommandsEvent + ( + Event *ev + ) + + { + int index; + + index = ev->GetInteger( 1 ); + ProcessInitCommands( index, qfalse ); + } + +void Entity::EventHideModel + ( + Event *ev + ) + + { + hideModel(); + } + +void Entity::EventShowModel + ( + Event *ev + ) + + { + showModel(); + } + +void Entity::SetTeamEvent + ( + Event *ev + ) + + { + moveteam = ev->GetString( 1 ); + } + +void Entity::TriggerEvent + ( + Event *ev + ) + + { + const char *name; + Event *event; + Entity *ent; + TargetList *tlist; + int i; + int num; + + name = ev->GetString( 1 ); + + // Check for object commands + if ( name && name[ 0 ] == '$' ) + { + tlist = world->GetTargetList( str( name + 1 ) ); + num = tlist->list.NumObjects(); + for ( i = 1; i <= num; i++ ) + { + ent = tlist->list.ObjectAt( i ); + + assert( ent ); + + event = new Event( EV_Activate ); + event->SetSource( ev->GetSource() ); + event->SetThread( ev->GetThread() ); + event->SetLineNumber( ev->GetLineNumber() ); + event->AddEntity( this ); + ent->ProcessEvent( event ); + } + } + else if ( name[ 0 ] == '*' ) // Check for entnum commands + { + if ( !IsNumeric( &name[ 1 ] ) ) + { + ev->Error( "Expecting numeric value for * command, but found '%s'\n", &name[ 1 ] ); + } + else + { + ent = G_GetEntity( atoi( &name[ 1 ] ) ); + if ( ent ) + { + event = new Event( EV_Activate ); + event->SetSource( ev->GetSource() ); + event->SetThread( ev->GetThread() ); + event->SetLineNumber( ev->GetLineNumber() ); + event->AddEntity( this ); + ent->ProcessEvent( event ); + } + else + { + ev->Error( "Entity not found for * command\n" ); + } + } + return; + } + else + { + ev->Error( "Invalid entity reference '%s'.\n", name ); + } + } + +void Entity::setAlpha + ( + float alpha + ) + + { + if ( alpha > 1.0f ) + { + alpha = 1.0f; + } + if ( alpha < 0 ) + { + alpha = 0; + } + edict->s.alpha = alpha; + } + +void Entity::setScale + ( + float scale + ) + + { + edict->s.scale = scale; + } + +void Entity::setSolidType + ( + solid_t type + ) + + { + if ( + ( !LoadingSavegame ) && + ( type == SOLID_BSP ) && + ( this != world ) && + ( + !model.length() || + ( + ( model[ 0 ] != '*' ) && + ( !strstr( model.c_str(), ".bsp" ) ) + ) + ) + ) + { + error( "setSolidType", "SOLID_BSP entity at x%.2f y%.2f z%.2f with no BSP model", origin[ 0 ], origin[ 1 ], origin[ 2 ] ); + } + edict->solid = type; + + // + // set the appropriate contents type + if ( edict->solid == SOLID_BBOX ) + { + if ( !getContents() ) + setContents( CONTENTS_SOLID ); + } + else if ( edict->solid == SOLID_NOT ) + { + if ( getContents() == CONTENTS_SOLID ) + setContents( 0 ); + } + else if ( edict->solid == SOLID_BSP ) + { + if ( !getContents() ) + setContents( CONTENTS_SOLID ); + } + + link(); + + edict->svflags &= ~SVF_NOCLIENT; + if ( hidden() ) + { + edict->svflags |= SVF_NOCLIENT; + } + } + +void Entity::setSize + ( + Vector min, + Vector max + ) + + { + Vector delta; + + if ( flags & FL_ROTATEDBOUNDS ) + { + vec3_t tempmins, tempmaxs; + + // + // rotate the mins and maxs for the model + // + min.copyTo( tempmins ); + max.copyTo( tempmaxs ); + + CalculateRotatedBounds2( edict->s.mat, tempmins, tempmaxs ); + + mins = Vector( tempmins ); + maxs = Vector( tempmaxs ); + size = max - min; + + mins.copyTo( edict->mins ); + maxs.copyTo( edict->maxs ); + edict->radius = size.length() * 0.5; + edict->radius2 = edict->radius * edict->radius; + } + else + { + if ( ( min == edict->mins ) && ( max == edict->maxs ) ) + { + return; + } + + mins = min; + maxs = max; + size = max - min; + + mins.copyTo( edict->mins ); + maxs.copyTo( edict->maxs ); + + // + // get the full mins and maxs for this model + // + if ( gi.IsModel( edict->s.modelindex ) ) + { + vec3_t fullmins, fullmaxs; + Vector delta; + + gi.CalculateBounds( edict->s.modelindex, edict->s.scale, fullmins, fullmaxs ); + + delta = Vector( fullmaxs ) - Vector( fullmins ); + edict->radius = delta.length() * 0.5; + edict->radius2 = edict->radius * edict->radius; + } + else + { + edict->radius = size.length() * 0.5; + edict->radius2 = edict->radius * edict->radius; + } + } + + link(); + } + +Vector Entity::getLocalVector + ( + Vector vec + ) + + { + Vector pos; + + pos[ 0 ] = vec * orientation[ 0 ]; + pos[ 1 ] = vec * orientation[ 1 ]; + pos[ 2 ] = vec * orientation[ 2 ]; + + return pos; + } + +void Entity::link + ( + void + ) + + { + gi.linkentity( edict ); + absmin = edict->absmin; + absmax = edict->absmax; + centroid = ( absmin + absmax ) * 0.5; + centroid.copyTo( edict->centroid ); + + // If this has a parent, then set the areanum the same + // as the parent's + if ( edict->s.parent != ENTITYNUM_NONE ) + { + edict->areanum = g_entities[ edict->s.parent ].areanum; + } + } + +void Entity::addOrigin + ( + Vector add + ) + + { + setOrigin( localorigin + add ); + } + +void Entity::setOrigin + ( + void + ) + + { + setOrigin( localorigin ); + } + +void Entity::setOrigin + ( + Vector org + ) + + { + Entity * ent; + int i,num; + + if ( bindmaster ) + { + localorigin = org; + + if ( bind_use_my_angles ) + MatrixTransformVector( localorigin, orientation, origin ); + else + MatrixTransformVector( localorigin, bindmaster->orientation, origin ); + + origin += bindmaster->origin; + origin.copyTo( edict->s.netorigin ); + } + // If entity has a parent, then set the origin as the + // centroid of the parent, and set edict->s.netorigin + // as the local origin of the entity which will be used + // to position this entity on the client. + else if ( edict->s.parent != ENTITYNUM_NONE ) + { + VectorClear( edict->s.netorigin ); + ent = ( Entity * )G_GetEntity( edict->s.parent ); + + ent->GetTag( edict->s.tag_num & TAG_MASK, &origin ); + + origin += edict->s.attach_offset; + + localorigin = vec_zero; + } + else + { + origin = org; + localorigin = org; + origin.copyTo( edict->s.netorigin ); + } + + origin.copyTo( edict->s.origin ); + origin.copyTo( edict->currentOrigin ); + + link(); + +#if 0 + if ( this->isClient() ) + { + i = CurrentAnim(); + j = CurrentFrame(); + + G_DrawCoordSystem( origin, orientation[0], orientation[1], orientation[2], 30 ); + gi.Printf( "%s:legs anim:%s frame %i\n", this->getClassname(), gi.Anim_NameForNum( edict->s.modelindex, i ), j ); + } +#endif + + + // + // go through and set our children + // + num = numchildren; + for( i = 0; ( i < MAX_MODEL_CHILDREN ) && num; i++ ) + { + if ( children[ i ] == ENTITYNUM_NONE ) + { + continue; + } + ent = ( Entity * )G_GetEntity( children[ i ] ); + ent->setOrigin(); + num--; + } + } + +void Entity::GetRawTag + ( + int tagnum, + orientation_t * orient + ) + + { + int anim; + int frame; + + anim = CurrentAnim(); + frame = CurrentFrame(); + + *orient = gi.Tag_Orientation( edict->s.modelindex, anim, frame, tagnum & TAG_MASK, edict->s.scale, edict->s.bone_tag, edict->s.bone_quat ); + } + +qboolean Entity::GetRawTag + ( + const char *name, + orientation_t * orient + ) + { + int tagnum; + + tagnum = gi.Tag_NumForName( edict->s.modelindex, name ); + + if ( tagnum < 0 ) + return false; + + GetRawTag( tagnum, orient ); + return true; + } + +void Entity::GetTag + ( + int tagnum, + orientation_t * orient + ) + + { + orientation_t or; + int i; + + GetRawTag( tagnum, &or ); + + VectorCopy( origin, orient->origin ); + + for ( i = 0 ; i < 3 ; i++ ) + { + VectorMA( orient->origin, or.origin[i], orientation[i], orient->origin ); + } + MatrixMultiply( or.axis, orientation, orient->axis ); + } + +qboolean Entity::GetTag + ( + const char *name, + orientation_t * orient + ) + { + int tagnum; + + tagnum = gi.Tag_NumForName( edict->s.modelindex, name ); + + if ( tagnum < 0 ) + return false; + + GetTag( tagnum, orient ); + return true; + } + +void Entity::GetTag + ( + int tagnum, + Vector *pos, + Vector *forward, + Vector *left, + Vector *up + ) + + { + orientation_t or; + + GetTag( tagnum, &or ); + + if ( pos ) + { + *pos = Vector( or.origin ); + } + if ( forward ) + { + *forward = Vector( or.axis[ 0 ] ); + } + if ( left ) + { + *left = Vector( or.axis[ 1 ] ); + } + if ( up ) + { + *up = Vector( or.axis[ 2 ] ); + } + } + +qboolean Entity::GetTag + ( + const char *name, + Vector *pos, + Vector *forward, + Vector *left, + Vector *up + ) + + { + int tagnum; + + tagnum = gi.Tag_NumForName( edict->s.modelindex, name ); + + if ( tagnum < 0 ) + return false; + + GetTag( tagnum, pos, forward, left, up ); + return true; + } + +void Entity::addAngles + ( + Vector add + ) + + { + if ( bindmaster ) + { + setAngles( localangles + add ); + } + else + { + setAngles( angles + add ); + } + } + +void Entity::setAngles + ( + void + ) + + { + if ( bindmaster ) + { + setAngles( localangles ); + } + else + { + setAngles( angles ); + } + } + + +void Entity::setAngles + ( + Vector ang + ) + + { + Entity * ent; + int num,i; + + angles[ 0 ] = AngleMod( ang[ 0 ] ); + angles[ 1 ] = AngleMod( ang[ 1 ] ); + angles[ 2 ] = AngleMod( ang[ 2 ] ); + + localangles = angles; + if ( bindmaster ) + { + float mat[3][3]; + AnglesToAxis( localangles, mat ); + R_ConcatRotations( mat, bindmaster->orientation, orientation ); + MatrixToEulerAngles( orientation, angles ); + } + else + { + AnglesToAxis( angles, orientation ); + } + + angles.copyTo( edict->s.netangles ); + angles.copyTo( edict->s.angles ); + angles.copyTo( edict->currentAngles ); + // Fill the edicts matrix + VectorCopy( orientation[ 0 ], edict->s.mat[ 0 ] ); + VectorCopy( orientation[ 1 ], edict->s.mat[ 1 ] ); + VectorCopy( orientation[ 2 ], edict->s.mat[ 2 ] ); + + // + // go through and set our children + // + num = numchildren; + for (i=0;(i < MAX_MODEL_CHILDREN) && num;i++) + { + if ( children[i] == ENTITYNUM_NONE ) + continue; + ent = ( Entity * )G_GetEntity( children[i] ); + ent->setAngles(); + num--; + } + } + +qboolean Entity::droptofloor + ( + float maxfall + ) + + { + trace_t trace; + Vector end; + Vector start; + + start = origin + Vector( "0 0 1" ); + end = origin; + end[ 2 ]-= maxfall; + + trace = G_Trace( start, mins, maxs, end, this, edict->clipmask, false, "Entity::droptofloor" ); + if ( trace.fraction == 1 || trace.startsolid || trace.allsolid || !trace.ent ) + { + groundentity = world->edict; + return false; + } + + setOrigin( trace.endpos ); + + groundentity = trace.ent; + + return true; + } + +void Entity::DamageType + ( + Event *ev + ) + + { + str damage; + damage = ev->GetString( 1 ); + if ( damage == "all" ) + { + damage_type = -1; + } + else + { + damage_type = MOD_string_to_int( damage ); + } + } + +void Entity::Damage + ( + Entity *inflictor, + Entity *attacker, + float damage, + Vector position, + Vector direction, + Vector normal, + int knockback, + int dflags, + int meansofdeath + ) + + { + Event *ev; + + // if our damage types do not match, return + if ( !MOD_matches( meansofdeath, damage_type ) ) + { + return; + } + + if ( !attacker ) + { + attacker = world; + } + if ( !inflictor ) + { + inflictor = world; + } + + ev = new Event( EV_Damage ); + ev->AddFloat( damage ); + ev->AddEntity ( inflictor ); + ev->AddEntity ( attacker ); + ev->AddVector ( position ); + ev->AddVector ( direction ); + ev->AddVector ( normal ); + ev->AddInteger( knockback ); + ev->AddInteger( dflags ); + ev->AddInteger( meansofdeath ); + ProcessEvent ( ev ); + } + +void Entity::DamageEvent + ( + Event *ev + ) + + { + Entity *inflictor; + Entity *attacker; + int damage; + Vector dir; + Vector momentum; + Event *event; + float m; + + if ( ( takedamage == DAMAGE_NO ) || ( movetype == MOVETYPE_NOCLIP ) ) + { + return; + } + + damage = ev->GetInteger( 1 ); + inflictor = ev->GetEntity( 2 ); + attacker = ev->GetEntity( 3 ); + + // figure momentum add + if ( ( inflictor != world ) && + ( movetype != MOVETYPE_NONE ) && + ( movetype != MOVETYPE_STATIONARY ) && + ( movetype != MOVETYPE_BOUNCE ) && + ( movetype != MOVETYPE_PUSH ) && + ( movetype != MOVETYPE_STOP ) ) + { + dir = origin - ( inflictor->origin + ( inflictor->mins + inflictor->maxs ) * 0.5 ); + dir.normalize(); + + if ( mass < 50) + { + m = 50; + } + else + { + m = mass; + } + + momentum = dir * damage * ( 1700.0 / m ); + velocity += momentum; + } + + // check for godmode or invincibility + if ( flags & FL_GODMODE ) + { + return; + } + + // team play damage avoidance + //if ( ( global->teamplay == 1 ) && ( edict->team > 0 ) && ( edict->team == attacker->edict->team ) ) + // { + // return; + // } + + if ( !deathmatch->integer && isSubclassOf( Player ) ) + { + damage *= 0.15; + } + + if ( deadflag ) + { + // Check for gib. + if ( inflictor->isSubclassOf( Projectile ) ) + { + Event *gibEv; + + health -= damage; + + gibEv = new Event( EV_Gib ); + gibEv->AddEntity( this ); + gibEv->AddFloat( health ); + ProcessEvent( gibEv ); + } + return; + } + + // do the damage + health -= damage; + if ( health <= 0 ) + { + if ( attacker ) + { + event = new Event( EV_GotKill ); + event->AddEntity( this ); + event->AddInteger( damage ); + event->AddEntity( inflictor ); + event->AddInteger( ev->GetInteger( 9 ) ); + event->AddInteger( 0 ); + attacker->ProcessEvent( event ); + } + + event = new Event( EV_Killed ); + event->AddEntity( attacker ); + event->AddInteger( damage ); + event->AddEntity( inflictor ); + ProcessEvent( event ); + return; + } + + event = new Event( EV_Pain ); + event->AddFloat( damage ); + event->AddEntity( attacker ); + ProcessEvent( event ); + } + +void Entity::Stun + ( + float time + ) + + { + Event *ev = new Event( EV_Stun ); + ev->AddFloat( time ); + ProcessEvent( ev ); + } + +/* +============ +CanDamage + +Returns true if the inflictor can directly damage the target. Used for +explosions and melee attacks. +============ +*/ +qboolean Entity::CanDamage + ( + Entity *target, + Entity *skip_ent + ) + + { + trace_t trace; + Vector pos; + Entity *skip_entity; + + if ( skip_ent ) + skip_entity = skip_ent; + else + skip_entity = this; + + trace = G_Trace( origin, vec_origin, vec_origin, target->centroid, skip_entity, MASK_SHOT, false, "Entity::CanDamage 1" ); + if ( trace.fraction == 1 || trace.ent == target->edict ) + { + return true; + } + pos = target->centroid + Vector( 15, 15, 0 ); + trace = G_Trace( origin, vec_origin, vec_origin, pos, skip_entity, MASK_SHOT, false, "Entity::CanDamage 3" ); + if ( trace.fraction == 1 || trace.ent == target->edict ) + { + return true; + } + pos = target->centroid + Vector( -15, 15, 0 ); + trace = G_Trace( origin, vec_zero, vec_zero, pos, skip_entity, MASK_SHOT, false, "Entity::CanDamage 4" ); + if ( trace.fraction == 1 || trace.ent == target->edict ) + { + return true; + } + pos = target->centroid + Vector( 15, -15, 0 ); + trace = G_Trace( origin, vec_zero, vec_zero, pos, skip_entity, MASK_SHOT, false, "Entity::CanDamage 5" ); + if ( trace.fraction == 1 || trace.ent == target->edict ) + { + return true; + } + pos = target->centroid + Vector( -15, -15, 0 ); + trace = G_Trace( origin, vec_zero, vec_zero, pos, skip_entity, MASK_SHOT, false, "Entity::CanDamage 6" ); + if ( trace.fraction == 1 || trace.ent == target->edict ) + { + return true; + } + + return false; + } + +qboolean Entity::IsTouching + ( + Entity *e1 + ) + + { + if ( e1->absmin.x > absmax.x ) + { + return false; + } + if ( e1->absmin.y > absmax.y ) + { + return false; + } + if ( e1->absmin.z > absmax.z ) + { + return false; + } + if ( e1->absmax.x < absmin.x ) + { + return false; + } + if ( e1->absmax.y < absmin.y ) + { + return false; + } + if ( e1->absmax.z < absmin.z ) + { + return false; + } + + return true; + } + +void Entity::FadeNoRemove + ( + Event *ev + ) + + { + float rate; + float target; + float myalpha; + + if ( ev->NumArgs() > 1 ) + { + target = ev->GetFloat( 2 ); + } + else + { + target = 0; + } + + if ( ev->NumArgs() > 0 ) + { + rate = ev->GetFloat( 1 ); + assert( rate ); + if ( rate > 0 ) + rate = FRAMETIME / rate; + } + else + { + rate = 0.03; + } + + myalpha = edict->s.alpha; + myalpha -= rate; + + if ( myalpha < target ) + myalpha = target; + + setAlpha( myalpha ); + + if ( myalpha > target ) + { + PostEvent( *ev, FRAMETIME ); + } + + G_SetConstantLight( &edict->s.constantLight, &myalpha, &myalpha, &myalpha, 0 ); + } + +void Entity::FadeOut + ( + Event *ev + ) + + { + float myscale; + float myalpha; + + myscale = edict->s.scale; + myscale -= 0.03f; + myalpha = edict->s.alpha; + myalpha -= 0.03f; + if ( myscale < 0 ) + myscale = 0; + if ( myalpha < 0 ) + myalpha = 0; + + if ( myscale <= 0 && myalpha <= 0 ) + { + PostEvent( EV_Remove, 0 ); + } + else + { + PostEvent( *ev, FRAMETIME ); + } + + setScale( myscale ); + setAlpha( myalpha ); + } + +void Entity::FadeIn + ( + Event *ev + ) + + { + float rate; + float target; + float myalpha; + + if ( ev->NumArgs() > 1 ) + { + target = ev->GetFloat( 2 ); + } + else + { + target = 1; + } + + if ( ev->NumArgs() > 0 ) + { + rate = ev->GetFloat( 1 ); + assert( rate ); + if ( rate > 0 ) + rate = FRAMETIME / rate; + } + else + { + rate = 0.03; + } + + + myalpha = edict->s.alpha; + myalpha += rate; + + if ( myalpha > target ) + myalpha = target; + + if ( myalpha < target ) + { + PostEvent( *ev, FRAMETIME ); + } + setAlpha( myalpha ); + } + +void Entity::Fade + ( + Event *ev + ) + + { + float rate; + float target; + float myalpha; + + if ( ev->NumArgs() > 1 ) + { + target = ev->GetFloat( 2 ); + } + else + { + target = 0; + } + + if ( ev->NumArgs() > 0 ) + { + rate = ev->GetFloat( 1 ); + assert( rate ); + if ( rate > 0 ) + rate = FRAMETIME / rate; + } + else + { + rate = 0.03; + } + + myalpha = edict->s.alpha; + myalpha -= rate; + + if ( myalpha <= 0 ) + { + PostEvent( EV_Remove, 0 ); + return; + } + + if ( myalpha < target ) + myalpha = target; + + if ( myalpha > target ) + { + PostEvent( *ev, FRAMETIME ); + } + + setAlpha( myalpha ); + G_SetConstantLight( &edict->s.constantLight, &myalpha, &myalpha, &myalpha, 0 ); + } + +void Entity::SetMassEvent + ( + Event *ev + ) + + { + mass = ev->GetFloat( 1 ); + } + +void Entity::CheckGround + ( + void + ) + + { + Vector point; + trace_t trace; + + if ( flags & ( FL_SWIM | FL_FLY ) ) + { + return; + } + + if ( velocity.z > 100 ) + { + groundentity = NULL; + return; + } + + // if the hull point one-quarter unit down is solid the entity is on ground + point = origin; + point.z -= 0.25; + trace = G_Trace( origin, mins, maxs, point, this, edict->clipmask, false, "Entity::CheckGround" ); + + // check steepness + if ( ( trace.plane.normal[ 2 ] <= 0.7 ) && !trace.startsolid ) + { + groundentity = NULL; + return; + } + + groundentity = trace.ent; + groundplane = trace.plane; + groundcontents = trace.contents; + + if ( !trace.startsolid && !trace.allsolid ) + { + setOrigin( trace.endpos ); + velocity.z = 0; + } + } + +void Entity::BecomeSolid + ( + Event *ev + ) + + { + if ( ( model.length() ) && ( ( model[ 0 ] == '*' ) || ( strstr( model.c_str(), ".bsp" ) ) ) ) + { + setSolidType( SOLID_BSP ); + } + else + { + setSolidType( SOLID_BBOX ); + } + } + +void Entity::BecomeNonSolid + ( + Event *ev + ) + + { + setSolidType( SOLID_NOT ); + } + +void Entity::Ghost + ( + Event *ev + ) + + { + // Make not solid, but send still send over whether it is hidden or not + setSolidType( SOLID_NOT ); + edict->svflags &= ~SVF_NOCLIENT; + } + +void Entity::LoopSound + ( + Event *ev + ) + + { + str sound_name; + float volume = DEFAULT_VOL; + float min_dist = DEFAULT_MIN_DIST; + str min_dist_string; + + + if (ev->NumArgs() < 1) + return; + + // Get parameters + + sound_name = ev->GetString( 1 ); + + if ( ev->NumArgs() > 1 ) + volume = ev->GetFloat( 2 ); + + if ( ev->NumArgs() > 2 ) + { + min_dist_string = ev->GetString( 3 ); + + if ( min_dist_string == LEVEL_WIDE_STRING ) + min_dist = LEVEL_WIDE_MIN_DIST; + else + min_dist = ev->GetFloat( 3 ); + } + + // Add this sound to loop + + LoopSound( sound_name.c_str(), volume, min_dist ); + } + +void Entity::LoopSound( str sound_name, float volume, float min_dist ) + { + const char *name = NULL; + str random_alias; + + + // Get the real sound to be played + + if ( sound_name.length() > 0 ) + { + // Get the real sound to play + + name = gi.GlobalAlias_FindRandom( sound_name.c_str() ); + + if ( !name ) + { + random_alias = GetRandomAlias( sound_name ).c_str(); + + if ( random_alias.length() > 0 ) + name = random_alias.c_str(); + } + + if ( !name ) + name = sound_name.c_str(); + + // Add the looping sound to the entity + + edict->s.loopSound = gi.soundindex( name ); + edict->s.loopSoundVolume = volume; + edict->s.loopSoundMinDist = min_dist; + } + } + +void Entity::StopLoopSound( Event *ev ) + { + StopLoopSound(); + } + +void Entity::StopLoopSound( void ) + { + edict->s.loopSound = 0; + } + +void Entity::Sound( Event *ev ) + { + str sound_name; + float volume; + int channel; + float min_dist; + int i; + str min_dist_string; + + + // Set defaults + + volume = DEFAULT_VOL; + min_dist = DEFAULT_MIN_DIST; + channel = CHAN_BODY; + + // Get sound parameters + + for ( i = 1 ; i <= ev->NumArgs() ; i++ ) + { + switch (i-1) + { + case 0: + sound_name = ev->GetString( i ); + break; + case 1: + channel = ev->GetInteger( i ); + break; + case 2: + volume = ev->GetFloat( i ); + break; + case 3: + min_dist_string = ev->GetString( i ); + + if ( min_dist_string == LEVEL_WIDE_STRING ) + min_dist = LEVEL_WIDE_MIN_DIST; + else + min_dist = ev->GetFloat( i ); + break; + default: + break; + } + } + + Sound( sound_name, channel, volume, min_dist, NULL ); + } + +void Entity::StopSound + ( + Event *ev + ) + + { + if (ev->NumArgs() < 1) + StopSound( CHAN_BODY ); + else + StopSound( ev->GetInteger( 1 ) ); + } + +void Entity::StopSound + ( + int channel + ) + + { + gi.StopSound( entnum, channel ); + } + +void Entity::SetLight + ( + Event *ev + ) + + { + float r, g, b; + + if ( ev->NumArgs() == 1 ) + { + Vector tmp; + + tmp = ev->GetVector( 1 ); + r = tmp.x; + g = tmp.y; + b = tmp.z; + } + else + { + r = ev->GetFloat( 1 ); + g = ev->GetFloat( 2 ); + b = ev->GetFloat( 3 ); + lightRadius = ev->GetFloat( 4 ); + } + + G_SetConstantLight( &edict->s.constantLight, &r, &g, &b, &lightRadius ); + } + +void Entity::LightOn + ( + Event *ev + ) + + { + G_SetConstantLight( &edict->s.constantLight, NULL, NULL, NULL, &lightRadius ); + } + +void Entity::LightOff + ( + Event *ev + ) + + { + float radius = 0; + + G_SetConstantLight( &edict->s.constantLight, NULL, NULL, NULL, &radius ); + } + +void Entity::LightRed + ( + Event *ev + ) + + { + float r; + + r = ev->GetFloat( 1 ); + G_SetConstantLight( &edict->s.constantLight, &r, NULL, NULL, NULL ); + } + +void Entity::LightGreen + ( + Event *ev + ) + + { + float g; + + g = ev->GetFloat( 1 ); + G_SetConstantLight( &edict->s.constantLight, NULL, &g, NULL, NULL ); + } + +void Entity::LightBlue + ( + Event *ev + ) + + { + float b; + + b = ev->GetFloat( 1 ); + G_SetConstantLight( &edict->s.constantLight, NULL, NULL, &b, NULL ); + } + +void Entity::LightRadius + ( + Event *ev + ) + + { + lightRadius = ev->GetFloat( 1 ); + G_SetConstantLight( &edict->s.constantLight, NULL, NULL, NULL, &lightRadius ); + } + +void Entity::LightStyle + ( + Event *ev + ) + + { + int style; + + style = ev->GetInteger( 1 ); + G_SetConstantLight( &edict->s.constantLight, NULL, NULL, NULL, NULL, &style ); + } + +void Entity::SetHealth + ( + Event *ev + ) + + { + health = ev->GetFloat( 1 ); + max_health = health; + } + +void Entity::SetSize + ( + Event *ev + ) + + { + Vector min, max; + + min = ev->GetVector( 1 ); + max = ev->GetVector( 2 ); + setSize( min, max ); + } + +void Entity::SetMins + ( + Event *ev + ) + + { + Vector min; + + min = ev->GetVector( 1 ); + setSize( min, maxs ); + } + +void Entity::SetMaxs + ( + Event *ev + ) + + { + Vector max; + + max = ev->GetVector( 1 ); + setSize( mins, max ); + } + +void Entity::SetScale + ( + Event *ev + ) + + { + setScale( ev->GetFloat( 1 ) ); + } + +void Entity::SetAlpha + ( + Event *ev + ) + + { + setAlpha( ev->GetFloat( 1 ) ); + } + +void Entity::SetOrigin + ( + Event *ev + ) + + { + setOrigin( ev->GetVector( 1 ) ); + } + +void Entity::SetTargetName + ( + Event *ev + ) + + { + SetTargetName( ev->GetString( 1 ) ); + } + +void Entity::SetTarget + ( + Event *ev + ) + + { + SetTarget( ev->GetString( 1 ) ); + } + +void Entity::SetKillTarget + ( + Event *ev + ) + + { + SetKillTarget( ev->GetString( 1 ) ); + } + +void Entity::SetAngles + ( + Event *ev + ) + + { + setAngles( ev->GetVector( 1 ) ); + } + +Vector Entity::GetControllerAngles + ( + int num + ) + + { + Vector controller_angles; + + assert( ( num >= 0 ) && ( num < NUM_BONE_CONTROLLERS ) ); + + if ( ( num < 0 ) || ( num >= NUM_BONE_CONTROLLERS ) ) + { + error( "GetControllerAngles", "Bone controller index out of range (%d)\n", num ); + return vec_zero; + } + + controller_angles = edict->s.bone_angles[ num ]; + + return controller_angles; + } + +void Entity::SetControllerAngles + ( + int num, + vec3_t angles + ) + + { + assert( ( num >= 0 ) && ( num < NUM_BONE_CONTROLLERS ) ); + + if ( ( num < 0 ) || ( num >= NUM_BONE_CONTROLLERS ) ) + { + error( "SetControllerAngles", "Bone controller index out of range (%d)\n", num ); + return; + } + + VectorCopy( angles, edict->s.bone_angles[ num ] ); + EulerToQuat( edict->s.bone_angles[ num ], edict->s.bone_quat[ num ] ); + } + +void Entity::SetControllerAngles + ( + Event *ev + ) + + { + int num; + Vector angles; + + if ( ev->NumArgs() < 2 ) + return; + + num = ev->GetInteger( 1 ); + angles = ev->GetVector( 2 ); + + SetControllerAngles( num, angles ); + } + +void Entity::SetControllerTag + ( + int num, + int tag_num + ) + + { + assert( ( num >= 0 ) && ( num < NUM_BONE_CONTROLLERS ) ); + + if ( ( num < 0 ) || ( num >= NUM_BONE_CONTROLLERS ) ) + { + error( "SetControllerTag", "Bone controller index out of range (%d)\n", num ); + return; + } + + edict->s.bone_tag[ num ] = tag_num; + } + +void Entity::RegisterAlias + ( + Event *ev + ) + + { + char parameters[100]; + int i; + + // Get the parameters for this alias command + + parameters[0] = 0; + + for( i = 3 ; i <= ev->NumArgs() ; i++ ) + { + strcat( parameters, ev->GetString( i ) ); + strcat( parameters, " "); + } + + gi.Alias_Add( edict->s.modelindex, ev->GetString( 1 ), ev->GetString( 2 ), parameters ); + } + +void Entity::Cache + ( + Event *ev + ) + + { + CacheResource( ev->GetString( 1 ), this ); + } + +void Entity::RegisterAliasAndCache + ( + Event *ev + ) + + { + RegisterAlias(ev); + + CacheResource( ev->GetString( 2 ), this ); + } + +void Entity::Sound + ( + str sound_name, + int channel, + float volume, + float min_dist, + Vector *sound_origin + ) + { + const char *name = NULL; + vec3_t org; + str random_alias; + + + if ( sound_name.length() > 0 ) + { + // Get the real sound to play + + name = gi.GlobalAlias_FindRandom( sound_name.c_str() ); + + if ( !name ) + { + random_alias = GetRandomAlias( sound_name ).c_str(); + + if ( random_alias.length() > 0 ) + name = random_alias.c_str(); + } + + if ( !name ) + name = sound_name.c_str(); + + // Play the sound + + if ( name != NULL ) + { + if ( sound_origin != NULL) + { + sound_origin->copyTo( org ); + entnum = ENTITYNUM_NONE; + } + else + { + VectorCopy( edict->s.origin, org ); + } + + gi.Sound( &org, entnum, channel, name, volume, min_dist ); + } + } + else + { + warning( "Sound", "Null sample pointer" ); + } + } + +qboolean Entity::attach + ( + int parent_entity_num, + int tag_num, + qboolean use_angles, + Vector offset + ) + + { + int i; + Entity * parent; + + if ( entnum == parent_entity_num ) + { + warning("attach","Trying to attach to oneself." ); + return false; + } + + if ( edict->s.parent != ENTITYNUM_NONE ) + detach(); + + // + // make sure this is a modelanim entity so that the attach works properly + // + if ( edict->s.eType == ET_GENERAL ) + { + edict->s.eType = ET_MODELANIM; + } + + // + // get the parent + // + parent = ( Entity * )G_GetEntity( parent_entity_num ); + + if (parent->numchildren < MAX_MODEL_CHILDREN) + { + // + // find a free spot in the parent + // + for ( i=0; i < MAX_MODEL_CHILDREN; i++ ) + if ( parent->children[i] == ENTITYNUM_NONE ) + { + break; + } + edict->s.parent = parent_entity_num; + setSolidType( SOLID_NOT ); + parent->children[i] = entnum; + parent->numchildren++; + edict->s.tag_num = tag_num; + edict->s.attach_use_angles = use_angles; + offset.copyTo( edict->s.attach_offset ); + setOrigin(); + return true; + } + return false; + } + +void Entity::KillAttach + ( + Event *ev + ) + + { + int i; + Entity *child = NULL; + + + // Kill all of this entities children + + for ( i = 0 ; i < MAX_MODEL_CHILDREN; i++ ) + { + if ( children[i] != ENTITYNUM_NONE ) + { + // Remove child + child = ( Entity * )G_GetEntity( children[i] ); + + if ( child ) + child->ProcessEvent( EV_Remove ); + + // Remove child from this entity + children[i] = ENTITYNUM_NONE; + } + } + + numchildren = 0; + } + +void Entity::detach + ( + void + ) + + { + int i; + int num; + Entity * parent; + + if ( edict->s.parent == ENTITYNUM_NONE ) + return; + + parent = ( Entity * )G_GetEntity( edict->s.parent ); + if (!parent) + return; + for ( i=0,num = parent->numchildren; i < MAX_MODEL_CHILDREN; i++ ) + { + if ( parent->children[i] == ENTITYNUM_NONE ) + { + continue; + } + if (parent->children[i] == entnum) + { + parent->children[i] = ENTITYNUM_NONE; + parent->numchildren--; + break; + } + num--; + if (!num) + break; + } + edict->s.parent = ENTITYNUM_NONE; + setOrigin( origin ); + } + +void Entity::Flags( Event *ev ) + { + const char *flag; + int mask; + int action; + int i; + + for ( i = 1; i <= ev->NumArgs(); i++ ) + { + action = FLAG_IGNORE; + flag = ev->GetString( i ); + switch( flag[0] ) + { + case '+': + action = FLAG_ADD; + flag++; + break; + case '-': + action = FLAG_CLEAR; + flag++; + break; + default: + ev->Error( "Entity::Flags", "First character is not '+' or '-', assuming '+'\n" ); + action = FLAG_ADD; + break; + } + + // + // WARNING: please change the Event decleration, + // to match this function, if flags are added or + // deleted the event must be updated. + // + if ( !stricmp( flag, "blood" ) ) + mask = FL_BLOOD; + else if ( !stricmp( flag, "explode" ) ) + mask = FL_DIE_EXPLODE; + else if ( !stricmp( flag, "die_gibs" ) ) + mask = FL_DIE_GIBS; + else if ( !stricmp( flag, "autoaim" ) ) + mask = FL_AUTOAIM; + else if ( !stricmp( flag, "god" ) ) + mask = FL_GODMODE; + else + { + mask = 0; + action = FLAG_IGNORE; + ev->Error( "Unknown flag '%s'", flag ); + } + switch (action) + { + case FLAG_ADD: + flags |= mask; + break; + case FLAG_CLEAR: + flags &= ~mask; + break; + case FLAG_IGNORE: + break; + } + } + if ( !com_blood->integer ) + { + if ( flags & (FL_BLOOD|FL_DIE_GIBS) ) + { + flags &= ~FL_BLOOD; + flags &= ~FL_DIE_GIBS; + } + } + } + + +void Entity::Effects( Event *ev ) + { + const char *flag; + int mask=0; + int action; + int i; + + for ( i = 1; i <= ev->NumArgs(); i++ ) + { + action = 0; + flag = ev->GetString( i ); + switch( flag[0] ) + { + case '+': + action = FLAG_ADD; + flag++; + break; + case '-': + action = FLAG_CLEAR; + flag++; + break; + default: + ev->Error( "Entity::Effects", "First character is not '+' or '-', assuming '+'\n" ); + action = FLAG_ADD; + break; + } + + // + // WARNING: please change the Event decleration, + // to match this function, if flags are added or + // deleted the event must be updated. + // + if ( !stricmp( flag, "everyframe" ) ) + mask = EF_EVERYFRAME; + if ( !stricmp( flag, "antisbjuice" ) ) + mask = EF_ANTISBJUICE; + else + { + action = FLAG_IGNORE; + ev->Error( "Unknown token %s.", flag ); + } + + switch (action) + { + case FLAG_ADD: + edict->s.eFlags |= mask; + break; + case FLAG_CLEAR: + edict->s.eFlags &= ~mask; + break; + case FLAG_IGNORE: + break; + } + } + } + +void Entity::RenderEffects( Event *ev ) + { + const char *flag; + int mask=0; + int action; + int i; + + for ( i = 1; i <= ev->NumArgs(); i++ ) + { + action = 0; + flag = ev->GetString( i ); + switch( flag[0] ) + { + case '+': + action = FLAG_ADD; + flag++; + break; + case '-': + action = FLAG_CLEAR; + flag++; + break; + default: + ev->Error( "Entity::RenderEffects", "First character is not '+' or '-', assuming '+'\n" ); + action = FLAG_ADD; + break; + } + + // + // WARNING: please change the Event decleration, + // to match this function, if flags are added or + // deleted the event must be updated. + // + if ( !stricmp( flag, "dontdraw" ) ) + mask = RF_DONTDRAW; + else if ( !stricmp( flag, "betterlighting" ) ) + mask = RF_EXTRALIGHT; + else if ( !stricmp ( flag, "lensflare" ) ) + mask = RF_LENSFLARE; + else if ( !stricmp ( flag, "viewlensflare" ) ) + mask = RF_VIEWLENSFLARE; + else if ( !stricmp ( flag, "lightoffset" ) ) + mask = RF_LIGHTOFFSET; + else if ( !stricmp( flag, "skyorigin" ) ) + mask = RF_SKYORIGIN; + else if ( !stricmp( flag, "fullbright" ) ) + mask = RF_FULLBRIGHT; + else if ( !stricmp( flag, "minlight" ) ) + mask = RF_MINLIGHT; + else if ( !stricmp( flag, "additivedynamiclight" ) ) + mask = RF_ADDITIVE_DLIGHT; + else if ( !stricmp( flag, "lightstyledynamiclight" ) ) + mask = RF_LIGHTSTYLE_DLIGHT; + else if ( !stricmp( flag, "shadow" ) ) + mask = RF_SHADOW; + else if ( !stricmp( flag, "preciseshadow" ) ) + mask = RF_SHADOW_PRECISE; + else if ( !stricmp( flag, "invisible" ) ) + mask = RF_INVISIBLE; + else + { + action = FLAG_IGNORE; + ev->Error( "Unknown token %s.", flag ); + } + + switch (action) + { + case FLAG_ADD: + edict->s.renderfx |= mask; + break; + case FLAG_CLEAR: + edict->s.renderfx &= ~mask; + break; + case FLAG_IGNORE: + break; + } + } + } + +void Entity::SVFlags + ( + Event *ev + ) + + { + const char *flag; + int mask=0; + int action; + int i; + + for ( i = 1; i <= ev->NumArgs(); i++ ) + { + action = 0; + flag = ev->GetString( i ); + switch( flag[0] ) + { + case '+': + action = FLAG_ADD; + flag++; + break; + case '-': + action = FLAG_CLEAR; + flag++; + break; + default: + ev->Error( "Entity::SVFlags", "First character is not '+' or '-', assuming '+'\n" ); + action = FLAG_ADD; + break; + } + + // + // WARNING: please change the Event decleration, + // to match this function, if flags are added or + // deleted the event must be updated. + // + if ( !stricmp( flag, "broadcast" ) ) + mask = SVF_BROADCAST; + else if ( !stricmp( flag, "sendonce" ) ) + mask = SVF_SENDONCE; + else + { + action = FLAG_IGNORE; + ev->Error( "Unknown token %s.", flag ); + } + + switch (action) + { + case FLAG_ADD: + edict->svflags |= mask; + break; + case FLAG_CLEAR: + edict->svflags &= ~mask; + break; + case FLAG_IGNORE: + break; + } + } + + if ( edict->svflags & SVF_SENDONCE ) + { + // Turn this entity into an event if the SENDONCE flag is sent + edict->s.eType = ET_EVENTS; + } + } + +void Entity::BroadcastSound + ( + float rad + ) + + { + if ( !( this->flags & FL_NOTARGET ) ) + { + G_BroadcastSound( this, centroid, rad ); + } + } + +void Entity::BroadcastSound + ( + Event *ev + ) + + { + float rad; + + if ( !( this->flags & FL_NOTARGET ) ) + { + rad = ev->NumArgs() < 1 ? SOUND_RADIUS : ev->GetFloat( 1 ); + BroadcastSound( rad ); + } + } + +void Entity::Think + ( + void + ) + + { + } + +void Entity::SetWaterType + ( + void + ) + + { + qboolean isinwater; + + watertype = gi.pointcontents( origin, 0 ); + isinwater = watertype & MASK_WATER; + + if ( isinwater ) + { + waterlevel = 1; + } + else + { + waterlevel = 0; + } + } + +void Entity::DamageSkin + ( + trace_t * trace, + float damage + ) + + { + /* FIXME : Do we need damage skins? + int surface; + + // FIXME handle different bodyparts + surface = trace->intersect.surface; + if ( !edict->s.surfaces[ surface ] ) + { + edict->s.surfaces[ surface ]++; + } + */ + } + +void Entity::Kill + ( + Event *ev + ) + + { + health = 0; + Damage( this, this, 10, origin, vec_zero, vec_zero, 0, 0, MOD_SUICIDE ); + } + + +void Entity::SurfaceCommand + ( + const char * surf_name, + const char * token + ) + + { + const char * current_surface_name; + int surface_num; + int mask; + int action; + qboolean do_all = false; + qboolean mult = false; + + + if ( surf_name[ strlen( surf_name ) - 1 ] == '*' ) + { + mult = true; + surface_num = 0; + } + else if ( str( surf_name ) != str( "all" ) ) + { + surface_num = gi.Surface_NameToNum( edict->s.modelindex, surf_name ); + + if (surface_num < 0) + { + warning( "SurfaceCommand", "group %s not found.", surf_name ); + return; + } + } + else + { + surface_num = 0; + do_all = true; + } + + action = 0; + switch( token[0] ) + { + case '+': + action = FLAG_ADD; + token++; + break; + case '-': + action = FLAG_CLEAR; + token++; + break; + default: + warning( "Entity::SurfaceModelEvent", "First character is not '+' or '-', assuming '+'\n" ); + action = FLAG_ADD; + break; + } + // + // WARNING: please change the Event decleration, + // to match this function, if flags are added or + // deleted the event must be updated. + // + if (!strcmpi( token, "skin1")) + { + mask = MDL_SURFACE_SKINOFFSET_BIT0; + } + else if (!strcmpi (token, "skin2")) + { + mask = MDL_SURFACE_SKINOFFSET_BIT1; + } + else if (!strcmpi (token, "nodraw")) + { + mask = MDL_SURFACE_NODRAW; + } + else if (!strcmpi (token, "crossfade")) + { + mask = MDL_SURFACE_CROSSFADE_SKINS; + } + else + { + mask = 0; + warning( "SurfaceCommand", "Unknown token %s.", token ); + action = FLAG_IGNORE; + } + for( ; surface_num < numsurfaces ; surface_num++ ) + { + if ( mult ) + { + current_surface_name = gi.Surface_NumToName( edict->s.modelindex, surface_num ); + + if ( Q_stricmpn( current_surface_name, surf_name, strlen( surf_name ) - 1) != 0 ) + continue; + } + + switch (action) + { + case FLAG_ADD: + edict->s.surfaces[ surface_num ] |= mask; + break; + case FLAG_CLEAR: + edict->s.surfaces[ surface_num ] &= ~mask; + break; + case FLAG_IGNORE: + break; + } + + if ( !do_all && !mult ) + break; + } + } + +void Entity::SurfaceModelEvent + ( + Event *ev + ) + + { + const char * surf_name; + const char * token; + int i; + + surf_name = ev->GetString( 1 ); + + for ( i = 2; i <= ev->NumArgs() ; i++ ) + { + token = ev->GetString( i ); + SurfaceCommand( surf_name, token ); + } + } + +void Entity::AttachEvent + ( + Event * ev + ) + { + Entity * parent; + const char * bone; + int tagnum; + qboolean use_angles = qtrue; + Vector offset; + + parent = ev->GetEntity( 1 ); + bone = ev->GetString( 2 ); + + if ( ev->NumArgs() > 2 ) + use_angles = ev->GetInteger( 3 ); + + if ( ev->NumArgs() > 3 ) + offset = ev->GetVector( 4 ); + + if ( !parent ) + return; + + tagnum = gi.Tag_NumForName( parent->edict->s.modelindex, bone ); + if ( tagnum >= 0 ) + { + attach( parent->entnum, tagnum, use_angles, offset ); + } + else + { + warning( "AttachEvent", "Tag %s not found", bone ); + } + } + +void Entity::AttachModelEvent + ( + Event * ev + ) + { + Entity * obj; + const char * bone; + str modelname; + int tagnum; + float remove_time,fade_time,fade_delay; + Vector offset; + + obj = new Animate; + + modelname = ev->GetString( 1 ); + bone = ev->GetString( 2 ); + if ( ev->NumArgs() > 2 ) + { + obj->setScale( ev->GetFloat( 3 ) ); + } + if ( ev->NumArgs() > 3 ) + { + obj->SetTargetName( ev->GetString( 4 ) ); + } + + if ( ev->NumArgs() > 4 ) + obj->detach_at_death = ev->GetInteger( 5 ); + + if ( ev->NumArgs() > 5 ) + { + remove_time = ev->GetFloat( 6 ); + + if ( remove_time != -1 ) + { + Event *remove_event = new Event( EV_Remove ); + obj->PostEvent( remove_event, remove_time ); + } + } + + if ( ev->NumArgs() > 6 ) + { + Event *fade_event; + + fade_time = ev->GetFloat( 7 ); + + if ( fade_time != -1 ) + { + obj->setAlpha( 0 ); + + fade_event = new Event( EV_FadeIn ); + fade_event->AddFloat( fade_time ); + obj->PostEvent( fade_event, 0 ); + } + } + + if ( ev->NumArgs() > 7 ) + { + Event *fade_event; + + fade_delay = ev->GetFloat( 8 ); + + if ( fade_delay != -1 ) + { + if ( ev->NumArgs() > 8 ) + fade_time = ev->GetFloat( 9 ); + else + fade_time = 0; + + fade_event = new Event( EV_Fade ); + + if ( fade_time ) + fade_event->AddFloat( fade_time ); + + obj->PostEvent( fade_event, fade_delay ); + } + } + + if ( ev->NumArgs() > 9 ) + offset = ev->GetVector( 10 ); + + obj->setModel( modelname ); + + tagnum = gi.Tag_NumForName( edict->s.modelindex, bone ); + if ( tagnum >= 0 ) + { + if ( !obj->attach( this->entnum, tagnum, true, offset ) ) + { + //warning( "AttachModelEvent", "Could not attach model %s", modelname.c_str() ); + delete obj; + return; + } + } + else + { + warning( "AttachModelEvent", "Tag %s not found", bone ); + } + } + +void Entity::RemoveAttachedModelEvent + ( + Event *ev + ) + { + const char *tag_name; + int tag_num; + int num; + int i; + Entity *ent; + float fade_rate = 0; + Event *fade_event; + str model_name; + + tag_name = ev->GetString( 1 ); + tag_num = gi.Tag_NumForName( edict->s.modelindex, tag_name ); + + if ( ev->NumArgs() > 1 ) + fade_rate = ev->GetFloat( 2 ); + + if ( ev->NumArgs() > 2 ) + model_name = ev->GetString( 3 ); + + if ( tag_num >= 0 ) + { + num = numchildren; + + for ( i = 0 ; (i < MAX_MODEL_CHILDREN) && num ; i++ ) + { + if ( children[i] == ENTITYNUM_NONE ) + continue; + + ent = ( Entity * )G_GetEntity( children[i] ); + + if ( ent->edict->s.tag_num == tag_num ) + { + if ( !model_name.length() || model_name == ent->model ) + { + if ( fade_rate ) + { + fade_event = new Event( EV_Fade ); + fade_event->AddFloat( fade_rate ); + fade_event->AddFloat( 0 ); + ent->PostEvent( fade_event, 0 ); + } + + ent->PostEvent( EV_Remove, fade_rate ); + } + } + + num--; + } + } + } + +void Entity::DetachEvent + ( + Event * ev + ) + + { + if ( edict->s.parent == ENTITYNUM_NONE ) + { + return; + } + detach(); + } + +void Entity::TakeDamageEvent + ( + Event * ev + ) + { + takedamage = DAMAGE_YES; + } + +void Entity::NoDamageEvent + ( + Event * ev + ) + { + takedamage = DAMAGE_NO; + } + +void Entity::Gravity + ( + Event *ev + ) + + { + gravity = ev->GetFloat( 1 ); + } + +void Entity::UseBoundingBoxEvent + ( + Event *ev + ) + { + edict->svflags |= SVF_USEBBOX; + } + +void Entity::HurtEvent + ( + Event *ev + ) + { + Vector normal; + float dmg; + int means_of_death; + Vector direction; + + if ( ev->NumArgs() < 1 ) + { + dmg = 50; + } + else + { + dmg = ev->GetFloat( 1 ); + } + + if ( ev->NumArgs() > 1 ) + means_of_death = MOD_string_to_int( ev->GetString( 2 ) ); + else + means_of_death = MOD_CRUSH; + + if ( ev->NumArgs() > 2 ) + { + direction = ev->GetVector( 3 ); + direction.normalize(); + } + else + { + direction = vec_zero; + } + + normal = Vector( orientation[ 0 ] ); + Damage( world, world, dmg, centroid, direction, normal, dmg, 0, means_of_death ); + } + +void Entity::IfSkillEvent + ( + Event *ev + ) + + { + float skilllevel; + + skilllevel = ev->GetFloat( 1 ); + + if ( skill->value == skilllevel ) + { + int argc; + int numargs; + Event *event; + int i; + + numargs = ev->NumArgs(); + argc = numargs - 2 + 1; + + event = new Event( ev->GetToken( 2 ) ); + + for( i = 1; i < argc; i++ ) + { + event->AddToken( ev->GetToken( 2 + i ) ); + } + ProcessEvent( event ); + } + } + +void Entity::Censor + ( + Event *ev + ) + + { + Vector delta; + float oldsize; + float newsize; + + if ( com_blood->integer ) + return; + + oldsize = size.length(); + setSolidType( SOLID_NOT ); + setModel( "censored.tik" ); + gi.CalculateBounds( edict->s.modelindex, 1, mins, maxs ); + delta = maxs - mins; + newsize = delta.length(); + edict->s.scale = oldsize / newsize; + mins *= edict->s.scale; + maxs *= edict->s.scale; + setSize( mins, maxs ); + setOrigin(); + } + +void Entity::StationaryEvent + ( + Event *ev + ) + + { + setMoveType( MOVETYPE_STATIONARY ); + } + +void Entity::Explosion + ( + Event *ev + ) + + { + str expmodel; + str tag_name; + //orientation_t orient; + Vector explosion_origin; + + expmodel = ev->GetString( 1 ); + explosion_origin = origin; + + if ( ev->NumArgs() > 1 ) + { + tag_name = ev->GetString( 2 ); + + //if ( GetRawTag( tag_name.c_str(), &orient, legs ) ) + // VectorAdd( orient.origin, origin, explosion_origin ); + + GetTag( tag_name.c_str(), &explosion_origin ); + } + + ExplosionAttack( explosion_origin, this, expmodel ); + } + +void Entity::Shader + ( + Event *ev + ) + + { + const char * token; + + if ( gi.IsModel( edict->s.modelindex ) ) + { + ev->Error( "shader event being called on TIKI model\n" ); + } + // + // get sub shader command + // + token = ev->GetString( 1 ); + + // + // WARNING: please change the Event decleration, + // to match this function, if flags are added or + // deleted the event must be updated. + // + if (!strcmpi( token, "translation")) + { + float x, y; + + x = ev->GetFloat( 2 ); + y = ev->GetFloat( 3 ); + TRANSLATION_TO_PKT( x, edict->s.tag_num ); + TRANSLATION_TO_PKT( y, edict->s.skinNum ); + } + else if (!strcmpi( token, "offset")) + { + float x, y; + + x = ev->GetFloat( 2 ); + y = ev->GetFloat( 3 ); + OFFSET_TO_PKT( x, edict->s.tag_num ); + OFFSET_TO_PKT( y, edict->s.skinNum ); + } + else if (!strcmpi (token, "rotation")) + { + float rot; + + rot = ev->GetFloat( 2 ); + ROTATE_TO_PKT( rot, edict->s.tag_num ); + } + else if (!strcmpi (token, "frame")) + { + edict->s.frame = ev->GetInteger( 2 ); + } + else if (!strcmpi (token, "wavebase")) + { + float base; + + base = ev->GetFloat( 2 ); + BASE_TO_PKT( base, edict->s.surfaces[ 0 ] ); + } + else if (!strcmpi (token, "waveamp")) + { + float amp; + + amp = ev->GetFloat( 2 ); + AMPLITUDE_TO_PKT( amp, edict->s.surfaces[ 1 ] ); + } + else if (!strcmpi (token, "wavephase")) + { + float phase; + + phase = ev->GetFloat( 2 ); + PHASE_TO_PKT( phase, edict->s.surfaces[ 2 ] ); + } + else if (!strcmpi (token, "wavefreq")) + { + float freq; + + freq = ev->GetFloat( 2 ); + FREQUENCY_TO_PKT( freq, edict->s.surfaces[ 3 ] ); + } + } + +void Entity::DropToFloorEvent + ( + Event *ev + ) + + { + float range; + + if ( ev->NumArgs() > 0 ) + { + range = ev->GetFloat( 1 ); + } + else + { + range = MAP_SIZE; + } + if ( !droptofloor( range ) ) + { + } + } + + +//************************************************************************* +// +// BIND code +// +//************************************************************************* + +qboolean Entity::isBoundTo + ( + Entity *master + ) + + { + Entity *ent; + + for( ent = bindmaster; ent != NULL; ent = ent->bindmaster ) + { + if ( ent == master ) + { + return true; + } + } + + return false; + } + +void Entity::bind + ( + Entity *master, + qboolean use_my_angles + ) + + { + float mat[ 3 ][ 3 ]; + float local[ 3 ][ 3 ]; + Vector ang; + + assert( master ); + if ( !master ) + { + warning( "bind", "Null master entity" ); + return; + } + + if ( master == this ) + { + warning( "bind", "Trying to bind to oneself." ); + return; + } + + // unbind myself from my master + unbind(); + + bindmaster = master; + edict->s.bindparent = master->entnum; + bind_use_my_angles = use_my_angles; + + // We are now separated from our previous team and are either + // an individual, or have a team of our own. Now we can join + // the new bindmaster's team. Bindmaster must be set before + // joining the team, or we will be placed in the wrong position + // on the team. + joinTeam( master ); + + // calculate local angles + TransposeMatrix( bindmaster->orientation, mat ); + R_ConcatRotations( mat, orientation, local ); + MatrixToEulerAngles( local, ang ); + setAngles( ang ); + + setOrigin( getParentVector( localorigin - bindmaster->origin ) ); + + return; + } + +void Entity::unbind + ( + void + ) + + { + Entity *prev; + Entity *next; + Entity *last; + Entity *ent; + + if ( !bindmaster ) + { + return; + } + + //bindmaster = NULL; + + // Check this GAMEFIX - should it be origin? + localorigin = Vector( edict->s.origin ); + localangles = Vector( edict->s.angles ); + + if ( !teammaster ) + { + bindmaster = NULL; + edict->s.bindparent = ENTITYNUM_NONE; + //Teammaster already has been freed + return; + } + + // We're still part of a team, so that means I have to extricate myself + // and any entities that are bound to me from the old team. + // Find the node previous to me in the team + prev = teammaster; + + for( ent = teammaster->teamchain; ent && ( ent != this ); ent = ent->teamchain ) + { + prev = ent; + } + + // If ent is not pointing to me, then something is very wrong. + assert( ent ); + if ( !ent ) + { + error( "unbind", "corrupt team chain\n" ); + } + + // Find the last node in my team that is bound to me. + // Also find the first node not bound to me, if one exists. + last = this; + for( next = teamchain; next != NULL; next = next->teamchain ) + { + if ( !next->isBoundTo( this ) ) + { + break; + } + + // Tell them I'm now the teammaster + next->teammaster = this; + last = next; + } + + // disconnect the last member of our team from the old team + last->teamchain = NULL; + + // connect up the previous member of the old team to the node that + // follow the last node bound to me (if one exists). + if ( teammaster != this ) + { + prev->teamchain = next; + if ( !next && ( teammaster == prev ) ) + { + prev->teammaster = NULL; + } + } + else if ( next ) + { + // If we were the teammaster, then the nodes that were not bound to me are now + // a disconnected chain. Make them into their own team. + for( ent = next; ent->teamchain != NULL; ent = ent->teamchain ) + { + ent->teammaster = next; + } + next->teammaster = next; + next->flags &= ~FL_TEAMSLAVE; + } + + // If we don't have anyone on our team, then clear the team variables. + if ( teamchain ) + { + // make myself my own team + teammaster = this; + } + else + { + // no longer a team + teammaster = NULL; + } + + flags &= ~FL_TEAMSLAVE; + bindmaster = NULL; + edict->s.bindparent = ENTITYNUM_NONE; + } + +void Entity::EventUnbind + ( + Event *ev + ) + + { + unbind(); + } + +void Entity::BindEvent + ( + Event *ev + ) + + { + Entity *ent; + + ent = ev->GetEntity( 1 ); + if ( ent ) + { + bind( ent ); + } + } + + +Vector Entity::getParentVector + ( + Vector vec + ) + + { + Vector pos; + + if ( !bindmaster ) + { + return vec; + } + + pos[ 0 ] = vec * bindmaster->orientation[ 0 ]; + pos[ 1 ] = vec * bindmaster->orientation[ 1 ]; + pos[ 2 ] = vec * bindmaster->orientation[ 2 ]; + + return pos; + } + +// +// Team methods +// + +void Entity::joinTeam + ( + Entity *teammember + ) + + { + Entity *ent; + Entity *master; + Entity *prev; + Entity *next; + + if ( teammaster && ( teammaster != this ) ) + { + quitTeam(); + } + + assert( teammember ); + if ( !teammember ) + { + warning( "joinTeam", "Null entity" ); + return; + } + + master = teammember->teammaster; + if ( !master ) + { + master = teammember; + teammember->teammaster = teammember; + teammember->teamchain = this; + + // make anyone who's bound to me part of the new team + for( ent = teamchain; ent != NULL; ent = ent->teamchain ) + { + ent->teammaster = master; + } + } + else + { + // skip past the chain members bound to the entity we're teaming up with + prev = teammember; + next = teammember->teamchain; + if ( bindmaster ) + { + // if we have a bindmaster, joing after any entities bound to the entity + // we're joining + while( next && (( Entity *)next)->isBoundTo( teammember ) ) + { + prev = next; + next = next->teamchain; + } + } + else + { + // if we're not bound to someone, then put us at the end of the team + while( next ) + { + prev = next; + next = next->teamchain; + } + } + + // make anyone who's bound to me part of the new team and + // also find the last member of my team + for( ent = this; ent->teamchain != NULL; ent = ent->teamchain ) + { + ent->teamchain->teammaster = master; + } + + prev->teamchain = this; + ent->teamchain = next; + } + + teammaster = master; + flags |= FL_TEAMSLAVE; + } + +void Entity::quitTeam + ( + void + ) + + { + Entity *ent; + + if ( !teammaster ) + { + return; + } + + if ( teammaster == this ) + { + if ( !teamchain->teamchain ) + { + teamchain->teammaster = NULL; + } + else + { + // make next teammate the teammaster + for( ent = teamchain; ent; ent = ent->teamchain ) + { + ent->teammaster = teamchain; + } + } + + teamchain->flags &= ~FL_TEAMSLAVE; + } + else + { + assert( flags & FL_TEAMSLAVE ); + assert( teammaster->teamchain ); + + ent = teammaster; + while( ent->teamchain != this ) + { + // this should never happen + assert( ent->teamchain ); + + ent = ent->teamchain; + } + + ent->teamchain = teamchain; + + if ( !teammaster->teamchain ) + { + teammaster->teammaster = NULL; + } + } + + teammaster = NULL; + teamchain = NULL; + flags &= ~FL_TEAMSLAVE; + } + +void Entity::EventQuitTeam + ( + Event *ev + ) + + { + quitTeam(); + } + + +void Entity::JoinTeam + ( + Event *ev + ) + + { + Entity *ent; + + ent = ev->GetEntity( 1 ); + if ( ent ) + { + joinTeam( ent ); + } + } + +void Entity::AddToSoundManager + ( + Event *ev + ) + + { + SoundMan.AddEntity( this ); + } + +inline qboolean Entity::HitSky + ( + trace_t *trace + ) + + { + assert( trace ); + if ( trace->surfaceFlags & SURF_SKY ) + { + return true; + } + return false; + } + +qboolean Entity::HitSky + ( + void + ) + + { + return HitSky( &level.impact_trace ); + } + +void Entity::SetAngleEvent + ( + Event *ev + ) + { + Vector movedir; + + movedir = G_GetMovedir( ev->GetFloat( 1 ) ); + setAngles( movedir.toAngles() ); + } + +void Entity::NoLerpThisFrame + ( + void + ) + { + edict->s.eFlags ^= EF_TELEPORT_BIT; + } + +void Entity::Postthink + ( + void + ) + + { + } + +void Entity::TouchTriggersEvent + ( + Event *ev + ) + { + flags |= FL_TOUCH_TRIGGERS; + } + +void Entity::DeathSinkStart + ( + Event *ev + ) + { + float time; + + // Stop the sink when we can't be seen anymore + + if ( maxs[2] >= 0 && maxs[2] < 200 ) + time = maxs[2] / 20; + else + time = 1; + + PostEvent( EV_Remove, time ); + + // Start the sinking + + ProcessEvent( EV_DeathSink ); + } + +void Entity::DeathSink + ( + Event *ev + ) + { + // Sink just a little + + origin[2] -= 1; + setOrigin( origin ); + + // Make sure the sink happens again next frame + + PostEvent( EV_DeathSink, FRAMETIME ); + } + +void Entity::LookAtMe + ( + Event *ev + ) + { + if ( ev->NumArgs() > 0 ) + look_at_me = ev->GetBoolean( 1 ); + else + look_at_me = true; + } + +void Entity::VelocityModified + ( + void + ) + { + } + +void Entity::DetachAllChildren + ( + Event *ev + ) + + { + int i; + + for (i=0;iPostEvent( EV_Remove, 0 ); + } + } + } diff --git a/source/source/fgame/entity.h b/source/source/fgame/entity.h new file mode 100644 index 0000000..ff78388 --- /dev/null +++ b/source/source/fgame/entity.h @@ -0,0 +1,1189 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/entity.h $ +// $Revision:: 59 $ +// $Author:: Markd $ +// $Date:: 7/25/00 8:00a $ +// +// Copyright (C) 1997 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source is may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/entity.h $ +// +// 59 7/25/00 8:00a Markd +// Added GLobal_FindRandomAlias to alias code +// +// 58 7/23/00 1:47p Aldie +// Added detach all children command +// +// 57 7/21/00 3:47p Steven +// Made showModel a virtual function. +// +// 56 7/11/00 8:55p Aldie +// Added in an autoaim flag +// +// 55 6/30/00 3:08p Markd +// fixed rise animation issues +// +// 54 6/26/00 5:50p Markd +// re-did some renderfx commands, fixed anti-sb juice stuff +// +// 53 6/23/00 8:41p Markd +// made a lot of changes to different constructors for saved game support +// +// 52 6/14/00 11:18a Markd +// cleaned up code using Intel compiler +// +// 51 6/09/00 6:55p Markd +// fixed camera being bound to other objects +// +// 50 5/31/00 5:34p Steven +// Added look at me stuff. +// +// 49 5/27/00 2:56p Markd +// Save games 2nd pass +// +// 48 5/26/00 7:44p Markd +// 2nd phase save games +// +// 47 5/24/00 3:14p Markd +// first phase of save/load games +// +// 46 5/05/00 2:18p Steven +// Made EV_RemoveAttachedModel visible to other classes. +// +// 45 4/15/00 5:43p Steven +// Made damage fractioanl again. +// +// 44 4/15/00 5:18p Aldie +// Added stun events and fixed yet another bug with Ammo and AutoPutaway +// +// 43 4/13/00 3:45p Aldie +// Added more flashbang support. Added damage_type to entities used to specify +// what type of damage they take. +// +// 42 4/11/00 5:43p Steven +// Sinking into ground work. +// +// 41 4/10/00 6:49p Steven +// Added bind_use_my_angles so that a bound entity could use its angles for +// its local offset or its bindmaster. +// +// 40 4/01/00 3:55p Markd +// Added FL_TOUCH_TRIGGERS support +// +// 39 4/01/00 3:45p Markd +// added FL_TOUCH_TRIGGERS flag and implementation +// +// 38 3/21/00 5:06p Markd +// added vehicle support +// +// 37 3/20/00 3:01p Markd +// added more functionality to falling rock +// +// 36 3/16/00 10:50a Markd +// Fixed some bad syntax in headers that exhibited itself in non-visualc +// compilers +// +// 35 3/15/00 5:52p Aldie +// Added pushsound to func_pushobject and removed a printf. +// +// 34 3/15/00 4:09p Aldie +// Fixed a bug with using weapons, and added some ability to force a state in +// the player +// +// 33 3/14/00 4:56p Aldie +// Added new script damage command +// +// 32 3/04/00 5:05p Steven +// Added a skipent to CanDamage. +// +// 31 3/04/00 11:48a Markd +// Added light style support +// +// 30 3/01/00 10:58a Jimdose +// added TriggerEvent +// +// 29 2/26/00 12:59p Jimdose +// externed EV_Kill +// +// 28 2/26/00 11:23a Steven +// Added partial immobile flag. +// +// 27 2/21/00 4:39p Markd +// Added fade command to entity +// +// 26 2/21/00 3:33p Steven +// Added a GetControllerAngles function. +// +// 25 1/31/00 3:56p Aldie +// working on the auto aim / tracking code +// +// 24 1/19/00 7:59p Markd +// Rewrote Surface Model Event and also added changeoutfit command to player +// +// 23 1/19/00 7:09p Steven +// Added a removeattachedmodel event. +// +// 22 1/15/00 3:57p Markd +// Eliminated multiple "angle" events and replaced them with EV_SetAngle +// +// 21 1/14/00 5:06p Markd +// Removed surface num, tri_num and damage_multiplier from multiple functions +// and events +// +// 20 1/13/00 7:08p Steven +// Made a SetControllerAngles event so I could post them in the future. +// +// 19 1/10/00 6:17p Jimdose +// more code cleanup +// +// 18 1/05/00 7:25p Jimdose +// made angle functions all use the same coordinate system +// AngleVectors now returns left instead of right +// no longer need to invert pitch +// +// 17 12/17/99 8:26p Jimdose +// got rid of unused vars and functions +// +// 16 12/17/99 6:35p Jimdose +// changed spawnarg code +// added Level class for spawning and map control +// got rid of unused or superflous variables +// changed setjmp/longjmp calls to try/throw/catch exception handling +// +// 15 12/14/18 2:43p Jimdose +// moved blood_model to Sentient +// +// 14 12/02/99 6:57p Jimdose +// removed classname variable from Entity +// +// 13 11/19/99 2:27p Steven +// Made sure all entity stuff would save correctly. +// +// 12 11/18/99 6:26p Steven +// Fixed some tag stuff because CurrentAnim and CurrentFrame had different +// paramters in Entity and Animate which made the virtual stuff not work +// properly. +// +// 11 11/12/99 6:52p Markd +// fixed up sound manager saving and loading +// +// 10 11/01/99 4:01p Jimdose +// added SetControllerAngles and SetControllerTag +// +// 9 10/28/99 6:08p Steven +// Added a use_angles flag and an offset to the entity attach stuff. +// +// 8 10/25/99 6:39p Markd +// removed size and other unused variables, added radius and centroid to both +// server and game code +// +// 7 10/21/99 10:58a Markd +// Added fadein +// +// 6 10/19/99 7:52p Markd +// Removed three part model system +// +// 5 10/01/99 2:42p Markd +// moved all the binding code back into Entity from Mover +// +// 4 9/29/99 7:43p Markd +// Made items behave better when dropping to floor +// +// 3 9/27/99 5:44p Markd +// began documentation and cleanup phase after merge +// +// 2 9/16/99 4:50p Jimdose +// removed unused code +// +// 1 9/10/99 10:53a Jimdose +// +// 1 9/08/99 3:15p Aldie +// +// 42 9/02/99 5:41p Markd +// made CacheResource utility functions changed code every where else +// +// 41 9/02/99 2:33p Markd +// Added cache ability to entities +// +// 40 9/01/99 8:21p Steven +// Fixed a typo. +// +// 39 9/01/99 12:03p Steven +// Added blood spurts. +// +// 38 8/31/99 2:46p Steven +// Added detach_at_death flag for attached models. +// +// 37 8/30/99 3:25p Steven +// Added an event to kill all of an entities attachments. +// +// 36 8/30/99 2:37p Steven +// Added support for volume and minimum distance for loop sounds. +// +// 35 8/28/99 11:46a Steven +// Removed global from sound function calls. +// +// 34 8/27/99 5:07p Steven +// Added anti Sucknblaugh juice powerup. +// +// 33 8/25/99 9:01p Markd +// working on RF_ stuff and local color for entities on client +// +// 32 8/17/99 4:59p Steven +// Added new immobile flag. +// +// 31 8/06/99 3:35p Markd +// Cleaned up cgame, added shader commands and shader manipulation support +// +// 30 7/30/99 6:45p Aldie +// Added explosion command +// +// 29 7/30/99 4:49p Steven +// Added a stationary command to entities and a gas explode flag. +// +// 28 7/06/99 8:33p Jimdose +// removed unused player code +// added state machine for player animation +// +// DESCRIPTION: +// Base class for all enities that are controlled by Sin. If you have any +// object that should be called on a periodic basis and it is not an entity, +// then you have to have an dummy entity that calls it. +// +// An entity in Sin is any object that is not part of the world. Any non-world +// object that is visible in Sin is an entity, although it is not required that +// all entities be visible to the player. Some objects are basically just virtual +// constructs that act as an instigator of certain actions, for example, some +// triggers are invisible and cannot be touched, but when activated by other +// objects can cause things to happen. +// +// All entities are capable of receiving messages from Sin or from other entities. +// Messages received by an entity may be ignored, passed on to their superclass, +// or acted upon by the entity itself. The programmer must decide on the proper +// action for the entity to take to any message. There will be many messages +// that are completely irrelevant to an entity and should be ignored. Some messages +// may require certain states to exist and if they are received by an entity when +// it these states don't exist may indicate a logic error on the part of the +// programmer or map designer and should be reported as warnings (if the problem is +// not severe enough for the game to be halted) or as errors (if the problem should +// not be ignored at any cost). +// + +#ifndef __ENTITY_H__ +#define __ENTITY_H__ + +#include "g_local.h" +#include "class.h" +#include "vector.h" +#include "script.h" +#include "listener.h" + + +// modification flags +#define FLAG_IGNORE 0 +#define FLAG_CLEAR 1 +#define FLAG_ADD 2 + +typedef enum + { + DAMAGE_NO, + DAMAGE_YES, // will take damage if hit + DAMAGE_AIM // auto targeting recognizes this + } damage_t; + +typedef enum + { + legs, + torso, + all + } bodypart_t; + +//deadflag +#define DEAD_NO 0 +#define DEAD_DYING 1 +#define DEAD_DEAD 2 +#define DEAD_RESPAWNABLE 3 + +// flags +#define FL_FLY (1<<0) +#define FL_SWIM (1<<1) // implied immunity to drowining +#define FL_INWATER (1<<2) +#define FL_GODMODE (1<<3) +#define FL_NOTARGET (1<<4) +#define FL_PARTIALGROUND (1<<5) // not all corners are valid +#define FL_TEAMSLAVE (1<<6) // not the first on the team +#define FL_NO_KNOCKBACK (1<<7) +#define FL_THINK (1<<8) +#define FL_BLOOD (1<<9) // when hit, it should bleed. +#define FL_DIE_GIBS (1<<10) // when it dies, it should gib +#define FL_DIE_EXPLODE (1<<11) // when it dies, it will explode +#define FL_ROTATEDBOUNDS (1<<12) // model uses rotated mins and maxs +#define FL_DONTSAVE (1<<13) // don't add to the savegame +#define FL_IMMOBILE (1<<14) // entity has been immobolized somehow +#define FL_PARTIAL_IMMOBILE (1<<15) // entity has been immobolized somehow +#define FL_POSTTHINK (1<<17) // call a think function after the physics have been run +#define FL_TOUCH_TRIGGERS (1<<18) // should this entity touch triggers +#define FL_AUTOAIM (1<<19) // Autoaim on this entity + + +// damage flags +#define DAMAGE_RADIUS 0x00000001 // damage was indirect +#define DAMAGE_NO_ARMOR 0x00000002 // armour does not protect from this damage +#define DAMAGE_ENERGY 0x00000004 // damage is from an energy based weapon +#define DAMAGE_NO_KNOCKBACK 0x00000008 // do not affect velocity, just view angles +#define DAMAGE_BULLET 0x00000010 // damage is from a bullet (used for ricochets) +#define DAMAGE_NO_PROTECTION 0x00000020 // armor, shields, invulnerability, and godmode have no effect +#define DAMAGE_NO_SKILL 0x00000040 // damage is not affected by skill level + +extern Event EV_ClientMove; +extern Event EV_ClientEndFrame; + +// Generic entity events +extern Event EV_Classname; +extern Event EV_Activate; +extern Event EV_Use; +extern Event EV_FadeNoRemove; +extern Event EV_FadeOut; +extern Event EV_FadeIn; +extern Event EV_Fade; +extern Event EV_Killed; +extern Event EV_GotKill; +extern Event EV_Pain; +extern Event EV_Damage; +extern Event EV_Stun; +extern Event EV_Gib; +extern Event EV_Kill; +extern Event EV_DeathSinkStart; + +// Physics events +extern Event EV_MoveDone; +extern Event EV_Touch; +extern Event EV_Blocked; +extern Event EV_Attach; +extern Event EV_AttachModel; +extern Event EV_RemoveAttachedModel; +extern Event EV_Detach; +extern Event EV_UseBoundingBox; + +// Animation events +extern Event EV_NewAnim; +extern Event EV_LastFrame; +extern Event EV_TakeDamage; +extern Event EV_NoDamage; + +// script stuff +extern Event EV_Model; +extern Event EV_Hide; +extern Event EV_Show; +extern Event EV_BecomeSolid; +extern Event EV_BecomeNonSolid; +extern Event EV_Sound; +extern Event EV_StopSound; +extern Event EV_Bind; +extern Event EV_Unbind; +extern Event EV_JoinTeam; +extern Event EV_QuitTeam; +extern Event EV_SetHealth; +extern Event EV_SetSize; +extern Event EV_SetAlpha; +extern Event EV_SetOrigin; +extern Event EV_SetTargetName; +extern Event EV_SetTarget; +extern Event EV_SetKillTarget; +extern Event EV_SetAngles; +extern Event EV_SetAngle; +extern Event EV_RegisterAlias; +extern Event EV_Anim; +extern Event EV_StartAnimating; +extern Event EV_SurfaceModelEvent; +extern Event EV_ProcessInitCommands; +extern Event EV_Stop; +extern Event EV_StopLoopSound; +extern Event EV_SetControllerAngles; + +// dir is 1 +// power is 2 +// minsize is 3 +// maxsize is 4 +// percentage is 5 +// thickness 6 +// entity is 7 +// origin 8 + +// AI sound events +extern Event EV_BroadcastSound; +extern Event EV_HeardSound; +extern Event EV_Hurt; +extern Event EV_IfSkill; + + +// Define ScriptMaster +class ScriptMaster; + +// +// Spawn args +// +// "spawnflags" +// "alpha" default 1.0 +// "model" +// "origin" +// "targetname" +// "target" +// +#define MAX_MODEL_CHILDREN 8 + +class Entity; + +typedef SafePtr EntityPtr; + +class Entity : public Listener + { + public: + CLASS_PROTOTYPE( Entity ); + + // spawning variables + int entnum; + gentity_t *edict; + gclient_t *client; + int spawnflags; + + // standard variables + str model; + + // physics variables + float move_time; // how much time total_delta will take + Vector total_delta; // total unprocessed movement + Vector mins; + Vector maxs; + Vector absmin; + Vector absmax; + Vector centroid; + Vector velocity; + Vector avelocity; + Vector origin; + Vector angles; + Vector size; + int movetype; + int mass; + float gravity; // per entity gravity multiplier (1.0 is normal) + float orientation[3][3]; + + gentity_t *groundentity; + cplane_t groundplane; + int groundcontents; + + // Model Binding variables + int numchildren; + int children[MAX_MODEL_CHILDREN]; + + // Surface variables + int numsurfaces; + + // Light variables + float lightRadius; + + // Team variables + str moveteam; + Entity *teamchain; + Entity *teammaster; + + // Binding variables + Entity *bindmaster; + qboolean bind_use_my_angles; + Vector localorigin; + Vector localangles; + + // targeting variables + str target; + str targetname; + str killtarget; + + // Character state + float health; + float max_health; + int deadflag; + int flags; + + // underwater variables + int watertype; + int waterlevel; + + // Pain and damage variables + damage_t takedamage; + EntityPtr enemy; + float pain_finished; + float damage_debounce_time; + int damage_type; + + qboolean detach_at_death; + + qboolean look_at_me; + + Entity(); + virtual ~Entity(); + + void SetEntNum( int num ); + void ClassnameEvent( Event *ev ); + void SpawnFlagsEvent( Event *ev ); + + qboolean DistanceTo( Vector pos ); + qboolean DistanceTo( Entity *ent ); + qboolean WithinDistance( Vector pos, float dist ); + qboolean WithinDistance( Entity *ent, float dist ); + + const char *Target( void ); + void SetTarget( const char *target ); + qboolean Targeted( void ); + const char *TargetName( void ); + void SetTargetName( const char *target ); + void SetKillTarget( const char *killtarget ); + const char *KillTarget( void ); + + virtual void setModel( const char *model ); + void setModel( str &mdl ); + void SetModelEvent( Event *ev ); + void SetTeamEvent( Event *ev ); + virtual void TriggerEvent( Event *ev ); + void hideModel( void ); + void EventHideModel( Event *ev ); + virtual void showModel( void ); + void EventShowModel( Event *ev ); + qboolean hidden( void ); + void ProcessInitCommandsEvent( Event *ev ); + void ProcessInitCommands( int index, qboolean cache = qfalse ); + + void setAlpha( float alpha ); + float alpha( void ); + + void setMoveType( int type ); + int getMoveType( void ); + + void setSolidType( solid_t type ); + int getSolidType( void ); + + virtual Vector getParentVector( Vector vec ); + Vector getLocalVector( Vector vec ); + + virtual void setSize( Vector min, Vector max ); + virtual void setOrigin( Vector org ); + virtual void setOrigin( void ); + virtual void addOrigin( Vector org ); + + void GetRawTag( int tagnum, orientation_t * orient ); + qboolean GetRawTag( const char * tagname, orientation_t * orient ); + + void GetTag( int tagnum, orientation_t * orient ); + qboolean GetTag( const char *name, orientation_t * orient ); + void GetTag( int tagnum, Vector *pos, Vector *forward = NULL, Vector *left = NULL, Vector *up = NULL ); + qboolean GetTag( const char *name, Vector *pos, Vector *forward = NULL, Vector *left = NULL, Vector *up = NULL ); + + virtual int CurrentFrame( bodypart_t part = legs ); + virtual int CurrentAnim( bodypart_t part = legs ); + + virtual void setAngles( Vector ang ); + virtual void setAngles( void ); + void SetOrigin( Event *ev ); + + Vector GetControllerAngles( int num ); + void SetControllerAngles( int num, vec3_t angles ); + void SetControllerAngles( Event *ev ); + void SetControllerTag( int num, int tag_num ); + + void link( void ); + void unlink( void ); + + void setContents( int type ); + int getContents( void ); + void setScale( float scale ); + + qboolean droptofloor( float maxfall ); + qboolean isClient( void ); + + virtual void SetDeltaAngles( void ); + virtual void DamageEvent( Event *event ); + void Damage( Entity *inflictor, + Entity *attacker, + float damage, + Vector position, + Vector direction, + Vector normal, + int knockback, + int flags, + int meansofdeath ); + void Stun( float time ); + + void DamageType( Event *ev ); + virtual qboolean CanDamage( Entity *target, Entity *skip_ent = NULL ); + + qboolean IsTouching( Entity *e1 ); + + void FadeNoRemove( Event *ev ); + void FadeOut( Event *ev ); + void FadeIn( Event *ev ); + void Fade( Event *ev ); + + virtual void CheckGround( void ); + virtual qboolean HitSky( trace_t *trace ); + virtual qboolean HitSky( void ); + + void BecomeSolid( Event *ev ); + void BecomeNonSolid( Event *ev ); + void SetHealth( Event *ev ); + void SetSize( Event *ev ); + void SetMins( Event *ev ); + void SetMaxs( Event *ev ); + void SetScale( Event *ev ); + void SetAlpha( Event *ev ); + void SetTargetName( Event *ev ); + void SetTarget( Event *ev ); + void SetKillTarget( Event *ev ); + void SetAngles( Event *ev ); + void SetAngleEvent( Event *ev ); + void TouchTriggersEvent( Event *ev ); + + str GetRandomAlias( str name ); + void SetWaterType( void ); + + // model binding functions + qboolean attach( int parent_entity_num, int tag_num, qboolean use_angles = qtrue, Vector attach_offset = "0 0 0"); + void detach( void ); + + void RegisterAlias( Event *ev ); + void RegisterAliasAndCache( Event *ev ); + void Cache( Event *ev ); + + qboolean GlobalAliasExists( const char *name ); + qboolean AliasExists( const char *name ); + + void Sound( Event *ev ); + virtual void Sound( str sound_name, int channel = CHAN_BODY, float volume = -1.0, + float min_dist = -1.0, Vector *origin = NULL ); + void StopSound( int channel ); + void StopSound( Event *ev ); + void LoopSound( Event *ev ); + void LoopSound( str sound_name, float volume = -1.0, float min_dist = -1.0 ); + void StopLoopSound( Event *ev ); + void StopLoopSound( void ); + + void SetLight(Event *ev); + void LightOn(Event *ev); + void LightOff(Event *ev); + void LightRed(Event *ev); + void LightGreen(Event *ev); + void LightBlue(Event *ev); + void LightRadius(Event *ev); + void LightStyle(Event *ev); + void Flags( Event *ev ); + void Effects( Event *ev ); + void RenderEffects( Event *ev ); + void SVFlags( Event *ev ); + + void BroadcastSound( float pos = SOUND_RADIUS ); + void BroadcastSound( Event *ev ); + void Kill( Event *ev ); + void SurfaceModelEvent( Event *ev ); + void SurfaceCommand( const char * surf_name, const char * token ); + + virtual void Postthink( void ); + virtual void Think( void ); + void DamageSkin( trace_t * trace, float damage ); + + void AttachEvent( Event *ev ); + void AttachModelEvent( Event *ev ); + void RemoveAttachedModelEvent( Event *ev ); + void DetachEvent( Event *ev ); + void TakeDamageEvent( Event *ev ); + void NoDamageEvent( Event *ev ); + void Gravity( Event *ev ); + void GiveOxygen( float time ); + void UseBoundingBoxEvent( Event *ev ); + void HurtEvent( Event *ev ); + void IfSkillEvent( Event *ev ); + void SetMassEvent( Event *ev ); + void Censor( Event *ev ); + void Ghost( Event *ev ); + + void StationaryEvent( Event *ev ); + void Explosion( Event *ev ); + + void Shader( Event *ev ); + + void KillAttach( Event *ev ); + void SetBloodModel( Event *ev ); + + void DropToFloorEvent( Event *ev ); + + // Binding methods + void joinTeam( Entity *teammember ); + void quitTeam( void ); + qboolean isBoundTo( Entity *master ); + virtual void bind( Entity *master, qboolean use_my_angles=false ); + virtual void unbind( void ); + + void JoinTeam( Event *ev ); + void EventQuitTeam( Event *ev ); + void BindEvent( Event *ev ); + void EventUnbind( Event *ev ); + void AddToSoundManager( Event *ev ); + void NoLerpThisFrame( void ); + + virtual void addAngles( Vector add ); + + void DeathSinkStart( Event *ev ); + void DeathSink( Event *ev ); + + void LookAtMe( Event *ev ); + void DetachAllChildren( Event *ev ); + + virtual void VelocityModified( void ); + virtual void Archive( Archiver &arc ); + }; + +inline int Entity::getSolidType + ( + void + ) + + { + return edict->solid; + } + + +inline qboolean Entity::DistanceTo + ( + Vector pos + ) + + { + Vector delta; + + delta = origin - pos; + return delta.length(); + } + +inline qboolean Entity::DistanceTo + ( + Entity *ent + ) + + { + Vector delta; + + assert( ent ); + + if ( !ent ) + { + // "Infinite" distance + return 999999; + } + + delta = origin - ent->origin; + return delta.length(); + } + +inline qboolean Entity::WithinDistance + ( + Vector pos, + float dist + ) + + { + Vector delta; + + delta = origin - pos; + + // check squared distance + return ( ( delta * delta ) < ( dist * dist ) ); + } + +inline qboolean Entity::WithinDistance + ( + Entity *ent, + float dist + ) + + { + Vector delta; + + assert( ent ); + + if ( !ent ) + { + return false; + } + + delta = origin - ent->origin; + + // check squared distance + return ( ( delta * delta ) < ( dist * dist ) ); + } + +inline const char *Entity::Target + ( + void + ) + + { + return target.c_str(); + } + +inline qboolean Entity::Targeted + ( + void + ) + + { + if ( !targetname.length() ) + { + return false; + } + return true; + } + +inline const char *Entity::TargetName + ( + void + ) + + { + return targetname.c_str(); + } + +inline const char * Entity::KillTarget + ( + void + ) + + { + return killtarget.c_str(); + } + +inline qboolean Entity::hidden + ( + void + ) + + { + if ( edict->s.renderfx & RF_DONTDRAW ) + { + return true; + } + return false; + } + +inline void Entity::setModel + ( + str &mdl + ) + + { + setModel( mdl.c_str() ); + } + +inline void Entity::SetModelEvent + ( + Event *ev + ) + + { + setModel( ev->GetString( 1 ) ); + } + +inline void Entity::hideModel + ( + void + ) + + { + edict->s.renderfx |= RF_DONTDRAW; + if ( getSolidType() <= SOLID_TRIGGER ) + { + edict->svflags |= SVF_NOCLIENT; + } + } + +inline void Entity::showModel + ( + void + ) + + { + edict->s.renderfx &= ~RF_DONTDRAW; + edict->svflags &= ~SVF_NOCLIENT; + } + +inline float Entity::alpha + ( + void + ) + + { + return edict->s.alpha; + } + +inline void Entity::setMoveType + ( + int type + ) + + { + movetype = type; + } + +inline int Entity::getMoveType + ( + void + ) + + { + return movetype; + } + +inline void Entity::unlink + ( + void + ) + + { + gi.unlinkentity( edict ); + } + +inline void Entity::setContents + ( + int type + ) + + { + edict->contents = type; + } + +inline int Entity::getContents + ( + void + ) + + { + return edict->contents; + } + +inline qboolean Entity::isClient + ( + void + ) + + { + if ( client ) + { + return true; + } + return false; + } + +inline void Entity::SetDeltaAngles + ( + void + ) + + { + int i; + + if ( client ) + { + for( i = 0; i < 3; i++ ) + { + client->ps.delta_angles[ i ] = ANGLE2SHORT( client->ps.viewangles[ i ] ); + } + } + } + +inline qboolean Entity::GlobalAliasExists + ( + const char *name + ) + + { + assert( name ); + + return ( gi.GlobalAlias_FindRandom( name ) != NULL ); + } + +inline qboolean Entity::AliasExists + ( + const char *name + ) + + { + assert( name ); + + return ( gi.Alias_FindRandom( edict->s.modelindex, name ) != NULL ); + } + +inline str Entity::GetRandomAlias + ( + str name + ) + + { + str realname; + const char *s; + + s = gi.Alias_FindRandom( edict->s.modelindex, name.c_str() ); + if ( s ) + { + realname = s; + } + else + { + s = gi.GlobalAlias_FindRandom( name.c_str() ); + if ( s ) + { + realname = s; + } + } + + return realname; + } + +inline int Entity::CurrentFrame + ( + bodypart_t part + ) + + { + part = part; + return 0; + } + +inline int Entity::CurrentAnim + ( + bodypart_t part + ) + + { + part = part; + return 0; + } + +inline void Entity::Archive + ( + Archiver &arc + ) + + { + int tempInt; + + Listener::Archive( arc ); + + G_ArchiveEdict( arc, edict ); + + arc.ArchiveInteger( &spawnflags ); + + arc.ArchiveString( &model ); + if ( arc.Loading() && model.length() ) + { + setModel( model ); + } + + arc.ArchiveFloat( &move_time ); + arc.ArchiveVector( &total_delta ); + arc.ArchiveVector( &mins ); + arc.ArchiveVector( &maxs ); + arc.ArchiveVector( &absmin ); + arc.ArchiveVector( &absmax ); + arc.ArchiveVector( ¢roid ); + arc.ArchiveVector( &velocity ); + arc.ArchiveVector( &avelocity ); + arc.ArchiveVector( &origin ); + arc.ArchiveVector( &angles ); + arc.ArchiveVector( &size ); + arc.ArchiveInteger( &movetype ); + arc.ArchiveInteger( &mass ); + arc.ArchiveFloat( &gravity ); + arc.ArchiveRaw( orientation, sizeof( orientation ) ); + + if ( arc.Saving() ) + { + if ( groundentity ) + { + tempInt = groundentity - g_entities; + } + else + { + tempInt = -1; + } + } + + arc.ArchiveInteger( &tempInt ); + + if ( arc.Loading() ) + { + if ( tempInt == -1 ) + { + groundentity = NULL; + } + else + { + groundentity = &g_entities[ tempInt ]; + } + } + + arc.ArchiveRaw( &groundplane, sizeof( groundplane ) ); + arc.ArchiveInteger( &groundcontents ); + + arc.ArchiveInteger( &numchildren ); + arc.ArchiveRaw( children, sizeof( children ) ); + + arc.ArchiveInteger( &numsurfaces ); + + arc.ArchiveFloat( &lightRadius ); + + arc.ArchiveString( &moveteam ); + arc.ArchiveObjectPointer( ( Class ** )&teamchain ); + arc.ArchiveObjectPointer( ( Class ** )&teammaster ); + + arc.ArchiveObjectPointer( ( Class ** )&bindmaster ); + arc.ArchiveBoolean( &bind_use_my_angles ); + arc.ArchiveVector( &localorigin ); + arc.ArchiveVector( &localangles ); + + arc.ArchiveString( &target ); + arc.ArchiveString( &targetname ); + // add to target list to rebuild targetlists + arc.ArchiveString( &killtarget ); + + if ( arc.Loading() ) + { + // reset target stuff + SetTargetName( targetname.c_str() ); + SetTarget( target.c_str() ); + } + + arc.ArchiveFloat( &health ); + arc.ArchiveFloat( &max_health ); + arc.ArchiveInteger( &deadflag ); + arc.ArchiveInteger( &flags ); + + arc.ArchiveInteger( &watertype ); + arc.ArchiveInteger( &waterlevel ); + + ArchiveEnum( takedamage, damage_t ); + + arc.ArchiveSafePointer( &enemy ); + arc.ArchiveFloat( &pain_finished ); + arc.ArchiveFloat( &damage_debounce_time ); + arc.ArchiveInteger( &damage_type ); + + arc.ArchiveBoolean( &detach_at_death ); + + arc.ArchiveBoolean( &look_at_me ); + } + +#include "worldspawn.h" + +#endif + diff --git a/source/source/fgame/events.h b/source/source/fgame/events.h new file mode 100644 index 0000000..658928a --- /dev/null +++ b/source/source/fgame/events.h @@ -0,0 +1,70 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/events.h $ +// $Revision:: 1 $ +// $Author:: Jimdose $ +// $Date:: 9/10/99 10:53a $ +// +// Copyright (C) 1997 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source is may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/events.h $ +// +// 1 9/10/99 10:53a Jimdose +// +// 1 9/08/99 3:15p Aldie +// +// DESCRIPTION: +// Event definitions for communication between Sin and DLL's +// + +#ifndef __EVENTS_H__ +#define __EVENTS_H__ + +#if 1 +typedef int event_t; + +enum + { + EVENT_DEFAULT_MINEVENT = 1, + + // Player events + EVENT_CLIENTCONNECT = EVENT_DEFAULT_MINEVENT, + EVENT_CLIENTDISCONNECT, + EVENT_CLIENTKILL, + EVENT_CLIENTMOVE, + EVENT_CLIENTENDFRAME, + EVENT_SETNEWPARMS, + EVENT_SETCHANGEPARMS, + EVENT_PRETHINK, + EVENT_POSTTHINK, + + // Generic entity events + EVENT_SPAWN, + EVENT_REMOVE, + EVENT_PRECACHE, + EVENT_THINK, + EVENT_ACTIVATE, + EVENT_USE, + EVENT_FOOTSTEP, + + // Physics events + EVENT_MOVEDONE, + EVENT_TOUCH, + EVENT_BLOCKED, + + // Animation events + EVENT_ANIM_FRAME, + EVENT_ANIM_NEWANIM, + EVENT_ANIM_LASTFRAME, + + // For subclass events + EVENT_DEFAULT_MAXEVENT + }; + +#endif + +#endif /* events.h */ diff --git a/source/source/fgame/explosion.cpp b/source/source/fgame/explosion.cpp new file mode 100644 index 0000000..f0eeceb --- /dev/null +++ b/source/source/fgame/explosion.cpp @@ -0,0 +1,768 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/explosion.cpp $ +// $Revision:: 24 $ +// $Author:: Steven $ +// $Date:: 7/22/00 5:53p $ +// +// Copyright (C) 1997 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source is may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/explosion.cpp $ +// +// 24 7/22/00 5:53p Steven +// Made it so a remove event is only posted if explosions have a life set. +// +// 23 7/16/00 2:10p Markd +// fixed multi use func_explodeobjects +// +// 22 7/16/00 12:44p Markd +// fixed multi-use func_explodeobjects +// +// 21 7/06/00 3:26p Markd +// added rock to func_explodeobject +// +// 20 6/27/00 5:46p Steven +// Added some CacheResource calls to make sure explosions are cached correctly. +// +// 19 6/23/00 8:41p Markd +// made a lot of changes to different constructors for saved game support +// +// 18 6/14/00 3:50p Markd +// Cleaned up more Intel Compiler warnings +// +// 17 5/27/00 3:32p Markd +// 2nd pass save games +// +// 16 4/21/00 3:01p Markd +// fixed up explode_object explosions +// +// 15 4/18/00 5:57p Markd +// fixed multi arg support for debris models +// +// 14 4/18/00 4:20p Markd +// added random scale ability to func_explodeobject and func_multiexploder +// +// 13 4/18/00 4:01p Markd +// fixed up explosions +// +// 12 2/07/00 4:21p Markd +// Added "thread" to quaked sections for better documentation +// +// 11 2/03/00 9:33a Markd +// added VISIBLE flag to func_multi_exploder and func_explodeobject +// +// 10 2/02/00 7:18p Markd +// fixed some commented out code +// +// 9 2/02/00 7:14p Markd +// Added func_explodeobject and TossObject +// +// 8 2/01/00 5:41p Markd +// Made Multi-Exploder multi-use +// +// 7 1/12/00 6:16p Jimdose +// rewrote CreateExplosion +// +// 6 1/06/00 11:08p Jimdose +// cleaning up unused code +// +// 5 11/12/99 11:47a Markd +// Added sound manager support and retro-fitted TriggerSpeaker and TriggerMusic +// to work with everything +// +// 4 11/01/99 6:11p Steven +// Changed some old attenuation stuff to min dist stuff. +// +// 3 9/29/99 5:18p Steven +// Event formatting. +// +// 2 9/16/99 11:18a Markd +// Continuing merge of code, not functional yet but closer +// +// 1 9/10/99 10:53a Jimdose +// +// 1 9/08/99 3:15p Aldie +// +// 20 8/28/99 11:44a Steven +// Removed global from sound function calls. +// +// 19 8/18/99 3:28p Jimdose +// added cylindrical collision detection +// +// 18 8/03/99 3:37p Aldie +// Removed some old explosion stuff +// +// 17 7/30/99 6:24p Aldie +// Updated weapons and utils to use new methods +// +// 16 7/30/99 3:00p Steven +// New temporary stuff for gas explosions. +// +// 15 6/11/99 1:23p Phook +// +// 14 6/11/99 12:58p Phook +// Changed from SINED comments to QUAKED +// +// 13 6/11/99 12:46p Phook +// EClass color changes +// +// DESCRIPTION: +// Standard explosion object that is spawned by other entites and not map designers. +// Explosion is used by many of the weapons for the blast effect, but is also used +// by the Exploder and MultiExploder triggers. These triggers create one or more +// explosions each time they are activated. +// + +#include "g_local.h" +#include "entity.h" +#include "trigger.h" +#include "explosion.h" +#include "weaputils.h" + +#define MULTI_USE (1<<0) +#define RANDOM_TIME (1<<1) +#define VISIBLE (1<<2) +#define RANDOM_SCALE (1<<3) +#define NO_EXPLOSIONS (1<<4) + +Event EV_Exploder_SetDmg + ( + "dmg", + EV_DEFAULT, + "i", + "damage", + "Sets the damage the explosion does." + ); +Event EV_Exploder_SetDuration + ( + "duration", + EV_DEFAULT, + "f", + "duration", + "Sets the duration of the explosion." + ); +Event EV_Exploder_SetWait + ( + "wait", + EV_DEFAULT, + "f", + "explodewait", + "Sets the wait time of the explosion." + ); +Event EV_Exploder_SetRandom + ( + "random", + EV_DEFAULT, + "f", + "randomness", + "Sets the randomness value of the explosion." + ); + +void CreateExplosion + ( + Vector pos, + float damage, + Entity *inflictor, + Entity *attacker, + Entity *ignore, + const char *explosionModel, + float scale + ) + + { + Explosion *explosion; + Event *ev; + + assert( inflictor ); + + if ( !inflictor ) + { + return; + } + + if ( !attacker ) + { + attacker = world; + } + + if ( !explosionModel ) + { + explosionModel = "fx_explosion.tik"; + } + + explosion = new Explosion; + + // Create a new explosion entity and set it off + explosion->setModel( explosionModel ); + + explosion->setSolidType( SOLID_NOT ); + explosion->CancelEventsOfType( EV_ProcessInitCommands ); + explosion->ProcessInitCommands( explosion->edict->s.modelindex ); + + explosion->owner = attacker->entnum; + explosion->edict->ownerNum = attacker->entnum; + explosion->setMoveType( MOVETYPE_FLYMISSILE ); + explosion->edict->clipmask = MASK_PROJECTILE; + explosion->setSize( explosion->mins, explosion->maxs ); + explosion->setOrigin( pos ); + explosion->origin.copyTo( explosion->edict->s.origin2 ); + + if ( explosion->dlight_radius ) + { + G_SetConstantLight( &explosion->edict->s.constantLight, + &explosion->dlight_color[0], + &explosion->dlight_color[1], + &explosion->dlight_color[2], + &explosion->dlight_radius + ); + } + + explosion->BroadcastSound(); + + explosion->RandomAnimate( "idle", EV_StopAnimating ); + RadiusDamage( inflictor, attacker, damage, ignore, MOD_EXPLOSION ); + + if ( explosion->life ) + { + ev = new Event( EV_Remove ); + explosion->PostEvent( ev, explosion->life ); + } + } + + +/*****************************************************************************/ +/*QUAKED func_exploder (0 0.25 0.5) (0 0 0) (8 8 8) + + Spawns an explosion when triggered. Triggers any targets. + + "dmg" specifies how much damage to cause. Default indicates 120. + "key" The item needed to activate this. (default nothing) + "thread" name of thread to trigger. This can be in a different script file as well\ +by using the '::' notation. +******************************************************************************/ + +CLASS_DECLARATION( Trigger, Exploder, "func_exploder" ) + { + { &EV_Touch, NULL }, + { &EV_Trigger_Effect, MakeExplosion }, + { &EV_Exploder_SetDmg, SetDmg }, + { NULL, NULL } + }; + +void Exploder::MakeExplosion + ( + Event *ev + ) + + { + CreateExplosion + ( + origin, + damage, + this, + ev->GetEntity( 1 ), + this + ); + } + +Exploder::Exploder() + { + damage = 120; + respondto = TRIGGER_PLAYERS | TRIGGER_MONSTERS | TRIGGER_PROJECTILES; + } + +void Exploder::SetDmg + ( + Event *ev + ) + + { + damage = ev->GetInteger( 1 ); + if ( damage < 0 ) + { + damage = 0; + } + } + +/*****************************************************************************/ +/*QUAKED func_multi_exploder (0 0.25 0.5) ? MULTI_USE RANDOM_TIME VISIBLE RANDOM_SCALE + + Spawns an explosion when triggered. Triggers any targets. + size of brush determines where explosions will occur. + + "dmg" specifies how much damage to cause from each explosion. (Default 120) + "delay" delay before exploding (Default 0 seconds) + "duration" how long to explode for (Default 1 second) + "wait" time between each explosion (default 0.25 seconds) + "random" random factor (default 0.25) + "key" The item needed to activate this. (default nothing) + "thread" name of thread to trigger. This can be in a different script file as well\ +by using the '::' notation. + "health" makes the object damageable + "scale" set the maximum size for spawned debris and explosions. + + MULTI_USE allows the func_multi_exploder to be used more than once + RANDOM_TIME adjusts the wait between each explosion by the random factor + VISIBLE allows you to make the trigger visible + RANDOM_SCALE scale explosions randomly. size will be between 0.25 and 1 times scale + +******************************************************************************/ + +CLASS_DECLARATION( Trigger, MultiExploder, "func_multi_exploder" ) + { + { &EV_Touch, NULL }, + { &EV_Trigger_Effect, MakeExplosion }, + { &EV_Exploder_SetDmg, SetDmg }, + { &EV_Exploder_SetDuration, SetDuration }, + { &EV_Exploder_SetWait, SetWait }, + { &EV_Exploder_SetRandom, SetRandom }, + { NULL, NULL } + }; + +void MultiExploder::MakeExplosion + ( + Event *ev + ) + + { + Vector pos; + float t, scale; + Entity *other; + Event *event; + + other = ev->GetEntity( 1 ); + + // make sure other is valid + if ( !other ) + { + other = world; + } + + // prevent the trigger from triggering again + trigger_time = -1; + + if ( !explode_time ) + { + hideModel(); + explode_time = level.time + duration; + } + + if ( spawnflags & RANDOM_TIME ) + { + t = explodewait * ( 1 + G_CRandom( randomness ) ); + } + else + { + t = explodewait; + } + + event = new Event( EV_Trigger_Effect ); + event->AddEntity( other ); + PostEvent( event, t ); + + if ( level.time > explode_time ) + { + if ( spawnflags & MULTI_USE ) + { + // + // reset the trigger in a half second + // + trigger_time = level.time + 0.5f; + explode_time = 0; + CancelEventsOfType( EV_Trigger_Effect ); + // + // reset health if necessary + // + health = max_health; + return; + } + else + { + PostEvent( EV_Remove, 0 ); + return; + } + } + + pos[ 0 ] = absmin[ 0 ] + G_Random( absmax[ 0 ] - absmin[ 0 ] ); + pos[ 1 ] = absmin[ 1 ] + G_Random( absmax[ 1 ] - absmin[ 1 ] ); + pos[ 2 ] = absmin[ 2 ] + G_Random( absmax[ 2 ] - absmin[ 2 ] ); + + if ( spawnflags & RANDOM_SCALE ) + { + scale = edict->s.scale * 0.25f; + scale += G_Random( 3 * scale ); + } + else + { + scale = 1.0f; + } + + CreateExplosion + ( + pos, + damage, + this, + other, + this, + NULL, + scale + ); + } + +MultiExploder::MultiExploder() + { + if ( LoadingSavegame ) + { + return; + } + + damage = 120; + duration = 1.0; + explodewait = 0.25; + randomness = 0.25; + explode_time = 0; + + if ( spawnflags & VISIBLE ) + { + PostEvent( EV_Show, EV_POSTSPAWN ); + } + else + { + PostEvent( EV_Hide, EV_POSTSPAWN ); + } + + // So that we don't get deleted after we're triggered + count = -1; + + respondto = TRIGGER_PLAYERS | TRIGGER_MONSTERS | TRIGGER_PROJECTILES; + } + +void MultiExploder::SetDmg + ( + Event *ev + ) + + { + damage = ev->GetInteger( 1 ); + if ( damage < 0 ) + { + damage = 0; + } + } + +void MultiExploder::SetDuration + ( + Event *ev + ) + + { + duration = ev->GetFloat( 1 ); + } + +void MultiExploder::SetWait + ( + Event *ev + ) + + { + explodewait = ev->GetFloat( 1 ); + } + +void MultiExploder::SetRandom + ( + Event *ev + ) + + { + randomness = ev->GetFloat( 1 ); + } + + +#define METAL_DEBRIS (1<<5) +#define ROCK_DEBRIS (1<<6) +#define NOTSOLID (1<<7) + +/*****************************************************************************/ +/*QUAKED func_explodeobject (0 0.25 0.5) ? MULTI_USE RANDOM_TIME VISIBLE RANDOM_SCALE NO_EXPLOSIONS METAL_DEBRIS ROCK_DEBRIS NOTSOLID + + Spawns different kinds of debris when triggered. Triggers any targets. + size of brush determines where explosions and debris will be spawned. + + "dmg" specifies how much damage to cause from each explosion. (Default 120) + "delay" delay before exploding (Default 0 seconds) + "duration" how long to explode for (Default 1 second) + "wait" time between each explosion (default 0.25 seconds) + "random" random factor (default 0.25) + "health" if specified, object must be damaged to trigger + "key" The item needed to activate this. (default nothing) + "severity" how violent the debris should be ejected from the object( default 1.0 ) + "debrismodel" What kind of debris to spawn (default nothing) + "amount" how much debris to spawn for each explosion (default 4) + "thread" name of thread to trigger. This can be in a different script file as well\ +by using the '::' notation. + "health" makes the object damageable + "scale" set the maximum size for spawned debris and explosions + + MULTI_USE allows the func_explodeobject to be used more than once + RANDOM_TIME adjusts the wait between each explosion by the random factor + VISIBLE allows you to make the trigger visible + RANDOM_SCALE scale explosions and debris randomly. size will be between 0.25 and 1 times scale + NO_EXPLOSIONS, if checked no explosions will be created + METAL_DEBRIS automatically spawn metal debris, no need for debrismodel to be set + ROCK_DEBRIS automatically spawn rock debris, no need for debrismodel to be set + NOTSOLID debris is not solid + + other valid tiki files include: + + obj_debris_glass1-4.tik + obj_debris_wood1-4.tik + +******************************************************************************/ + +Event EV_ExplodeObject_SetSeverity + ( + "severity", + EV_DEFAULT, + "f", + "newSeverity", + "How violently the debris should be ejected." + ); + +Event EV_ExplodeObject_SetDebrisModel + ( + "debrismodel", + EV_DEFAULT, + "s", + "debrisModel", + "What kind of debris to spawn when triggered." + ); + +Event EV_ExplodeObject_SetDebrisAmount + ( + "amount", + EV_DEFAULT, + "i", + "amountOfDebris", + "How much debris to spawn each time." + ); + + +CLASS_DECLARATION( MultiExploder, ExplodeObject, "func_explodeobject" ) + { + { &EV_Touch, NULL }, + { &EV_Trigger_Effect, MakeExplosion }, + { &EV_ExplodeObject_SetSeverity, SetSeverity }, + { &EV_ExplodeObject_SetDebrisModel, SetDebrisModel }, + { &EV_ExplodeObject_SetDebrisAmount, SetDebrisAmount }, + { NULL, NULL } + }; + +void ExplodeObject::SetDebrisModel + ( + Event *ev + ) + + { + char string[ 1024 ]; + const char *ptr; + + // there could be multiple space delimited models, so we need to search for the spaces. + strcpy( string, ev->GetString( 1 ) ); + ptr = strtok( string, " " ); + while ( ptr ) + { + debrismodels.AddUniqueObject( str( ptr ) ); + CacheResource( ptr, this ); + ptr = strtok( NULL, " " ); + } + } + +void ExplodeObject::SetSeverity + ( + Event *ev + ) + + { + severity = ev->GetFloat( 1 ); + } + +void ExplodeObject::SetDebrisAmount + ( + Event *ev + ) + + { + debrisamount = ev->GetInteger( 1 ); + } + +void ExplodeObject::MakeExplosion + ( + Event *ev + ) + + { + Vector pos; + float t, scale; + Entity *other; + Event *event; + + other = ev->GetEntity( 1 ); + + // make sure other is valid + if ( !other ) + { + other = world; + } + + // prevent the trigger from triggering again + trigger_time = -1; + + if ( !explode_time ) + { + setSolidType( SOLID_NOT ); + hideModel(); + explode_time = level.time + duration; + } + + if ( spawnflags & RANDOM_TIME ) + { + t = explodewait * ( 1 + G_CRandom( randomness ) ); + } + else + { + t = explodewait; + } + + event = new Event( EV_Trigger_Effect ); + event->AddEntity( other ); + PostEvent( event, t ); + + if ( level.time > explode_time ) + { + if ( spawnflags & MULTI_USE ) + { + // + // reset the trigger in a half second + // + trigger_time = level.time + 0.5f; + explode_time = 0; + CancelEventsOfType( EV_Trigger_Effect ); + // + // reset health if necessary + // + health = max_health; + if ( health ) + { + setSolidType( SOLID_BBOX ); + } + if ( spawnflags & VISIBLE ) + { + PostEvent( EV_Show, 0.5f ); + } + return; + } + else + { + PostEvent( EV_Remove, 0 ); + return; + } + } + + pos[ 0 ] = absmin[ 0 ] + G_Random( absmax[ 0 ] - absmin[ 0 ] ); + pos[ 1 ] = absmin[ 1 ] + G_Random( absmax[ 1 ] - absmin[ 1 ] ); + pos[ 2 ] = absmin[ 2 ] + G_Random( absmax[ 2 ] - absmin[ 2 ] ); + + if ( spawnflags & RANDOM_SCALE ) + { + scale = edict->s.scale * 0.25f; + scale += G_Random( 3 * scale ); + } + else + { + scale = 1.0f; + } + + if ( !( spawnflags & NO_EXPLOSIONS ) ) + { + CreateExplosion + ( + pos, + damage, + this, + other, + this, + NULL, + scale + ); + } + if ( debrismodels.NumObjects() ) + { + TossObject *to; + int i; + for ( i = 0; i < debrisamount; i++ ) + { + int num; + + if ( spawnflags & RANDOM_SCALE ) + { + scale = edict->s.scale * 0.25f; + scale += G_Random( 3 * scale ); + } + else + { + scale = 1.0f; + } + + num = G_Random( debrismodels.NumObjects() ) + 1; + to = new TossObject( debrismodels.ObjectAt( num ) ); + to->setScale( scale ); + to->setOrigin( pos ); + to->SetVelocity( severity ); + if ( spawnflags & NOTSOLID ) + { + to->setSolidType( SOLID_NOT ); + } + pos[ 0 ] = absmin[ 0 ] + G_Random( absmax[ 0 ] - absmin[ 0 ] ); + pos[ 1 ] = absmin[ 1 ] + G_Random( absmax[ 1 ] - absmin[ 1 ] ); + pos[ 2 ] = absmin[ 2 ] + G_Random( absmax[ 2 ] - absmin[ 2 ] ); + } + } + + } + +ExplodeObject::ExplodeObject() + { + if ( !LoadingSavegame ) + { + duration = 1; + explodewait = 0.25f; + severity = 1.0f; + debrismodels.ClearObjectList(); + debrisamount = 2; + if ( spawnflags & METAL_DEBRIS ) + { + debrismodels.AddUniqueObject( str( "obj_debris_metal1.tik" ) ); + debrismodels.AddUniqueObject( str( "obj_debris_metal2.tik" ) ); + debrismodels.AddUniqueObject( str( "obj_debris_metal3.tik" ) ); + CacheResource( "obj_debris_metal1.tik", this ); + CacheResource( "obj_debris_metal2.tik", this ); + CacheResource( "obj_debris_metal3.tik", this ); + } + else if ( spawnflags & ROCK_DEBRIS ) + { + debrismodels.AddUniqueObject( str( "obj_debris_rock1.tik" ) ); + debrismodels.AddUniqueObject( str( "obj_debris_rock2.tik" ) ); + debrismodels.AddUniqueObject( str( "obj_debris_rock3.tik" ) ); + debrismodels.AddUniqueObject( str( "obj_debris_rock4.tik" ) ); + CacheResource( "obj_debris_rock1.tik", this ); + CacheResource( "obj_debris_rock2.tik", this ); + CacheResource( "obj_debris_rock3.tik", this ); + CacheResource( "obj_debris_rock4.tik", this ); + } + } + } + diff --git a/source/source/fgame/explosion.h b/source/source/fgame/explosion.h new file mode 100644 index 0000000..01b87aa --- /dev/null +++ b/source/source/fgame/explosion.h @@ -0,0 +1,172 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/explosion.h $ +// $Revision:: 10 $ +// $Author:: Markd $ +// $Date:: 6/14/00 2:17p $ +// +// Copyright (C) 1997 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source is may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/explosion.h $ +// +// 10 6/14/00 2:17p Markd +// fixed compiler warnings for Intel Compiler +// +// 9 5/26/00 7:44p Markd +// 2nd phase save games +// +// 8 5/24/00 3:14p Markd +// first phase of save/load games +// +// 7 4/18/00 4:20p Markd +// added random scale ability to func_explodeobject and func_multiexploder +// +// 6 4/18/00 4:01p Markd +// fixed up explosions +// +// 5 2/02/00 7:14p Markd +// Added func_explodeobject and TossObject +// +// 4 1/12/00 6:13p Jimdose +// added base_velocity and random_velocity +// rewrote CreateExplosion +// +// 3 1/06/00 11:08p Jimdose +// cleaning up unused code +// +// 2 11/01/99 6:12p Steven +// Changed some old attenuation stuff to min dist stuff. +// +// 1 9/10/99 10:53a Jimdose +// +// 1 9/08/99 3:16p Aldie +// +// 6 7/30/99 6:24p Aldie +// Updated weapons and utils to use new methods +// +// 5 7/30/99 3:00p Steven +// New temporary stuff for gas explosions. +// +// DESCRIPTION: +// Standard explosion object that is spawned by other entites and not map designers. +// Explosion is used by many of the weapons for the blast effect, but is also used +// by the Exploder and MultiExploder triggers. These triggers create one or more +// explosions each time they are activated. +// + +#ifndef __EXPLOSION_H__ +#define __EXPLOSION_H__ + +#include "g_local.h" +#include "entity.h" +#include "trigger.h" + +class Exploder : public Trigger + { + private: + int damage; + + void MakeExplosion( Event *ev ); + void SetDmg( Event *ev ); + + public: + CLASS_PROTOTYPE( Exploder ); + + Exploder(); + virtual void Archive( Archiver &arc ); + }; + +inline void Exploder::Archive + ( + Archiver &arc + ) + + { + Trigger::Archive( arc ); + + arc.ArchiveInteger( &damage ); + } + +class MultiExploder : public Trigger + { + protected: + float explodewait; + float explode_time; + float duration; + int damage; + float randomness; + + void MakeExplosion( Event *ev ); + void SetDmg( Event *ev ); + void SetDuration( Event *ev ); + void SetWait( Event *ev ); + void SetRandom( Event *ev ); + + public: + CLASS_PROTOTYPE( MultiExploder ); + + MultiExploder(); + virtual void Archive( Archiver &arc ); + }; + +inline void MultiExploder::Archive + ( + Archiver &arc + ) + { + Trigger::Archive( arc ); + + arc.ArchiveFloat( &explodewait ); + arc.ArchiveFloat( &explode_time ); + arc.ArchiveFloat( &duration ); + arc.ArchiveInteger( &damage ); + arc.ArchiveFloat( &randomness ); + } + +void CreateExplosion + ( + Vector pos, + float damage = 120, + Entity *inflictor = NULL, + Entity *attacker = NULL, + Entity *ignore = NULL, + const char *explosionModel = NULL, + float scale = 1.0f + ); + +class ExplodeObject : public MultiExploder + { + private: + Container debrismodels; + int debrisamount; + float severity; + + void SetDebrisModel( Event *ev ); + void SetSeverity( Event *ev ); + void SetDebrisAmount( Event *ev ); + void MakeExplosion( Event *ev ); + + public: + CLASS_PROTOTYPE( ExplodeObject ); + + ExplodeObject(); + virtual void Archive( Archiver &arc ); + }; + +inline void ExplodeObject::Archive + ( + Archiver &arc + ) + { + MultiExploder::Archive( arc ); + + arc.ArchiveFloat( &severity ); + arc.ArchiveInteger( &debrisamount ); + debrismodels.Archive( arc ); + } + +#endif /* explosion.h */ diff --git a/source/source/fgame/fgame.dsp b/source/source/fgame/fgame.dsp new file mode 100644 index 0000000..32ea101 --- /dev/null +++ b/source/source/fgame/fgame.dsp @@ -0,0 +1,756 @@ +# Microsoft Developer Studio Project File - Name="fgame" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 6.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102 + +CFG=fgame - 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 "fgame.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 "fgame.mak" CFG="fgame - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "fgame - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE "fgame - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library") +!MESSAGE + +# Begin Project +# PROP AllowPerConfigDependencies 0 +# PROP Scc_ProjName ""$/fakk2_code/fakk2_new/fgame", FYHAAAAA" +# PROP Scc_LocalPath "." +CPP=cl.exe +MTL=midl.exe +RSC=rc.exe + +!IF "$(CFG)" == "fgame - 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" /D "_MBCS" /D "_USRDLL" /D "FGAME_EXPORTS" /YX /FD /c +# ADD CPP /nologo /MT /W3 /GX /Zi /O2 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "FGAME_EXPORTS" /D "GAME_DLL" /FR /YX /FD /c +# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 +# ADD LINK32 kernel32.lib user32.lib winmm.lib /nologo /dll /map /machine:I386 /out:"../Release/fgamex86.dll" +# SUBTRACT LINK32 /debug + +!ELSEIF "$(CFG)" == "fgame - 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" /D "_MBCS" /D "_USRDLL" /D "FGAME_EXPORTS" /YX /FD /GZ /c +# ADD CPP /nologo /MTd /W4 /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "FGAME_EXPORTS" /D "GAME_DLL" /FR /YX /FD /GZ /c +# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32 +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept +# ADD LINK32 kernel32.lib user32.lib winmm.lib /nologo /dll /debug /machine:I386 /out:"../Debug/fgamex86.dll" /pdbtype:sept + +!ENDIF + +# Begin Target + +# Name "fgame - Win32 Release" +# Name "fgame - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat" +# Begin Source File + +SOURCE=.\actor.cpp +# End Source File +# Begin Source File + +SOURCE=.\ammo.cpp +# End Source File +# Begin Source File + +SOURCE=.\animate.cpp +# End Source File +# Begin Source File + +SOURCE=.\archive.cpp +# End Source File +# Begin Source File + +SOURCE=.\armor.cpp +# End Source File +# Begin Source File + +SOURCE=.\beam.cpp +# End Source File +# Begin Source File + +SOURCE=.\behavior.cpp +# End Source File +# Begin Source File + +SOURCE=.\bg_misc.c +# End Source File +# Begin Source File + +SOURCE=.\bg_pmove.c +# End Source File +# Begin Source File + +SOURCE=.\bspline.cpp +# End Source File +# Begin Source File + +SOURCE=.\camera.cpp +# End Source File +# Begin Source File + +SOURCE=.\characterstate.cpp +# End Source File +# Begin Source File + +SOURCE=.\class.cpp +# End Source File +# Begin Source File + +SOURCE=.\clusterbomb.cpp +# End Source File +# Begin Source File + +SOURCE=.\crossbow.cpp +# End Source File +# Begin Source File + +SOURCE=.\debuglines.cpp +# End Source File +# Begin Source File + +SOURCE=.\decals.cpp +# End Source File +# Begin Source File + +SOURCE=.\doors.cpp +# End Source File +# Begin Source File + +SOURCE=.\earthquake.cpp +# End Source File +# Begin Source File + +SOURCE=.\edenwater.cpp +# End Source File +# Begin Source File + +SOURCE=.\entity.cpp +# End Source File +# Begin Source File + +SOURCE=.\explosion.cpp +# End Source File +# Begin Source File + +SOURCE=.\flamethrower.cpp +# End Source File +# Begin Source File + +SOURCE=.\flashbang.cpp +# End Source File +# Begin Source File + +SOURCE=.\g_main.cpp +# End Source File +# Begin Source File + +SOURCE=.\g_phys.cpp +# End Source File +# Begin Source File + +SOURCE=.\g_spawn.cpp +# End Source File +# Begin Source File + +SOURCE=.\g_utils.cpp +# End Source File +# Begin Source File + +SOURCE=.\game.cpp +# End Source File +# Begin Source File + +SOURCE=.\game.def +# End Source File +# Begin Source File + +SOURCE=.\gamecmds.cpp +# End Source File +# Begin Source File + +SOURCE=.\gamecvars.cpp +# End Source File +# Begin Source File + +SOURCE=.\gamescript.cpp +# End Source File +# Begin Source File + +SOURCE=.\gibs.cpp +# End Source File +# Begin Source File + +SOURCE=.\goo.cpp +# End Source File +# Begin Source File + +SOURCE=.\gravpath.cpp +# End Source File +# Begin Source File + +SOURCE=.\health.cpp +# End Source File +# Begin Source File + +SOURCE=.\hornofconjuring.cpp +# End Source File +# Begin Source File + +SOURCE=.\inventoryitem.cpp +# End Source File +# Begin Source File + +SOURCE=.\ipfilter.cpp +# End Source File +# Begin Source File + +SOURCE=.\item.cpp +# End Source File +# Begin Source File + +SOURCE=.\level.cpp +# End Source File +# Begin Source File + +SOURCE=.\light.cpp +# End Source File +# Begin Source File + +SOURCE=.\listener.cpp +# End Source File +# Begin Source File + +SOURCE=.\misc.cpp +# End Source File +# Begin Source File + +SOURCE=.\mover.cpp +# End Source File +# Begin Source File + +SOURCE=.\nature.cpp +# End Source File +# Begin Source File + +SOURCE=.\navigate.cpp +# End Source File +# Begin Source File + +SOURCE=.\object.cpp +# End Source File +# Begin Source File + +SOURCE=.\path.cpp +# End Source File +# Begin Source File + +SOURCE=.\player.cpp +# End Source File +# Begin Source File + +SOURCE=.\player_combat.cpp +# End Source File +# Begin Source File + +SOURCE=.\player_util.cpp +# End Source File +# Begin Source File + +SOURCE=.\PlayerStart.cpp +# End Source File +# Begin Source File + +SOURCE=.\portal.cpp +# End Source File +# Begin Source File + +SOURCE=.\powerups.cpp +# End Source File +# Begin Source File + +SOURCE=.\q_math.c +# End Source File +# Begin Source File + +SOURCE=.\q_mathsys.c +# End Source File +# Begin Source File + +SOURCE=.\q_shared.c +# End Source File +# Begin Source File + +SOURCE=.\rope.cpp +# End Source File +# Begin Source File + +SOURCE=.\script.cpp +# End Source File +# Begin Source File + +SOURCE=.\scriptmaster.cpp +# End Source File +# Begin Source File + +SOURCE=.\scriptslave.cpp +# End Source File +# Begin Source File + +SOURCE=.\scriptvariable.cpp +# End Source File +# Begin Source File + +SOURCE=.\sentient.cpp +# End Source File +# Begin Source File + +SOURCE=.\shield.cpp +# End Source File +# Begin Source File + +SOURCE=.\soulsucker.cpp +# End Source File +# Begin Source File + +SOURCE=.\soundman.cpp +# End Source File +# Begin Source File + +SOURCE=.\spawners.cpp +# End Source File +# Begin Source File + +SOURCE=.\specialfx.cpp +# End Source File +# Begin Source File + +SOURCE=.\steering.cpp +# End Source File +# Begin Source File + +SOURCE=.\str.cpp +# End Source File +# Begin Source File + +SOURCE=.\sword.cpp +# End Source File +# Begin Source File + +SOURCE=.\trigger.cpp +# End Source File +# Begin Source File + +SOURCE=.\vehicle.cpp +# End Source File +# Begin Source File + +SOURCE=.\viewthing.cpp +# End Source File +# Begin Source File + +SOURCE=.\weapon.cpp +# End Source File +# Begin Source File + +SOURCE=.\weaputils.cpp +# End Source File +# Begin Source File + +SOURCE=..\win32\win_bounds.cpp +# End Source File +# Begin Source File + +SOURCE=.\worldspawn.cpp +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl" +# Begin Source File + +SOURCE=.\actor.h +# End Source File +# Begin Source File + +SOURCE=.\ammo.h +# End Source File +# Begin Source File + +SOURCE=.\animate.h +# End Source File +# Begin Source File + +SOURCE=.\archive.h +# End Source File +# Begin Source File + +SOURCE=.\armor.h +# End Source File +# Begin Source File + +SOURCE=.\beam.h +# End Source File +# Begin Source File + +SOURCE=.\behavior.h +# End Source File +# Begin Source File + +SOURCE=.\bg_local.h +# End Source File +# Begin Source File + +SOURCE=.\bg_public.h +# End Source File +# Begin Source File + +SOURCE=.\bspline.h +# End Source File +# Begin Source File + +SOURCE=.\camera.h +# End Source File +# Begin Source File + +SOURCE=.\characterstate.h +# End Source File +# Begin Source File + +SOURCE=.\class.h +# End Source File +# Begin Source File + +SOURCE=.\clusterbomb.h +# End Source File +# Begin Source File + +SOURCE=.\container.h +# End Source File +# Begin Source File + +SOURCE=.\crossbow.h +# End Source File +# Begin Source File + +SOURCE=.\debuglines.h +# End Source File +# Begin Source File + +SOURCE=.\decals.h +# End Source File +# Begin Source File + +SOURCE=.\doors.h +# End Source File +# Begin Source File + +SOURCE=.\earthquake.h +# End Source File +# Begin Source File + +SOURCE=.\edenwater.h +# End Source File +# Begin Source File + +SOURCE=.\entity.h +# End Source File +# Begin Source File + +SOURCE=.\explosion.h +# End Source File +# Begin Source File + +SOURCE=.\flamethrower.h +# End Source File +# Begin Source File + +SOURCE=.\flashbang.h +# End Source File +# Begin Source File + +SOURCE=.\g_local.h +# End Source File +# Begin Source File + +SOURCE=.\g_main.h +# End Source File +# Begin Source File + +SOURCE=.\g_phys.h +# End Source File +# Begin Source File + +SOURCE=.\g_public.h +# End Source File +# Begin Source File + +SOURCE=.\g_spawn.h +# End Source File +# Begin Source File + +SOURCE=.\g_utils.h +# End Source File +# Begin Source File + +SOURCE=.\game.h +# End Source File +# Begin Source File + +SOURCE=.\gamecmds.h +# End Source File +# Begin Source File + +SOURCE=.\gamecvars.h +# End Source File +# Begin Source File + +SOURCE=.\gamescript.h +# End Source File +# Begin Source File + +SOURCE=.\gibs.h +# End Source File +# Begin Source File + +SOURCE=.\goo.h +# End Source File +# Begin Source File + +SOURCE=.\gravpath.h +# End Source File +# Begin Source File + +SOURCE=.\health.h +# End Source File +# Begin Source File + +SOURCE=.\hornofconjuring.h +# End Source File +# Begin Source File + +SOURCE=.\inventoryitem.h +# End Source File +# Begin Source File + +SOURCE=.\ipfilter.h +# End Source File +# Begin Source File + +SOURCE=.\item.h +# End Source File +# Begin Source File + +SOURCE=.\level.h +# End Source File +# Begin Source File + +SOURCE=.\light.h +# End Source File +# Begin Source File + +SOURCE=.\Linklist.h +# End Source File +# Begin Source File + +SOURCE=.\listener.h +# End Source File +# Begin Source File + +SOURCE=.\misc.h +# End Source File +# Begin Source File + +SOURCE=.\mover.h +# End Source File +# Begin Source File + +SOURCE=.\nature.h +# End Source File +# Begin Source File + +SOURCE=.\navigate.h +# End Source File +# Begin Source File + +SOURCE=.\object.h +# End Source File +# Begin Source File + +SOURCE=.\path.h +# End Source File +# Begin Source File + +SOURCE=.\player.h +# End Source File +# Begin Source File + +SOURCE=.\PlayerStart.h +# End Source File +# Begin Source File + +SOURCE=.\portal.h +# End Source File +# Begin Source File + +SOURCE=.\powerups.h +# End Source File +# Begin Source File + +SOURCE=.\q_shared.h +# End Source File +# Begin Source File + +SOURCE=.\queue.h +# End Source File +# Begin Source File + +SOURCE=.\rope.h +# End Source File +# Begin Source File + +SOURCE=.\script.h +# End Source File +# Begin Source File + +SOURCE=.\scriptmaster.h +# End Source File +# Begin Source File + +SOURCE=.\scriptslave.h +# End Source File +# Begin Source File + +SOURCE=.\scriptvariable.h +# End Source File +# Begin Source File + +SOURCE=.\sentient.h +# End Source File +# Begin Source File + +SOURCE=.\shield.h +# End Source File +# Begin Source File + +SOURCE=.\soulsucker.h +# End Source File +# Begin Source File + +SOURCE=.\soundman.h +# End Source File +# Begin Source File + +SOURCE=.\spawners.h +# End Source File +# Begin Source File + +SOURCE=.\specialfx.h +# End Source File +# Begin Source File + +SOURCE=.\stack.h +# End Source File +# Begin Source File + +SOURCE=.\steering.h +# End Source File +# Begin Source File + +SOURCE=.\str.h +# End Source File +# Begin Source File + +SOURCE=.\surfaceflags.h +# End Source File +# Begin Source File + +SOURCE=.\sword.h +# End Source File +# Begin Source File + +SOURCE=.\trigger.h +# End Source File +# Begin Source File + +SOURCE=.\umap.h +# End Source File +# Begin Source File + +SOURCE=.\vector.h +# End Source File +# Begin Source File + +SOURCE=.\vehicle.h +# End Source File +# Begin Source File + +SOURCE=.\viewthing.h +# End Source File +# Begin Source File + +SOURCE=.\weapon.h +# End Source File +# Begin Source File + +SOURCE=.\weaputils.h +# End Source File +# Begin Source File + +SOURCE=.\worldspawn.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/source/source/fgame/fgame.dsw b/source/source/fgame/fgame.dsw new file mode 100644 index 0000000..4988e95 --- /dev/null +++ b/source/source/fgame/fgame.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 6.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "fgame"=.\fgame.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/source/source/fgame/fists.cpp b/source/source/fgame/fists.cpp new file mode 100644 index 0000000..c1e8837 --- /dev/null +++ b/source/source/fgame/fists.cpp @@ -0,0 +1,175 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/fists.cpp $ +// $Revision:: 1 $ +// $Author:: Jimdose $ +// $Date:: 9/10/99 10:53a $ +// +// Copyright (C) 1998 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source is may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/fists.cpp $ +// +// 1 9/10/99 10:53a Jimdose +// +// 1 9/08/99 3:16p Aldie +// +// 9 8/28/99 11:44a Steven +// Removed global from sound function calls. +// +// 8 8/18/99 3:28p Jimdose +// added cylindrical collision detection +// +// DESCRIPTION: +// Normal Hands +// + +#include "g_local.h" +#include "fists.h" +#include "misc.h" +#include "specialfx.h" +//#include "surface.h" + +CLASS_DECLARATION( Weapon, Fists, NULL ) + { + { &EV_Weapon_Shoot, Shoot }, + { NULL, NULL } + }; + +Fists::Fists() + { + SetModels( NULL, "view_punch.def" ); + SetAmmo( NULL, 0, 0 ); + SetRank( 10, 10 ); + strike_reach = 64; + strike_damage = 20; + SetMaxRange( strike_reach ); + SetType( WEAPON_MELEE ); + kick = 40; + meansofdeath = MOD_FISTS; + } + +void Fists::Shoot( Event * ev ) + { + trace_t trace; + Vector start; + Vector end; + float damage; + Vector org; + Vector dir; + int surfflags; + int surftype; + + assert( owner ); + if ( !owner ) + { + return; + } + + NextAttack( 1 ); + + damage = G_Random(strike_damage)+strike_damage; + + GetMuzzlePosition( &start, &dir ); + end = start + dir * strike_reach; + + trace = G_FullTrace( start, vec_zero, vec_zero, end, 64, owner, MASK_PROJECTILE, false, "Fists::Shoot" ); + + if ( !trace.surface ) + { + surfflags = 0; + surftype = 0; + } + else + { + surfflags = trace.surface->flags; + surftype = SURFACETYPE_FROM_FLAGS( surfflags ); +// surfaceManager.DamageSurface( &trace, damage, owner ); + } + dir = Vector(trace.endpos) - start; + dir.normalize(); + + org = Vector(trace.endpos) - dir; + + if ( (trace.fraction < 1.0f) ) + { + if ( trace.ent->entity && trace.ent->entity->takedamage ) + { + if ( trace.ent->entity->flags & FL_BLOOD ) + { + if ( ( meansofdeath == MOD_MUTANTHANDS ) || ( trace.ent->entity->health < -500 ) ) + { + owner->Sound( "impact_goryimpact" ); + } + else + { + owner->Sound( "impact_bodyimpact" ); + } + SpawnBlood( org, trace.plane.normal, damage ); + } + else + { +/* GAMEFIX + gi.WriteByte( svc_temp_entity ); + gi.WriteByte( TE_STRIKE ); + gi.WritePosition( org.vec3() ); + gi.WriteDir( trace.plane.normal ); + gi.WriteByte( 120 ); + gi.WriteByte( surftype ); + gi.multicast( org.vec3(), MULTICAST_PVS ); + */ + } + if ( trace.intersect.valid ) + { + // take the ground out so that the kick works + trace.ent->entity->groundentity = NULL; + + // We hit a valid surface so send in location based damage + trace.ent->entity->Damage( this, + owner, + damage, + trace.endpos, + dir, + trace.plane.normal, + kick, + 0, + meansofdeath, + trace.intersect.surface, + -1, + 1 ); + //trace.intersect.damage_multiplier ); + } + else + { + // We didn't hit any surfaces, so send in generic damage + trace.ent->entity->Damage( this, + owner, + damage, + trace.endpos, + dir, + trace.plane.normal, + kick, + 0, + meansofdeath, + -1, + -1, + 1 ); + } + } + else + { +/* GAMEFIX + gi.WriteByte( svc_temp_entity ); + gi.WriteByte( TE_STRIKE ); + gi.WritePosition( org.vec3() ); + gi.WriteDir( trace.plane.normal ); + gi.WriteByte( 120 ); + gi.WriteByte( surftype ); + gi.multicast( org.vec3(), MULTICAST_PVS ); + */ + } + } + } diff --git a/source/source/fgame/fists.h b/source/source/fgame/fists.h new file mode 100644 index 0000000..8574ddd --- /dev/null +++ b/source/source/fgame/fists.h @@ -0,0 +1,70 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/fists.h $ +// $Revision:: 1 $ +// $Author:: Jimdose $ +// $Date:: 9/10/99 10:53a $ +// +// Copyright (C) 1998 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source is may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/fists.h $ +// +// 1 9/10/99 10:53a Jimdose +// +// 1 9/08/99 3:16p Aldie +// +// DESCRIPTION: +// Mutant Hands +// + +#ifndef __FISTS_H__ +#define __FISTS_H__ + +#include "g_local.h" +#include "item.h" +#include "weapon.h" + +class Fists : public Weapon + { + public: + float strike_reach; + float strike_damage; + int meansofdeath; + + CLASS_PROTOTYPE( Fists ); + + Fists::Fists(); + virtual void Shoot( Event *ev ); + virtual void Archive( Archiver &arc ); + virtual void Unarchive( Archiver &arc ); + }; + +inline void Fists::Archive + ( + Archiver &arc + ) + { + Weapon::Archive( arc ); + + arc.WriteFloat( strike_reach ); + arc.WriteFloat( strike_damage ); + arc.WriteInteger( meansofdeath ); + } + +inline void Fists::Unarchive + ( + Archiver &arc + ) + { + Weapon::Unarchive( arc ); + + arc.ReadFloat( &strike_reach ); + arc.ReadFloat( &strike_damage ); + arc.ReadInteger( &meansofdeath ); + } + +#endif /* Fists.h */ diff --git a/source/source/fgame/flamethrower.cpp b/source/source/fgame/flamethrower.cpp new file mode 100644 index 0000000..2a557e1 --- /dev/null +++ b/source/source/fgame/flamethrower.cpp @@ -0,0 +1,108 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/flamethrower.cpp $ +// $Revision:: 6 $ +// $Author:: Markd $ +// $Date:: 6/23/00 8:41p $ +// +// Copyright (C) 1998 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/flamethrower.cpp $ +// +// 6 6/23/00 8:41p Markd +// made a lot of changes to different constructors for saved game support +// +// 5 6/14/00 3:50p Markd +// Cleaned up more Intel Compiler warnings +// +// 4 5/06/00 2:06p Steven +// Fixed a precendence bug. +// +// 3 5/05/00 5:17p Aldie +// comment +// +// 2 5/05/00 5:17p Aldie +// Flamethrower +// +// DESCRIPTION: +// Flamethrower weapon + +#include "flamethrower.h" + +CLASS_DECLARATION( Weapon, Flamethrower, NULL ) + { + { NULL, NULL } + }; + +Flamethrower::Flamethrower + ( + ) + + { + // Attach the gasoline model to the flamethrower + Event *ev; + + if ( LoadingSavegame ) + { + return; + } + + ev = new Event ( EV_AttachModel ); + ev->AddString( "weapon_flamethrowergas.tik" ); + ev->AddString( "tag_gas" ); + + PostEvent( ev, FRAMETIME ); + + m_gas = NULL; + } + +void Flamethrower::Shoot + ( + Event *ev + ) + + { + firemode_t mode = FIRE_PRIMARY; + + if ( ev->NumArgs() > 0 ) + { + mode = WeaponModeNameToNum( ev->GetString( 1 ) ); + + if ( mode == FIRE_ERROR ) + return; + } + + // Find a pointer to the gas + if ( !m_gas ) + { + if ( numchildren == 1 ) + { + m_gas = ( Animate * )G_GetEntity( children[ 0 ] ); + m_gas->RandomAnimate( "gas" ); + m_gas->StopAnimating(); + m_gas->SetFrame( 0 ); + } + } + // Check the ammo level and see if we need to adjust the gas animation + + if ( owner && m_gas ) + { + int amount = owner->AmmoCount( ammo_type[mode] ); + int maxamount = owner->MaxAmmoCount( ammo_type[mode] ); + float percentage = 1.0f - ( ( float )amount / ( float )maxamount ); + int numframes = m_gas->NumFrames(); + + m_gas->SetFrame( percentage * ( numframes - 1 ) ); + + if ( percentage >= 1 ) + m_gas->hideModel(); + else + m_gas->showModel(); + } + + Weapon::Shoot( ev ); + } diff --git a/source/source/fgame/flamethrower.h b/source/source/fgame/flamethrower.h new file mode 100644 index 0000000..936f5ce --- /dev/null +++ b/source/source/fgame/flamethrower.h @@ -0,0 +1,63 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/flamethrower.h $ +// $Revision:: 6 $ +// $Author:: Markd $ +// $Date:: 6/14/00 3:50p $ +// +// Copyright (C) 1998 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/flamethrower.h $ +// +// 6 6/14/00 3:50p Markd +// Cleaned up more Intel Compiler warnings +// +// 5 5/26/00 7:44p Markd +// 2nd phase save games +// +// 4 5/24/00 3:14p Markd +// first phase of save/load games +// +// 3 5/05/00 5:18p Aldie +// comment +// +// 2 5/05/00 5:17p Aldie +// Flamethrower +// +// DESCRIPTION: +// Flamethrower weapon + +#ifndef __FLAMETHROWER_H__ +#define __FLAMETHROWER_H__ + +#include "weapon.h" +#include "weaputils.h" + +class Flamethrower : public Weapon + { + private: + Animate *m_gas; + + public: + CLASS_PROTOTYPE( Flamethrower ); + + Flamethrower(); + virtual void Shoot( Event *ev ); + virtual void Archive( Archiver &arc ); + }; + +inline void Flamethrower::Archive + ( + Archiver &arc + ) + { + Weapon::Archive( arc ); + + arc.ArchiveObjectPointer( ( Class ** )&m_gas ); + } + +#endif // __FLAMETHROWER_H__ diff --git a/source/source/fgame/flashbang.cpp b/source/source/fgame/flashbang.cpp new file mode 100644 index 0000000..d28faf5 --- /dev/null +++ b/source/source/fgame/flashbang.cpp @@ -0,0 +1,174 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/flashbang.cpp $ +// $Revision:: 9 $ +// $Author:: Steven $ +// $Date:: 7/28/00 9:27a $ +// +// Copyright (C) 1998 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/flashbang.cpp $ +// +// 9 7/28/00 9:27a Steven +// Made it so flashbang projectiles actually animate correctly. +// +// 8 7/20/00 2:17p Aldie +// Fix for firing the flashbang +// +// 7 7/17/00 3:26p Aldie +// Fix for flashbangs, changed detail variable, and added forcetorsostate +// +// 6 4/15/00 5:18p Aldie +// Added stun events and fixed yet another bug with Ammo and AutoPutaway +// +// 5 4/14/00 6:05p Aldie +// Added some more flashbang functions +// +// 4 4/13/00 3:45p Aldie +// Added more flashbang support. Added damage_type to entities used to specify +// what type of damage they take. +// +// 3 4/07/00 6:00p Aldie +// Added flashing and fixed radius damage for explosions +// +// 2 4/07/00 4:01p Aldie +// First version +// +// DESCRIPTION: +// Flashbang weapon + +#include "flashbang.h" + +Event EV_FlashbangProjectile_StunTime + ( + "stuntime", + EV_DEFAULT, + "f", + "time", + "Amount of time to stun the target" + ); +Event EV_FlashbangProjectile_StunRadius + ( + "stunradius", + EV_DEFAULT, + "f", + "radius", + "Radius of the stun effect" + ); + +CLASS_DECLARATION( Projectile, FlashbangProjectile, NULL ) + { + { &EV_FlashbangProjectile_StunTime, StunTime }, + { &EV_FlashbangProjectile_StunRadius, StunRadius }, + { NULL, NULL } + }; + +FlashbangProjectile::FlashbangProjectile + ( + ) + + { + } + +void FlashbangProjectile::StunTime + ( + Event *ev + ) + + { + stunTime = ev->GetFloat( 1 ); + } + +void FlashbangProjectile::StunRadius + ( + Event *ev + ) + + { + stunRadius = ev->GetFloat( 1 ); + } + +void FlashbangProjectile::Explode + ( + Event *ev + ) + + { + Entity *owner; + + // Get the owner of this projectile + owner = G_GetEntity( this->owner ); + + // If the owner's not here, make the world the owner + if ( !owner ) + owner = world; + + // When a flashbang explodes, it whites the screen and does some damage + if ( explosionmodel.length() ) + { + ExplosionAttack( origin, owner, explosionmodel, Vector( 0,0,0 ), NULL ); + StunAttack( origin, owner, this, this->stunRadius, this->stunTime, NULL ); + } + + PostEvent( EV_Remove, 0 ); + } + + +CLASS_DECLARATION( Weapon, Flashbang, NULL ) + { + { NULL, NULL } + }; + +Flashbang::Flashbang + ( + ) + + { + } + +void Flashbang::SpecialFireProjectile + ( + Vector pos, + Vector forward, + Vector right, + Vector up, + Entity *owner, + str projectileModel, + float charge_fraction + ) + + { + // Do a trace forward to see if a solid is hit + Vector norm,angles; + FlashbangProjectile *fb; + Event *ev; + + fb = new FlashbangProjectile; + fb->setModel( projectileModel ); + fb->CancelEventsOfType( EV_ProcessInitCommands ); + fb->ProcessInitCommands( fb->edict->s.modelindex ); + fb->setMoveType( MOVETYPE_NONE ); + + fb->owner = owner->entnum; + fb->edict->ownerNum = owner->entnum; + + // Explode the flashbang after it's life expires + ev = new Event( EV_Projectile_Explode ); + fb->PostEvent( ev, fb->life ); + + // Spawn a flashbang at the player's feet. + Vector org = owner->origin + Vector( 0,0,32 ); + Vector end = org + ( forward * 32 ); + trace_t trace = G_Trace( org, vec_zero, vec_zero, end, owner, MASK_SOLID, qfalse, "Flashbang::SpecialFireProjectile" ); + + fb->setOrigin( trace.endpos ); + fb->setAngles( Vector( 0, owner->angles[1] + 180, 0 ) ); + fb->droptofloor( 64 ); + fb->RandomAnimate( "idle" ); + } + + diff --git a/source/source/fgame/flashbang.h b/source/source/fgame/flashbang.h new file mode 100644 index 0000000..c42316c --- /dev/null +++ b/source/source/fgame/flashbang.h @@ -0,0 +1,85 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/flashbang.h $ +// $Revision:: 6 $ +// $Author:: Markd $ +// $Date:: 5/26/00 7:44p $ +// +// Copyright (C) 1998 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/flashbang.h $ +// +// 6 5/26/00 7:44p Markd +// 2nd phase save games +// +// 5 5/24/00 3:14p Markd +// first phase of save/load games +// +// 4 4/15/00 5:18p Aldie +// Added stun events and fixed yet another bug with Ammo and AutoPutaway +// +// 3 4/07/00 6:00p Aldie +// Added flashing and fixed radius damage for explosions +// +// 2 4/07/00 4:01p Aldie +// First version +// +// DESCRIPTION: +// Flashbang weapon + +#ifndef __FLASHBANG_H__ +#define __FLASHBANG_H__ + +#include "weapon.h" +#include "weaputils.h" + +class Flashbang : public Weapon + { + public: + CLASS_PROTOTYPE( Flashbang ); + + Flashbang(); + + virtual void SpecialFireProjectile( Vector pos, + Vector forward, + Vector right, + Vector up, + Entity *owner, + str projectileModel, + float charge_fraction + ); + + }; + +class FlashbangProjectile : public Projectile + { + private: + float stunRadius; + float stunTime; + + public: + CLASS_PROTOTYPE( FlashbangProjectile ); + + FlashbangProjectile(); + virtual void Explode( Event *ev ); + void StunTime( Event *ev ); + void StunRadius( Event *ev ); + virtual void Archive( Archiver &arc ); + }; + +inline void FlashbangProjectile::Archive + ( + Archiver &arc + ) + { + Projectile::Archive( arc ); + + arc.ArchiveFloat( &stunRadius ); + arc.ArchiveFloat( &stunTime ); + } + +#endif // __FLASHBANG_H__ diff --git a/source/source/fgame/g_local.h b/source/source/fgame/g_local.h new file mode 100644 index 0000000..72cce66 --- /dev/null +++ b/source/source/fgame/g_local.h @@ -0,0 +1,219 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/g_local.h $ +// $Revision:: 18 $ +// $Author:: Jimdose $ +// $Date:: 29.07.00 10:52p $ +// +// Copyright (C) 1998 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source is may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/g_local.h $ +// +// 18 29.07.00 10:52p Jimdose +// moved radius2 out of server section of gentity_s +// +// 17 29.07.00 10:51p Jimdose +// added radius2 to gentity_t +// +// 16 6/14/00 11:18a Markd +// cleaned up code using Intel compiler +// +// 15 6/01/00 3:18p Markd +// rewrote giveItem and item management in sentient +// +// 14 4/10/00 11:57a Steven +// Moved process init commands to happen before EV_POSTSPAWN. +// +// 13 2/11/00 7:25p Aldie +// Fixed some rope setup problems and fixed some reloading issues with loop +// fire weapons +// +// 12 1/19/00 10:22a Steven +// Increased the sound radius so monsters could hear sounds from a reasonable +// distance. +// +// 11 1/10/00 5:30p Markd +// Removed old TAG_GAME +// +// 10 1/06/00 11:08p Jimdose +// cleaning up unused code +// +// 9 12/17/99 6:35p Jimdose +// changed spawnarg code +// added Level class for spawning and map control +// got rid of unused or superflous variables +// changed setjmp/longjmp calls to try/throw/catch exception handling +// +// 8 12/11/99 3:37p Markd +// q3a gold checkin, first time +// +// 7 10/25/99 6:39p Markd +// removed size and other unused variables, added radius and centroid to both +// server and game code +// +// 6 10/18/99 3:58p Aldie +// Fix for beam endpoints +// +// 5 10/07/99 9:57a Markd +// made fov come out of playerstate not cvar, got rid of timestamp +// +// 4 10/01/99 2:42p Markd +// moved all the binding code back into Entity from Mover +// +// 3 9/16/99 4:50p Jimdose +// removed unused variables +// +// 2 9/13/99 3:30p Jimdose +// merge +// +// 1 9/10/99 10:53a Jimdose +// +// 1 9/08/99 3:16p Aldie +// +// 16 7/07/99 11:26a Steven +// Added some stuff on the sector pathfinding approach. +// +// DESCRIPTION: +// local definitions for game module +// + +#ifndef __G_LOCAL_H__ +#define __G_LOCAL_H__ + +#include "q_shared.h" + +// define GAME_INCLUDE so that game.h does not define the +// short, server-visible gclient_t and gentity_t structures, +// because we define the full size ones in this file +#define GAME_INCLUDE +#include "g_public.h" +#include "bg_public.h" +#include "container.h" +#include "str.h" + +// the "gameversion" client command will print this plus compile date +#define GAMEVERSION "fakk2" + +// times for posting events +// Even though negative times technically don't make sense, the effect is to +// sort events that take place at the start of a map so that they are executed +// in the proper order. For example, spawnargs must occur before any script +// commands take place, while unused entities must be removed before the spawnargs +// are parsed. + +#define EV_REMOVE -11 // remove any unused entities before spawnargs are parsed +#define EV_SPAWNARG -10 // for spawn args passed in by the bsp file +#define EV_LINKDOORS -9 // for finding out which doors are linked together +#define EV_LINKBEAMS -9 // for finding out the endpoints of beams +#define EV_SETUP_ROPEPIECE -8 +#define EV_SETUP_ROPEBASE -7 +#define EV_PROCESS_INIT -6 + +#define EV_POSTSPAWN -1 // for any processing that must occur after all objects are spawned + +#define SOUND_RADIUS 1500 // Sound travel distance for AI + +#define random() ((rand () & 0x7fff) / ((float)0x7fff)) +#define crandom() (2.0 * (random() - 0.5)) + +// predefine Entity so that we can add it to gentity_t without any errors +class Entity; + +// client data that stays across multiple level loads +typedef struct + { + char userinfo[MAX_INFO_STRING]; + char netname[16]; + + // values saved and restored from edicts when changing levels + int health; + int max_health; + + } client_persistant_t; + +// this structure is cleared on each PutClientInServer(), +// except for 'client->pers' +typedef struct gclient_s + { + // known to server + playerState_t ps; // communicated by server to clients + int ping; + + // private to game + client_persistant_t pers; + vec3_t cmd_angles; // angles sent over in the last command + } gclient_t; + +struct gentity_s + { + entityState_t s; // communicated by server to clients + struct gclient_s *client; // NULL if not a player + qboolean inuse; + qboolean linked; // qfalse if not in any good cluster + int linkcount; + + int svflags; // SVF_NOCLIENT, SVF_BROADCAST, etc + + qboolean bmodel; // if false, assume an explicit mins / maxs bounding box + // only set by gi.SetBrushModel + vec3_t mins, maxs; + int contents; // CONTENTS_TRIGGER, CONTENTS_SOLID, CONTENTS_BODY, etc + // a non-solid entity should set to 0 + + vec3_t absmin, absmax; // derived from mins/maxs and origin + rotation + + float radius; // radius of object + vec3_t centroid; // centroid, to be used with radius + int areanum; // areanum needs to be seen inside the game as well + + // currentOrigin will be used for all collision detection and world linking. + // it will not necessarily be the same as the trajectory evaluation for the current + // time, because each entity must be moved one at a time after time is advanced + // to avoid simultanious collision issues + vec3_t currentOrigin; + vec3_t currentAngles; + + int ownerNum; // objects never interact with their owners, to + // prevent player missiles from immediately + // colliding with their owner + + solid_t solid; // Added for FAKK2 + + // DO NOT MODIFY ANYTHING ABOVE THIS, THE SERVER + // EXPECTS THE FIELDS IN THAT ORDER! + + //================================ + + Entity *entity; + float freetime; // svs.time when the object was freed + float spawntime; // svs.time when the object was spawned + + float radius2; // squared radius of object. Used in findradius in g_utils.cpp + + char entname[ 64 ]; + + // GAMEFIX Moved some of the old fields here for the game code. These + // might still be needed or might not :-) + int clipmask; + + gentity_t *next; + gentity_t *prev; + }; + +#include "vector.h" +#include "linklist.h" +#include "class.h" +#include "game.h" +#include "g_main.h" +#include "listener.h" +#include "g_utils.h" +#include "g_spawn.h" +#include "g_phys.h" +#include "debuglines.h" + +#endif // __G_LOCAL_H__ + diff --git a/source/source/fgame/g_main.cpp b/source/source/fgame/g_main.cpp new file mode 100644 index 0000000..d585ca8 --- /dev/null +++ b/source/source/fgame/g_main.cpp @@ -0,0 +1,1989 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/g_main.cpp $ +// $Revision:: 89 $ +// $Author:: Markd $ +// $Date:: 8/08/00 8:34p $ +// +// Copyright (C) 1998 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source is may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/g_main.cpp $ +// +// 89 8/08/00 8:34p Markd +// increased error messages to handle 4k instead of 1024 +// +// 88 7/31/00 1:32a Markd +// added some debugging information +// +// 87 7/29/00 3:13p Markd +// made sure pointers were valid in G_ClientUserinfoChanged +// +// 86 7/28/00 10:07p Markd +// Added archive lightStyles +// +// 85 7/27/00 11:43p Aldie +// Removed statement I accidentally added +// +// 84 7/27/00 10:54p Steven +// Bumped up savegame version. +// +// 83 7/27/00 9:43p Aldie +// Changed dialog for invalid save games +// +// 82 7/27/00 3:03p Markd +// return false on LevelArchiveValid if file doesn't exist +// +// 81 7/27/00 2:05a Markd +// increased savegame_version +// +// 80 7/25/00 9:25p Steven +// Bumped up savegame version. +// +// 79 7/23/00 6:03p Markd +// added fadeout and fadesound to dieing and level change +// +// 78 7/22/00 1:18p Steven +// Bumped up savegame version. +// +// 77 7/19/00 9:20p Steven +// Made the proc Loaded get called for each player after everything has been +// loaded so that some things can be set up correctly. +// +// 76 7/18/00 4:26p Steven +// Bumped up savegame version. +// +// 75 7/17/00 12:36a Markd +// Made sure to close the log file when exiting a level or shutting down a +// server +// +// 74 7/16/00 10:47a Steven +// Bumped up savegame version. +// +// 73 7/15/00 12:49p Steven +// Bumped up savegame version. +// +// 72 7/13/00 8:47p Markd +// reset savegame version and persistant version +// +// 71 7/13/00 3:44p Steven +// Bumped up savegame version. +// +// 70 7/12/00 11:38a Steven +// Bumped up savegame and persistant version. +// +// 69 7/11/00 8:02a Steven +// In G_ClientDisconnect made sure to check that ent is not NULL. +// +// 68 7/10/00 6:34p Aldie +// Added SVF_SENDONCE flag +// +// 67 7/10/00 6:26p Steven +// Bumped up savegame version. +// +// 66 7/09/00 1:43p Markd +// Changed center print for game saved +// +// 65 7/07/00 6:36p Steven +// Bumped up savegame version. +// +// 64 7/06/00 7:48p Markd +// Added LevelArchiveValid function +// +// 63 7/06/00 1:25p Steven +// Bimped savegame version. +// +// 62 7/05/00 9:55p Markd +// Increased savegame and persistant version +// +// 61 7/05/00 7:35p Steven +// Bumped the PERSISTANT_VERSION up. +// +// 60 7/05/00 6:15p Steven +// Bumped up savegame version. +// +// 59 7/01/00 6:07p Steven +// Bumped savegame version. +// +// 58 6/27/00 5:48p Steven +// Bumped savegame version. +// +// 57 6/23/00 8:27p Markd +// increased save game version +// +// 56 6/23/00 11:49a Markd +// fixed various imagindexes and saved games +// +// 55 6/23/00 10:47a Markd +// fixed loading of out of date savegame files +// +// 54 6/22/00 3:45p Markd +// bumped savegame version +// +// 53 6/20/00 7:01p Steven +// Bumped savegame version. +// +// 52 6/19/00 4:13p Markd +// fixed load/save bug with targetnames +// +// 51 6/17/00 11:57a Steven +// Bumped up the savegame version. +// +// 50 6/15/00 8:04p Markd +// Added CleanupGame +// +// 49 6/13/00 3:57p Markd +// Added centerprint message when saving the game +// +// 48 6/13/00 3:44p Steven +// Added alias saving stuff. +// +// 47 6/10/00 4:23p Markd +// rewrote map restarting and loading out of date save games +// +// 46 6/02/00 4:43p Markd +// changed Persistant data to use separate persistant version number instead of +// GAME_API_VERSION number +// +// 45 6/02/00 4:24p Markd +// cleaned up archive functions +// +// 44 6/02/00 2:01p Markd +// Fixed client persistant data issues +// +// 43 5/31/00 3:50p Markd +// fixed precaching issue +// +// 42 5/30/00 7:06p Markd +// saved games 4th pass +// +// 41 5/29/00 1:16p Markd +// 3rd round of saved games +// +// 40 5/26/00 2:24p Aldie +// Added waitforplayer commands so we can use it for cinematics when waiting +// for player to finish holstering +// +// 39 5/25/00 4:28p Markd +// fixed up archive functions +// +// 38 5/16/00 4:11p Markd +// fixed precision on total number of traces +// +// 37 2/26/00 12:58p Jimdose +// added level.restart +// +// 36 2/16/00 6:55p Markd +// increment time at the end of a frame so that player stuff will work properly +// +// 35 2/01/00 4:11p Markd +// Added Frame bounding box support +// +// 34 1/25/00 6:06p Markd +// Put in fix for player movement +// +// 33 1/25/00 4:43p Markd +// cleaned up main routine so that level.settime would be used properly +// +// 32 1/19/00 4:20p Aldie +// Fix for level.fixedframetime +// +// 31 1/15/00 1:39p Markd +// Fixed old command in G_ExitLevel +// +// 30 1/13/00 5:19p Jimdose +// removed clearsavegames +// +// 29 1/10/00 5:27p Markd +// Added DeAllocGameData +// +// 28 1/06/00 11:08p Jimdose +// cleaning up unused code +// +// 27 1/05/00 7:25p Jimdose +// made angle functions all use the same coordinate system +// AngleVectors now returns left instead of right +// no longer need to invert pitch +// +// 26 12/17/99 6:35p Jimdose +// changed spawnarg code +// added Level class for spawning and map control +// got rid of unused or superflous variables +// changed setjmp/longjmp calls to try/throw/catch exception handling +// +// 25 12/11/99 3:37p Markd +// q3a gold checkin, first time +// +// 24 12/10/99 11:52a Aldie +// Adjusted player angles a bit +// +// 23 12/09/99 3:32p Aldie +// Removed a line where player origin was being multiplied by 0.125 +// +// 22 12/01/99 11:26a Aldie +// Couple of fixes for emitters and more ammo stuff +// +// 21 11/12/99 11:47a Markd +// Added sound manager support and retro-fitted TriggerSpeaker and TriggerMusic +// to work with everything +// +// 20 11/04/99 10:03a Markd +// complete overhaul of the camera system +// +// 19 10/27/99 12:19p Markd +// added smooth camera lerping +// +// 18 10/26/99 5:27p Aldie +// Fix for gravpaths +// +// 17 10/25/99 6:39p Markd +// removed size and other unused variables, added radius and centroid to both +// server and game code +// +// 16 10/12/99 2:23p Markd +// Rewrote camera and player movetype system +// +// 15 10/06/99 3:09p Steven +// Added dumpevents command. +// +// 14 10/05/99 5:03p Markd +// Removed un-used game function ClientPredict +// +// 13 10/02/99 6:51p Markd +// Put in backend work for event documentation and fixed a lot of event +// documentation bugs +// +// 12 10/01/99 6:31p Markd +// added commands hidden inside fgame so that they would show up for command +// completion +// +// 11 9/29/99 11:52a Markd +// removed some unused enums and variables form shared headers between cgame +// and fgame +// +// 10 9/28/99 4:26p Markd +// merged listener, class and vector between 3 projects +// +// 9 9/22/99 4:47p Markd +// fixed more G_GetEntity, G_FindClass and G_GetNextEntity bugs +// +// 8 9/21/99 7:51p Markd +// Fixed a lot of entitynum_none issues +// +// 7 9/16/99 4:48p Jimdose +// removed unused code and variables +// rewrote G_ClientConnect for merge +// +// 6 9/16/99 11:18a Markd +// Continuing merge of code, not functional yet but closer +// +// 5 9/15/99 6:57p Aldie +// Update to get game working +// +// 4 9/13/99 4:22p Jimdose +// merge +// +// 3 9/13/99 3:30p Jimdose +// merge +// +// 2 9/10/99 5:45p Jimdose +// merge +// +// 1 9/10/99 10:53a Jimdose +// +// 1 9/08/99 3:16p Aldie +// +// 29 8/28/99 3:23p Markd +// got rid of bulletholes and blood splats +// +// 28 8/27/99 8:25p Markd +// added pengingevents and fixed some event holes +// +// 27 8/19/99 6:18p Markd +// took out con_clearfade stuff from g_main, to be replaced later on with +// proper level restarting +// +// 26 7/07/99 11:25a Steven +// Added some stuff on the sector pathfinding approach. +// +// 25 6/23/99 3:57p Markd +// Added viewthing support +// +// DESCRIPTION: +// + +#define SAVEGAME_VERSION 8 +#define PERSISTANT_VERSION 1 + +#include "g_local.h" +#include "g_utils.h" +#include "gamecmds.h" +#include "Entity.h" +#include "vector.h" +#include "scriptmaster.h" +#include "navigate.h" +#include "player.h" +#include "gravpath.h" +#include "camera.h" +#include "level.h" +#include "viewthing.h" +#include "ipfilter.h" +#include "../qcommon/alias.h" + +Vector vec_origin = "0 0 0"; +Vector vec_zero = "0 0 0"; + +qboolean LoadingSavegame = false; +qboolean LoadingServer = false; +game_import_t gi; +game_export_t globals; + +gentity_t *g_entities = NULL; +gentity_t active_edicts; +gentity_t free_edicts; + +int sv_numtraces; + +usercmd_t *current_ucmd; + +void ( *ServerError )( int level, const char *fmt, ... ); + +/* +=============== +G_Error + +Abort the server with a game error +=============== +*/ +void G_Error + ( + int level, + const char *fmt, + ... + ) + + { + va_list argptr; + char error[ 4096 ]; + + va_start( argptr, fmt ); + vsprintf( error, fmt, argptr ); + va_end( argptr ); + + assert( 0 ); + + throw error; + } + +/* +=============== +G_ExitWithError + +Calls the server's error function with the last error that occurred. +Should only be called after an exception. +=============== +*/ +void G_ExitWithError + ( + const char *error + ) + + { + static char G_ErrorMessage[ 4096 ]; + + //ServerError( ERR_DROP, error ); + + Q_strncpyz( G_ErrorMessage, error, sizeof( G_ErrorMessage ) ); + + globals.error_message = G_ErrorMessage; + } + +/* +================= +G_CleanupGame + +Frees up resources from current level +================= +*/ +void G_CleanupGame + ( + void + ) + + { + try + { + gi.DPrintf ("==== CleanupGame ====\n"); + + level.CleanUp(); + } + + catch( const char *error ) + { + G_ExitWithError( error ); + } + } + +/* +================= +G_ShutdownGame + +Frees up any resources +================= +*/ +void G_ShutdownGame + ( + void + ) + + { + try + { + gi.DPrintf ("==== ShutdownGame ====\n"); + + // close the player log file if necessary + ClosePlayerLogFile(); + + level.CleanUp(); + + L_ShutdownEvents(); + + // destroy the game data + G_DeAllocGameData(); + } + + catch( const char *error ) + { + G_ExitWithError( error ); + } + } + +/* +============ +G_InitGame + +This will be called when the dll is first loaded, which +only happens when a new game is begun +============ +*/ +void G_InitGame + ( + int startTime, + int randomSeed + ) + + { + gi.DPrintf ("==== InitGame ====\n"); + + // Install our own error handler, since we can't + // call the EXE's handler from within a C++ class + ServerError = gi.Error; + gi.Error = G_Error; + + // If we get an error, call the server's error function + try + { + srand( randomSeed ); + + // setup all the cvars the game needs + CVAR_Init(); + + // initialize the game variables + gameVars.ClearList(); + + level.fixedframetime = ( 1.0f / sv_fps->value ); + level.startTime = startTime; + + G_InitConsoleCommands(); + L_InitEvents(); + + sv_numtraces = 0; + + // setup ViewMaster + Viewmodel.Init(); + + game.maxentities = maxentities->integer; + if (maxclients->integer * 8 > game.maxentities) + { + game.maxentities = maxclients->integer * 8; + } + game.maxclients = maxclients->integer; + + G_AllocGameData(); + } + + catch( const char *error ) + { + G_ExitWithError( error ); + } + } + +void G_AllocGameData + ( + void + ) + + { + int i; + + // de-allocate from previous level + G_DeAllocGameData(); + + // Initialize debug lines + G_AllocDebugLines(); + + // initialize all entities for this game + game.maxentities = maxentities->integer; + g_entities = ( gentity_t * )gi.Malloc (game.maxentities * sizeof(g_entities[0]) ); + + // clear out the entities + memset( g_entities, 0, sizeof( g_entities[ 0 ] ) * game.maxentities ); + globals.gentities = g_entities; + globals.max_entities = game.maxentities; + + // Add all the edicts to the free list + LL_Reset( &free_edicts, next, prev ); + LL_Reset( &active_edicts, next, prev ); + for( i = 0; i < game.maxentities; i++ ) + { + LL_Add( &free_edicts, &g_entities[ i ], next, prev ); + } + + // initialize all clients for this game + game.clients = ( gclient_t * )gi.Malloc( game.maxclients * sizeof( game.clients[ 0 ] ) ); + memset( game.clients, 0, game.maxclients * sizeof( game.clients[ 0 ] ) ); + for( i = 0; i < game.maxclients; i++ ) + { + // set client fields on player ents + g_entities[ i ].client = game.clients + i; + + G_InitClientPersistant (&game.clients[i]); + } + globals.num_entities = game.maxclients; + + // Tell the server about our data + gi.LocateGameData( g_entities, globals.num_entities, sizeof( gentity_t ), &game.clients[0].ps, sizeof( game.clients[0] ) ); + } + +void G_DeAllocGameData + ( + void + ) + + { + // Initialize debug lines + G_DeAllocDebugLines(); + + // free up the entities + if ( g_entities ) + { + gi.Free( g_entities ); + g_entities = NULL; + } + + // free up the clients + if ( game.clients ) + { + gi.Free( game.clients ); + game.clients = NULL; + } + } + +void G_SpawnEntities + ( + const char *mapname, + const char *entities, + int levelTime + ) + + { + try + { + level.NewMap( mapname, entities, levelTime ); + } + + catch( const char *error ) + { + G_ExitWithError( error ); + } + } + +void G_ArchivePersistantData + ( + Archiver &arc + ) + { + gentity_t *ed; + int i; + + for( i = 0; i < game.maxclients; i++ ) + { + Entity *ent; + + ed = &g_entities[ i ]; + if ( !ed->inuse || !ed->entity ) + continue; + + ent = ed->entity; + if ( !ent->isSubclassOf( Player ) ) + continue; + ( ( Player * )ent )->ArchivePersistantData( arc ); + } + } + +qboolean G_ArchivePersistant + ( + const char *name, + qboolean loading + ) + + { + int version; + Archiver arc; + + if ( loading ) + { + if ( !arc.Read( name, qfalse ) ) + { + return qfalse; + } + + arc.ArchiveInteger( &version ); + if ( version < PERSISTANT_VERSION ) + { + gi.Printf( "Persistant data from an older version (%d) of FAKK2.\n", version ); + arc.Close(); + return qfalse; + } + else if ( version > PERSISTANT_VERSION ) + { + gi.DPrintf( "Persistnat data from newer version %d of FAKK2.\n", version ); + arc.Close(); + return qfalse; + } + } + else + { + arc.Create( name ); + + version = PERSISTANT_VERSION; + arc.ArchiveInteger( &version ); + } + + + arc.ArchiveObject( &gameVars ); + G_ArchivePersistantData( arc ); + + arc.Close(); + return qtrue; + } + + +qboolean G_ReadPersistant + ( + const char *name + ) + + { + try + { + return G_ArchivePersistant( name, qtrue ); + } + + catch( const char *error ) + { + G_ExitWithError( error ); + } + return qfalse; + } + +/* +============ +G_WritePersistant + +This will be called whenever the game goes to a new level, + +A single player death will automatically restore from the +last save position. +============ +*/ + +void G_WritePersistant + ( + const char *name + ) + + { + try + { + G_ArchivePersistant( name, qfalse ); + } + + catch( const char *error ) + { + G_ExitWithError( error ); + } + } + + +/* +================= +LevelArchiveValid +================= +*/ +qboolean LevelArchiveValid + ( + Archiver &arc + ) + { + int version; + int savegame_version; + + // read the version number + arc.ArchiveInteger( &version ); + arc.ArchiveInteger( &savegame_version ); + + if ( version < GAME_API_VERSION ) + { + gi.Printf( "Savegame from an older version (%d) of FAKK 2.\n", version ); + return qfalse; + } + else if ( version > GAME_API_VERSION ) + { + gi.Printf( "Savegame from version %d of FAKK 2.\n", version ); + return qfalse; + } + + if ( savegame_version < SAVEGAME_VERSION ) + { + gi.Printf( "Savegame from an older version (%d) of FAKK 2.\n", version ); + return qfalse; + } + else if ( savegame_version > SAVEGAME_VERSION ) + { + gi.Printf( "Savegame from version %d of Sin.\n", version ); + return qfalse; + } + return qtrue; + } + + +void ArchiveAliases + ( + Archiver &arc + ) + + { + int i; + byte another; + AliasList_t *alias_list; + AliasListNode_t *alias_node; + AliasActorNode_t *actor_node; + str alias_name; + str model_name; + const char *name; + int model_index; + int actor_number; + int number_of_times_played; + byte been_played_this_loop; + int last_time_played; + + + if ( arc.Saving() ) + { + for( i = 0 ; i < MAX_MODELS ; i++ ) + { + alias_list = (AliasList_t *)gi.Alias_GetList( i ); + + if ( alias_list ) + alias_node = alias_list->data_list; + else + alias_node = NULL; + + if ( alias_node ) + { + name = gi.NameForNum( i ); + + if ( name ) + { + another = true; + arc.ArchiveByte( &another ); + + model_name = name; + arc.ArchiveString( &model_name ); + + // Go through all aliases in this model + + while ( alias_node ) + { + another = true; + arc.ArchiveByte( &another ); + + alias_name = alias_node->alias_name; + + arc.ArchiveString( &alias_name ); + + arc.ArchiveInteger( &alias_node->number_of_times_played ); + arc.ArchiveByte( &alias_node->been_played_this_loop ); + arc.ArchiveInteger( &alias_node->last_time_played ); + + actor_node = alias_node->actor_list; + + // Go through actor info + + while ( actor_node ) + { + another = true; + arc.ArchiveByte( &another ); + + arc.ArchiveInteger( &actor_node->actor_number ); + arc.ArchiveInteger( &actor_node->number_of_times_played ); + arc.ArchiveByte( &actor_node->been_played_this_loop ); + arc.ArchiveInteger( &actor_node->last_time_played ); + + actor_node = actor_node->next; + } + + another = false; + arc.ArchiveByte( &another ); + + alias_node = alias_node->next; + } + + another = false; + arc.ArchiveByte( &another ); + } + } + } + + another = false; + arc.ArchiveByte( &another ); + } + else + { + arc.ArchiveByte( &another ); + + while( another ) + { + arc.ArchiveString( &model_name ); + + model_index = gi.modelindex( model_name.c_str() ); + + arc.ArchiveByte( &another ); + + while( another ) + { + // Read in aliases + + arc.ArchiveString( &alias_name ); + arc.ArchiveInteger( &number_of_times_played ); + arc.ArchiveByte( &been_played_this_loop ); + arc.ArchiveInteger( &last_time_played ); + + gi.Alias_UpdateDialog( model_index, alias_name.c_str(), number_of_times_played, been_played_this_loop, last_time_played ); + + arc.ArchiveByte( &another ); + + while( another ) + { + // Read in actor infos + + arc.ArchiveInteger( &actor_number ); + arc.ArchiveInteger( &number_of_times_played ); + arc.ArchiveByte( &been_played_this_loop ); + arc.ArchiveInteger( &last_time_played ); + + gi.Alias_AddActorDialog( model_index, alias_name.c_str(), actor_number, number_of_times_played, been_played_this_loop, last_time_played ); + + arc.ArchiveByte( &another ); + } + + arc.ArchiveByte( &another ); + } + + arc.ArchiveByte( &another ); + } + } + } + + +/* +================= +G_ArchiveLevel + +================= +*/ +qboolean G_ArchiveLevel + ( + const char *filename, + qboolean autosave, + qboolean loading + ) + + { + try + { + int i; + int num; + Archiver arc; + gentity_t *edict; + + + if ( loading ) + { + LoadingSavegame = true; + LoadingServer = true; + + // Get rid of anything left over from the last level + level.CleanUp(); + + arc.Read( filename ); + + if ( !LevelArchiveValid( arc ) ) + { + arc.Close(); + return qfalse; + } + + // Read in the pending events. These are read in first in case + // later objects need to post events. + L_UnarchiveEvents( arc ); + } + else + { + int temp; + + if ( autosave ) + { + for( i = 0; i < game.maxclients; i++ ) + { + edict = &g_entities[ i ]; + if ( !edict->inuse && !edict->entity ) + { + continue; + } + + delete edict->entity; + } + } + + arc.Create( filename ); + + // write out the version number + temp = GAME_API_VERSION; + arc.ArchiveInteger( &temp ); + temp = SAVEGAME_VERSION; + arc.ArchiveInteger( &temp ); + + // Write out the pending events. These are written first in case + // later objects need to post events when reading the archive. + L_ArchiveEvents( arc ); + } + // archive the game object + arc.ArchiveObject( &game ); + + // archive the game variables + arc.ArchiveObject( &gameVars ); + + // archive Level + arc.ArchiveObject( &level ); + + if ( arc.Loading() ) + { + // Set up for a new map + PathManager.Init( level.mapname.c_str() ); + } + + // archive script librarian + arc.ArchiveObject( &ScriptLib ); + + // archive gravity paths + arc.ArchiveObject( &gravPathManager ); + + // archive camera paths + arc.ArchiveObject( &CameraMan ); + + // archive paths + arc.ArchiveObject( &PathManager ); + + // archive script controller + arc.ArchiveObject( &Director ); + + // archive lightstyles + arc.ArchiveObject( &lightStyles ); + + if ( arc.Saving() ) + { + // count the entities + num = 0; + for( i = 0; i < globals.num_entities; i++ ) + { + edict = &g_entities[ i ]; + if ( edict->inuse && edict->entity && !( edict->entity->flags & FL_DONTSAVE ) ) + { + num++; + } + } + } + + // archive all the entities + arc.ArchiveInteger( &globals.num_entities ); + arc.ArchiveInteger( &num ); + + if ( arc.Saving() ) + { + // write out the world + arc.ArchiveObject( world ); + + for( i = 0; i < globals.num_entities; i++ ) + { + edict = &g_entities[ i ]; + if ( !edict->inuse || !edict->entity || ( edict->entity->flags & FL_DONTSAVE ) ) + { + continue; + } + + arc.ArchiveObject( edict->entity ); + } + } + else + { + // Tell the server about our data + gi.LocateGameData( g_entities, globals.num_entities, sizeof( gentity_t ), &game.clients[0].ps, sizeof( game.clients[0] ) ); + + // read in the world + arc.ReadObject(); + + for( i = 0; i < num; i++ ) + { + arc.ReadObject(); + } + } + + ArchiveAliases( arc ); + + arc.Close(); + + if ( arc.Loading() ) + { + LoadingSavegame = false; + + // call the precache scripts + level.Precache(); + } + else + { + gi.centerprintf( &g_entities[ 0 ], "@textures/menu/gamesaved" ); + } + + if ( arc.Loading() ) + { + // Make sure all code that needs to setup the player after they have been loaded is run + + for( i = 0; i < game.maxclients; i++ ) + { + edict = &g_entities[ i ]; + + if ( edict->inuse && edict->entity ) + { + Player *player = (Player *)edict->entity; + player->Loaded(); + } + } + } + + return qtrue; + } + + catch( const char *error ) + { + G_ExitWithError( error ); + } + return qfalse; + } + +/* +================= +G_WriteLevel + +================= +*/ +void G_WriteLevel + ( + const char *filename, + qboolean autosave + ) + + { + game.autosaved = autosave; + G_ArchiveLevel( filename, autosave, qfalse ); + game.autosaved = false; + } + +/* +================= +G_ReadLevel + +SpawnEntities will already 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. + +No clients are connected yet. +================= +*/ +qboolean G_ReadLevel + ( + const char *filename + ) + + { + qboolean status; + + status = G_ArchiveLevel( filename, qfalse, qtrue ); + // if the level load failed make sure that these variables are not set + if ( !status ) + { + LoadingSavegame = false; + LoadingServer = false; + } + return status; + } + +/* +================= +G_LevelArchiveValid +================= +*/ +qboolean G_LevelArchiveValid + ( + const char *filename + ) + { + try + { + qboolean ret; + + Archiver arc; + + if ( !arc.Read( filename ) ) + { + return qfalse; + } + + ret = LevelArchiveValid( arc ); + + arc.Close(); + + return ret; + } + + catch( const char *error ) + { + G_ExitWithError( error ); + return qfalse; + } + } + + +/* +================= +GetGameAPI + +Returns a pointer to the structure with all entry points +and global variables +================= +*/ +game_export_t *GetGameAPI + ( + game_import_t *import + ) + + { + gi = *import; + + globals.apiversion = GAME_API_VERSION; + globals.Init = G_InitGame; + globals.Shutdown = G_ShutdownGame; + globals.Cleanup = G_CleanupGame; + globals.SpawnEntities = G_SpawnEntities; + + globals.WritePersistant = G_WritePersistant; + globals.ReadPersistant = G_ReadPersistant; + globals.WriteLevel = G_WriteLevel; + globals.ReadLevel = G_ReadLevel; + globals.LevelArchiveValid = G_LevelArchiveValid; + + globals.ClientThink = G_ClientThink; + globals.ClientConnect = G_ClientConnect; + globals.ClientUserinfoChanged = G_ClientUserinfoChanged; + globals.ClientDisconnect = G_ClientDisconnect; + globals.ClientBegin = G_ClientBegin; + globals.ClientCommand = G_ClientCommand; + + globals.ConsoleCommand = G_ConsoleCommand; + globals.RunFrame = G_RunFrame; + + globals.gentitySize = sizeof(gentity_t); + globals.error_message = NULL; + + return &globals; + } + +/* +================= +G_ClientEndServerFrames +================= +*/ +void G_ClientEndServerFrames + ( + void + ) + + { + int i; + gentity_t *ent; + + // calc the player views now that all pushing + // and damage has been added + for( i = 0; i < maxclients->integer; i++ ) + { + ent = g_entities + i; + if ( !ent->inuse || !ent->client || !ent->entity ) + { + continue; + } + + ent->entity->ProcessEvent( EV_ClientEndFrame ); + } + } + +void G_MoveClientToIntermission + ( + Entity *ent + ) + + { + } + +void G_BeginIntermission + ( + const char *map + ) + + { + gentity_t *client; + Entity *ent; + Entity *path; + int i; + Event *event; + + assert( map ); + if ( !map ) + { + gi.DPrintf( "G_BeginIntermission : Null map name\n" ); + return; + } + + if ( level.intermissiontime ) + { + // already activated + return; + } + + if ( deathmatch->integer ) + { + level.intermissiontime = level.time + 5.0f; + } + else + { + level.intermissiontime = level.time + 1.0f; + G_FadeOut( 1 ); + G_FadeSound( 1 ); + } + + level.nextmap = map; + + // find an intermission spot + ent = G_FindClass( NULL, "info_player_intermission" ); + + // Only do the camera stuff if the node exists. + if ( ent ) + { + SetCamera( ent, CAMERA_SWITCHTIME ); + event = new Event( EV_Camera_Orbit ); + + // Find the end node + path = G_FindTarget( NULL, "endnode1" ); + if ( path ) + { + event->AddEntity( path ); + ent->ProcessEvent( event ); + event = new Event( EV_Camera_Cut ); + ent->ProcessEvent( event ); + } + } + + // Display scores for all the clients + for( i = 0; i < maxclients->integer; i++ ) + { + client = g_entities + i; + if ( !client->inuse ) + { + continue; + } + + ent = G_GetEntity( client->s.number ); + G_MoveClientToIntermission( ent ); + } + + // tell the script that the player's not ready so that if we return to this map, + // we can do something about it. + Director.PlayerNotReady(); + } + +/* +============= +G_ExitLevel +============= +*/ +void G_ExitLevel + ( + void + ) + + { + char command[ 256 ]; + int j; + gentity_t *ent; + + // close the player log file if necessary + ClosePlayerLogFile(); + + // kill the sounds + Com_sprintf( command, sizeof( command ), "stopsound\n" ); + gi.SendConsoleCommand( command ); + + Com_sprintf( command, sizeof( command ), "gamemap \"%s\"\n", level.nextmap.c_str() ); + gi.SendConsoleCommand( command ); + + level.nextmap = ""; + + level.exitintermission = 0; + level.intermissiontime = 0; + + // Tell all the client that the level is done + for( j = 0; j < game.maxclients; j++ ) + { + ent = &g_entities[ j ]; + if ( !ent->inuse || !ent->entity ) + { + continue; + } + + ent->entity->ProcessEvent( EV_Player_EndLevel ); + } + + G_ClientEndServerFrames(); + + // tell the script that the player's not ready so that if we return to this map, + // we can do something about it. + Director.PlayerNotReady(); + } + +/* +================ +G_RunFrame + +Advances the world by 0.1 seconds +================ +*/ +void G_RunFrame + ( + int levelTime, + int frameTime + ) + + { + gentity_t *edict; + Entity *ent; + int num; + qboolean showentnums; + int start; + int end; + + try + { + if ( level.restart ) + { + level.Restart(); + } +#if 0 + { + int i, num; + + num = 0; + edict = g_entities; + for ( i = maxclients->integer; i < globals.num_entities; i++, edict++ ) + { + // the first couple seconds of server time can involve a lot of + // freeing and allocating, so relax the replacement policy + if ( + edict->inuse + ) + { + num++; + } + } + + Com_Printf( "num_entities = %d\n", num ); + } +#endif + + level.setTime( levelTime, frameTime ); + + if ( g_showmem->integer ) + { + DisplayMemoryUsage(); + } + + // exit intermissions + if ( level.exitintermission ) + { + G_ExitLevel(); + return; + } + + path_checksthisframe = 0; + + // Reset debug lines + G_InitDebugLines(); + + // testing coordinate system + if ( csys_draw->integer ) + { + G_DrawCSystem(); + } + + PathManager.ShowNodes(); + + // don't show entnums during deathmatch + showentnums = ( sv_showentnums->integer && ( !deathmatch->integer || sv_cheats->integer ) ); + + // Wake up any monsters in the area + AI_TargetPlayer(); + + // Process most of the events before the physics are run + // so that we can affect the physics immediately + L_ProcessPendingEvents(); + + // + // treat each object in turn + // + for( edict = active_edicts.next, num = 0; edict != &active_edicts; edict = level.next_edict, num++ ) + { + assert( edict ); + assert( edict->inuse ); + assert( edict->entity ); + + level.next_edict = edict->next; + + // Paranoia - It's a way of life + assert( num <= MAX_GENTITIES ); + if ( num > MAX_GENTITIES ) + { + gi.DPrintf( "Possible infinite loop in G_RunFrame.\n"); + break; + } + + ent = edict->entity; + if ( g_timeents->integer ) + { + start = gi.Milliseconds(); + G_RunEntity( ent ); + end = gi.Milliseconds(); + + if ( g_timeents->value <= ( end - start ) ) + { + gi.DebugPrintf( "%d: '%s'(%d) : %d\n", level.framenum, ent->targetname.c_str(), ent->entnum, end - start ); + } + } + else + { + G_RunEntity( ent ); + } + + if ( ( edict->svflags & SVF_SENDONCE ) && ( edict->svflags & SVF_SENT ) ) + { + // Entity has been sent once, and is marked as such, then remove it + ent->PostEvent( EV_Remove, 0 ); + } + + if ( showentnums ) + { + G_DrawDebugNumber( ent->origin + Vector( 0, 0, ent->maxs.z + 2 ), ent->entnum, 2, 1, 1, 0 ); + } + } + + // Process any pending events that got posted during the physics code. + L_ProcessPendingEvents(); + + // build the playerstate_t structures for all players + G_ClientEndServerFrames(); + + // see if we should draw the bounding boxes + G_ClientDrawBoundingBoxes(); + + // show how many traces the game code is doing + if ( sv_traceinfo->integer ) + { + if ( sv_traceinfo->integer == 3 ) + { + gi.DebugPrintf( "%0.2f : Total traces %d\n", level.time, sv_numtraces ); + } + else + { + gi.DPrintf( "%0.2f : Total traces %d\n", level.time, sv_numtraces ); + } + } + + // reset out count of the number of game traces + sv_numtraces = 0; + + level.framenum++; + + // we increment time so that events that occurr before we think again are automatically on the next frame + levelTime += frameTime; + level.setTime( levelTime, frameTime ); + } + + catch( const char *error ) + { + G_ExitWithError( error ); + } + } + +void G_ClientThink + ( + gentity_t *ent, + usercmd_t *ucmd + ) + + { + try + { + if ( ent->entity ) + { + current_ucmd = ucmd; + ent->entity->ProcessEvent( EV_ClientMove ); + current_ucmd = NULL; + } + } + + catch( const char *error ) + { + G_ExitWithError( error ); + } + } + +/* +=========== +G_ClientBegin + +called when a client has finished connecting, and is ready +to be placed into the game. This will happen every level load. +============ +*/ +void G_ClientBegin + ( + gentity_t *ent, + usercmd_t *cmd + ) + + { + try + { + if ( ent->inuse && ent->entity ) + { + // the client has cleared the client side viewangles upon + // connecting to the server, which is different than the + // state when the game is saved, so we need to compensate + // with deltaangles + ent->entity->SetDeltaAngles(); + } + else + { + Player *player; + + // a spawn point will completely reinitialize the entity + level.spawn_entnum = ent->s.number; + player = new Player; + } + + if ( level.intermissiontime && ent->entity ) + { + G_MoveClientToIntermission( ent->entity ); + } + else + { + // send effect if in a multiplayer game + if ( game.maxclients > 1 ) + { + gi.Printf ( "%s entered the game\n", ent->client->pers.netname ); + } + } + + // make sure all view stuff is valid + if ( ent->entity ) + { + ent->entity->ProcessEvent( EV_ClientEndFrame ); + + if ( !Director.PlayerReady() ) + { + // let any threads waiting on us know they can go ahead + Director.PlayerSpawned(); + } + } + } + + catch( const char *error ) + { + G_ExitWithError( error ); + } + } + +/* +=========== +G_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 G_ClientUserinfoChanged + ( + gentity_t *ent, + const char *userinfo + ) + + { + const char *s; + int playernum; + Player *player; + float fov; + Event *ev; + + try + { + if ( !ent ) + { + assert( 0 ); + return; + } + + player = ( Player * )ent->entity; + + if ( !player ) + { + assert( 0 ); + return; + } + + // set name + s = Info_ValueForKey( userinfo, "name" ); + if ( !s ) + { + assert( 0 ); + return; + } + strncpy( ent->client->pers.netname, s, sizeof( ent->client->pers.netname ) - 1 ); + + // send over a subset of the userinfo keys so other clients can + // print scoreboards, display models, and play custom sounds + playernum = ent - g_entities; + gi.setConfigstring( CS_PLAYERS + playernum, va( "name\\%s", ent->client->pers.netname ) ); + + // Fov + if ( player ) + { + fov = atof( Info_ValueForKey( userinfo, "fov" ) ); + if ( fov < 1 ) + { + fov = 90; + } + else if ( fov > 160 ) + { + fov = 160; + } + ev = new Event( EV_Player_Fov ); + ev->AddFloat( fov ); + player->ProcessEvent( ev ); + } + + // save off the userinfo in case we want to check something later + strncpy( ent->client->pers.userinfo, userinfo, sizeof( ent->client->pers.userinfo ) - 1 ); + } + + catch( const char *error ) + { + G_ExitWithError( error ); + } + } + +/* +=========== +ClientConnect + +Called when a player begins connecting to the server. +Called again for every map change or tournement restart. + +The session information will be valid after exit. + +Return NULL if the client should be allowed, otherwise return +a string with the reason for denial. + +Otherwise, the client will be sent the current gamestate +and will eventually get to ClientBegin. + +firstTime will be qtrue the very first time a client connects +to the server machine, but qfalse on map changes and tournement +restarts. +============ +*/ +char *G_ClientConnect + ( + int clientNum, + qboolean firstTime + ) + + { + const char *value; + gentity_t *ent; + char userinfo[ MAX_INFO_STRING ]; + gclient_t *client; + + try + { + ent = &g_entities[ clientNum ]; + gi.getUserinfo( clientNum, userinfo, sizeof( userinfo ) ); + + // check to see if they are on the banned IP list + value = Info_ValueForKey( userinfo, "ip" ); + if ( SV_FilterPacket( value ) ) + { + return "Banned IP"; + } + + // check for a password + value = Info_ValueForKey( userinfo, "password" ); + if ( strcmp( password->string, value ) != 0 ) + { + return "Invalid password"; + } + + // they can connect + ent->client = game.clients + clientNum; + client = ent->client; + + // read or initialize the session data + // if there is already a body waiting for us (a loadgame), just + // take it, otherwise spawn one from scratch + if ( firstTime ) + { + memset( client, 0, sizeof( *client ) ); + + // clear the respawning variables + if ( !game.autosaved ) + { + G_InitClientPersistant( client ); + } + } + + G_ClientUserinfoChanged( ent, userinfo ); + + if ( firstTime && game.maxclients > 1 ) + { + gi.Printf( "%s connected\n", ent->client->pers.netname ); + } + + LoadingServer = false; + } + + catch( const char *error ) + { + G_ExitWithError( error ); + } + + return NULL; + } + +/* +=========== +G_ClientDisconnect + +called when a player drops from the server + +============ +*/ +void G_ClientDisconnect + ( + gentity_t *ent + ) + + { + try + { + if ( !ent || ( !ent->client ) || ( !ent->entity ) ) + { + return; + } + + delete ent->entity; + ent->entity = NULL; + } + + catch( const char *error ) + { + G_ExitWithError( error ); + } + } + +/* +================= +G_ClientDrawBoundingBoxes +================= +*/ +void G_ClientDrawBoundingBoxes + ( + void + ) + + { + gentity_t *edict; + Entity *ent; + Vector eye; + + // don't show bboxes during deathmatch + if ( ( !g_showgravpath->integer && !sv_showbboxes->integer ) || ( deathmatch->integer && !sv_cheats->integer ) ) + { + return; + } + + if ( sv_showbboxes->integer ) + { + edict = g_entities; + ent = edict->entity; + if ( ent ) + { + eye = ent->origin; + ent = findradius( NULL, eye, 1000 ); + while( ent ) + { + switch ((int)sv_showbboxes->integer) + { + case 1: + if ( ent->edict != edict && ent->edict->s.solid) + { + G_DebugBBox( ent->origin, ent->mins, ent->maxs, 1, 1, 0, 1 ); + } + break; + case 2: + if ( ent->edict != edict && ent->edict->s.solid) + { + G_DebugBBox( vec_zero, ent->edict->absmin, ent->edict->absmax, 1, 0, 1, 1 ); + } + break; + case 3: + if ( ent->edict->s.modelindex && !(ent->edict->s.renderfx & RF_DONTDRAW) ) + G_DebugBBox( ent->origin, ent->mins, ent->maxs, 1, 1, 0, 1 ); + break; + case 4: + G_DebugBBox( ent->origin, ent->mins, ent->maxs, 1, 1, 0, 1 ); + break; + case 5: + default: + if ( ent->isSubclassOf( Animate ) && gi.IsModel( ent->edict->s.modelindex ) ) + { + Animate * anim; + vec3_t mins, maxs; + + anim = ( Animate * )ent; + gi.Frame_Bounds( ent->edict->s.modelindex, anim->CurrentAnim(), anim->CurrentFrame(), ent->edict->s.scale, mins, maxs ); + G_DebugBBox( ent->origin, mins, maxs, 0, 1, 0, 1 ); + } + else + { + G_DebugBBox( ent->origin, ent->mins, ent->maxs, 1, 1, 0, 1 ); + } + break; + } + ent = findradius( ent, eye, 1000 ); + } + } + } + + if ( g_showgravpath->integer ) + { + // Draw the gravity node paths + gravPathManager.DrawGravPaths(); + } + } + +//====================================================================== + +#ifndef GAME_HARD_LINKED +// this is only here so the functions in q_shared.c and q_shwin.c can link +void Com_Error ( int level, const char *error, ... ) { + va_list argptr; + char text[4096]; + + va_start (argptr, error); + vsprintf (text, error, argptr); + va_end (argptr); + + gi.Error( level, "%s", text); +} + +void Sys_Error + ( + const char *error, + ... + ) + + { + va_list argptr; + char text[4096]; + + va_start (argptr, error); + vsprintf (text, error, argptr); + va_end (argptr); + + gi.Error (ERR_FATAL, "%s", text); + } + +void Com_Printf + ( + const char *msg, + ... + ) + + { + va_list argptr; + char text[4096]; + + va_start (argptr, msg); + vsprintf (text, msg, argptr); + va_end (argptr); + + gi.DPrintf ("%s", text); + } + +#endif diff --git a/source/source/fgame/g_main.h b/source/source/fgame/g_main.h new file mode 100644 index 0000000..e8b8f95 --- /dev/null +++ b/source/source/fgame/g_main.h @@ -0,0 +1,142 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/g_main.h $ +// $Revision:: 16 $ +// $Author:: Markd $ +// $Date:: 7/17/00 12:36a $ +// +// Copyright (C) 1998 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source is may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/g_main.h $ +// +// 16 7/17/00 12:36a Markd +// Made sure to close the log file when exiting a level or shutting down a +// server +// +// 15 7/06/00 7:48p Markd +// Added LevelArchiveValid function +// +// 14 6/15/00 8:04p Markd +// Added CleanupGame +// +// 13 6/14/00 2:17p Markd +// fixed compiler warnings for Intel Compiler +// +// 12 6/14/00 11:18a Markd +// cleaned up code using Intel compiler +// +// 11 6/10/00 4:23p Markd +// rewrote map restarting and loading out of date save games +// +// 10 6/02/00 4:26p Markd +// renamed ReadGame functions to ReadPersistant +// +// 9 1/10/00 5:33p Markd +// Added DeallocGameData +// +// 8 1/06/00 11:08p Jimdose +// cleaning up unused code +// +// 7 12/17/99 6:35p Jimdose +// changed spawnarg code +// added Level class for spawning and map control +// got rid of unused or superflous variables +// changed setjmp/longjmp calls to try/throw/catch exception handling +// +// 6 12/11/99 3:37p Markd +// q3a gold checkin, first time +// +// 5 12/10/99 11:52a Aldie +// Adjusted player angles a bit +// +// 4 12/01/99 11:26a Aldie +// Couple of fixes for emitters and more ammo stuff +// +// 3 10/05/99 5:03p Markd +// Removed un-used game function ClientPredict +// +// 2 9/16/99 4:50p Jimdose +// removed unused variables +// changed G_ClientConnect +// +// 1 9/10/99 10:53a Jimdose +// +// 1 9/08/99 3:16p Aldie +// +// 7 8/28/99 3:24p Markd +// got rid of maxbulletholes and max bloodsplats +// +// DESCRIPTION: +// Global header file for g_main.cpp +// + +#ifndef __G_MAIN_H__ +#define __G_MAIN_H__ + +#include "g_local.h" +#include "gamecvars.h" +#include "level.h" + +extern Vector vec_origin; +extern Vector vec_zero; + +extern qboolean LoadingSavegame; +extern qboolean LoadingServer; + +extern game_import_t gi; +extern game_export_t globals; + +extern gentity_t *g_entities; +extern gentity_t active_edicts; +extern gentity_t free_edicts; + +extern int sv_numtraces; + +extern usercmd_t *current_ucmd; + +#define DM_FLAG( flag ) ( deathmatch->integer && ( ( int )dmflags->integer & ( flag ) ) ) + +void G_BeginIntermission( const char *map ); +void G_MoveClientToIntermission( Entity *client ); +void G_WriteClient( Archiver &arc, gclient_t *client ); +void G_AllocGameData( void ); +void G_DeAllocGameData( void ); +void G_ClientDrawBoundingBoxes( void ); + +void G_ExitWithError( const char *error ); + +extern "C" { + void G_SpawnEntities( const char *mapname, const char *entities, int time ); + void G_ClientEndServerFrames( void ); + void G_ClientThink( gentity_t *ent, usercmd_t *cmd ); + char *G_ClientConnect( int clientNum, qboolean firstTime ); + void G_ClientUserinfoChanged( gentity_t *ent, const char *userinfo ); + void G_ClientDisconnect( gentity_t *ent ); + void G_ClientBegin( gentity_t *ent, usercmd_t *cmd ); + void G_WritePersistant( const char *filename ); + qboolean G_ReadPersistant( const char *filename ); + void G_WriteLevel( const char *filename, qboolean autosave ); + qboolean G_ReadLevel( const char *filename ); + qboolean G_LevelArchiveValid( const char *filename ); + void G_InitGame( int startTime, int randomSeed ); + void G_ShutdownGame( void ); + void G_CleanupGame( void ); + void G_RunFrame( int levelTime, int frametime ); + void G_ServerCommand( void ); + void G_ClientThink( gentity_t *ent, usercmd_t *ucmd ); + } + +void ClosePlayerLogFile( void ); + +qboolean SV_FilterPacket( const char *from ); +void SVCmd_AddIP_f( void ); +void SVCmd_RemoveIP_f( void ); +void SVCmd_ListIP_f( void ); +void SVCmd_WriteIP_f( void ); + +#endif /* g_main.h */ + diff --git a/source/source/fgame/g_phys.cpp b/source/source/fgame/g_phys.cpp new file mode 100644 index 0000000..b9ac8f1 --- /dev/null +++ b/source/source/fgame/g_phys.cpp @@ -0,0 +1,1673 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/g_phys.cpp $ +// $Revision:: 33 $ +// $Author:: Markd $ +// $Date:: 6/30/00 10:45a $ +// +// Copyright (C) 1998 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source is may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/g_phys.cpp $ +// +// 33 6/30/00 10:45a Markd +// added MOVETYPE_STATIONARY and revamped some physics +// +// 32 6/26/00 3:32p Markd +// changed aliases for entering and leaving water +// +// 31 6/17/00 4:04p Steven +// Fixed a bug in G_Impact that wasn't allowing entities with +// CONTENTS_SHOOTABLE_ONLY from hitting things. +// +// 30 6/16/00 7:37p Markd +// fixed some physics code +// +// 29 6/16/00 6:50p Steven +// Made G_Push not block when running into shootable only things. +// +// 28 6/14/00 3:50p Markd +// Cleaned up more Intel Compiler warnings +// +// 27 4/29/00 11:28a Markd +// removed old rope code, cleaned up rope interface +// +// 26 4/24/00 6:20p Markd +// removed touch code for gibs and movetype_bounce since it was unnecessary +// +// 25 4/21/00 3:01p Markd +// Added EV_Touch support to gibs and bounce physics +// +// 24 4/10/00 11:17a Markd +// added new rope code +// +// 23 4/01/00 3:55p Markd +// Added FL_TOUCH_TRIGGERS support +// +// 22 4/01/00 3:45p Markd +// added FL_TOUCH_TRIGGERS flag and implementation +// +// 21 3/23/00 6:22p Aldie +// Added a continue for moving not solid objects +// +// 20 3/21/00 5:06p Markd +// added vehicle support +// +// 19 3/17/00 3:59p Steven +// G_Push now ignores entities with a content type of CONTENTS_CORPSE. +// +// 18 2/26/00 11:22a Steven +// Added partial immobile flag. +// +// 17 2/09/00 10:38a Steven +// Made G_Physics_Step actually use the actor's clipmask. +// +// 16 1/29/00 12:33p Jimdose +// G_Impact no longer sends touch events to world +// Removed ImpactDamage +// +// 15 1/22/00 12:42p Jimdose +// got rid of calls to vec3() +// +// 14 1/12/00 4:31p Steven +// Added new movetype MOVETYPE_GIB. +// +// 13 1/05/00 3:07p Jimdose +// changed call to AnglesToMat to AnglesToAxis +// +// 12 1/05/00 1:49p Steven +// Stop entities from spinning after they bounce on the ground (doing this so +// gibs will land correctly). +// +// 11 12/17/99 8:26p Jimdose +// got rid of unused vars and functions +// +// 10 12/01/99 3:44p Steven +// Changed the mask of dead actors to MASK_DEADSOLID from MASK_MONSTERSOLID. +// +// 9 10/28/99 10:42a Aldie +// Added rope functions +// +// 8 10/27/99 10:28a Steven +// Stopped running physics on an entity that has been immobilized. +// +// 7 10/22/99 3:29p Jimdose +// added G_FixEntityPosition +// added better entity pushing that doesn't get stuck as often +// +// 6 10/14/99 5:08p Markd +// removed a lot of G_GetMoveDir calls from the initialization code +// +// 5 10/06/99 12:35p Markd +// Removed Mover casts and fixed Push bug +// +// 4 9/17/99 4:54p Aldie +// Fix for parent +// +// 3 9/16/99 4:48p Jimdose +// removed unused code +// +// 2 9/16/99 11:18a Markd +// Continuing merge of code, not functional yet but closer +// +// 1 9/10/99 10:53a Jimdose +// +// 1 9/08/99 3:16p Aldie +// +// 21 9/01/99 6:48p Markd +// added no physics for entities that are attached to others +// +// 20 8/28/99 6:44p Jimdose +// clients now get their view rotated when pushed by rotating objects +// +// 19 8/28/99 11:44a Steven +// Removed global from sound function calls. +// +// 18 8/18/99 3:28p Jimdose +// added cylindrical collision detection +// +// 17 7/06/99 8:33p Jimdose +// removed unused player code +// added state machine for player animation +// +// DESCRIPTION: +// + +#include "g_local.h" +#include "animate.h" +#include "sentient.h" +#include "actor.h" +#include "rope.h" + +/* + + +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. + +*/ + +typedef struct + { + Entity *ent; + Vector localorigin; + Vector origin; + Vector localangles; + Vector angles; + float deltayaw; + } pushed_t; + +pushed_t pushed[ MAX_GENTITIES ]; +pushed_t *pushed_p; + +Entity *obstacle; + +/* +============ +G_FixEntityPosition + +============ +*/ +Entity *G_FixEntityPosition + ( + Entity *ent + ) + + { + int mask; + trace_t trace; + Vector start; + + mask = ent->edict->clipmask; + if ( !mask ) + { + mask = MASK_SOLID; + } + + start = ent->origin; + start.z += 8; + if ( ent->client ) + { + trace = G_Trace( start, ent->mins, ent->maxs, ent->origin, ent, mask, true, "G_TestEntityPosition1" ); + } + else + { + trace = G_Trace( start, ent->mins, ent->maxs, ent->origin, ent, mask, false, "G_TestEntityPosition2" ); + } + + if ( trace.startsolid ) + { + //return g_entities->entity; + assert( trace.ent ); + assert( trace.ent->entity ); + return trace.ent->entity; + } + + ent->setOrigin( trace.endpos ); + + return NULL; + } + + +/* +============ +G_TestEntityPosition + +============ +*/ +Entity *G_TestEntityPosition + ( + Entity *ent + ) + + { + int mask; + trace_t trace; + + mask = ent->edict->clipmask; + if ( !mask ) + mask = MASK_SOLID; + + if ( ent->client ) + { + trace = G_Trace( ent->origin, ent->mins, ent->maxs, ent->origin, ent, mask, true, "G_TestEntityPosition1" ); + } + else + { + trace = G_Trace( ent->origin, ent->mins, ent->maxs, ent->origin, ent, mask, false, "G_TestEntityPosition2" ); + } + + if ( trace.startsolid ) + { + //return g_entities->entity; + assert( trace.ent ); + assert( trace.ent->entity ); + return trace.ent->entity; + } + + return NULL; + } + + +/* +================ +G_CheckVelocity +================ +*/ +void G_CheckVelocity + ( + Entity *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; + } + } + } + +/* +================== +G_Impact + +Two entities have touched, so run their touch functions +================== +*/ +void G_Impact + ( + Entity *e1, + trace_t *trace + ) + + { + gentity_t *e2; + Event *ev; + + e2 = trace->ent; + + level.impact_trace = *trace; + + // touch anything, including the world + if ( e1->edict->solid != SOLID_NOT ) + { + ev = new Event( EV_Touch ); + ev->AddEntity( e2->entity ); + e1->ProcessEvent( ev ); + } + + // entity could have been removed, so check if he's in use before sending the event + if ( + e2->entity && + ( e2->solid != SOLID_NOT ) && + ( !( e2->contents & CONTENTS_SHOOTABLE_ONLY ) ) && + ( e2->entity != world ) + ) + { + ev = new Event( EV_Touch ); + ev->AddEntity( e1 ); + e2->entity->ProcessEvent( ev ); + } + + memset( &level.impact_trace, 0, sizeof( level.impact_trace ) ); + } + +/* +================== +G_ClipVelocity + +Slide off of the impacting object +returns the blocked flags (1 = floor, 2 = step / wall) +================== +*/ +#define STOP_EPSILON 0.1 + +int G_ClipVelocity + ( + Vector& in, + Vector& normal, + Vector& out, + float overbounce + ) + + { + int i; + int blocked; + float backoff; + + blocked = 0; + + if ( normal[ 2 ] > 0 ) + { + // floor + blocked |= 1; + } + if ( !normal[ 2 ] ) + { + // step + blocked |= 2; + } + + backoff = ( in * normal ) * overbounce; + + out = in - normal * backoff; + for( i = 0; i < 3; i++ ) + { + if ( out[ i ] > -STOP_EPSILON && out[ i ] < STOP_EPSILON ) + { + out[ i ] = 0; + } + } + + return blocked; + } + + +/* +============ +G_FlyMove + +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 + +int G_FlyMove + ( + Entity *ent, + Vector basevel, + float time, + int mask + ) + + { + Entity *hit; + gentity_t *edict; + int bumpcount, numbumps; + Vector dir; + float d; + int numplanes; + vec3_t planes[ MAX_CLIP_PLANES ]; + Vector primal_velocity, original_velocity, new_velocity; + int i, j; + trace_t trace; + Vector end; + float time_left; + int blocked; +#if 0 + Vector move; + Vector v; +#endif + + edict = ent->edict; + + numbumps = 4; + + blocked = 0; + original_velocity = ent->velocity; + primal_velocity = ent->velocity; + numplanes = 0; + +#if 1 + time_left = time; +#else + time_left = 1.0;//time; + + v = ent->total_delta; + v[ 1 ] = -v[ 1 ]; // sigh... + MatrixTransformVector( v, ent->orientation, move ); + move += ent->velocity * time; + ent->total_delta = vec_zero; +#endif + + ent->groundentity = NULL; + for( bumpcount = 0; bumpcount < numbumps; bumpcount++ ) + { +#if 1 + end = ent->origin + time_left * ( ent->velocity + basevel ); +#else + end = ent->origin + time_left * move; +#endif + + trace = G_Trace( ent->origin, ent->mins, ent->maxs, end, ent, mask, false, "G_FlyMove" ); + + if ( + ( trace.allsolid ) || + ( + ( trace.startsolid ) && + ( ent->movetype == MOVETYPE_VEHICLE ) + ) + ) + { + // entity is trapped in another solid + ent->velocity = vec_zero; + return 3; + } + + if ( trace.fraction > 0 ) + { + // actually covered some distance + ent->setOrigin( trace.endpos ); + original_velocity = ent->velocity; + numplanes = 0; + } + + if ( trace.fraction == 1 ) + { + // moved the entire distance + break; + } + + assert( trace.ent ); + hit = trace.ent->entity; + + if ( trace.plane.normal[ 2 ] > 0.7 ) + { + // floor + blocked |= 1; + if ( hit->getSolidType() == SOLID_BSP ) + { + ent->groundentity = hit->edict; + ent->groundplane = trace.plane; + ent->groundcontents = trace.contents; + } + } + + if ( !trace.plane.normal[ 2 ] ) + { + // step + blocked |= 2; + } + + // + // run the impact function + // + G_Impact( ent, &trace ); + if ( !edict->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 + ent->velocity = vec_zero; + return 3; + } + + VectorCopy( trace.plane.normal, planes[ numplanes ] ); + numplanes++; + + // + // modify original_velocity so it parallels all of the clip planes + // + for( i = 0; i < numplanes; i++ ) + { + G_ClipVelocity( original_velocity, Vector( planes[ i ] ), new_velocity, 1.01 ); + for( j = 0; j < numplanes; j++ ) + { + if ( j != i ) + { + if ( ( new_velocity * planes[ j ] ) < 0 ) + { + // not ok + break; + } + } + } + + if ( j == numplanes ) + { + break; + } + } + + if ( i != numplanes ) + { + // go along this plane + ent->velocity = new_velocity; + } + else + { + // go along the crease + if ( numplanes != 2 ) + { + ent->velocity = vec_zero; + return 7; + } + CrossProduct( planes[ 0 ], planes[ 1 ], dir ); + d = dir * ent->velocity; + ent->velocity = dir * d; + } + + // + // if original velocity is against the original velocity, stop dead + // to avoid tiny occilations in sloping corners + // + if ( ( ent->velocity * primal_velocity ) <= 0 ) + { + ent->velocity = vec_zero; + return blocked; + } + } + + return blocked; + } + + +/* +============ +G_AddGravity + +============ +*/ +void G_AddGravity + ( + Entity *ent + ) + + { + float grav; + + if ( ent->waterlevel > 2 ) + { + grav = ent->gravity * 60 * level.frametime; + } + else + { + grav = ent->gravity * sv_gravity->value * level.frametime; + } + + ent->velocity[ 2 ] -= grav; + } + +/* +=============================================================================== + +PUSHMOVE + +=============================================================================== +*/ + +/* +============ +G_PushEntity + +Does not change the entities velocity at all +============ +*/ +trace_t G_PushEntity + ( + Entity *ent, + Vector push + ) + + { + trace_t trace; + Vector start; + Vector end; + int mask; + gentity_t *edict; + + start = ent->origin; + end = start + push; + +retry: + if ( ent->edict->clipmask ) + { + mask = ent->edict->clipmask; + } + else + { + mask = MASK_SOLID; + } + + trace = G_Trace( start, ent->mins, ent->maxs, end, ent, mask, false, "G_PushEntity" ); + + edict = ent->edict; + + ent->setOrigin( trace.endpos ); + + if ( trace.fraction != 1.0 ) + { + G_Impact( ent, &trace ); + + // if the pushed entity went away and the pusher is still there + if ( ( !trace.ent || !trace.ent->inuse ) && edict->inuse ) + { + // move the pusher back and try again + ent->setOrigin( start ); + goto retry; + } + } + + if ( edict && ( edict != ent->edict ) ) + { + if ( ent->flags & FL_TOUCH_TRIGGERS ) + { + G_TouchTriggers( ent ); + } + } + + return trace; + } + +/* +============ +G_SlideEntity +============ +*/ +trace_t G_SlideEntity + ( + Entity *ent, + Vector push + ) + + { + trace_t trace; + Vector start; + Vector end; + int mask; + + start = ent->origin; + end = start + push; + + if ( ent->edict->clipmask ) + { + mask = ent->edict->clipmask; + } + else + { + mask = MASK_SOLID; + } + + trace = G_Trace( start, ent->mins, ent->maxs, end, ent, mask, false, "G_SlideEntity" ); + + ent->setOrigin( trace.endpos ); + + return trace; + } + + +/* +================ +G_SnapPosition + +================ +*/ +/* +qboolean G_SnapPosition + ( + Entity *ent + ) + + { + int x, y, z; + Vector offset( 0, -1, 1 ); + Vector base; + + base = ent->origin; + for ( z = 0; z < 3; z++ ) + { + ent->origin.z = base.z + offset[ z ]; + for ( y = 0; y < 3; y++ ) + { + ent->origin.y = base.y + offset[ y ]; + for ( x = 0; x < 3; x++ ) + { + ent->origin.x = base.x + offset[ x ]; + if ( G_TestEntityPosition( ent ) ) + { + ent->origin.x += offset[ x ]; + ent->origin.y += offset[ y ]; + ent->origin.z += offset[ z ]; + ent->setOrigin( ent->origin ); + return true; + } + } + } + } + + // can't find a good position, so put him back. + ent->origin = base; + + return false; + } +*/ + +/* +============ +G_Push + +Objects need to be moved back on a failed push, +otherwise riders would continue to slide. +============ +*/ +qboolean G_Push + ( + Entity *pusher, + Vector pushermove, + Vector pusheramove + ) + + { + Entity *check, *block; + gentity_t *edict; + Vector move, amove; + Vector mins, maxs; + Vector save; + pushed_t *p; + Vector org, org2, move2; + Vector norm; + float mat[ 3 ][ 3 ]; + pushed_t *pusher_p; + float radius; +#if 1 + int i, num; + int touch[ MAX_GENTITIES ]; +#else + gentity_t *next; +#endif + + // save the pusher's original position + pusher_p = pushed_p; + pushed_p->ent = pusher; + pushed_p->localorigin = pusher->localorigin; + pushed_p->origin = pusher->origin; + pushed_p->localangles = pusher->localangles; + pushed_p->angles = pusher->angles; + + if ( pusher->client ) + { + pushed_p->deltayaw = pusher->client->ps.delta_angles[ YAW ]; + } + + pushed_p++; + + if ( pushed_p >= &pushed[ MAX_GENTITIES ] ) + { + gi.Error( ERR_FATAL, "Pushed too many entities." ); + } + + // move the pusher to it's final position + pusher->addAngles( pusheramove ); + pusher->addOrigin( pushermove ); + + if ( pusher->edict->solid == SOLID_NOT ) + { + // Doesn't push anything + return true; + } + + // change the move to worldspace + move = pusher->origin - pusher_p->origin; + amove = pusher->angles - pusher_p->angles; + + // we need this for pushing things later + AnglesToAxis( amove, mat ); + + // find the bounding box + mins = pusher->absmin; + maxs = pusher->absmax; + +#if 1 + num = gi.AreaEntities( mins, maxs, touch, MAX_GENTITIES ); + for( i = 0; i < num; i++ ) + { + edict = &g_entities[ touch[ i ] ]; + assert( edict ); + assert( edict->inuse ); + assert( edict->entity ); + check = edict->entity; + + if ( check->movetype == MOVETYPE_PUSH || + check->movetype == MOVETYPE_STOP || + check->movetype == MOVETYPE_NONE || + check->movetype == MOVETYPE_NOCLIP ) + { + continue; + } +#else + // see if any solid entities are inside the final position + for( edict = active_edicts.next; edict != &active_edicts; edict = next ) + { + assert( edict ); + assert( edict->inuse ); + assert( edict->entity ); + + next = edict->next; + check = edict->entity; + + if ( check->movetype == MOVETYPE_PUSH || + check->movetype == MOVETYPE_STOP || + check->movetype == MOVETYPE_NONE || + check->movetype == MOVETYPE_NOCLIP ) + { + continue; + } +#endif + + if ( check->edict->contents == CONTENTS_SHOOTABLE_ONLY || check->edict->contents == CONTENTS_CORPSE ) + continue; + + // if the entity is standing on the pusher, it will definitely be moved + if ( check->groundentity != pusher->edict ) + { + // Only move triggers and non-solid objects if they're sitting on a moving object + if ( check->edict->solid == SOLID_TRIGGER || check->edict->solid == SOLID_NOT ) + { + continue; + } + + // 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 ( !G_TestEntityPosition( check ) ) + { + continue; + } + } + + if ( + ( pusher->movetype == MOVETYPE_PUSH ) || + ( check->groundentity == pusher->edict ) + ) + { + pushed_p->localorigin = check->localorigin; + pushed_p->localangles = check->localangles; + // move this entity + pushed_p->ent = check; + pushed_p->origin = check->origin; + pushed_p->angles = check->angles; + pushed_p++; + + if ( pushed_p >= &pushed[ MAX_GENTITIES ] ) + { + gi.Error( ERR_FATAL, "Pushed too many entities." ); + } + + // save off the origin + save = check->localorigin; + + // try moving the contacted entity + move2 = move; + + // FIXME: doesn't rotate monsters? + if ( check->client ) + { + check->client->ps.delta_angles[YAW] += ANGLE2SHORT( amove[ YAW ] ); + } + + // get the radius of the entity + if ( check->size.x > check->size.z ) + { + radius = check->size.z * 0.5; + } + else + { + radius = check->size.x * 0.5; + } + + // figure movement due to the pusher's amove + org = check->origin - pusher->origin; + org.z += radius; + + MatrixTransformVector( org, mat, org2 ); + + move2 += org2 - org; + + //FIXME + // We should probably do a flymove here so that we slide against other objects + check->addOrigin( check->getParentVector( move2 ) ); + + // may have pushed them off an edge + if ( check->groundentity != pusher->edict ) + { + check->groundentity = NULL; + } + + block = G_TestEntityPosition( check ); + if ( block ) + { + block = G_FixEntityPosition( check ); + } + if ( !block ) + { + // pushed ok + check->link(); + + // impact? + continue; + } + + // try to snap it to a good position + /* + if ( G_SnapPosition( check ) ) + { + // snapped ok. we don't have to link since G_SnapPosition does it for us. + 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 + check->setOrigin( save ); + block = G_TestEntityPosition( check ); + if ( !block ) + { + pushed_p--; + continue; + } + } + + if ( check->edict->solid == SOLID_NOT ) + 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-- ) + { + p->ent->angles = p->angles; + p->ent->origin = p->origin; + + p->ent->localangles = p->localangles; + p->ent->localorigin = p->localorigin; + + if ( p->ent->client ) + { + p->ent->client->ps.delta_angles[ YAW ] = p->deltayaw; + } + } + + // Only "really" move it in order so that the bound coordinate system is correct + for( p = pushed; p < pushed_p; p++ ) + { + p->ent->setAngles(); + p->ent->setOrigin(); + } + + 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-- ) + { + if ( p->ent->flags & FL_TOUCH_TRIGGERS ) + { + G_TouchTriggers( p->ent ); + } + } + + return true; + } + +/* +================ +G_PushMove +================ +*/ +qboolean G_PushMove + ( + Entity *ent, + Vector move, + Vector amove + ) + + { + Entity *part; + Vector m, a; + Event *ev; + + m = move; + a = amove; + + pushed_p = pushed; + for( part = ent; part; part = part->teamchain ) + { + if ( !G_Push( part, m, a ) ) + { + // move was blocked + // call the pusher's "blocked" function + // otherwise, just stay in place until the obstacle is gone + ev = new Event( EV_Blocked ); + ev->AddEntity( obstacle ); + part->ProcessEvent( ev ); + return false; + } + + m = vec_zero; + a = vec_zero; + } + + return true; + } + +/* +================ +G_Physics_Pusher + +Bmodel objects don't interact with each other, but +push all box objects +================ +*/ +void G_Physics_Pusher + ( + Entity *ent + ) + + { + Vector move, amove; + Entity *part, *mv; + Event *ev; + + // team slaves are only moved by their captains + if ( ent->flags & FL_TEAMSLAVE ) + { + return; + } + + // Check if anyone on the team is moving + for( part = ent; part; part = part->teamchain ) + { + if ( part->velocity != vec_zero || part->avelocity != vec_zero ) + { + break; + } + } + + // 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; + while( part ) + { + move = part->velocity * level.frametime; + amove = part->avelocity * level.frametime; + + if ( !G_Push( part, move, amove ) ) + { + // move was blocked + break; + } + + part = part->teamchain; + } + + if ( part ) + { + // the move failed, bump all movedone times + for( mv = ent; mv; mv = mv->teamchain ) + { + mv->PostponeEvent( EV_MoveDone, FRAMETIME ); + } + + // if the pusher has a "blocked" function, call it + // otherwise, just stay in place until the obstacle is gone + ev = new Event( EV_Blocked ); + ev->AddEntity( obstacle ); + part->ProcessEvent( ev ); + } + } + +//================================================================== + +/* +============= +G_Physics_Noclip + +A moving object that doesn't obey physics +============= +*/ +void G_Physics_Noclip + ( + Entity *ent + ) + + { + ent->angles += ent->avelocity * level.frametime; + ent->origin += ent->velocity * level.frametime; + ent->link(); + } + +/* +============================================================================== + +TOSS / BOUNCE + +============================================================================== +*/ + +/* +============= +G_Physics_Toss + +Toss, bounce, and fly movement. When onground, do nothing. +============= +*/ +void G_Physics_Toss + ( + Entity *ent + ) + + { + trace_t trace; + Vector move; + float backoff; + Entity *slave; + qboolean wasinwater; + qboolean isinwater; + Vector origin2; + Vector basevel; + gentity_t *edict; + qboolean onconveyor; + + // 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 && !ent->groundentity->inuse ) + { + ent->groundentity = NULL; + } + + onconveyor = ( basevel != vec_zero ); + + // if onground, return without moving + if ( ent->groundentity && !onconveyor && ( ent->movetype != MOVETYPE_VEHICLE ) ) + { + if ( ent->avelocity.length() ) + { + // move angles + ent->setAngles( ent->angles + ent->avelocity * level.frametime ); + } + ent->velocity = vec_zero; + return; + } + + origin2 = ent->origin; + + G_CheckVelocity( ent ); + + // add gravity + if ( !onconveyor && ent->movetype != MOVETYPE_FLY && ent->movetype != MOVETYPE_FLYMISSILE ) + { + G_AddGravity( ent ); + } + + // move angles + ent->setAngles( ent->angles + ent->avelocity * level.frametime ); + + // move origin + move = ( ent->velocity + basevel ) * level.frametime; + + edict = ent->edict; + if ( ent->movetype == MOVETYPE_VEHICLE ) + { + int mask; + + if ( ent->edict->clipmask ) + { + mask = ent->edict->clipmask; + } + else + { + mask = MASK_MONSTERSOLID; + } + G_FlyMove( ent, basevel, FRAMETIME, mask ); + if ( ent->flags & FL_TOUCH_TRIGGERS ) + { + G_TouchTriggers( ent ); + } + return; + } + else + { + trace = G_PushEntity( ent, move ); + } + + if ( (trace.fraction == 0) && (ent->movetype == MOVETYPE_SLIDE) ) + { + // Check for slide by removing the downward velocity + Vector slide; + + slide[ 0 ] = move[ 0 ] * 0.7f; + slide[ 1 ] = move[ 1 ] * 0.7f; + slide[ 2 ] = 0; + G_PushEntity( ent, slide ); + } + + if ( !edict->inuse ) + { + return; + } + + if ( trace.fraction < 1 ) + { + if ( ent->movetype == MOVETYPE_BOUNCE || ent->movetype == MOVETYPE_GIB ) + { + backoff = 1.5; + } + else + { + backoff = 1; + } + + G_ClipVelocity( ent->velocity, Vector( 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->movetype != MOVETYPE_GIB) ) && + (ent->movetype != MOVETYPE_SLIDE)) + { + ent->groundentity = trace.ent; + ent->groundplane = trace.plane; + ent->groundcontents = trace.contents; + ent->velocity = vec_zero; + ent->avelocity = vec_zero; + ent->ProcessEvent( EV_Stop ); + } + else if ( ent->movetype == MOVETYPE_GIB ) + { + // Stop spinning after we bounce on the ground + ent->avelocity = vec_zero; + } + } + } + + if ( ( move[ 2 ] == 0 ) && onconveyor ) + { + // Check if we still have a ground + ent->CheckGround(); + } + + // check for water transition + wasinwater = ( ent->watertype & MASK_WATER ); + ent->watertype = gi.pointcontents( ent->origin, 0 ); + isinwater = ent->watertype & MASK_WATER; + + if ( isinwater ) + { + ent->waterlevel = 1; + } + else + { + ent->waterlevel = 0; + } + + if ( ( edict->spawntime < ( level.time - FRAMETIME ) ) && ( ent->mass > 0 ) ) + { + if ( !wasinwater && isinwater ) + { + ent->Sound( "impact_watersplash", CHAN_BODY, DEFAULT_VOL, DEFAULT_MIN_DIST, &origin2 ); + } + else if ( wasinwater && !isinwater ) + { + ent->Sound( "impact_leavewater", CHAN_BODY, DEFAULT_VOL, DEFAULT_MIN_DIST, &origin2 ); + } + } + + // GAMEFIX - Is this necessary? + // move teamslaves + for( slave = ent->teamchain; slave; slave = slave->teamchain ) + { + slave->setOrigin( slave->localorigin ); + slave->setAngles( slave->localangles ); + } + + if ( ent->flags & FL_TOUCH_TRIGGERS ) + { + G_TouchTriggers( ent ); + } + } + +/* +=============================================================================== + +STEPPING MOVEMENT + +=============================================================================== +*/ + +void G_AddRotationalFriction + ( + Entity *ent + ) + + { + int n; + float adjustment; + + ent->angles += level.frametime * ent->avelocity; + adjustment = level.frametime * sv_stopspeed->value * sv_friction->value; + 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; + } + } + } + } + +/* +============= +G_CheckWater + +============= +*/ + +void G_CheckWater + ( + Entity *ent + ) + + { + if ( ent->isSubclassOf( Actor ) ) + { + ( ( Actor * )ent )->CheckWater(); + } + else + { + ent->watertype = gi.pointcontents( ent->origin, 0 ); + if ( ent->watertype & MASK_WATER ) + { + ent->waterlevel = 1; + } + else + { + ent->waterlevel = 0; + } + } + } + +/* +============= +G_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? +============= +*/ + +void G_Physics_Step + ( + Entity *ent + ) + + { + qboolean wasonground; + qboolean hitsound = false; + Vector vel; + float speed, newspeed, control; + float friction; + int mask; + Vector basevel; + + // airborn monsters should always check for ground + if ( !ent->groundentity ) + { + ent->CheckGround(); + } + + if ( ent->groundentity ) + { + wasonground = true; + } + else + { + wasonground = false; + } + + G_CheckVelocity( ent ); + + if ( ent->avelocity != vec_zero ) + { + G_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 * ent->gravity * -0.1 ) + { + hitsound = true; + } + + // Testing water gravity. If this doesn't work, just restore the uncommented lines + //if ( ent->waterlevel == 0 ) + //{ + G_AddGravity( ent ); + //} + } + } + } + + // friction for flying monsters that have been given vertical velocity + if ( ( ent->flags & FL_FLY ) && ( ent->velocity.z != 0 ) ) + { + speed = fabs( ent->velocity.z ); + control = speed < sv_stopspeed->value ? sv_stopspeed->value : speed; + friction = sv_friction->value / 3; + newspeed = speed - ( level.frametime * control * friction ); + if ( newspeed < 0 ) + { + newspeed = 0; + } + newspeed /= speed; + ent->velocity.z *= newspeed; + } + + // friction for flying monsters that have been given vertical velocity + if ( ( ent->flags & FL_SWIM ) && ( ent->velocity.z != 0 ) ) + { + speed = fabs( ent->velocity.z ); + control = speed < sv_stopspeed->value ? sv_stopspeed->value : speed; + newspeed = speed - ( level.frametime * control * sv_waterfriction->value * ent->waterlevel ); + if ( newspeed < 0 ) + { + newspeed = 0; + } + newspeed /= speed; + ent->velocity.z *= newspeed; + } + + if ( ent->velocity != vec_zero ) + { + // 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; + vel.z = 0; + speed = vel.length(); + if ( speed ) + { + friction = sv_friction->value; + + control = speed < sv_stopspeed->value ? sv_stopspeed->value : speed; + newspeed = speed - level.frametime * control * friction; + + if ( newspeed < 0 ) + { + newspeed = 0; + } + + newspeed /= speed; + + ent->velocity.x *= newspeed; + ent->velocity.y *= newspeed; + } + } + } + } + + if ( ( basevel != vec_zero ) || ( ent->velocity != vec_zero ) || ( ent->total_delta != vec_zero ) ) + { + if ( ent->edict->svflags & SVF_MONSTER ) + { + mask = ent->edict->clipmask; + } + else + { + mask = MASK_SOLID; + } + + G_FlyMove( ent, basevel, level.frametime, mask ); + + ent->link(); + + G_CheckWater( ent ); + if ( ent->flags & FL_TOUCH_TRIGGERS ) + { + G_TouchTriggers( ent ); + } + + if ( ent->groundentity && !wasonground && hitsound ) + { + ent->Sound( "impact_softland", CHAN_BODY, 0.5f ); + } + } + } + +//============================================================================ + +/* +================ +G_RunEntity + +================ +*/ +void G_RunEntity + ( + Entity *ent + ) + + { + gentity_t *edict; + + edict = ent->edict; + + if ( edict->inuse && ( ent->flags & FL_THINK ) ) + { + ent->Think(); + } + + // only run physics if in use and not bound and not immobilized + if ( edict->inuse && ( edict->s.parent == ENTITYNUM_NONE ) && !(ent->flags & FL_IMMOBILE) && !(ent->flags & FL_PARTIAL_IMMOBILE) ) + { + switch ( ( int )ent->movetype ) + { + case MOVETYPE_PUSH: + case MOVETYPE_STOP: + G_Physics_Pusher( ent ); + break; + case MOVETYPE_NONE: + case MOVETYPE_STATIONARY: + case MOVETYPE_WALK: + break; + case MOVETYPE_NOCLIP: + G_Physics_Noclip( ent ); + break; + case MOVETYPE_STEP: + G_Physics_Step( ent ); + break; + case MOVETYPE_TOSS: + case MOVETYPE_BOUNCE: + case MOVETYPE_GIB: + case MOVETYPE_FLY: + case MOVETYPE_FLYMISSILE: + case MOVETYPE_SLIDE: + case MOVETYPE_VEHICLE: + G_Physics_Toss( ent ); + break; + case MOVETYPE_ROPE: + G_Physics_Rope(((RopePiece *)ent)); + break; + default: + gi.Error( ERR_DROP, "G_Physics: bad movetype %i", ( int )ent->movetype ); + } + } + if ( ( edict->inuse ) && ( ent->flags & FL_POSTTHINK ) ) + { + ent->Postthink(); + } + } + diff --git a/source/source/fgame/g_phys.h b/source/source/fgame/g_phys.h new file mode 100644 index 0000000..906a9c3 --- /dev/null +++ b/source/source/fgame/g_phys.h @@ -0,0 +1,93 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/g_phys.h $ +// $Revision:: 10 $ +// $Author:: Markd $ +// $Date:: 6/30/00 10:45a $ +// +// Copyright (C) 1998 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source is may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/g_phys.h $ +// +// 10 6/30/00 10:45a Markd +// added MOVETYPE_STATIONARY and revamped some physics +// +// 9 6/14/00 11:18a Markd +// cleaned up code using Intel compiler +// +// 8 3/21/00 5:06p Markd +// added vehicle support +// +// 7 2/24/00 4:17p Jimdose +// removed duplicate definition of STEPSIZE +// +// 6 1/29/00 12:32p Jimdose +// removed MOVETYPE_HURL +// +// 5 1/21/00 6:47p Steven +// Added a STEPMOVE_BLOCKED_BY_DOOR for AI pathfinding. +// +// 4 1/12/00 4:31p Steven +// Added new movetype MOVETYPE_GIB. +// +// 3 12/17/99 8:26p Jimdose +// got rid of unused vars and functions +// +// 2 10/28/99 10:42a Aldie +// Added rope functions +// +// 1 9/10/99 10:54a Jimdose +// +// 1 9/08/99 3:16p Aldie +// +// DESCRIPTION: +// Global header file for g_phys.cpp +// + +#ifndef __G_PHYS_H__ +#define __G_PHYS_H__ + +#include "g_local.h" +#include "entity.h" + +typedef enum + { + STEPMOVE_OK, + STEPMOVE_BLOCKED_BY_ENTITY, + STEPMOVE_BLOCKED_BY_WORLD, + STEPMOVE_BLOCKED_BY_WATER, + STEPMOVE_BLOCKED_BY_FALL, + STEPMOVE_BLOCKED_BY_DOOR, + STEPMOVE_STUCK + } stepmoveresult_t; + +// movetype values +typedef enum + { + MOVETYPE_NONE, // never moves + MOVETYPE_STATIONARY, // never moves but does collide agains push objects + 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_FLYMISSILE, // extra size to monsters + MOVETYPE_BOUNCE, + MOVETYPE_SLIDE, + MOVETYPE_ROPE, + MOVETYPE_GIB, + MOVETYPE_VEHICLE + } movetype_t; + +void G_RunEntity( Entity *ent ); +void G_Impact( Entity *e1, trace_t *trace ); +qboolean G_PushMove( Entity *pusher, Vector move, Vector amove ); +void G_CheckWater( Entity *ent ); + +#endif /* g_phys.h */ diff --git a/source/source/fgame/g_public.h b/source/source/fgame/g_public.h new file mode 100644 index 0000000..a926418 --- /dev/null +++ b/source/source/fgame/g_public.h @@ -0,0 +1,529 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/g_public.h $ +// $Revision:: 42 $ +// $Author:: Aldie $ +// $Date:: 7/16/00 2:09p $ +// +// Copyright (C) 1998 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/g_public.h $ +// +// 42 7/16/00 2:09p Aldie +// Changed some of the player logging +// +// 41 7/14/00 8:21p Aldie +// Added logstats +// +// 40 7/10/00 6:33p Aldie +// Added SVF_SENDONCE flag and water power for swiping determination +// +// 39 7/06/00 7:48p Markd +// Added LevelArchiveValid function +// +// 38 6/16/00 5:14p Aldie +// Added locational printing (print anywhere on the screen) +// +// 37 6/15/00 8:04p Markd +// Added CleanupGame +// +// 36 6/14/00 11:18a Markd +// cleaned up code using Intel compiler +// +// 35 6/13/00 3:46p Steven +// Added saving alias stuff. +// +// 34 6/10/00 4:23p Markd +// rewrote map restarting and loading out of date save games +// +// 33 6/05/00 3:11p Markd +// fixed HasCommands calls in server +// +// 32 6/02/00 4:26p Markd +// renamed ReadGame functions to ReadPersistant +// +// 31 5/27/00 8:07p Markd +// Saved games 3rd pass +// +// 30 5/11/00 11:13a Steven +// Added pointbrushnum. +// +// 29 3/31/00 11:51a Markd +// Added SetSkyPortal method +// +// 28 3/04/00 11:48a Markd +// Added light style support +// +// 27 2/14/00 5:38p Jimdose +// added uselegs to Tag_OrientationEx +// +// 26 2/01/00 4:11p Markd +// Added Frame bounding box support +// +// 25 1/27/00 11:35a Markd +// Fixed solid/notsolid client side entities +// +// 24 1/22/00 5:08p Steven +// Added ClipToEntity to exported interface. +// +// 23 1/20/00 6:57p Markd +// removed get_lip functions and merged them with SoundLength and +// SoundAmplitudes +// +// 22 1/20/00 5:20p Markd +// Added skin support into the game +// +// 21 1/19/00 8:50p Jimdose +// added Anim_AbsolueDelta +// +// 20 1/11/00 7:29p Jimdose +// added Tag_OrientationEx +// +// 19 1/10/00 5:33p Markd +// Cleaned up memory allocation routines +// +// 18 12/17/99 6:35p Jimdose +// changed spawnarg code +// added Level class for spawning and map control +// got rid of unused or superflous variables +// changed setjmp/longjmp calls to try/throw/catch exception handling +// +// 17 12/11/99 3:37p Markd +// q3a gold checkin, first time +// +// 16 12/06/99 6:41p Jimdose +// removed fulltrace, cvar_forceset, and Surface_DamageMultiplier +// +// 15 11/01/99 4:01p Jimdose +// made tags work with bone controllers +// +// 14 10/25/99 6:39p Markd +// removed size and other unused variables, added radius and centroid to both +// server and game code +// +// 13 10/19/99 7:52p Markd +// Removed three part model system +// +// 12 10/05/99 5:03p Markd +// Removed un-used game function ClientPredict +// +// 11 10/05/99 2:05p Markd +// Added SVF_SENDPVS which forces an entity to be checked by the PVS for +// sending and not trivially rejected because of lack of modelindex or sound +// +// 10 10/01/99 6:31p Markd +// added commands hidden inside fgame so that they would show up for command +// completion +// +// 9 9/28/99 4:26p Markd +// merged listener, class and vector between 3 projects +// +// 8 9/20/99 4:50p Markd +// fixed memory allocation for snapshot entities, put in farplane culling on +// entities being sent over the net +// +// 7 9/16/99 4:51p Jimdose +// changed ClientConnect +// added setUserInfo and getUserInfo +// +// 6 9/15/99 6:57p Aldie +// Update to get game working +// +// 5 9/14/99 2:38p Aldie +// code merge +// +// 4 9/13/99 6:18p Aldie +// code merge +// +// 3 9/13/99 4:22p Jimdose +// merge +// +// 2 9/13/99 3:27p Aldie +// code merge +// +// 1 9/10/99 10:54a Jimdose +// +// 1 9/08/99 3:16p Aldie +// +// 27 8/19/99 6:59p Markd +// removed the old tiki_cmd structure, now tiki_cmd_t is passed into the tiki +// functions +// +// 26 8/18/99 3:28p Jimdose +// added cylindrical collision detection +// +// 25 8/17/99 5:08p Markd +// Changed all FS_ReadFile's to FS_ReadFileEx's in game code +// +// 24 7/30/99 7:53p Markd +// Added jumping ability to the player +// +// 23 7/29/99 11:41a Markd +// Added precache and global support +// +// 22 7/07/99 11:26a Steven +// Added some stuff on the sector pathfinding approach. +// +// DESCRIPTION: +// Game module information visible to server + + +#ifndef __G_PUBLIC_H__ +#define __G_PUBLIC_H__ + +#define GAME_API_VERSION 4 + +#define FRAMETIME ( level.fixedframetime ) + +// entity->svFlags +// the server does not know how to interpret most of the values +// in entityStates (level eType), so the game must explicitly flag +// special server behaviors +#define SVF_NOCLIENT (1<<0) // don't send entity to clients, even if it has effects +#define SVF_BOT (1<<1) +#define SVF_BROADCAST (1<<2) // send to all connected clients +#define SVF_PORTAL (1<<3) // merge a second pvs at origin2 into snapshots +#define SVF_SENDPVS (1<<4) // even though it doesn't have a sound or modelindex, still run it through the pvs +#define SVF_USE_CURRENT_ORIGIN (1<<5) // entity->currentOrigin instead of entity->s.origin + // for link position (missiles and movers) +#define SVF_DEADMONSTER (1<<6) // treat as CONTENTS_DEADMONSTER for collision +#define SVF_MONSTER (1<<7) // treat as CONTENTS_MONSTER for collision +#define SVF_USEBBOX (1<<9) // do not perform perfect collision use the bbox instead +#define SVF_ONLYPARENT (1<<10) // only send this entity to its parent +#define SVF_HIDEOWNER (1<<11) // hide the owner of the client +#define SVF_MONSTERCLIP (1<<12) // treat as CONTENTS_MONSTERCLIP for collision +#define SVF_PLAYERCLIP (1<<13) // treat as CONTENTS_PLAYERCLIP for collision +#define SVF_SENDONCE (1<<14) // Send this entity over the network at least one time +#define SVF_SENT (1<<15) // This flag is set when the entity has been sent over at least one time + +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; + +//=============================================================== + +typedef struct gentity_s gentity_t; +typedef struct gclient_s gclient_t; + +#ifndef GAME_INCLUDE + +// the server needs to know enough information to handle collision and snapshot generation + +struct gentity_s + { + entityState_t s; // communicated by server to clients + struct playerState_s *client; + qboolean inuse; + qboolean linked; // qfalse if not in any good cluster + int linkcount; + + int svFlags; // SVF_NOCLIENT, SVF_BROADCAST, etc + + qboolean bmodel; // if false, assume an explicit mins / maxs bounding box + // only set by gi.SetBrushModel + vec3_t mins, maxs; + int contents; // CONTENTS_TRIGGER, CONTENTS_SOLID, CONTENTS_BODY, etc + // a non-solid entity should set to 0 + + vec3_t absmin, absmax; // derived from mins/maxs and origin + rotation + + float radius; // radius of object + vec3_t centroid; // centroid, to be used with radius + int areanum; // areanum needs to be seen inside the game as well + + // currentOrigin will be used for all collision detection and world linking. + // it will not necessarily be the same as the trajectory evaluation for the current + // time, because each entity must be moved one at a time after time is advanced + // to avoid simultanious collision issues + vec3_t currentOrigin; + vec3_t currentAngles; + + // when a trace call is made and passEntityNum != ENTITYNUM_NONE, + // an ent will be excluded from testing if: + // ent->s.number == passEntityNum (don't interact with self) + // ent->s.ownerNum = passEntityNum (don't interact with your own missiles) + // entity[ent->s.ownerNum].ownerNum = passEntityNum (don't interact with other missiles from owner) + int ownerNum; + //gentity_t *owner; // objects never interact with their owners, to + // prevent player missiles from immediately + // colliding with their owner + + solid_t solid; + // the game dll can add anything it wants after + // this point in the structure + }; + +#endif // GAME_INCLUDE + +//=============================================================== + +// +// functions provided by the main engine +// +typedef struct + { + //============== general Quake services ================== + + // print message on the local console + void (*Printf)( const char *fmt, ... ); + void (*DPrintf)( const char *fmt, ... ); + void (*DebugPrintf)( const char *fmt, ... ); + + // abort the game + void (*Error)( int errorLevel, const char *fmt, ... ); + + // get current time for profiling reasons this should NOT be used for any game related tasks, + // because it is not journaled + int (*Milliseconds)( void ); + + // managed memory allocation + void *(*Malloc)( int size ); + void (*Free)( void *block ); + + // console variable interaction + cvar_t *(*cvar)( const char *var_name, const char *value, int flags ); + void (*cvar_set)( const char *var_name, const char *value ); + + // ClientCommand and ServerCommand parameter access + int (*argc)( void ); + char *(*argv)( int n ); + const char *(*args)(void); + void (*AddCommand)( const char *cmd ); + + // 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_ReadFile)( const char *name, void **buf, qboolean quiet ); + void (*FS_FreeFile)( void *buf ); + void (*FS_WriteFile)( const char *qpath, const void *buffer, int size ); + fileHandle_t (*FS_FOpenFileWrite)( const char *qpath ); + fileHandle_t (*FS_FOpenFileAppend)( const char *filename ); + + char * (*FS_PrepFileWrite)( const char *filename ); + int (*FS_Write)( const void *buffer, int len, fileHandle_t f ); + int (*FS_Read)( void *buffer, int len, fileHandle_t f ); + void (*FS_FCloseFile)( fileHandle_t f ); + int (*FS_FTell)( fileHandle_t f ); + int (*FS_FSeek)( fileHandle_t f, long offset, int origin ); + void (*FS_Flush)( fileHandle_t f ); + + const char * (*GetArchiveFileName)( const char *filename, const char *extension ); + // add commands to the console as if they were typed in for map changing, etc + void (*SendConsoleCommand)( const char *text ); + void (*DebugGraph)( float value, int color ); + + //=========== server specific functionality ============= + + // SendServerCommand reliably sends a command string to be interpreted by the given + // client. If ent is NULL, it will be sent to all clients + void (*SendServerCommand)( int clientnum, const char *fmt, ... ); + + // config strings hold all the index strings, the lightstyles, and misc data like the cdtrack. + // All of the current configstrings are sent to clients when they connect, and + // changes are sent to all connected clients. + void (*setConfigstring)( int index, const char *val ); + char * (*getConfigstring)( int index ); + + void (*setUserinfo)( int index, const char *val ); + void (*getUserinfo)( int index, char *buffer, int bufferSize ); + + // sets mins and maxs based on the brushmodel name + void (*SetBrushModel)( gentity_t *ent, const char *name ); + + // collision detection + void (*trace)( trace_t *result, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int passEntityNum, int contentmask, qboolean cylinder ); + int (*pointcontents)( const vec3_t point, int passEntityNum ); + int (*pointbrushnum)( const vec3_t point, int passEntityNum ); + qboolean (*inPVS)( vec3_t p1, vec3_t p2 ); + qboolean (*inPVSIgnorePortals)( vec3_t p1, vec3_t p2 ); + void (*AdjustAreaPortalState)( gentity_t *ent, 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)( gentity_t *ent ); + void (*unlinkentity)( gentity_t *ent ); // call before removing an interactive entity + + // EntitiesInBox will perform exact checking to bmodels, as well as bounding box + // intersection tests to other models + int (*AreaEntities)( vec3_t mins, vec3_t maxs, int *list, int maxcount ); + void (*ClipToEntity)( trace_t *trace, const vec3_t start, const vec3_t mins, const vec3_t maxs, const vec3_t end, int entityNum, int contentmask ); + + + int (*imageindex)( const char *name ); + int (*itemindex)( const char *name ); + int (*soundindex)( const char *name ); + int (*modelindex)( const char *name ); + + void (*SetLightStyle)( int i, const char *data ); + + const char *(*GameDir)( void ); + + // + // MODEL UTILITY FUNCTIONS + // + qboolean (*IsModel)( int index ); + void (*setmodel)( gentity_t *ent, const char *name ); + + // DEF SPECIFIC STUFF + int (*NumAnims)( int modelindex ); + int (*NumSkins)( int modelindex ); + int (*NumSurfaces)( int modelindex ); + int (*NumTags)( int modelindex ); + qboolean (*InitCommands)( int modelindex, tiki_cmd_t * tiki_cmd ); + void (*CalculateBounds)( int modelindex, float scale, vec3_t mins, vec3_t maxs ); + + // ANIM SPECIFIC STUFF + const char * (*Anim_NameForNum)( int modelindex, int animnum ); + int (*Anim_NumForName)( int modelindex, const char * name ); + int (*Anim_Random)( int modelindex, const char * name ); + int (*Anim_NumFrames)( int modelindex, int animnum ); + float (*Anim_Time)( int modelindex, int animnum ); + void (*Anim_Delta)( int modelindex, int animnum, vec3_t delta ); + void (*Anim_AbsoluteDelta)( int modelindex, int animnum, vec3_t delta ); + int (*Anim_Flags)( int modelindex, int animnum ); + qboolean (*Anim_HasCommands) ( int modelindex, int animnum ); + + // FRAME SPECIFIC STUFF + qboolean (*Frame_Commands)( int modelindex, int animnum, int framenum, tiki_cmd_t * tiki_cmd ); + void (*Frame_Delta)( int modelindex, int animnum, int framenum, vec3_t delta ); + float (*Frame_Time)( int modelindex, int animnum, int framenum ); + void (*Frame_Bounds)( int modelindex, int animnum, int framenum, float scale, vec3_t mins, vec3_t maxs ); + + // SURFACE SPECIFIC STUFF + int (*Surface_NameToNum)( int modelindex, const char * name ); + const char * (*Surface_NumToName)( int modelindex, int num ); + int (*Surface_Flags)( int modelindex, int num ); + int (*Surface_NumSkins)( int modelindex, int num ); + + // TAG SPECIFIC STUFF + int (*Tag_NumForName)( int modelindex, const char * name ); + const char * (*Tag_NameForNum)( int modelindex, int num ); + orientation_t (*Tag_Orientation)( int modelindex, int anim, int frame, int num, float scale, int *bone_tag, vec4_t *bone_quat ); + orientation_t (*Tag_OrientationEx)( int modelindex, int anim, int frame, int num, float scale, int *bone_tag, vec4_t *bone_quat, + int crossblend_anim, int crossblend_frame, float crossblend_lerp, qboolean uselegs, qboolean usetorso, int torso_anim, int torso_frame, + int torso_crossblend_anim, int torso_crossblend_frame, float torso_crossblend_lerp ); + + qboolean (*Alias_Add)( int modelindex, const char * alias, const char * name, const char *parameters ); + const char * (*Alias_FindRandom)( int modelindex, const char * alias ); + void (*Alias_Dump)( int modelindex ); + void (*Alias_Clear)( int modelindex ); + const char * (*Alias_FindDialog)( int modelindex, const char * alias, int random, int entity_number ); + void *(*Alias_GetList)( int modelindex ); + void (*Alias_UpdateDialog)( int model_index, const char *alias, int number_of_times_played, byte been_played_this_loop, int last_time_played ); + void (*Alias_AddActorDialog)( int model_index, const char *alias, int actor_number, int number_of_times_played, byte been_played_this_loop, int last_time_played ); + + + const char * (*NameForNum)( int modelindex ); + + // GLOBAL ALIAS SYSTEM + qboolean (*GlobalAlias_Add)( const char * alias, const char * name, const char *parameters ); + const char * (*GlobalAlias_FindRandom)( const char * alias ); + void (*GlobalAlias_Dump)( void ); + void (*GlobalAlias_Clear)( void ); + + void (*centerprintf)( gentity_t *ent, const char *fmt, ...); + void (*locationprintf)( gentity_t *ent, int x, int y, const char *fmt, ...); + + // Sound + void (*Sound)( vec3_t *org, int entnum, int channel, const char *sound_name, float volume, float attenuation ); + void (*StopSound)( int entnum, int channel ); + float (*SoundLength) ( const char *path ); + byte *(*SoundAmplitudes)( const char * name, int *number_of_amplitudes ); + + + unsigned short (*CalcCRC)(const unsigned char *start, int count); + + debugline_t **DebugLines; + int *numDebugLines; + + void (*LocateGameData)( gentity_t *gEnts, int numGEntities, int sizeofGEntity_t, + playerState_t *clients, int sizeofGameClient ); + + void (*SetFarPlane)( int farplane ); + void (*SetSkyPortal)( qboolean skyportal ); + + } game_import_t; + +// +// functions exported by the game subsystem +// +typedef struct { + int apiversion; + + // 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) ( int startTime, int randomSeed); + void (*Shutdown) (void); + void (*Cleanup) (void); + + // each new level entered will cause a call to SpawnEntities + void (*SpawnEntities) (const char *mapname, const char *entstring, int levelTime); + + // return NULL if the client is allowed to connect, otherwise return + // a text string with the reason for denial + char *(*ClientConnect)( int clientNum, qboolean firstTime ); + + void (*ClientBegin)( gentity_t *ent, usercmd_t *cmd ); + void (*ClientUserinfoChanged)( gentity_t *ent, const char *userinfo ); + void (*ClientDisconnect)( gentity_t *ent ); + void (*ClientCommand)( gentity_t *ent ); + void (*ClientThink)( gentity_t *ent, usercmd_t *cmd ); + + void (*BotBegin)( gentity_t *ent ); + void (*BotThink)( gentity_t *ent, int msec ); + + void (*PrepFrame)( void ); + void (*RunFrame)( int levelTime, int frameTime ); + + // ConsoleCommand will be called when a command has been issued + // that is not recognized as a builtin function. + // The game can issue gi.argc() / gi.argv() commands to get the command + // and parameters. Return qfalse if the game doesn't recognize it as a command. + qboolean (*ConsoleCommand)( void ); + + // Read/Write Persistant 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 every time a level is entered. + void (*WritePersistant)( const char *filename ); + qboolean (*ReadPersistant)( const 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)( const char *filename, qboolean autosave ); + qboolean (*ReadLevel)( const char *filename ); + qboolean (*LevelArchiveValid)( const char *filename ); + + // + // global variables shared between game and server + // + + // The gentities 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 + // the server can't just use pointer arithmetic on gentities, because the + // server's sizeof(struct gentity_s) doesn't equal gentitySize + struct gentity_s *gentities; + int gentitySize; + int num_entities; // current number, <= max_entities + int max_entities; + + const char *error_message; +} game_export_t; + +game_export_t *GetGameApi (game_import_t *import); + +#endif // __G_PUBLIC_H__ + diff --git a/source/source/fgame/g_spawn.cpp b/source/source/fgame/g_spawn.cpp new file mode 100644 index 0000000..8e2d44c --- /dev/null +++ b/source/source/fgame/g_spawn.cpp @@ -0,0 +1,606 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/g_spawn.cpp $ +// $Revision:: 22 $ +// $Author:: Markd $ +// $Date:: 7/27/00 9:52p $ +// +// Copyright (C) 1998 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source is may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/g_spawn.cpp $ +// +// 22 7/27/00 9:52p Markd +// Added FindClass function +// +// 21 6/14/00 4:06p Markd +// fixed two typos +// +// 20 6/14/00 3:50p Markd +// Cleaned up more Intel Compiler warnings +// +// 19 5/26/00 7:44p Markd +// 2nd phase save games +// +// 18 5/24/00 3:14p Markd +// first phase of save/load games +// +// 17 1/26/00 7:00p Markd +// fixed imbedded labels in entity scripts +// +// 16 1/10/00 5:28p Markd +// inhibited all lights from spawning +// +// 15 1/07/00 6:34p Steven +// Don't spawn an actor if the model is not found. +// +// 14 12/17/99 6:35p Jimdose +// changed spawnarg code +// added Level class for spawning and map control +// got rid of unused or superflous variables +// changed setjmp/longjmp calls to try/throw/catch exception handling +// +// 13 12/06/99 6:39p Jimdose +// changed call to cvar_forceset to cvar_set +// +// 12 10/06/99 7:26p Markd +// simplified makestatic code +// +// 11 10/06/99 7:25p Markd +// removed TIMESTAMP, time and fixed make_static bug +// +// 10 10/06/99 7:04p Markd +// Added make_static support +// +// 9 10/06/99 6:25p Markd +// put in MAKE_STATIC support into spawn code +// +// 8 10/04/99 10:47a Markd +// Fixed assertions which were actually errors +// +// 7 10/01/99 4:52p Markd +// Made Warning level 4 work on all projects +// +// 6 9/29/99 11:52a Markd +// removed some unused enums and variables form shared headers between cgame +// and fgame +// +// 5 9/28/99 4:26p Markd +// merged listener, class and vector between 3 projects +// +// 4 9/16/99 4:48p Jimdose +// removed unused code +// +// 3 9/16/99 11:18a Markd +// Continuing merge of code, not functional yet but closer +// +// 2 9/15/99 6:57p Aldie +// Update to get game working +// +// 1 9/10/99 10:54a Jimdose +// +// 1 9/08/99 3:16p Aldie +// +// 20 8/30/99 8:09p Markd +// made bad classname a developer 2 bug +// +// 19 8/28/99 3:42p Jimdose +// changed some doubles to floats +// +// 18 8/25/99 12:42p Markd +// Fixed some minor and major scripting bugs +// +// 17 8/19/99 6:59p Markd +// removed the old tiki_cmd structure, now tiki_cmd_t is passed into the tiki +// functions +// +// 16 8/17/99 3:20p Markd +// Fixed spawn issues with "script" key-value pair +// +// 15 8/02/99 11:19a Markd +// plugged potential empty line script bug +// +// 14 8/02/99 10:52a Markd +// Put in \n delimiters into initialization script +// +// 13 7/29/99 11:41a Markd +// Added precache and global support +// +// 12 6/18/99 6:00p Markd +// Added Script Initialization for most objects +// +// DESCRIPTION: +// + +#include "g_local.h" +#include "class.h" +#include "Entity.h" +#include "g_spawn.h" +#include "navigate.h" +#include "player.h" +#include "gravpath.h" +#include "object.h" + +CLASS_DECLARATION( Class, SpawnArgs, NULL ) + { + { NULL, NULL } + }; + +SpawnArgs::SpawnArgs() + { + } + +SpawnArgs::SpawnArgs + ( + SpawnArgs &otherlist + ) + + { + int num; + int i; + + num = otherlist.NumArgs(); + keyList.Resize( num ); + valueList.Resize( num ); + for( i = 1; i <= num; i++ ) + { + keyList.AddObject( otherlist.keyList.ObjectAt( i ) ); + valueList.AddObject( otherlist.valueList.ObjectAt( i ) ); + } + } + +void SpawnArgs::Clear + ( + void + ) + + { + keyList.FreeObjectList(); + valueList.FreeObjectList(); + } + +/* +==================== +Parse + +Parses spawnflags out of the given string, returning the new position. +Clears out any previous args. +==================== +*/ +const char *SpawnArgs::Parse + ( + const char *data + ) + + { + str keyname; + const char *com_token; + + Clear(); + + // parse the opening brace + com_token = COM_Parse( &data ); + if ( !data ) + { + return NULL; + } + + if ( com_token[ 0 ] != '{' ) + { + gi.Error( ERR_DROP, "SpawnArgs::Parse : found %s when expecting {", com_token ); + } + + // go through all the dictionary pairs + while( 1 ) + { + // parse key + com_token = COM_Parse( &data ); + if ( com_token[ 0 ] == '}' ) + { + break; + } + + if ( !data ) + { + gi.Error( ERR_DROP, "SpawnArgs::Parse : EOF without closing brace" ); + } + + keyname = com_token; + + // parse value + com_token = COM_Parse( &data ); + if ( !data ) + { + gi.Error( ERR_DROP, "SpawnArgs::Parse : EOF without closing brace" ); + } + + if ( com_token[ 0 ] == '}' ) + { + gi.Error( ERR_DROP, "SpawnArgs::Parse : closing brace without data" ); + } + + // keynames with a leading underscore are used for utility comments, + // and are immediately discarded by Fakk + if ( keyname[ 0 ] == '_' ) + { + continue; + } + + setArg( keyname.c_str(), com_token ); + } + + return data; + } + +const char *SpawnArgs::getArg + ( + const char *key, + const char *defaultValue + ) + + { + int i; + int num; + + num = keyList.NumObjects(); + for( i = 1; i <= num; i++ ) + { + if ( keyList.ObjectAt( i ) == key ) + { + return valueList.ObjectAt( i ); + } + } + + return defaultValue; + } + +void SpawnArgs::setArg + ( + const char *key, + const char *value + ) + + { + int i; + int num; + + num = keyList.NumObjects(); + for( i = 1; i <= num; i++ ) + { + if ( keyList.ObjectAt( i ) == key ) + { + valueList.ObjectAt( i ) = value; + return; + } + } + + keyList.AddObject( str( key ) ); + valueList.AddObject( str( value ) ); + } + +void SpawnArgs::operator= + ( + SpawnArgs &otherlist + ) + + { + int num; + int i; + + Clear(); + + num = otherlist.NumArgs(); + keyList.Resize( num ); + valueList.Resize( num ); + + for( i = 1; i <= num; i++ ) + { + keyList.AddObject( otherlist.keyList.ObjectAt( i ) ); + valueList.AddObject( otherlist.valueList.ObjectAt( i ) ); + } + } + +int SpawnArgs::NumArgs + ( + void + ) + + { + return keyList.NumObjects(); + } + +const char *SpawnArgs::getKey + ( + int index + ) + + { + return keyList.ObjectAt( index + 1 ); + } + +const char *SpawnArgs::getValue + ( + int index + ) + + { + return valueList.ObjectAt( index + 1 ); + } + +void SpawnArgs::Archive + ( + Archiver &arc + ) + + { + Class::Archive( arc ); + + keyList.Archive( arc ); + valueList.Archive( arc ); + } + +/* +=============== +getClass + +Finds the spawn function for the entity and returns ClassDef * +=============== +*/ + +ClassDef *SpawnArgs::getClassDef + ( + qboolean *tikiWasStatic + ) + + { + const char *classname; + ClassDef *cls = NULL; + + classname = getArg( "classname" ); + + if ( tikiWasStatic ) + { + *tikiWasStatic = qfalse; + } + + // + // check normal spawn functions + // see if the class name is stored within the model + // + if ( classname ) + { + // + // explicitly inhibit lights + // + if ( !strcmpi( classname, "light" ) ) + { + // + // HACK HACK HACK + // hack to suppress a warning message + // + if ( tikiWasStatic ) + { + *tikiWasStatic = qtrue; + } + return NULL; + } + + cls = getClassForID( classname ); + if ( !cls ) + { + cls = getClass( classname ); + } + } + + if ( !cls ) + { + const char *model; + + // + // get Object in case we cannot find an alternative + // + cls = &Object::ClassInfo; + model = getArg( "model" ); + if ( model ) + { + tiki_cmd_t cmds; + int modelindex; + int i; + + // + // get handle to def file + // + if ( ( strlen( model ) >= 3 ) && ( !strcmpi( &model[ strlen(model) - 3 ], "tik" ) ) ) + { + modelindex = modelIndex( model ); + + if ( modelindex == -1 ) + return NULL; + + if ( gi.IsModel( modelindex ) ) + { + const char * s; + + s = getArg( "make_static" ); + if ( s && atoi( s ) ) + { + // + // if make_static then we don't want to spawn + // + if ( tikiWasStatic ) + { + *tikiWasStatic = qtrue; + } + + return NULL; + } + + if ( gi.InitCommands( modelindex, &cmds ) ) + { + for( i = 0; i < cmds.num_cmds; i++ ) + { + if ( !strcmpi( cmds.cmds[ i ].args[ 0 ], "classname" ) ) + { + cls = getClass( cmds.cmds[ i ].args[ 1 ] ); + break; + } + } + if ( i == cmds.num_cmds ) + { + if ( developer->integer == 2 ) + gi.DPrintf( "Classname %s used, but 'classname' was not found in Initialization commands, using Object.\n", classname ); + } + } + else + gi.DPrintf( "Classname %s used, but TIKI had no Initialization commands, using Object.\n", classname ); + } + else + gi.DPrintf( "Classname %s used, but TIKI was not valid, using Object.\n", classname ); + } + else + gi.DPrintf( "Classname %s used, but model was not a TIKI, using Object.\n", classname ); + } + else + { + gi.DPrintf( "Classname %s' used, but no model was set, using Object.\n", classname ); + } + } + + return cls; + } + +/* +=============== +Spawn + +Finds the spawn function for the entity and calls it. +Returns pointer to Entity +=============== +*/ + +Entity *SpawnArgs::Spawn + ( + void + ) + + { + str classname; + ClassDef *cls; + Entity *obj; + Event *ev; + int i; + qboolean tikiWasStatic; // used to determine if entity was intentionally suppressed + + classname = getArg( "classname", "Unspecified" ); + cls = getClassDef( &tikiWasStatic ); + if ( !cls ) + { + if ( !tikiWasStatic ) + { + gi.DPrintf( "%s doesn't have a spawn function\n", classname.c_str() ); + } + + return NULL; + } + + obj = ( Entity * )cls->newInstance(); + + // post spawnarg events + for( i = 0; i < NumArgs(); i++ ) + { + // if it is the "script" key, execute the script commands individually + if ( !Q_stricmp( getKey( i ), "script" ) ) + { + char *ptr; + char * token; + + ptr = const_cast< char * >( getValue( i ) ); + while ( 1 ) + { + token = COM_ParseExt( &ptr, qtrue ); + if ( !token[ 0 ] ) + break; + if ( strchr( token, ':' ) ) + { + gi.DPrintf( "Label %s imbedded inside editor script for %s.\n", token, classname.c_str() ); + } + else + { + ev = new Event( token ); + while ( 1 ) + { + token = COM_ParseExt( &ptr, qfalse ); + if ( !token[ 0 ] ) + break; + ev->AddToken( token ); + } + obj->PostEvent( ev, EV_SPAWNARG ); + } + } + } + else + { + ev = new Event( getKey( i ) ); + ev->AddToken( getValue( i ) ); + obj->PostEvent( ev, EV_SPAWNARG ); + } + } + + if ( !obj ) + { + gi.DPrintf( "%s failed on newInstance\n", classname.c_str() ); + return NULL; + } + + return obj; + } + +/* +============== +G_InitClientPersistant + +This is only called when the game first initializes in single player, +but is called after each death and level change in deathmatch +============== +*/ +void G_InitClientPersistant + ( + gclient_t *client + ) + + { + memset( &client->pers, 0, sizeof( client->pers ) ); + } + + +ClassDef *FindClass + ( + const char *name, + qboolean *isModel + ) + + { + ClassDef *cls; + + *isModel = qfalse; + + // first lets see if it is a registered class name + cls = getClass( name ); + if ( !cls ) + { + SpawnArgs args; + + // if that didn't work lets try to resolve it as a model + args.setArg( "model", name ); + + cls = args.getClassDef(); + if ( cls ) + { + *isModel = qtrue; + } + } + return cls; + } diff --git a/source/source/fgame/g_spawn.h b/source/source/fgame/g_spawn.h new file mode 100644 index 0000000..94e14ea --- /dev/null +++ b/source/source/fgame/g_spawn.h @@ -0,0 +1,88 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/g_spawn.h $ +// $Revision:: 5 $ +// $Author:: Markd $ +// $Date:: 7/27/00 9:52p $ +// +// Copyright (C) 1998 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source is may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/g_spawn.h $ +// +// 5 7/27/00 9:52p Markd +// Added FindClass function +// +// 4 6/14/00 11:18a Markd +// cleaned up code using Intel compiler +// +// 3 5/24/00 3:14p Markd +// first phase of save/load games +// +// 2 12/17/99 6:35p Jimdose +// changed spawnarg code +// added Level class for spawning and map control +// got rid of unused or superflous variables +// changed setjmp/longjmp calls to try/throw/catch exception handling +// +// 1 9/10/99 10:54a Jimdose +// +// 1 9/08/99 3:16p Aldie +// +// 7 8/28/99 3:42p Jimdose +// changed some doubles to floats +// +// DESCRIPTION: +// + +#ifndef __G_SPAWN_H__ +#define __G_SPAWN_H__ + +#include "entity.h" + +// 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_DEVELOPMENT 0x00002000 +#define SPAWNFLAG_DETAIL 0x00004000 + +class SpawnArgs : public Class + { + private: + Container keyList; + Container valueList; + + public: + CLASS_PROTOTYPE( SpawnArgs ); + + SpawnArgs(); + SpawnArgs( SpawnArgs &arglist ); + + void Clear( void ); + + const char *Parse( const char *data ); + const char *getArg( const char *key, const char *defaultValue = NULL ); + void setArg( const char *key, const char *value ); + + int NumArgs( void ); + const char *getKey( int index ); + const char *getValue( int index ); + void operator=( SpawnArgs &a ); + + ClassDef *getClassDef( qboolean *tikiWasStatic = NULL ); + Entity *Spawn( void ); + + virtual void Archive( Archiver &arc ); + }; + +void G_InitClientPersistant( gclient_t *client ); +ClassDef *FindClass( const char *name, qboolean *isModel ); + +#endif + diff --git a/source/source/fgame/g_utils.cpp b/source/source/fgame/g_utils.cpp new file mode 100644 index 0000000..50cf50e --- /dev/null +++ b/source/source/fgame/g_utils.cpp @@ -0,0 +1,2440 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/g_utils.cpp $ +// $Revision:: 93 $ +// $Author:: Steven $ +// $Date:: 8/10/00 4:01p $ +// +// Copyright (C) 1998 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source is may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/g_utils.cpp $ +// +// 93 8/10/00 4:01p Steven +// Fixed some case sensitive stuff in CacheResource. +// +// 92 8/04/00 3:54p Markd +// Added StartCinematic and StopCinematic +// +// 91 7/29/00 11:51p Aldie +// Added back in G_ClearFade +// +// 90 29.07.00 11:40p Jimdose +// fixed bug in findradius +// +// 88 29.07.00 10:51p Jimdose +// added radius2 to gentity_t +// +// 87 7/29/00 4:00p Aldie +// Added autofadein for skipping cinematics +// +// 86 7/28/00 6:57p Steven +// Made CloneEntity process init commands again and added some player died +// stuff. +// +// 85 7/28/00 1:10a Markd +// canceled init commands on fakeplayered julie +// +// 84 7/27/00 10:54p Steven +// Added means of death eat. +// +// 83 7/27/00 9:43p Aldie +// Changed dialog for invalid save games +// +// 82 7/24/00 5:55p Markd +// added back in centerprint on mission failed +// +// 81 7/23/00 6:03p Markd +// added fadeout and fadesound to dieing and level change +// +// 80 7/19/00 8:19p Steven +// Added gas blockable means of death. +// +// 79 7/19/00 5:08p Steven +// Added electric water means of death. +// +// 78 7/18/00 3:29p Markd +// added better caching for sounds in general +// +// 77 7/17/00 2:55p Steven +// Fixed mission failed graphic. +// +// 76 7/16/00 4:37p Steven +// Added new fire means of death. +// +// 75 7/15/00 12:52p Markd +// added mission failure code +// +// 74 7/13/00 12:30p Steven +// Added poison means of death, changed G_TraceEntities to find all entities at +// once instead of 1 at a time, and optimized broadcast sound. +// +// 73 7/11/00 8:03a Steven +// Fixed MOD_matches to return true when damage_type == all (-1) not the +// opposite. +// +// 72 7/11/00 12:01a Markd +// Added light sword as valid MOD_SWORD damage +// +// 71 7/10/00 11:54p Markd +// added exit level code +// +// 70 7/07/00 6:36p Steven +// Added mission failed stuff. +// +// 69 7/02/00 6:46p Markd +// added spawn thread to PlayerStart +// +// 68 7/02/00 1:11p Steven +// Changed means of death light to lightsword. +// +// 67 7/01/00 12:01p Steven +// Added electricsword and plasmashotgun means of death. +// +// 66 6/29/00 2:06p Steven +// Added caching of statemaps to CacheResource. +// +// 65 6/28/00 7:55p Aldie +// Added a MOD +// +// 64 6/17/00 11:55a Steven +// Fixed looping sounds in save games. +// +// 63 6/14/00 5:43p Steven +// Added plasmabeam means of death. +// +// 62 6/14/00 3:50p Markd +// Cleaned up more Intel Compiler warnings +// +// 61 6/13/00 6:46p Aldie +// Added some damage debug info. Added an ignoreEnt for explosion events +// +// 60 6/13/00 3:45p Steven +// Added a gib means of death. +// +// 59 6/08/00 1:45p Steven +// Added means of death light. +// +// 58 6/06/00 2:37p Steven +// Added sting2 means of death. +// +// 57 6/05/00 6:42p Steven +// Added radiation means of death. +// +// 56 6/05/00 3:29p Aldie +// Added flickering to waterstats +// +// 55 6/03/00 3:46p Aldie +// Added in g_debugtargets for debugging targetnames and targets +// +// 54 5/31/00 10:19a Markd +// 4th pass saved games +// +// 53 5/30/00 10:59a Aldie +// Added Circle of Protection Powerup +// +// 52 5/27/00 2:56p Markd +// Save games 2nd pass +// +// 51 5/25/00 4:28p Markd +// fixed up archive functions +// +// 50 5/22/00 5:13p Aldie +// First version of soulsucker +// +// 49 5/16/00 4:12p Markd +// increased level time precision on g_Showtrace +// +// 48 5/10/00 10:31a Steven +// Added means of death firesword. +// +// 47 5/05/00 2:15p Steven +// Added chainsword and on_fire means of death. +// +// 46 5/04/00 12:46p Steven +// Added an axe means of death. +// +// 45 4/27/00 12:04p Steven +// Added crush_every_frame means of death. +// +// 44 4/18/00 12:27p Markd +// added radius support to findradius +// +// 43 4/15/00 4:24p Markd +// Fixed player turning +// +// 42 4/10/00 1:20p Markd +// Fixed typo +// +// 41 4/05/00 3:51p Markd +// added label checking for scripts +// +// 40 3/23/00 12:19p Markd +// increased range of dynamic light radius +// +// 39 3/15/00 4:09p Aldie +// Fixed a bug with using weapons, and added some ability to force a state in +// the player +// +// 38 3/04/00 2:02p Markd +// fixed constantLight problem +// +// 37 3/04/00 11:48a Markd +// Added light style support +// +// 36 3/03/00 4:42p Markd +// added in debugging messages for music and reverb +// +// 35 2/29/00 5:51p Jimdose +// added alternate spawnpoint support +// +// 34 2/23/00 6:21p Aldie +// More inventory changes +// +// 33 2/17/00 6:26p Aldie +// Fixed naming conventions for weapon hand and also added various attachtotag +// functionality for weapons that attach to different tags depending on which +// hand they are wielded in. +// +// 32 1/22/00 5:09p Steven +// Added a trace entities function. +// +// 31 1/22/00 1:44p Markd +// Fixed attached entity bug +// +// 30 1/22/00 12:42p Jimdose +// got rid of calls to vec3() +// +// 29 1/14/00 5:06p Markd +// Removed surface num, tri_num and damage_multiplier from multiple functions +// and events +// +// 28 1/11/00 6:41p Markd +// Removed fulltrace code from the game +// +// 27 1/06/00 11:08p Jimdose +// cleaning up unused code +// +// 26 1/05/00 7:25p Jimdose +// made angle functions all use the same coordinate system +// AngleVectors now returns left instead of right +// no longer need to invert pitch +// +// 25 12/17/99 8:26p Jimdose +// got rid of unused vars and functions +// +// 24 12/17/99 6:35p Jimdose +// changed spawnarg code +// added Level class for spawning and map control +// got rid of unused or superflous variables +// changed setjmp/longjmp calls to try/throw/catch exception handling +// +// 23 12/02/99 6:58p Markd +// fixed attached entity bug with cloning entities +// +// 22 11/12/99 11:21a Markd +// Added Debug Circles and DebugPyramids +// +// 21 11/09/99 8:05p Markd +// Fixed ArchiveEdict function +// +// 20 11/01/99 4:00p Jimdose +// initialized quaternion values on bone controllers +// +// 19 10/29/99 6:46p Jimdose +// added bone controllers +// +// 18 10/29/99 2:18p Markd +// don't copy over the eflags +// +// 17 10/28/99 6:33p Markd +// Added fakeplayer ability, also added CloneEntity +// +// 16 10/25/99 6:39p Markd +// removed size and other unused variables, added radius and centroid to both +// server and game code +// +// 15 10/14/99 5:08p Markd +// removed a lot of G_GetMoveDir calls from the initialization code +// +// 14 10/13/99 4:47p Steven +// Fixed BroadcastSound. +// +// 13 10/12/99 2:23p Markd +// Rewrote camera and player movetype system +// +// 12 10/05/99 2:28p Markd +// fixed all assignment within conditional warnings +// +// 11 10/01/99 2:42p Markd +// moved all the binding code back into Entity from Mover +// +// 10 9/28/99 5:15p Markd +// Fixed more merge bugs with sharing class, vector and listener between three +// modules +// +// 9 9/28/99 4:26p Markd +// merged listener, class and vector between 3 projects +// +// 8 9/23/99 12:38p Markd +// fixed a lot of renderer startup warnings, errors and bugs +// +// 7 9/22/99 4:47p Markd +// fixed more G_GetEntity, G_FindClass and G_GetNextEntity bugs +// +// 6 9/21/99 7:51p Markd +// Fixed a lot of entitynum_none issues +// +// 5 9/16/99 11:18a Markd +// Continuing merge of code, not functional yet but closer +// +// 4 9/15/99 6:57p Aldie +// Update to get game working +// +// 3 9/13/99 4:22p Jimdose +// merge +// +// 2 9/13/99 3:27p Aldie +// code merge +// +// 1 9/10/99 10:54a Jimdose +// +// 1 9/08/99 3:16p Aldie +// +// 28 9/02/99 5:41p Markd +// made CacheResource utility functions changed code every where else +// +// 27 9/01/99 4:21p Jimdose +// fixed bug in findclientsinradius where passing in a NULL entity crashes +// +// 26 8/30/99 2:36p Steven +// Added support for volume and minimum distance for loop sounds. +// +// 25 8/28/99 3:22p Markd +// initialize r_constantlight to 1, 1, 1 +// +// 24 8/25/99 12:42p Markd +// Fixed some minor and major scripting bugs +// +// 23 8/18/99 3:28p Jimdose +// added cylindrical collision detection +// +// 22 8/17/99 5:08p Markd +// Changed all FS_ReadFile's to FS_ReadFileEx's in game code +// +// 21 7/29/99 5:33p Markd +// Fixed weird compiler bug +// +// 20 7/29/99 11:41a Markd +// Added precache and global support +// +// DESCRIPTION: +// + +#include "g_local.h" +#include "g_utils.h" +#include "ctype.h" +#include "worldspawn.h" +#include "scriptmaster.h" +#include "player.h" +#include "PlayerStart.h" + +char means_of_death_strings[ MOD_TOTAL_NUMBER ][ 32 ] = + { + "none", + "drown", + "suicide", + "crush", + "crush_every_frame", + "telefrag", + "lava", + "slime", + "falling", + "last_self_inflicted", + "explosion", + "explodewall", + "electric", + "electricwater", + "thrownobject", + "beam", + "rocket", + "impact", + "gas", + "gas_blockable", + "acid", + "sword", + "plasma", + "plasmabeam", + "plasmashotgun", + "sting", + "sting2", + "sling", + "bullet", + "fast_bullet", + "vehicle", + "fire", + "fire_blockable", + "vortex", + "lifedrain", + "flashbang", + "poo_explosion", + "axe", + "chainsword", + "on_fire", + "firesword", + "electricsword", + "circleofprotection", + "radiation", + "lightsword", + "gib", + "impale", + "uppercut", + "poison", + "eat" + }; + +int MOD_string_to_int( str immune_string ) + { + int i; + + for ( i = 0 ; i < MOD_TOTAL_NUMBER ; i++ ) + { + if ( !immune_string.icmp( means_of_death_strings[ i ] ) ) + return i; + } + + gi.DPrintf( "Unknown means of death - %s\n", immune_string.c_str() ); + return -1; + } + +qboolean MOD_matches + ( + int incoming_damage, + int damage_type + ) + { + if ( damage_type == -1 ) + { + return qtrue; + } + + // special case the sword + if ( damage_type == MOD_SWORD ) + { + if ( + ( incoming_damage == MOD_SWORD ) || + ( incoming_damage == MOD_ELECTRICSWORD ) || + ( incoming_damage == MOD_LIGHTSWORD ) || + ( incoming_damage == MOD_FIRESWORD ) + ) + { + return qtrue; + } + } + else if ( damage_type == incoming_damage ) + { + return qtrue; + } + + return qfalse; + } + +/* +============ +G_TouchTriggers + +============ +*/ +void G_TouchTriggers + ( + Entity *ent + ) + + { + int i; + int num; + int touch[ MAX_GENTITIES ]; + gentity_t *hit; + Event *ev; + + // dead things don't activate triggers! + if ( ( ent->client || ( ent->edict->svflags & SVF_MONSTER ) ) && ( ent->health <= 0 ) ) + { + return; + } + + num = gi.AreaEntities( ent->absmin, ent->absmax, touch, MAX_GENTITIES ); + + // be careful, it is possible to have an entity in this + // list removed before we get to it (killtriggered) + for( i = 0; i < num; i++ ) + { + hit = &g_entities[ touch[ i ] ]; + if ( !hit->inuse || ( hit->entity == ent ) || ( hit->solid != SOLID_TRIGGER ) ) + { + continue; + } + + assert( hit->entity ); + + // FIXME + // should we post the events on the list with zero time + ev = new Event( EV_Touch ); + ev->AddEntity( ent ); + hit->entity->ProcessEvent( ev ); + } + } + +/* +============ +G_TouchSolids + +Call after linking a new trigger in during gameplay +to force all entities it covers to immediately touch it +============ +*/ +void G_TouchSolids + ( + Entity *ent + ) + + { + int i; + int num; + int touch[ MAX_GENTITIES ]; + gentity_t *hit; + Event *ev; + + num = gi.AreaEntities( ent->absmin, ent->absmax, touch, MAX_GENTITIES ); + + // be careful, it is possible to have an entity in this + // list removed before we get to it (killtriggered) + for( i = 0; i < num; i++ ) + { + hit = &g_entities[ touch[ i ] ]; + if ( !hit->inuse ) + { + continue; + } + + assert( hit->entity ); + + //FIXME + // should we post the events so that we don't have to worry about any entities going away + ev = new Event( EV_Touch ); + ev->AddEntity( ent ); + hit->entity->ProcessEvent( ev ); + } + } + +void G_ShowTrace + ( + trace_t *trace, + gentity_t *passent, + const char *reason + ) + + { + str text; + str pass; + str hit; + + assert( reason ); + assert( trace ); + + if ( passent ) + { + pass = va( "'%s'(%d)", passent->entname, passent->s.number ); + } + else + { + pass = "NULL"; + } + + if ( trace->ent ) + { + hit = va( "'%s'(%d)", trace->ent->entname, trace->ent->s.number ); + } + else + { + hit = "NULL"; + } + + text = va( "%0.2f : Pass %s Frac %f Hit %s : '%s'\n", + level.time, pass.c_str(), trace->fraction, hit.c_str(), reason ? reason : "" ); + + if ( sv_traceinfo->integer == 3 ) + { + gi.DebugPrintf( text.c_str() ); + } + else + { + gi.DPrintf( "%s", text.c_str() ); + } + } + +void G_CalcBoundsOfMove + ( + Vector &start, + Vector &end, + Vector &mins, + Vector &maxs, + Vector *minbounds, + Vector *maxbounds + ) + + { + Vector bmin; + Vector bmax; + + ClearBounds( bmin, bmax ); + AddPointToBounds( start, bmin, bmax ); + AddPointToBounds( end, bmin, bmax ); + bmin += mins; + bmax += maxs; + + if ( minbounds ) + { + *minbounds = bmin; + } + + if ( maxbounds ) + { + *maxbounds = bmax; + } + } + +trace_t G_Trace + ( + vec3_t start, + vec3_t mins, + vec3_t maxs, + vec3_t end, + gentity_t *passent, + int contentmask, + qboolean cylinder, + const char *reason + ) + + { + int entnum; + trace_t trace; + + if ( passent ) + { + entnum = passent->s.number; + } + else + { + entnum = ENTITYNUM_NONE; + } + + gi.trace( &trace, start, mins, maxs, end, entnum, contentmask, cylinder ); + + if ( trace.entityNum == ENTITYNUM_NONE ) + { + trace.ent = NULL; + } + else + { + trace.ent = &g_entities[ trace.entityNum ]; + } + + if ( sv_traceinfo->integer > 1 ) + { + G_ShowTrace( &trace, passent, reason ); + } + sv_numtraces++; + + if ( sv_drawtrace->integer ) + { + G_DebugLine( Vector( start ), Vector( end ), 1, 1, 0, 1 ); + } + + return trace; + } + +trace_t G_Trace + ( + Vector &start, + Vector &mins, + Vector &maxs, + Vector &end, + Entity *passent, + int contentmask, + qboolean cylinder, + const char *reason + ) + + { + gentity_t *ent; + int entnum; + trace_t trace; + + assert( reason ); + + if ( passent == NULL ) + { + ent = NULL; + entnum = ENTITYNUM_NONE; + } + else + { + ent = passent->edict; + entnum = ent->s.number; + } + + gi.trace( &trace, start, mins, maxs, end, entnum, contentmask, cylinder ); + + if ( trace.entityNum == ENTITYNUM_NONE ) + { + trace.ent = NULL; + } + else + { + trace.ent = &g_entities[ trace.entityNum ]; + } + + if ( sv_traceinfo->integer > 1 ) + { + G_ShowTrace( &trace, ent, reason ); + } + + sv_numtraces++; + + if ( sv_drawtrace->integer ) + { + G_DebugLine( start, end, 1, 1, 0, 1 ); + } + + return trace; + } + +void G_TraceEntities + ( + Vector &start, + Vector &mins, + Vector &maxs, + Vector &end, + Container*victimlist, + int contentmask + ) + + { + trace_t trace; + vec3_t boxmins; + vec3_t boxmaxs; + int num; + int touchlist[MAX_GENTITIES]; + gentity_t *touch; + int i; + + + // Find the bounding box + + for ( i=0 ; i<3 ; i++ ) + { + if ( end[i] > start[i] ) + { + boxmins[i] = start[i] + mins[i] - 1; + boxmaxs[i] = end[i] + maxs[i] + 1; + } + else + { + boxmins[i] = end[i] + mins[i] - 1; + boxmaxs[i] = start[i] + maxs[i] + 1; + } + } + + // Find the list of entites + + num = gi.AreaEntities( boxmins, boxmaxs, touchlist, MAX_GENTITIES ); + + for ( i=0 ; isolid == SOLID_NOT) + continue; + if (touch->solid == SOLID_TRIGGER) + continue; + + gi.ClipToEntity( &trace, start, mins, maxs, end, touchlist[i], contentmask ); + + if ( trace.entityNum == touchlist[i] ) + victimlist->AddObject( touch->entity ); + } + } + +/* +======================================================================= + + SelectSpawnPoint + +======================================================================= +*/ + +/* +================ +PlayersRangeFromSpot + +Returns the distance to the nearest player from the given spot +================ +*/ +float PlayersRangeFromSpot + ( + Entity *spot + ) + + { + Entity *player; + float bestplayerdistance; + Vector v; + int n; + float playerdistance; + + bestplayerdistance = 9999999; + for( n = 0; n < maxclients->integer; n++ ) + { + if ( !g_entities[ n ].inuse || !g_entities[ n ].entity ) + { + continue; + } + + player = g_entities[ n ].entity; + if ( player->health <= 0 ) + { + continue; + } + + v = spot->origin - player->origin; + playerdistance = v.length(); + + if ( playerdistance < bestplayerdistance ) + { + bestplayerdistance = playerdistance; + } + } + + return bestplayerdistance; + } + +/* +================ +SelectRandomDeathmatchSpawnPoint + +go to a random point, but NOT the two points closest +to other players +================ +*/ +Entity *SelectRandomDeathmatchSpawnPoint + ( + void + ) + + { + Entity *spot, *spot1, *spot2; + int count = 0; + int selection; + float range, range1, range2; + + spot = NULL; + range1 = range2 = 99999; + spot1 = spot2 = NULL; + + for( spot = G_FindClass( spot, "info_player_deathmatch" ); spot ; spot = G_FindClass( spot, "info_player_deathmatch" ) ) + { + 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 = rand() % count; + + spot = NULL; + do + { + spot = G_FindClass( spot, "info_player_deathmatch" ); + + // if there are no more, break out + if ( !spot ) + break; + + if ( spot == spot1 || spot == spot2 ) + { + selection++; + } + } + while( selection-- ); + + return spot; + } + +/* +================ +SelectFarthestDeathmatchSpawnPoint + +================ +*/ +Entity *SelectFarthestDeathmatchSpawnPoint + ( + void + ) + + { + Entity *bestspot; + float bestdistance; + float bestplayerdistance; + Entity *spot; + + spot = NULL; + bestspot = NULL; + bestdistance = 0; + for( spot = G_FindClass( spot, "info_player_deathmatch" ); spot ; spot = G_FindClass( spot, "info_player_deathmatch" ) ) + { + 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_FindClass( NULL, "info_player_deathmatch" ); + + return spot; + } + +Entity *SelectDeathmatchSpawnPoint + ( + void + ) + + { + if ( DM_FLAG( DF_SPAWN_FARTHEST ) ) + { + return SelectFarthestDeathmatchSpawnPoint(); + } + else + { + return SelectRandomDeathmatchSpawnPoint(); + } + } + +/* +=========== +SelectSpawnPoint + +Chooses a player start, deathmatch start, etc +============ +*/ +void SelectSpawnPoint + ( + Vector &org, + Vector &ang, + str &thread + ) + + { + Entity *spot = NULL; + + if ( deathmatch->integer ) + { + spot = SelectDeathmatchSpawnPoint(); + } + + // find a single player start spot + if ( !spot ) + { + while( ( spot = G_FindClass( spot, "info_player_start" ) ) != NULL ) + { + if ( level.spawnpoint.icmp( spot->TargetName() ) == 0 ) + { + break; + } + } + + if ( !spot && !level.spawnpoint.length() ) + { + // there wasn't a spawnpoint without a target, so use any + spot = G_FindClass( NULL, "info_player_start" ); + } + + if ( !spot ) + { + gi.Error( ERR_DROP, "No player spawn position named '%s'. Can't spawn player.\n", level.spawnpoint.c_str() ); + } + } + + org = spot->origin; + ang = spot->angles; + // + // see if we have a thread + // + if ( spot->isSubclassOf( PlayerStart ) ) + { + thread = ( ( PlayerStart * )spot )->getThread(); + } + } + + +/* +============= +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 + ( + Entity *ent + ) + + { + Vector mins, maxs, start, stop; + trace_t trace; + int x, y; + float mid, bottom; + + mins = ent->origin + ent->mins * 0.5; + maxs = ent->origin + ent->maxs * 0.5; + + // 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, 0 ) != 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 ] - 3 * STEPSIZE;//2 * STEPSIZE; + + trace = G_Trace( start, vec_zero, vec_zero, stop, ent, MASK_MONSTERSOLID, false, "M_CheckBottom 1" ); + + 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 ]; + + trace = G_Trace( start, vec_zero, vec_zero, stop, ent, MASK_MONSTERSOLID, false, "M_CheckBottom 2" ); + + 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; + } + +Entity * G_FindClass + ( + Entity * ent, + const char *classname + ) + + { + int entnum; + gentity_t *from; + + if ( ent ) + { + entnum = ent->entnum; + } + else + { + entnum = -1; + } + + for ( from = &g_entities[ entnum + 1 ]; from < &g_entities[ globals.num_entities ] ; from++ ) + { + if ( !from->inuse ) + { + continue; + } + if ( !Q_stricmp ( from->entity->getClassID(), classname ) ) + { + return from->entity; + } + } + + return NULL; + } + +Entity * G_FindTarget + ( + Entity * ent, + const char *name + ) + + { + Entity *next; + + if ( name && name[ 0 ] ) + { + next = world->GetNextEntity( str( name ), ent ); + if ( next ) + { + return next; + } + } + + return NULL; + } + +Entity *G_NextEntity + ( + Entity *ent + ) + + { + gentity_t *from; + + if ( !g_entities ) + { + return NULL; + } + + if ( !ent ) + { + from = g_entities; + } + else + { + from = ent->edict + 1; + } + + if ( !from ) + { + return NULL; + } + + for ( ; from < &g_entities[ globals.num_entities ] ; from++ ) + { + if ( !from->inuse || !from->entity ) + { + continue; + } + + return from->entity; + } + + return NULL; + } + +// +// QuakeEd only writes a single float for angles (bad idea), so up and down are +// just constant angles. +// +Vector G_GetMovedir + ( + float angle + ) + + { + if ( angle == -1 ) + { + return Vector( 0, 0, 1 ); + } + else if ( angle == -2 ) + { + return Vector( 0, 0, -1 ); + } + + angle *= ( M_PI * 2 / 360 ); + return Vector( cos( angle ), sin( angle ), 0 ); + } + +/* +================= +KillBox + +Kills all entities that would touch the proposed new positioning +of ent. Ent should be unlinked before calling this! +================= +*/ +qboolean KillBox + ( + Entity *ent + ) + + { + int i; + int num; + int touch[ MAX_GENTITIES ]; + gentity_t *hit; + Vector min; + Vector max; + int fail; + + fail = 0; + + min = ent->origin + ent->mins; + max = ent->origin + ent->maxs; + + num = gi.AreaEntities( min, max, touch, MAX_GENTITIES ); + + for( i = 0; i < num; i++ ) + { + hit = &g_entities[ touch[ i ] ]; + + if ( !hit->inuse || ( hit->entity == ent ) || !hit->entity || ( hit->entity == world ) || ( !hit->entity->edict->solid ) ) + { + continue; + } + + hit->entity->Damage( ent, ent, hit->entity->health + 100000, ent->origin, vec_zero, vec_zero, + 0, DAMAGE_NO_PROTECTION, MOD_TELEFRAG ); + + // + // if we didn't kill it, fail + // + if ( hit->entity->getSolidType() != SOLID_NOT ) + { + fail++; + } + } + + // + // all clear + // + return !fail; + } + +qboolean IsNumeric + ( + const char *str + ) + + { + int len; + int i; + qboolean dot; + + if ( *str == '-' ) + { + str++; + } + + dot = false; + len = strlen( str ); + for( i = 0; i < len; i++ ) + { + if ( !isdigit( str[ i ] ) ) + { + if ( ( str[ i ] == '.' ) && !dot ) + { + dot = true; + continue; + } + return false; + } + } + + return true; + } + +/* +================= +findradius + +Returns entities that have origins within a spherical area + +findradius (org, radius) +================= +*/ +Entity *findradius + ( + Entity *startent, + Vector org, + float rad + ) + + { + Vector eorg; + gentity_t *from; + float r2, distance; + + if ( !startent ) + { + from = active_edicts.next; + } + else + { + from = startent->edict->next; + } + + assert( from ); + if ( !from ) + { + return NULL; + } + + assert( ( from == &active_edicts ) || ( from->inuse ) ); + + // square the radius so that we don't have to do a square root + r2 = rad * rad; + + for( ; from != &active_edicts; from = from->next ) + { + assert( from->inuse ); + assert( from->entity ); + + eorg = org - from->entity->centroid; + + // dot product returns length squared + distance = eorg * eorg; + + if ( distance <= r2 ) + { + return from->entity; + } + else + { + // subtract the object's own radius from this distance + distance -= from->radius2; + if ( distance <= r2 ) + { + return from->entity; + } + } + } + + return NULL; + } + +/* +================= +findclientinradius + +Returns clients that have origins within a spherical area + +findclientinradius (org, radius) +================= +*/ +Entity *findclientsinradius + ( + Entity *startent, + Vector org, + float rad + ) + + { + Vector eorg; + gentity_t *ed; + float r2; + int i; + + // square the radius so that we don't have to do a square root + r2 = rad * rad; + + if ( !startent ) + { + i = 0; + } + else + { + i = startent->entnum + 1; + } + + for( ; i < game.maxclients; i++ ) + { + ed = &g_entities[ i ]; + + if ( !ed->inuse || !ed->entity ) + { + continue; + } + + eorg = org - ed->entity->centroid; + + // dot product returns length squared + if ( ( eorg * eorg ) <= r2 ) + { + return ed->entity; + } + } + + return NULL; + } + +Vector G_CalculateImpulse + ( + Vector start, + Vector end, + float speed, + float gravity + ) + + { + float traveltime, vertical_speed; + Vector dir, xydir, velocity; + + dir = end - start; + xydir = dir; + xydir.z = 0; + traveltime = xydir.length() / speed; + vertical_speed = ( dir.z / traveltime ) + ( 0.5f * gravity * sv_gravity->value * traveltime ); + xydir.normalize(); + + velocity = speed * xydir; + velocity.z = vertical_speed; + return velocity; + } + +Vector G_PredictPosition + ( + Vector start, + Vector target, + Vector targetvelocity, + float speed + ) + + { + Vector projected; + float traveltime; + Vector dir, xydir; + + dir = target - start; + xydir = dir; + xydir.z = 0; + traveltime = xydir.length() / speed; + projected = target + ( targetvelocity * traveltime ); + + return projected; + } + +char *ClientTeam + ( + gentity_t *ent + ) + + { + static char value[512]; + + value[0] = 0; + + if (!ent->client) + return value; + + if ( DM_FLAG( DF_MODELTEAMS ) ) + COM_StripExtension( Info_ValueForKey( ent->client->pers.userinfo, "model" ), value ); + else if ( DM_FLAG( DF_SKINTEAMS ) ) + COM_StripExtension( Info_ValueForKey( ent->client->pers.userinfo, "skin" ), value ); + + return( value ); + } + + +qboolean OnSameTeam + ( + Entity *ent1, + Entity *ent2 + ) + + { + char ent1Team [512]; + char ent2Team [512]; + + if ( !DM_FLAG( DF_MODELTEAMS | DF_SKINTEAMS ) ) + return false; + + strcpy (ent1Team, ClientTeam (ent1->edict)); + strcpy (ent2Team, ClientTeam (ent2->edict)); + + if ( !strcmp( ent1Team, ent2Team ) ) + return true; + + return false; + } + +/* +============== +G_LoadAndExecScript + +Like the man says... +============== +*/ +qboolean G_LoadAndExecScript + ( + const char *filename, + const char *label, + qboolean quiet + ) + + { + ScriptThread *pThread; + + if ( gi.FS_ReadFile( filename, NULL, quiet ) != -1 ) + { + if ( Director.labelExists( filename, label ) ) + { + pThread = Director.CreateThread( filename, LEVEL_SCRIPT, label ); + if ( pThread ) + { + // start right away + pThread->StartImmediately(); + return qtrue; + } + else + { + gi.DPrintf( "G_LoadAndExecScript : %s could not create thread.\n", filename ); + return qfalse; + } + } + else + { + if ( !quiet ) + { + gi.DPrintf( "G_LoadAndExecScript : label %s does not exist in %s.\n", label, filename ); + } + return qfalse; + } + } + + return qfalse; + } + +ScriptThread * ExecuteThread + ( + str thread_name, + qboolean start + ) + { + GameScript * s; + + if ( thread_name.length() ) + { + ScriptThread * pThread; + + s = ScriptLib.GetScript( ScriptLib.GetGameScript() ); + if ( !s ) + { + gi.DPrintf( "StartThread::Null game script\n" ); + return false; + } + pThread = Director.CreateThread( s, thread_name.c_str() ); + if ( pThread ) + { + if ( start ) + { + // start right away + pThread->StartImmediately(); + } + } + else + { + gi.DPrintf( "StartThread::unable to go to %s\n", thread_name.c_str() ); + return NULL; + } + return pThread; + } + return NULL; + } + +/* +============== +G_ArchiveEdict +============== +*/ +void G_ArchiveEdict + ( + Archiver &arc, + gentity_t *edict + ) + + { + int i; + str tempStr; + + assert( edict ); + + // + // this is written funny because it is used for both saving and loading + // + + if ( edict->client ) + { + arc.ArchiveRaw( edict->client, sizeof( *edict->client ) ); + } + + arc.ArchiveInteger( &edict->s.eType ); + arc.ArchiveInteger( &edict->s.eFlags ); + + arc.ArchiveVec3( edict->s.netorigin ); + arc.ArchiveVec3( edict->s.origin ); + arc.ArchiveVec3( edict->s.origin2 ); + arc.ArchiveVec3( edict->s.netangles ); + arc.ArchiveVec3( edict->s.angles ); + + arc.ArchiveInteger( &edict->s.constantLight ); + + if ( arc.Saving() ) + { + if ( edict->s.loopSound ) + tempStr = gi.getConfigstring( CS_SOUNDS + edict->s.loopSound ); + else + tempStr = ""; + + arc.ArchiveString( &tempStr ); + } + else + { + arc.ArchiveString( &tempStr ); + + if ( tempStr.length() ) + edict->s.loopSound = gi.soundindex( tempStr.c_str() ); + else + edict->s.loopSound = 0; + } + + arc.ArchiveFloat( &edict->s.loopSoundVolume ); + arc.ArchiveFloat( &edict->s.loopSoundMinDist ); + + arc.ArchiveInteger( &edict->s.parent ); + arc.ArchiveInteger( &edict->s.tag_num ); + arc.ArchiveBoolean( &edict->s.attach_use_angles ); + arc.ArchiveVec3( edict->s.attach_offset ); + + arc.ArchiveInteger( &edict->s.modelindex ); + arc.ArchiveInteger( &edict->s.skinNum ); + arc.ArchiveInteger( &edict->s.anim ); + arc.ArchiveInteger( &edict->s.frame ); + + arc.ArchiveInteger( &edict->s.crossblend_time ); + + arc.ArchiveInteger( &edict->s.torso_anim ); + arc.ArchiveInteger( &edict->s.torso_frame ); + arc.ArchiveInteger( &edict->s.torso_crossblend_time ); + + for( i = 0; i < NUM_BONE_CONTROLLERS; i++ ) + { + arc.ArchiveInteger( &edict->s.bone_tag[ i ] ); + arc.ArchiveVec3( edict->s.bone_angles[ i ] ); + arc.ArchiveVec4( edict->s.bone_quat[ i ] ); + } + + arc.ArchiveRaw( &edict->s.surfaces, sizeof( edict->s.surfaces ) ); + + arc.ArchiveInteger( &edict->s.clientNum ); + arc.ArchiveInteger( &edict->s.groundEntityNum ); + arc.ArchiveInteger( &edict->s.solid ); + + arc.ArchiveFloat( &edict->s.scale ); + arc.ArchiveFloat( &edict->s.alpha ); + arc.ArchiveInteger( &edict->s.renderfx ); + arc.ArchiveVec4( edict->s.quat ); + arc.ArchiveRaw( &edict->s.mat, sizeof( edict->s.mat ) ); + + arc.ArchiveInteger( &edict->svflags ); + + arc.ArchiveVec3( edict->mins ); + arc.ArchiveVec3( edict->maxs ); + arc.ArchiveInteger( &edict->contents ); + arc.ArchiveVec3( edict->absmin ); + arc.ArchiveVec3( edict->absmax ); + arc.ArchiveFloat( &edict->radius ); + if ( !arc.Saving() ) { + edict->radius2 = edict->radius * edict->radius; + } + + arc.ArchiveVec3( edict->centroid ); + + arc.ArchiveVec3( edict->currentOrigin ); + arc.ArchiveVec3( edict->currentAngles ); + + arc.ArchiveInteger( &edict->ownerNum ); + ArchiveEnum( edict->solid, solid_t ); + arc.ArchiveFloat( &edict->freetime ); + arc.ArchiveFloat( &edict->spawntime ); + + tempStr = str( edict->entname ); + arc.ArchiveString( &tempStr ); + strncpy( edict->entname, tempStr.c_str(), sizeof( edict->entname ) - 1 ); + + arc.ArchiveInteger( &edict->clipmask ); + + if ( arc.Loading() ) + { + gi.linkentity( edict ); + } + } + +/* +========================================================================= + +model / sound configstring indexes + +========================================================================= +*/ + +/* +======================= +G_FindConfigstringIndex +======================= +*/ +int G_FindConfigstringIndex( char *name, int start, int max, qboolean create ) + { + int i; + char *s; + + if ( !name || !name[0] ) + { + return 0; + } + + for ( i=1 ; is.pos.trBase ); + ent->s.pos.trType = TR_STATIONARY; + ent->s.pos.trTime = 0; + ent->s.pos.trDuration = 0; + VectorClear( ent->s.pos.trDelta ); + + VectorCopy( org, ent->currentOrigin ); + VectorCopy( org, ent->s.origin ); + } + +/* +=============== +G_SetConstantLight + +Sets the encoded constant light parameter for entities +=============== +*/ +void G_SetConstantLight + ( + int * constantlight, + float * red, + float * green, + float * blue, + float * radius, + int * lightStyle + ) + + { + int ir, ig, ib, iradius; + + if ( !constantlight ) + return; + + ir = (*constantlight) & 255; + ig = ( (*constantlight) >> 8 ) & 255; + ib = ( (*constantlight) >> 16 ) & 255; + iradius = ( (*constantlight) >> 24 ) & 255; + + if ( red ) + { + ir = *red * 255; + if ( ir > 255 ) + ir = 255; + } + + if ( green ) + { + ig = *green * 255; + if ( ig > 255 ) + ig = 255; + } + + if ( blue ) + { + ib = *blue * 255; + if ( ib > 255 ) + ib = 255; + } + + if ( radius ) + { + iradius = *radius / CONSTANTLIGHT_RADIUS_SCALE; + if ( iradius > 255 ) + iradius = 255; + } + + if ( lightStyle ) + { + ir = *lightStyle; + if ( ir > 255 ) + ir = 255; + } + *constantlight = ( ir ) + ( ig << 8 ) + ( ib << 16 ) + ( iradius << 24 ); + } + +// +// caching commands +// +int modelIndex + ( + const char *mdl + ) + { + str name; + + assert( mdl ); + + if ( !mdl ) + { + return 0; + } + + // Prepend 'models/' to make things easier + if ( !strchr( mdl, '*' ) && !strchr( mdl, '\\' ) && !strchr( mdl, '/' ) ) + { + name = "models/"; + } + + name += mdl; + + return gi.modelindex( name.c_str() ); + } + + +void CacheResource + ( + const char * stuff, + Entity * ent + ) + + { + str real_stuff; + + if ( !stuff ) + return; + + if ( !strchr( stuff, '.' ) ) + { + // must be a global alias + stuff = gi.GlobalAlias_FindRandom( stuff ); + if ( !stuff ) + { + return; + } + } + + real_stuff = stuff; + real_stuff.tolower(); + + if ( strstr( real_stuff.c_str(), ".wav" ) ) + { + gi.soundindex( real_stuff.c_str() ); + } + else if ( strstr( real_stuff.c_str(), ".mp3" ) ) + { + gi.soundindex( real_stuff.c_str() ); + } + else if ( strstr( real_stuff.c_str(), ".tik" ) ) + { + int index; + + index = modelIndex( real_stuff.c_str() ); + + if ( index > 0 && ent ) + ent->ProcessInitCommands( index, qtrue ); + } + else if ( strstr( real_stuff.c_str(), ".spr" ) ) + { + gi.modelindex( real_stuff.c_str() ); + } + else if ( strstr( real_stuff.c_str(), ".st" ) ) + { + if ( strncmp( real_stuff.c_str(), "ai/", 3 ) == 0 ) + { + Actor *actor = new Actor; + CacheStatemap( stuff, ( Condition * )actor->Conditions ); + delete actor; + } + } + } + +void ChangeMusic + ( + const char *current, + const char *fallback, + qboolean force + ) + { + int j; + gentity_t *other; + + if ( current || fallback ) + { + for( j = 0; j < game.maxclients; j++ ) + { + other = &g_entities[ j ]; + if ( other->inuse && other->client ) + { + Player *client; + + client = ( Player * )other->entity; + client->ChangeMusic( current, fallback, force ); + } + } + if ( current && fallback ) + { + gi.DPrintf( "music set to %s with fallback %s\n", current, fallback ); + } + } + } + +void ChangeMusicVolume + ( + float volume, + float fade_time + ) + { + int j; + gentity_t *other; + + for( j = 0; j < game.maxclients; j++ ) + { + other = &g_entities[ j ]; + if ( other->inuse && other->client ) + { + Player *client; + + client = ( Player * )other->entity; + client->ChangeMusicVolume( volume, fade_time ); + } + } + gi.DPrintf( "music volume set to %.2f, fade time %.2f\n", volume, fade_time ); + } + +void RestoreMusicVolume + ( + float fade_time + ) + { + int j; + gentity_t *other; + + for( j = 0; j < game.maxclients; j++ ) + { + other = &g_entities[ j ]; + if ( other->inuse && other->client ) + { + Player *client; + + client = ( Player * )other->entity; + client->RestoreMusicVolume( fade_time ); + } + } + } + +void ChangeSoundtrack + ( + const char * soundtrack + ) + + { + level.saved_soundtrack = level.current_soundtrack; + level.current_soundtrack = soundtrack; + + gi.setConfigstring( CS_SOUNDTRACK, soundtrack ); + gi.DPrintf( "soundtrack switched to %s.\n", soundtrack ); + } + +void RestoreSoundtrack + ( + void + ) + + { + if ( level.saved_soundtrack.length() ) + { + level.current_soundtrack = level.saved_soundtrack; + level.saved_soundtrack = ""; + gi.setConfigstring( CS_SOUNDTRACK, level.current_soundtrack.c_str() ); + gi.DPrintf( "soundtrack restored %s.\n", level.current_soundtrack.c_str() ); + } + } + +void G_BroadcastSound + ( + Entity *soundent, + Vector origin, + float radius + ) + + { + Sentient *ent; + Vector delta; + Event *ev; + str name; + float r2; + float dist2; + int i; + int n; +#if 0 + int count; + + count = 0; +#endif + + assert( soundent ); + if ( soundent && !( soundent->flags & FL_NOTARGET ) ) + { + r2 = radius * radius; + n = SentientList.NumObjects(); + for( i = 1; i <= n; i++ ) + { + ent = SentientList.ObjectAt( i ); + if ( ( ent == soundent ) || ent->deadflag ) + { + continue; + } + + if ( ent->isSubclassOf( Actor ) ) + { + Actor *act = (Actor *)ent; + + if ( !act->IgnoreSounds() ) + { + delta = origin - ent->centroid; + + // dot product returns length squared + dist2 = delta * delta; + if ( + ( dist2 <= r2 ) && + ( + ( soundent->edict->areanum == ent->edict->areanum ) || + ( gi.AreasConnected( soundent->edict->areanum, ent->edict->areanum ) ) + ) + ) + + { + ev = new Event( EV_HeardSound ); + ev->AddEntity( soundent ); + ev->AddVector( origin ); + ent->PostEvent( ev, 0 ); +#if 0 + count++; +#endif + } + } + } + } + +#if 0 + gi.DPrintf( "Broadcast event %s to %d entities\n", ev->getName(), count ); +#endif + } + } + +void CloneEntity + ( + Entity * dest, + Entity * src + ) + { + int i, num; + + dest->setModel( src->model ); + // don't process our init commands + //dest->CancelEventsOfType( EV_ProcessInitCommands ); + dest->setOrigin( src->origin ); + dest->setAngles( src->angles ); + dest->setScale( src->edict->s.scale ); + dest->setAlpha( src->edict->s.alpha ); + dest->health = src->health; + // copy the surfaces + memcpy( dest->edict->s.surfaces, src->edict->s.surfaces, sizeof( src->edict->s.surfaces ) ); + dest->edict->s.constantLight = src->edict->s.constantLight; + //dest->edict->s.eFlags = src->edict->s.eFlags; + dest->edict->s.renderfx = src->edict->s.renderfx; + dest->edict->s.anim = src->edict->s.anim; + dest->edict->s.frame = src->edict->s.frame; + + num = src->numchildren; + for( i = 0; ( i < MAX_MODEL_CHILDREN ) && num; i++ ) + { + Entity * clone; + Entity * child; + + // duplicate the children + if ( !src->children[ i ] ) + { + continue; + } + child = G_GetEntity( src->children[ i ] ); + if ( child ) + { + clone = new Animate; + CloneEntity( clone, child ); + clone->attach( dest->entnum, child->edict->s.tag_num ); + } + num--; + } + dest->ProcessPendingEvents(); + } + +weaponhand_t WeaponHandNameToNum + ( + str side + ) + + { + if ( !side.length() ) + { + gi.DPrintf( "WeaponHandNameToNum : Weapon hand not specified\n" ); + return WEAPON_ERROR; + } + + if ( !side.icmp( "righthand" ) || !side.icmp( "right" ) ) + { + return WEAPON_RIGHT; + } + else if ( !side.icmp( "lefthand" ) || !side.icmp( "left" ) ) + { + return WEAPON_LEFT; + } + else if ( !side.icmp( "dualhand" ) || !side.icmp( "dual" ) ) + { + return WEAPON_DUAL; + } + else + { + return (weaponhand_t)atoi( side ); + } + } + +const char *WeaponHandNumToName + ( + weaponhand_t hand + ) + + { + switch( hand ) + { + case WEAPON_RIGHT: + return "righthand"; + case WEAPON_LEFT: + return "lefthand"; + case WEAPON_DUAL: + return "dualhand"; + case WEAPON_ANY: + return "anyhand"; + default: + return "Invalid Hand"; + } + } + +firemode_t WeaponModeNameToNum + ( + str mode + ) + + { + if ( !mode.length() ) + { + gi.DPrintf( "WeaponModeNameToNum : Weapon mode not specified\n" ); + return FIRE_ERROR; + } + + if ( !mode.icmp( "primary" ) ) + { + return FIRE_PRIMARY; + } + + if ( !mode.icmp( "alternate" ) ) + { + return FIRE_ALTERNATE; + } + else + { + return (firemode_t)atoi( mode ); + } + } + +void G_DebugTargets + ( + Entity *e, + str from + ) + + { + gi.DPrintf( "DEBUGTARGETS:%s ", from.c_str() ); + + if ( e->TargetName() && strlen( e->TargetName() ) ) + { + gi.DPrintf( "Targetname=\"%s\"\n", e->TargetName() ); + } + else + { + gi.DPrintf( "Targetname=\"None\"\n" ); + } + + if ( e->Target() && strlen( e->Target() ) ) + { + gi.DPrintf( "Target=\"%s\"\n", e->Target() ); + } + else + { + gi.DPrintf( "Target=\"None\"\n" ); + } + } + +void G_DebugDamage + ( + float damage, + Entity *victim, + Entity *attacker, + Entity *inflictor + ) + + { + gi.DPrintf( "Victim:%s Attacker:%s Inflictor:%s Damage:%f\n", victim->getClassname(), attacker->getClassname(), inflictor->getClassname(), damage ); + } + +void G_FadeOut + ( + float delaytime + ) + { + // Fade the screen out + level.m_fade_color = Vector( 0,0,0 ); + level.m_fade_alpha = 1.0f; + level.m_fade_time = delaytime; + level.m_fade_time_start = delaytime; + level.m_fade_type = fadeout; + level.m_fade_style = alphablend; + } + +void G_AutoFadeIn + ( + void + ) + + { + level.m_fade_time_start = 1; + level.m_fade_time = 1; + level.m_fade_color[0] = 0; + level.m_fade_color[1] = 0; + level.m_fade_color[2] = 0; + level.m_fade_alpha = 1; + level.m_fade_type = fadein; + level.m_fade_style = alphablend; + } + +void G_ClearFade + ( + void + ) + + { + level.m_fade_time = -1; + level.m_fade_type = fadein; + } + +void G_FadeSound + ( + float delaytime + ) + { + float time; + + // Fade the screen out + time = delaytime * 1000; + gi.SendServerCommand( NULL, va( "fadesound %0.2f", time ) ); + } + +// +// restarts the game after delaytime +// +void G_PlayerDied + ( + float delaytime + ) + { + int i; + + if ( level.died_already ) + return; + + level.died_already = true; + + // Restart the level soon + + for( i = 0; i < game.maxclients; i++ ) + { + if ( g_entities[ i ].inuse ) + { + if ( g_entities[ i ].entity ) + { + g_entities[ i ].entity->PostEvent( EV_Player_Respawn, delaytime ); + } + } + } + + G_FadeOut( delaytime ); + G_FadeSound( delaytime ); + } + +void G_MissionFailed + ( + void + ) + + { + // Make the music system play the failure music for this level + ChangeMusic( "failure", "normal", true ); + + G_PlayerDied( 3 ); + + // tell the player they f'd up + gi.centerprintf( &g_entities[ 0 ], "@textures/menu/mission.tga" ); + + level.mission_failed = true; + } + +void G_StartCinematic + ( + void + ) + + { + level.cinematic = true; + gi.cvar_set( "sv_cinematic", "1" ); + } + +void G_StopCinematic + ( + void + ) + + { + // clear out the skip thread + world->skipthread = ""; + level.cinematic = false; + gi.cvar_set( "sv_cinematic", "0" ); + } + diff --git a/source/source/fgame/g_utils.h b/source/source/fgame/g_utils.h new file mode 100644 index 0000000..e295b92 --- /dev/null +++ b/source/source/fgame/g_utils.h @@ -0,0 +1,403 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/g_utils.h $ +// $Revision:: 31 $ +// $Author:: Markd $ +// $Date:: 8/04/00 3:54p $ +// +// Copyright (C) 1998 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/g_utils.h $ +// +// 31 8/04/00 3:54p Markd +// Added StartCinematic and StopCinematic +// +// 30 7/29/00 11:23p Aldie +// Added g_clearfade +// +// 29 7/29/00 4:00p Aldie +// Added autofadein for skipping cinematics +// +// 28 7/23/00 6:03p Markd +// added fadeout and fadesound to dieing and level change +// +// 27 7/13/00 12:33p Steven +// Improved G_TraceEntities. +// +// 26 7/10/00 11:54p Markd +// added exit level code +// +// 25 7/07/00 6:35p Steven +// Added mission failed stuff. +// +// 24 7/02/00 6:46p Markd +// added spawn thread to PlayerStart +// +// 23 6/14/00 11:18a Markd +// cleaned up code using Intel compiler +// +// 22 6/13/00 6:46p Aldie +// Added some damage debug info. Added an ignoreEnt for explosion events +// +// 21 6/03/00 3:46p Aldie +// Added in g_debugtargets for debugging targetnames and targets +// +// 20 6/01/00 7:02p Markd +// removed activeWeapon variable +// +// 19 5/25/00 4:28p Markd +// fixed up archive functions +// +// 18 4/15/00 4:24p Markd +// Fixed player turning +// +// 17 3/04/00 11:48a Markd +// Added light style support +// +// 16 2/23/00 6:21p Aldie +// More inventory changes +// +// 15 2/17/00 6:26p Aldie +// Fixed naming conventions for weapon hand and also added various attachtotag +// functionality for weapons that attach to different tags depending on which +// hand they are wielded in. +// +// 14 1/22/00 5:07p Steven +// Added a trace entites function. +// +// 13 1/20/00 7:11p Jimdose +// removed angmod +// +// 12 1/11/00 6:41p Markd +// Removed fulltrace code from the game +// +// 11 1/10/00 5:34p Markd +// Added DeAllocateDebugLines +// +// 10 1/06/00 11:08p Jimdose +// cleaning up unused code +// +// 9 12/17/99 8:27p Jimdose +// got rid of unused vars and functions +// +// 8 12/17/99 6:35p Jimdose +// changed spawnarg code +// added Level class for spawning and map control +// got rid of unused or superflous variables +// changed setjmp/longjmp calls to try/throw/catch exception handling +// +// 7 11/12/99 11:21a Markd +// Added Debug Circles and DebugPyramids +// +// 6 10/28/99 6:33p Markd +// Added fakeplayer ability, also added CloneEntity +// +// 5 10/14/99 5:08p Markd +// removed a lot of G_GetMoveDir calls from the initialization code +// +// 4 9/28/99 5:15p Markd +// Fixed more merge bugs with sharing class, vector and listener between three +// modules +// +// 3 9/28/99 4:26p Markd +// merged listener, class and vector between 3 projects +// +// 2 9/22/99 4:47p Markd +// fixed more G_GetEntity, G_FindClass and G_GetNextEntity bugs +// +// 1 9/10/99 10:54a Jimdose +// +// 1 9/08/99 3:16p Aldie +// +// 13 9/02/99 5:41p Markd +// made CacheResource utility functions changed code every where else +// +// 12 8/18/99 3:28p Jimdose +// added cylindrical collision detection +// +// 11 7/29/99 11:41a Markd +// Added precache and global support +// +// DESCRIPTION: +// + +#ifndef __G_UTILS_H__ +#define __G_UTILS_H__ + +class Archiver; + +void G_ArchiveEdict( Archiver &arc, gentity_t *edict ); + +#include "entity.h" + +void G_AllocDebugLines( void ); +void G_DeAllocDebugLines( void ); + +void G_TouchTriggers (Entity *ent); +void G_TouchSolids (Entity *ent); + +Entity *G_FindClass( Entity *ent, const char *classname ); +Entity *G_NextEntity( Entity *ent ); + +void G_CalcBoundsOfMove( Vector &start, Vector &end, Vector &mins, Vector &maxs, Vector *minbounds, Vector *maxbounds ); + +void G_ShowTrace( trace_t *trace, gentity_t *passent, const char *reason ); +trace_t G_Trace( Vector &start, Vector &mins, Vector &maxs, Vector &end, Entity *passent, int contentmask, qboolean cylindrical, const char *reason ); +trace_t G_Trace( vec3_t start, vec3_t mins, vec3_t maxs, vec3_t end, gentity_t *passent, int contentmask, qboolean cylindrical, const char *reason ); +void G_TraceEntities( Vector &start, Vector &mins, Vector &maxs, Vector &end, Container*victimlist, int contentmask ); + +void SelectSpawnPoint( Vector &org, Vector &angles, str &thread ); + +Entity *G_FindTarget( Entity *ent, const char *name ); +Entity *G_NextEntity( Entity *ent ); + +qboolean M_CheckBottom( Entity *ent ); + +Vector G_GetMovedir( float angle ); +qboolean KillBox( Entity *ent ); +qboolean IsNumeric( const char *str ); + +Entity *findradius( Entity *startent, Vector org, float rad ); +Entity *findclientsinradius( Entity *startent, Vector org, float rad ); + +Vector G_CalculateImpulse( Vector start, Vector end, float speed, float gravity ); +Vector G_PredictPosition( Vector start, Vector target, Vector targetvelocity, float speed ); + +qboolean G_LoadAndExecScript( const char *filename, const char *label = NULL, qboolean quiet = qfalse ); +ScriptThread *ExecuteThread( str thread_name, qboolean start = true ); + +int MOD_string_to_int( str immune_string ); +qboolean MOD_matches( int incoming_damage, int damage_type ); + +void G_MissionFailed( void ); +void G_FadeOut( float delaytime ); +void G_FadeSound( float delaytime ); +void G_PlayerDied( float delaytime ); +void G_AutoFadeIn( void ); +void G_ClearFade( void ); +void G_StartCinematic( void ); +void G_StopCinematic( void ); + +// copy the entity exactly including all its children +void CloneEntity( Entity * dest, Entity * src ); + +qboolean OnSameTeam( Entity *ent1, Entity *ent2 ); + +// +// caching commands +// +void CacheResource( const char * stuff, Entity * ent = NULL ); +int modelIndex( const char *mdl ); + +void G_SetTrajectory( gentity_t *ent, vec3_t org ); +void G_SetConstantLight + ( + int * constantlight, + float * red, + float * green, + float * blue, + float * radius, + int * lightstyle = NULL + ); + +void ChangeMusic + ( + const char *current, + const char *fallback, + qboolean force + ); + +void ChangeMusicVolume + ( + float volume, + float fade_time + ); + +void RestoreMusicVolume + ( + float fade_time + ); + +void ChangeSoundtrack + ( + const char * soundtrack + ); + +void RestoreSoundtrack + ( + void + ); + +void G_BroadcastSound( Entity *ent, Vector origin, float radius = SOUND_RADIUS ); + +//================================================================== +// +// Inline functions +// +//================================================================== + +/* +================= +G_GetEntity + +Takes an index to an entity and returns pointer to it. +================= +*/ + +inline Entity *G_GetEntity + ( + int entnum + ) + + { + if ( ( entnum < 0 ) || ( entnum >= globals.max_entities ) ) + { + gi.Error( ERR_DROP, "G_GetEntity: %d out of valid range.", entnum ); + } + + return ( Entity * )g_entities[ entnum ].entity; + } + +/* +================= +G_Random + +Returns a number from 0<= num < 1 + +random() +================= +*/ + +inline float G_Random + ( + void + ) + + { + return ( ( float )( rand() & 0x7fff ) ) / ( ( float )0x8000 ); + } + +/* +================= +G_Random + +Returns a number from 0 <= num < n + +random() +================= +*/ + +inline float G_Random + ( + float n + ) + + { + return G_Random() * n; + } + +/* +================= +G_CRandom + +Returns a number from -1 <= num < 1 + +crandom() +================= +*/ + +inline float G_CRandom + ( + void + ) + + { + return G_Random( 2 ) - 1; + } + +/* +================= +G_CRandom + +Returns a number from -n <= num < n + +crandom() +================= +*/ + +inline float G_CRandom + ( + float n + ) + + { + return G_CRandom() * n; + } + +/* +================= +G_FixSlashes + +Converts all backslashes in a string to forward slashes. +Used to make filenames consistant. +================= +*/ + +inline str G_FixSlashes + ( + const char *filename + ) + + { + int i; + int len; + str text; + + if ( filename ) + { + // Convert all forward slashes to back slashes + text = filename; + len = text.length(); + for( i = 0; i < len; i++ ) + { + if ( text[ i ] == '\\' ) + { + text[ i ] = '/'; + } + } + } + + return text; + } + +typedef enum + { + WEAPON_RIGHT, + WEAPON_LEFT, + WEAPON_DUAL, + WEAPON_ANY, + WEAPON_ERROR + } weaponhand_t; + +#define NUM_ACTIVE_WEAPONS WEAPON_ANY + +typedef enum + { + FIRE_PRIMARY, + FIRE_ALTERNATE, + MAX_FIREMODES, + FIRE_ERROR + } firemode_t; + +firemode_t WeaponModeNameToNum( str mode ); +const char *WeaponHandNumToName( weaponhand_t hand ); +weaponhand_t WeaponHandNameToNum( str side ); +void G_DebugTargets( Entity *e, str from ); +void G_DebugDamage( float damage, Entity *victim, Entity *attacker, Entity *inflictor ); + +#endif /* g_utils.h */ + diff --git a/source/source/fgame/game.cpp b/source/source/fgame/game.cpp new file mode 100644 index 0000000..304dd1d --- /dev/null +++ b/source/source/fgame/game.cpp @@ -0,0 +1,78 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/game.cpp $ +// $Revision:: 5 $ +// $Date:: 5/25/00 7:52p $ +// +// Copyright (C) 1999 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source is may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/game.cpp $ +// +// 5 5/25/00 7:52p Markd +// 2nd pass save game stuff +// +// 4 5/24/00 3:14p Markd +// first phase of save/load games +// +// 3 1/10/00 5:29p Markd +// fixed bug in unarchiving game and archiving game where logic was inverted +// +// 2 1/06/00 11:08p Jimdose +// cleaning up unused code +// +// DESCRIPTION: +// + +#include "game.h" + +Game game; + +CLASS_DECLARATION( Class, Game, NULL ) + { + { NULL, NULL } + }; + +void Game::Init + ( + void + ) + + { + clients = NULL; + + autosaved = false; + + maxentities = 0; + maxclients = 0; + } + +void Game::Archive + ( + Archiver &arc + ) + + { + int i; + + Class::Archive( arc ); + + arc.ArchiveBoolean( &autosaved ); + + arc.ArchiveInteger( &maxentities ); + arc.ArchiveInteger( &maxclients ); + + if ( arc.Loading() ) + { + G_AllocGameData(); + } + + for( i = 0; i < maxclients; i++ ) + { + arc.ArchiveRaw( &clients[ i ], sizeof( gclient_t ) ); + } + } + diff --git a/source/source/fgame/game.def b/source/source/fgame/game.def new file mode 100644 index 0000000..df4958f --- /dev/null +++ b/source/source/fgame/game.def @@ -0,0 +1,2 @@ +EXPORTS + GetGameAPI diff --git a/source/source/fgame/game.h b/source/source/fgame/game.h new file mode 100644 index 0000000..b772fd8 --- /dev/null +++ b/source/source/fgame/game.h @@ -0,0 +1,56 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/game.h $ +// $Revision:: 3 $ +// $Date:: 5/24/00 3:14p $ +// +// Copyright (C) 1999 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source is may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/game.h $ +// +// 3 5/24/00 3:14p Markd +// first phase of save/load games +// +// 2 1/06/00 11:08p Jimdose +// cleaning up unused code +// +// DESCRIPTION: +// + +#ifndef __GAME_H__ +#define __GAME_H__ + +#include "g_local.h" +#include "class.h" + +// +// this structure is left intact through an entire game +// it should be initialized at dll load time, and read/written to +// the server.ssv file for savegames +// + +class Game : public Class + { + public: + CLASS_PROTOTYPE( Game ); + + gclient_t *clients; // [maxclients] + qboolean autosaved; + + // store latched cvars here that we want to get at often + int maxclients; + int maxentities; + + Game() { Init(); } + + void Init( void ); + virtual void Archive( Archiver &arc ); + }; + +extern Game game; + +#endif /* !__GAME_H__ */ diff --git a/source/source/fgame/gamecmds.cpp b/source/source/fgame/gamecmds.cpp new file mode 100644 index 0000000..90179c1 --- /dev/null +++ b/source/source/fgame/gamecmds.cpp @@ -0,0 +1,644 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/gamecmds.cpp $ +// $Revision:: 8 $ +// $Date:: 7/10/00 9:27p $ +// +// Copyright (C) 1999 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source is may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/gamecmds.cpp $ +// +// 8 7/10/00 9:27p Markd +// added ammo variables for how much ammo the player has. Added levelvars and +// gamevars commands +// +// 7 6/10/00 4:23p Markd +// rewrote map restarting and loading out of date save games +// +// 6 4/26/00 7:55p Markd +// Added more documentation code into various systems +// +// 5 2/17/00 4:18p Jimdose +// added checks in G_ClientCommand for NULL ent being passed in +// +// 4 1/28/00 5:43p Markd +// Added script command to the game +// +// 3 1/22/00 2:04p Markd +// Added "kill" to registered commands +// +// 2 1/06/00 11:10p Jimdose +// cleaning up unused code +// +// DESCRIPTION: +// + +#include "gamecmds.h" +#include "g_local.h" +#include "camera.h" +#include "viewthing.h" +#include "soundman.h" +#include "navigate.h" + +typedef struct + { + const char *command; + qboolean ( *func )( gentity_t *ent ); + qboolean allclients; + } consolecmd_t; + +consolecmd_t G_ConsoleCmds[] = + { + // command name function available in multiplayer? + { "say", G_SayCmd, qtrue }, + { "eventlist", G_EventListCmd, qfalse }, + { "pendingevents", G_PendingEventsCmd, qfalse }, + { "eventhelp", G_EventHelpCmd, qfalse }, + { "dumpevents", G_DumpEventsCmd, qfalse }, + { "classevents", G_ClassEventsCmd, qfalse }, + { "dumpclassevents", G_DumpClassEventsCmd,qfalse }, + { "dumpallclasses", G_DumpAllClassesCmd, qfalse }, + { "classlist", G_ClassListCmd, qfalse }, + { "classtree", G_ClassTreeCmd, qfalse }, + { "cam", G_CameraCmd, qfalse }, + { "snd", G_SoundCmd, qfalse }, + { "showvar", G_ShowVarCmd, qfalse }, + { "script", G_ScriptCmd, qfalse }, + { "levelvars", G_LevelVarsCmd, qfalse }, + { "gamevars", G_GameVarsCmd, qfalse }, + { NULL, NULL, NULL } + }; + +void G_InitConsoleCommands + ( + void + ) + + { + consolecmd_t *cmds; + + // + // the game server will interpret these commands, which will be automatically + // forwarded to the server after they are not recognized locally + // + gi.AddCommand( "give" ); + gi.AddCommand( "god" ); + gi.AddCommand( "notarget" ); + gi.AddCommand( "noclip" ); + gi.AddCommand( "kill" ); + gi.AddCommand( "script" ); + + for( cmds = G_ConsoleCmds; cmds->command != NULL; cmds++ ) + { + gi.AddCommand( cmds->command ); + } + } + +qboolean G_ConsoleCommand + ( + void + ) + + { + gentity_t *ent; + qboolean result; + + result = qfalse; + try + { + ent = &g_entities[ 0 ]; + result = G_ProcessClientCommand( ent ); + } + + catch( const char *error ) + { + G_ExitWithError( error ); + } + + return result; + } + +void G_ClientCommand + ( + gentity_t *ent + ) + + { + try + { + if ( ent && !G_ProcessClientCommand( ent ) ) + { + // anything that doesn't match a command will be a chat + G_Say( ent, false, true ); + } + } + + catch( const char *error ) + { + G_ExitWithError( error ); + } + } + +qboolean G_ProcessClientCommand + ( + gentity_t *ent + ) + + { + const char *cmd; + consolecmd_t *cmds; + int i; + int n; + Event *ev; + + if ( !ent || !ent->client || !ent->entity ) + { + // not fully in game yet + return qfalse; + } + + cmd = gi.argv( 0 ); + for( cmds = G_ConsoleCmds; cmds->command != NULL; cmds++ ) + { + // if we have multiple clients and this command isn't allowed by multiple clients, skip it + if ( ( game.maxclients > 1 ) && ( !cmds->allclients ) ) + { + continue; + } + + if ( !Q_stricmp( cmd, cmds->command ) ) + { + return cmds->func( ent ); + } + } + + if ( Event::Exists( cmd ) ) + { + ev = new Event( cmd ); + ev->SetSource( EV_FROM_CONSOLE ); + ev->SetConsoleEdict( ent ); + + n = gi.argc(); + for( i = 1; i < n; i++ ) + { + ev->AddToken( gi.argv( i ) ); + } + + if ( !Q_stricmpn( cmd, "ai_", 2 ) ) + { + return PathManager.ProcessEvent( ev ); + } + else if ( !Q_stricmpn( cmd, "view", 4 ) ) + { + return Viewmodel.ProcessEvent( ev ); + } + else + { + return ent->entity->ProcessEvent( ev ); + } + } + + return qfalse; + } + +/* +================== +Cmd_Say_f +================== +*/ +void G_Say + ( + gentity_t *ent, + qboolean team, + qboolean arg0 + ) + + { + int j; + gentity_t *other; + const char *p; + char text[ 2048 ]; + + if ( gi.argc() < 2 && !arg0 ) + { + return; + } + + if ( !ent->entity ) + { + // just in case we're not joined yet. + team = false; + } + + if ( !DM_FLAG( DF_MODELTEAMS | DF_SKINTEAMS ) ) + { + team = false; + } + + if ( team ) + { + Com_sprintf( text, sizeof( text ), "(%s): ", ent->client->pers.netname ); + } + else + { + Com_sprintf( text, sizeof( text ), "%s: ", ent->client->pers.netname ); + } + + if ( arg0 ) + { + strcat( text, gi.argv( 0 ) ); + strcat( text, " " ); + strcat( text, gi.args() ); + } + else + { + p = gi.args(); + + if ( *p == '"' ) + { + p++; + strcat( text, p ); + text[ strlen( text ) - 1 ] = 0; + } + else + { + strcat( text, p ); + } + } + + // don't let text be too long for malicious reasons + if ( strlen( text ) > 150 ) + { + text[ 150 ] = 0; + } + + strcat( text, "\n" ); + + if ( dedicated->integer ) + { + gi.SendServerCommand( NULL, "print \"%s\"", text ); + } + + for( j = 0; j < game.maxclients; j++ ) + { + other = &g_entities[ j ]; + if ( !other->inuse || !other->client || !other->entity ) + { + continue; + } + + if ( team ) + { + if ( !OnSameTeam( ent->entity, other->entity ) ) + { + continue; + } + } + + gi.SendServerCommand( NULL, "print \"%s\"", text ); + } + } + +qboolean G_CameraCmd + ( + gentity_t *ent + ) + + { + Event *ev; + const char *cmd; + int i; + int n; + + n = gi.argc(); + if ( !n ) + { + gi.Printf( "Usage: cam [command] [arg 1]...[arg n]\n" ); + return qtrue; + } + + cmd = gi.argv( 1 ); + if ( Event::Exists( cmd ) ) + { + ev = new Event( cmd ); + ev->SetSource( EV_FROM_CONSOLE ); + ev->SetConsoleEdict( NULL ); + + for( i = 2; i < n; i++ ) + { + ev->AddToken( gi.argv( i ) ); + } + + CameraMan.ProcessEvent( ev ); + } + else + { + gi.Printf( "Unknown camera command '%s'.\n", cmd ); + } + + return qtrue; + } + +qboolean G_SoundCmd + ( + gentity_t *ent + ) + + { + Event *ev; + const char *cmd; + int i; + int n; + + n = gi.argc(); + if ( !n ) + { + gi.Printf( "Usage: snd [command] [arg 1]...[arg n]\n" ); + return qtrue; + } + + cmd = gi.argv( 1 ); + if ( Event::Exists( cmd ) ) + { + ev = new Event( cmd ); + ev->SetSource( EV_FROM_CONSOLE ); + ev->SetConsoleEdict( NULL ); + + for( i = 2; i < n; i++ ) + { + ev->AddToken( gi.argv( i ) ); + } + + SoundMan.ProcessEvent( ev ); + } + else + { + gi.Printf( "Unknown sound command '%s'.\n", cmd ); + } + + return qtrue; + } + +qboolean G_SayCmd + ( + gentity_t *ent + ) + + { + G_Say( ent, false, false ); + + return qtrue; + } + +qboolean G_EventListCmd + ( + gentity_t *ent + ) + + { + const char *mask; + + mask = NULL; + if ( gi.argc() > 1 ) + { + mask = gi.argv( 1 ); + } + + Event::ListCommands( mask ); + + return qtrue; + } + +qboolean G_PendingEventsCmd + ( + gentity_t *ent + ) + + { + const char *mask; + + mask = NULL; + if ( gi.argc() > 1 ) + { + mask = gi.argv( 1 ); + } + + Event::PendingEvents( mask ); + + return qtrue; + } + +qboolean G_EventHelpCmd + ( + gentity_t *ent + ) + + { + const char *mask; + + mask = NULL; + if ( gi.argc() > 1 ) + { + mask = gi.argv( 1 ); + } + + Event::ListDocumentation( mask, false ); + + return qtrue; + } + +qboolean G_DumpEventsCmd + ( + gentity_t *ent + ) + + { + const char *mask; + + mask = NULL; + if ( gi.argc() > 1 ) + { + mask = gi.argv( 1 ); + } + + Event::ListDocumentation( mask, true ); + + return qtrue; + } + +qboolean G_ClassEventsCmd + ( + gentity_t *ent + ) + + { + const char *className; + + className = NULL; + if ( gi.argc() < 2 ) + { + gi.Printf( "Usage: classevents [className]\n" ); + className = gi.argv( 1 ); + } + else + { + className = gi.argv( 1 ); + ClassEvents( className ); + } + return qtrue; + } + +qboolean G_DumpClassEventsCmd + ( + gentity_t *ent + ) + + { + const char *className; + + className = NULL; + if ( gi.argc() < 2 ) + { + gi.Printf( "Usage: dumpclassevents [className]\n" ); + className = gi.argv( 1 ); + } + else + { + className = gi.argv( 1 ); + ClassEvents( className, qtrue ); + } + return qtrue; + } + +qboolean G_DumpAllClassesCmd + ( + gentity_t *ent + ) + + { + DumpAllClasses(); + return qtrue; + } + +qboolean G_ClassListCmd + ( + gentity_t *ent + ) + + { + listAllClasses(); + + return qtrue; + } + +qboolean G_ClassTreeCmd + ( + gentity_t *ent + ) + + { + if ( gi.argc() > 1 ) + { + listInheritanceOrder( gi.argv( 1 ) ); + } + else + { + gi.SendServerCommand( ent - g_entities, "print \"Syntax: classtree [classname].\n\"" ); + } + + return qtrue; + } + +qboolean G_ShowVarCmd + ( + gentity_t *ent + ) + + { + ScriptVariable *var; + + var = Director.GetExistingVariable( gi.argv( 1 ) ); + if ( var ) + { + gi.SendServerCommand( ent - g_entities, "print \"%s = '%s'\n\"", gi.argv( 1 ), var->stringValue() ); + } + else + { + gi.SendServerCommand( ent - g_entities, "print \"Variable '%s' does not exist.\"", gi.argv( 1 ) ); + } + + return qtrue; + } + +qboolean G_ScriptCmd + ( + gentity_t *ent + ) + + { + int i, argc; + const char *argv[ 32 ]; + char args[ 32 ][ 64 ]; + + argc = 0; + for( i = 1; i < gi.argc(); i++ ) + { + if ( argc < 32 ) + { + strncpy( args[ argc ], gi.argv( i ), 64 ); + argv[ argc ] = args[ argc ]; + argc++; + } + } + if ( argc > 0 ) + { + level.consoleThread->ProcessCommand( argc, argv ); + } + + return qtrue; + } + +void PrintVariableList + ( + ScriptVariableList * list + ) + { + ScriptVariable *var; + int i; + + for( i = 1; i <= list->NumVariables(); i++ ) + { + var = list->GetVariable( i ); + gi.Printf( "%s = %s\n", var->getName(), var->stringValue() ); + } + gi.Printf( "%d variables\n", list->NumVariables() ); + } + +qboolean G_LevelVarsCmd + ( + gentity_t *ent + ) + + { + gi.Printf( "Level Variables\n" ); + PrintVariableList( &levelVars ); + + return qtrue; + } + +qboolean G_GameVarsCmd + ( + gentity_t *ent + ) + + { + gi.Printf( "Game Variables\n" ); + PrintVariableList( &gameVars ); + + return qtrue; + } + diff --git a/source/source/fgame/gamecmds.h b/source/source/fgame/gamecmds.h new file mode 100644 index 0000000..4a18ea6 --- /dev/null +++ b/source/source/fgame/gamecmds.h @@ -0,0 +1,62 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/gamecmds.h $ +// $Revision:: 5 $ +// $Date:: 7/10/00 9:27p $ +// +// Copyright (C) 1999 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source is may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/gamecmds.h $ +// +// 5 7/10/00 9:27p Markd +// added ammo variables for how much ammo the player has. Added levelvars and +// gamevars commands +// +// 4 4/26/00 7:55p Markd +// Added more documentation code into various systems +// +// 3 1/28/00 5:43p Markd +// Added script command to the game +// +// 2 1/06/00 11:10p Jimdose +// cleaning up unused code +// +// DESCRIPTION: +// + +#ifndef __GAMECMDS_H__ +#define __GAMECMDS_H__ + +#include "g_local.h" + +extern "C" void G_ClientCommand( gentity_t *ent ); +extern "C" qboolean G_ConsoleCommand( void ); + +void G_InitConsoleCommands( void ); + +qboolean G_ProcessClientCommand( gentity_t *ent ); + +void G_Say( gentity_t *ent, qboolean team, qboolean arg0 ); +qboolean G_CameraCmd( gentity_t *ent ); +qboolean G_SoundCmd( gentity_t *ent ); +qboolean G_SayCmd( gentity_t *ent ); +qboolean G_EventListCmd( gentity_t *ent ); +qboolean G_PendingEventsCmd( gentity_t *ent ); +qboolean G_EventHelpCmd( gentity_t *ent ); +qboolean G_DumpEventsCmd( gentity_t *ent ); +qboolean G_ClassEventsCmd( gentity_t *ent ); +qboolean G_DumpClassEventsCmd( gentity_t *ent ); +qboolean G_DumpAllClassesCmd( gentity_t *ent ); +qboolean G_ClassListCmd( gentity_t *ent ); +qboolean G_ClassTreeCmd( gentity_t *ent ); +qboolean G_ShowVarCmd( gentity_t *ent ); +qboolean G_RestartCmd( gentity_t *ent ); +qboolean G_ScriptCmd( gentity_t *ent ); +qboolean G_LevelVarsCmd( gentity_t *ent ); +qboolean G_GameVarsCmd( gentity_t *ent ); + +#endif /* !__GAMECMDS_H__ */ \ No newline at end of file diff --git a/source/source/fgame/gamecvars.cpp b/source/source/fgame/gamecvars.cpp new file mode 100644 index 0000000..da45097 --- /dev/null +++ b/source/source/fgame/gamecvars.cpp @@ -0,0 +1,250 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/gamecvars.cpp $ +// $Revision:: 29 $ +// $Date:: 7/27/00 4:16p $ +// +// Copyright (C) 1999 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source is may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/gamecvars.cpp $ +// +// 29 7/27/00 4:16p Aldie +// Changed logstats to 0 +// +// 28 7/23/00 5:02p Markd +// made boss health a non-cvar +// +// 27 7/22/00 3:01p Steven +// Added boss health bar stuff. +// +// 26 7/21/00 2:31p Markd +// changed default value of "detail" +// +// 25 7/17/00 3:40p Steven +// Removed sv_gore stuff. +// +// 24 7/17/00 3:26p Aldie +// Fix for flashbangs, changed detail variable, and added forcetorsostate +// +// 23 7/14/00 10:04p Aldie +// Added g_logstats cvar +// +// 22 7/14/00 9:52p Markd +// added global volume dampener on ambient sound effects for cinematics +// +// 21 7/13/00 10:19p Aldie +// Increased default of g_crosshair_maxscale +// +// 20 7/12/00 6:34p Aldie +// Added in crosshair scaling for long distances +// +// 19 7/05/00 7:22p Markd +// +// 18 7/05/00 7:00p Markd +// Changed julie's model to julie_flightsuit.tik +// +// 17 6/13/00 6:46p Aldie +// Added some damage debug info. Added an ignoreEnt for explosion events +// +// 16 6/03/00 3:46p Aldie +// Added in g_debugtargets for debugging targetnames and targets +// +// 15 5/10/00 10:32a Steven +// Added com_blood stuff and removed parentmode and sv_gibs. +// +// 14 5/08/00 3:19p Aldie +// Added initial crosshair work +// +// 13 4/30/00 4:41p Markd +// fixed turning speeed when running +// +// 12 4/15/00 4:24p Markd +// Fixed player turning +// +// 11 3/18/00 3:55p Markd +// working on player turning +// +// 10 3/15/00 2:04p Markd +// fixed up camera node system and added new debug oriented circle +// +// 9 3/14/00 5:12p Markd +// removed unused cvars +// +// 8 3/06/00 8:07p Markd +// cleaned up unused cvar's +// +// 7 2/09/00 8:02p Aldie +// Added loopfire weapons +// +// 6 2/01/00 8:13p Aldie +// More autoaim work +// +// 5 1/19/00 7:46p Aldie +// Fixed func_spawns of various types and removed some unused misc classes +// +// 4 1/19/00 9:51a Markd +// Changed Player model back to julie +// +// 3 1/18/00 7:49p Jimdose +// changed player model +// +// 2 1/06/00 11:08p Jimdose +// cleaning up unused code +// +// DESCRIPTION: +// Definitions for any cvars used by the game. +// + +#include "gamecvars.h" + +cvar_t *developer; +cvar_t *deathmatch; +cvar_t *dmflags; +cvar_t *skill; +cvar_t *fraglimit; +cvar_t *timelimit; +cvar_t *password; +cvar_t *filterban; +cvar_t *flood_msgs; +cvar_t *flood_persecond; +cvar_t *flood_waitdelay; +cvar_t *maxclients; +cvar_t *maxentities; +cvar_t *nomonsters; +cvar_t *precache; +cvar_t *dedicated; +cvar_t *detail; +cvar_t *com_blood; +cvar_t *whereami; + +cvar_t *bosshealth; + +cvar_t *sv_maxvelocity; +cvar_t *sv_gravity; +cvar_t *sv_rollspeed; +cvar_t *sv_rollangle; +cvar_t *sv_cheats; +cvar_t *sv_showbboxes; +cvar_t *sv_showcameras; +cvar_t *sv_showentnums; +cvar_t *sv_stopspeed; +cvar_t *sv_friction; +cvar_t *sv_waterfriction; +cvar_t *sv_waterspeed; +cvar_t *sv_traceinfo; +cvar_t *sv_drawtrace; +cvar_t *sv_fps; +cvar_t *sv_cinematic; + +cvar_t *csys_posx; +cvar_t *csys_posy; +cvar_t *csys_posz; +cvar_t *csys_x; +cvar_t *csys_y; +cvar_t *csys_z; +cvar_t *csys_draw; + +cvar_t *g_showmem; +cvar_t *g_timeents; +cvar_t *g_showaxis; +cvar_t *g_showgravpath; +cvar_t *g_showplayerstate; +cvar_t *g_showplayeranim; +cvar_t *g_legswingspeed; +cvar_t *g_legclampangle; +cvar_t *g_legclamptolerance; +cvar_t *g_legtolerance; +cvar_t *g_numdebuglines; +cvar_t *g_playermodel; +cvar_t *g_statefile; +cvar_t *g_showbullettrace; +cvar_t *s_debugmusic; +cvar_t *g_showautoaim; +cvar_t *g_crosshair; +cvar_t *g_crosshair_maxscale; +cvar_t *g_debugtargets; +cvar_t *g_debugdamage; +cvar_t *g_logstats; + +void CVAR_Init + ( + void + ) + + { + developer = gi.cvar( "developer", "0", 0 ); + precache = gi.cvar( "sv_precache", "1", 0 ); + dedicated = gi.cvar( "dedicated", "0", CVAR_INIT ); + deathmatch = gi.cvar( "deathmatch", "0", CVAR_SERVERINFO|CVAR_LATCH ); + skill = gi.cvar( "skill", "1", CVAR_SERVERINFO|CVAR_LATCH ); + maxclients = gi.cvar( "sv_maxclients", "1", 0 ); + maxentities = gi.cvar( "maxentities", "1024", CVAR_LATCH ); + password = gi.cvar( "password", "", CVAR_USERINFO ); + filterban = gi.cvar( "filterban", "1", 0 ); + dmflags = gi.cvar( "dmflags", "0", CVAR_SERVERINFO ); + fraglimit = gi.cvar( "fraglimit", "0", CVAR_SERVERINFO ); + timelimit = gi.cvar( "timelimit", "0", CVAR_SERVERINFO ); + nomonsters = gi.cvar( "nomonsters", "0", CVAR_SERVERINFO ); + flood_msgs = gi.cvar( "flood_msgs", "4", 0 ); + flood_persecond = gi.cvar( "flood_persecond", "4", 0 ); + flood_waitdelay = gi.cvar( "flood_waitdelay", "10", 0 ); + detail = gi.cvar( "detail", "1", CVAR_ARCHIVE ); + com_blood = gi.cvar( "com_blood", "1", CVAR_USERINFO|CVAR_SERVERINFO|CVAR_ARCHIVE ); + whereami = gi.cvar( "whereami", "0", 0 ); + + bosshealth = gi.cvar( "bosshealth", "0", 0 ); + + sv_rollspeed = gi.cvar( "sv_rollspeed", "200", 0 ); + sv_rollangle = gi.cvar( "sv_rollangle", "2", 0 ); + sv_maxvelocity = gi.cvar( "sv_maxvelocity", "2000", 0 ); + sv_gravity = gi.cvar( "sv_gravity", "800", 0 ); + sv_traceinfo = gi.cvar( "sv_traceinfo", "0", 0 ); + sv_drawtrace = gi.cvar( "sv_drawtrace", "0", 0 ); + sv_showbboxes = gi.cvar( "sv_showbboxes", "0", 0 ); + sv_showcameras = gi.cvar( "sv_showcameras", "0", 0 ); + sv_showentnums = gi.cvar( "sv_showentnums", "0", 0 ); + sv_friction = gi.cvar( "sv_friction", "4", CVAR_SERVERINFO ); + sv_stopspeed = gi.cvar( "sv_stopspeed", "100", CVAR_SERVERINFO ); + sv_waterfriction = gi.cvar( "sv_waterfriction", "1", CVAR_SERVERINFO ); + sv_waterspeed = gi.cvar( "sv_waterspeed", "400", CVAR_SERVERINFO ); + sv_cheats = gi.cvar( "cheats", "0", CVAR_SERVERINFO|CVAR_LATCH ); + sv_fps = gi.cvar( "sv_fps", "20", CVAR_SERVERINFO ); + sv_cinematic = gi.cvar( "sv_cinematic", "0", CVAR_SERVERINFO|CVAR_ROM ); + + g_showmem = gi.cvar( "g_showmem", "0", 0 ); + g_timeents = gi.cvar( "g_timeents", "0", 0 ); + g_showaxis = gi.cvar( "g_showaxis", "0", 0 ); + g_showgravpath = gi.cvar( "g_drawgravpath", "0", 0 ); + g_showplayerstate = gi.cvar( "g_showplayerstate", "0", 0 ); + g_showplayeranim = gi.cvar( "g_showplayeranim", "0", 0 ); + g_showbullettrace = gi.cvar( "g_showbullettrace", "0", 0 ); + + g_legswingspeed = gi.cvar( "g_legswingspeed", "200", 0 ); + g_legclampangle = gi.cvar( "g_legclampangle", "90", 0 ); + g_legclamptolerance = gi.cvar( "g_legclamptolerance", "100", 0 ); + g_legtolerance = gi.cvar( "g_legtolerance", "40", 0 ); + + g_numdebuglines = gi.cvar( "g_numdebuglines", "4096", CVAR_LATCH ); + g_playermodel = gi.cvar( "g_playermodel", "julie", 0 ); + g_statefile = gi.cvar( "g_statefile", "global/julie", 0 ); + g_showautoaim = gi.cvar( "g_showautoaim", "0", 0 ); + g_crosshair = gi.cvar( "g_crosshair", "1", CVAR_ARCHIVE ); + g_crosshair_maxscale = gi.cvar( "g_crosshair_maxscale", "8", CVAR_ARCHIVE ); + g_debugtargets = gi.cvar( "g_debugtargets", "0", 0 ); + g_debugdamage = gi.cvar( "g_debugdamage", "0", 0 ); + g_logstats = gi.cvar( "g_logstats", "0", 0 ); + + csys_posx = gi.cvar( "csys_posx", "0", 0 ); + csys_posy = gi.cvar( "csys_posy", "0", 0 ); + csys_posz = gi.cvar( "csys_posz", "0", 0 ); + csys_x = gi.cvar( "csys_x", "0", 0 ); + csys_y = gi.cvar( "csys_y", "0", 0 ); + csys_z = gi.cvar( "csys_z", "0", 0 ); + csys_draw = gi.cvar( "csys_draw", "0", 0 ); + + s_debugmusic = gi.cvar( "s_debugmusic", "0", 0 ); + } diff --git a/source/source/fgame/gamecvars.h b/source/source/fgame/gamecvars.h new file mode 100644 index 0000000..434cf40 --- /dev/null +++ b/source/source/fgame/gamecvars.h @@ -0,0 +1,141 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/gamecvars.h $ +// $Revision:: 17 $ +// $Date:: 7/22/00 3:02p $ +// +// Copyright (C) 1999 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source is may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/gamecvars.h $ +// +// 17 7/22/00 3:02p Steven +// Added boss health bar stuff. +// +// 16 7/17/00 3:40p Steven +// Removed sv_gore stuff. +// +// 15 7/17/00 3:26p Aldie +// Fix for flashbangs, changed detail variable, and added forcetorsostate +// +// 14 7/14/00 10:04p Aldie +// Added g_logstats cvar +// +// 13 7/14/00 9:52p Markd +// added global volume dampener on ambient sound effects for cinematics +// +// 12 7/12/00 6:34p Aldie +// Added in crosshair scaling for long distances +// +// 11 6/13/00 6:46p Aldie +// Added some damage debug info. Added an ignoreEnt for explosion events +// +// 10 6/03/00 3:46p Aldie +// Added in g_debugtargets for debugging targetnames and targets +// +// 9 5/10/00 10:37a Steven +// Added com_blood. +// +// 8 5/08/00 3:19p Aldie +// Added initial crosshair work +// +// 7 3/15/00 2:04p Markd +// fixed up camera node system and added new debug oriented circle +// +// 6 3/06/00 8:07p Markd +// cleaned up unused cvar's +// +// 5 2/09/00 8:02p Aldie +// Added loopfire weapons +// +// 4 2/01/00 8:13p Aldie +// More autoaim work +// +// 3 1/19/00 7:46p Aldie +// Fixed func_spawns of various types and removed some unused misc classes +// +// 2 1/06/00 11:08p Jimdose +// cleaning up unused code +// +// DESCRIPTION: +// + +#ifndef __GAMECVARS_H__ +#define __GAMECVARS_H__ + +#include "g_local.h" + +extern cvar_t *developer; +extern cvar_t *deathmatch; +extern cvar_t *dmflags; +extern cvar_t *skill; +extern cvar_t *fraglimit; +extern cvar_t *timelimit; +extern cvar_t *password; +extern cvar_t *filterban; +extern cvar_t *flood_msgs; +extern cvar_t *flood_persecond; +extern cvar_t *flood_waitdelay; +extern cvar_t *maxclients; +extern cvar_t *maxentities; +extern cvar_t *nomonsters; +extern cvar_t *precache; +extern cvar_t *dedicated; +extern cvar_t *detail; +extern cvar_t *com_blood; +extern cvar_t *whereami; +extern cvar_t *bosshealth; + +extern cvar_t *sv_maxvelocity; +extern cvar_t *sv_gravity; +extern cvar_t *sv_rollspeed; +extern cvar_t *sv_rollangle; +extern cvar_t *sv_cheats; +extern cvar_t *sv_showbboxes; +extern cvar_t *sv_showcameras; +extern cvar_t *sv_showentnums; +extern cvar_t *sv_stopspeed; +extern cvar_t *sv_friction; +extern cvar_t *sv_waterfriction; +extern cvar_t *sv_waterspeed; +extern cvar_t *sv_traceinfo; +extern cvar_t *sv_drawtrace; +extern cvar_t *sv_fps; +extern cvar_t *sv_cinematic; + +extern cvar_t *csys_posx; +extern cvar_t *csys_posy; +extern cvar_t *csys_posz; +extern cvar_t *csys_x; +extern cvar_t *csys_y; +extern cvar_t *csys_z; +extern cvar_t *csys_draw; + +extern cvar_t *g_showmem; +extern cvar_t *g_timeents; +extern cvar_t *g_showaxis; +extern cvar_t *g_showgravpath; +extern cvar_t *g_showplayerstate; +extern cvar_t *g_showplayeranim; +extern cvar_t *g_showbullettrace; +extern cvar_t *g_legswingspeed; +extern cvar_t *g_legclampangle; +extern cvar_t *g_legclamptolerance; +extern cvar_t *g_legtolerance; +extern cvar_t *g_numdebuglines; +extern cvar_t *g_playermodel; +extern cvar_t *g_statefile; +extern cvar_t *g_showautoaim; +extern cvar_t *g_crosshair; +extern cvar_t *g_crosshair_maxscale; +extern cvar_t *g_debugtargets; +extern cvar_t *g_debugdamage; +extern cvar_t *s_debugmusic; +extern cvar_t *g_logstats; + +void CVAR_Init( void ); + +#endif /* !__GAMECVARS_H__ */ diff --git a/source/source/fgame/gamescript.cpp b/source/source/fgame/gamescript.cpp new file mode 100644 index 0000000..c57b0ff --- /dev/null +++ b/source/source/fgame/gamescript.cpp @@ -0,0 +1,543 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/gamescript.cpp $ +// $Revision:: 6 $ +// $Author:: Markd $ +// $Date:: 7/07/00 4:27p $ +// +// Copyright (C) 1997 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source is may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/gamescript.cpp $ +// +// 6 7/07/00 4:27p Markd +// made it so single : do not count as labels +// +// 5 4/24/00 12:09p Markd +// Fixed script loading issues for when no path is specified +// +// 4 4/05/00 3:51p Markd +// added label checking for scripts +// +// 3 2/22/00 2:23p Jimdose +// GetScript now checks if the name passed in is empty before calling +// FS_ReadFile. Fixes getting kicked out of game when there is no script and a +// trigger tries to start a thread +// +// 2 10/01/99 4:52p Markd +// Made Warning level 4 work on all projects +// +// 1 9/10/99 10:54a Jimdose +// +// 1 9/08/99 3:16p Aldie +// +// 6 8/17/99 5:08p Markd +// Changed all FS_ReadFile's to FS_ReadFileEx's in game code +// +// DESCRIPTION: +// Subclass of script that preprocesses labels +// + +#include "g_local.h" +#include "script.h" +#include "gamescript.h" + +ScriptLibrarian ScriptLib; + +CLASS_DECLARATION( Class, GameScriptMarker, NULL ) + { + { NULL, NULL } + }; + +CLASS_DECLARATION( Class, ScriptLibrarian, NULL ) + { + { NULL, NULL } + }; + +ScriptLibrarian::~ScriptLibrarian() + { + int i; + int num; + + num = scripts.NumObjects(); + for( i = 1; i <= num; i++ ) + { + delete scripts.ObjectAt( i ); + } + } + +void ScriptLibrarian::CloseScripts + ( + void + ) + + { + int i; + int num; + GameScript *scr; + + // Clear out the game and dialog scripts + SetGameScript( "" ); + SetDialogScript( "" ); + + num = scripts.NumObjects(); + for( i = num; i > 0; i-- ) + { + scr = scripts.ObjectAt( i ); + scripts.RemoveObjectAt( i ); + delete scr; + } + } + +void ScriptLibrarian::SetDialogScript + ( + str scriptname + ) + { + dialog_script = scriptname; + } + +void ScriptLibrarian::SetGameScript + ( + str scriptname + ) + { + game_script = scriptname; + } + +const char *ScriptLibrarian::GetGameScript + ( + void + ) + { + return game_script.c_str(); + } + +GameScript *ScriptLibrarian::FindScript + ( + const char *name + ) + + { + int i; + int num; + GameScript *scr; + str n; + + // Convert all forward slashes to back slashes + n = G_FixSlashes( name ); + + num = scripts.NumObjects(); + for( i = 1; i <= num; i++ ) + { + scr = scripts.ObjectAt( i ); + + if ( scr->Filename() == n ) + { + return scr; + } + } + + return NULL; + } + +GameScript *ScriptLibrarian::GetScript + ( + const char *name + ) + + { + GameScript *scr; + str n; + + n = G_FixSlashes( name ); + if ( !n.length() ) + { + return NULL; + } + + + // see if we have an absolute path specified, + // if we don't use the same path as the map file + if ( !strchr( n.c_str(), '/' ) ) + { + int i; + str mapname; + + mapname = "maps/"; + mapname += level.mapname; + for( i = mapname.length() - 1; i >= 0; i-- ) + { + if ( mapname[ i ] == '/' ) + { + // skip back over the '/' + i++; + mapname[ i ] = 0; + break; + } + } + mapname += n; + // copy it back into the write string + n = mapname; + } + + scr = FindScript( n.c_str() ); + if ( !scr && ( gi.FS_ReadFile( n.c_str(), NULL, qfalse ) != -1 ) ) + { + scr = new GameScript(); + scr->LoadFile( n.c_str() ); + scripts.AddObject( scr ); + } + + return scr; + } + +qboolean ScriptLibrarian::Goto + ( + GameScript *scr, + const char *name + ) + + { + const char *p; + GameScript *s; + str n; + + p = strstr( name, "::" ); + if ( !p ) + { + return scr->Goto( name ); + } + else + { + n = str( name, 0, p - name ); + if ( n == str( "dialog" ) ) + { + n = dialog_script; + } + s = GetScript( n.c_str() ); + if ( !s ) + { + return false; + } + + p += 2; + if ( s->labelExists( p ) ) + { + scr->SetSourceScript( s ); + return scr->Goto( p ); + } + } + + return false; + } + +qboolean ScriptLibrarian::labelExists + ( + GameScript *scr, + const char *name + ) + + { + const char *p; + GameScript *s; + str n; + + // if we got passed a NULL than that means just run the script so of course it exists + if ( !name ) + { + return qtrue; + } + + p = strstr( name, "::" ); + if ( !p ) + { + return scr->labelExists( name ); + } + else + { + n = str( name, 0, p - name ); + if ( n == str( "dialog" ) ) + { + n = dialog_script; + } + s = GetScript( n.c_str() ); + if ( !s ) + { + return false; + } + + p += 2; + return s->labelExists( p ); + } + } + +CLASS_DECLARATION( Script, GameScript, NULL ) + { + { NULL, NULL } + }; + +GameScript::GameScript() + { + sourcescript = this; + labelList = NULL; + crc = 0; + } + +GameScript::GameScript + ( + GameScript *scr + ) + + { + crc = 0; + labelList = NULL; + SetSourceScript( scr ); + } + +GameScript::~GameScript() + { + Close(); + } + +void GameScript::Close + ( + void + ) + + { + FreeLabels(); + Script::Close(); + sourcescript = this; + crc = 0; + } + +void GameScript::SetSourceScript + ( + GameScript *scr + ) + + { + if ( scr != this ) + { + Close(); + + sourcescript = scr->sourcescript; + crc = sourcescript->crc; + Parse( scr->buffer, scr->length, scr->Filename() ); + } + } + +void GameScript::FreeLabels + ( + void + ) + + { + int i; + int num; + + if ( labelList ) + { + num = labelList->NumObjects(); + for( i = 1; i <= num; i++ ) + { + delete labelList->ObjectAt( i ); + } + + delete labelList; + } + + labelList = NULL; + } + +void GameScript::LoadFile + ( + const char *name + ) + + { + str n; + + // Convert all forward slashes to back slashes + n = G_FixSlashes( name ); + + sourcescript = this; + Script::LoadFile( n.c_str() ); + FindLabels(); + + crc = gi.CalcCRC( (const unsigned char *)buffer, length ); + } + +void GameScript::FindLabels + ( + void + ) + + { + scriptmarker_t mark; + const char *tok; + script_label_t *label; + int len; + + FreeLabels(); + + labelList = new Container; + + MarkPosition( &mark ); + + Reset(); + + while( TokenAvailable( true ) ) + { + tok = GetToken( true ); + // see if it is a label + if ( tok ) + { + len = strlen( tok ); + if ( ( len > 1 ) && tok[ len - 1 ] == ':' ) + { + if ( !labelExists( tok ) ) + { + label = new script_label_t; + MarkPosition( &label->pos ); + label->labelname = tok; + labelList->AddObject( label ); + } + else + { + warning( "FindLabels", "Duplicate labels %s\n", tok ); + } + } + } + } + + RestorePosition( &mark ); + } + +qboolean GameScript::labelExists + ( + const char *name + ) + + { + str labelname; + script_label_t *label; + int i; + int num; + + // if we got passed a NULL than that means just run the script so of course it exists + if ( !name ) + { + return qtrue; + } + + if ( !sourcescript->labelList ) + { + return false; + } + + labelname = name; + if ( !labelname.length() ) + { + return false; + } + + if ( labelname[ labelname.length() - 1 ] != ':' ) + { + labelname += ":"; + } + + num = sourcescript->labelList->NumObjects(); + for( i = 1; i <= num; i++ ) + { + label = sourcescript->labelList->ObjectAt( i ); + if ( labelname == label->labelname ) + { + return true; + } + } + + return false; + } + +qboolean GameScript::Goto + ( + const char *name + ) + + { + str labelname; + script_label_t *label; + int i; + int num; + + if ( !sourcescript->labelList ) + { + return false; + } + + labelname = name; + if ( !labelname.length() ) + { + return false; + } + + if ( labelname[ labelname.length() - 1 ] != ':' ) + { + labelname += ":"; + } + + num = sourcescript->labelList->NumObjects(); + for( i = 1; i <= num; i++ ) + { + label = sourcescript->labelList->ObjectAt( i ); + if ( labelname == label->labelname ) + { + RestorePosition( &label->pos ); + return true; + } + } + + return false; + } + +void GameScript::Mark + ( + GameScriptMarker *mark + ) + + { + assert( mark ); + assert( sourcescript ); + + mark->filename = sourcescript->Filename(); + MarkPosition( &mark->scriptmarker ); + } + +void GameScript::Restore + ( + GameScriptMarker *mark + ) + + { + // If we change this function, we must update the unarchive function as well + GameScript *scr; + + assert( mark ); + + scr = ScriptLib.FindScript( mark->filename.c_str() ); + if ( scr ) + { + SetSourceScript( scr ); + } + else + { + LoadFile( mark->filename.c_str() ); + } + + RestorePosition( &mark->scriptmarker ); + } diff --git a/source/source/fgame/gamescript.h b/source/source/fgame/gamescript.h new file mode 100644 index 0000000..4bad35d --- /dev/null +++ b/source/source/fgame/gamescript.h @@ -0,0 +1,204 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/gamescript.h $ +// $Revision:: 3 $ +// $Author:: Markd $ +// $Date:: 5/26/00 7:44p $ +// +// Copyright (C) 1997 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source is may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/gamescript.h $ +// +// 3 5/26/00 7:44p Markd +// 2nd phase save games +// +// 2 5/24/00 3:14p Markd +// first phase of save/load games +// +// 1 9/10/99 10:54a Jimdose +// +// 1 9/08/99 3:16p Aldie +// +// DESCRIPTION: +// Subclass of script that preprocesses labels +// + +#ifndef __GAMESCRIPT_H__ +#define __GAMESCRIPT_H__ + +#include "class.h" +#include "script.h" + +typedef struct + { + scriptmarker_t pos; + str labelname; + } script_label_t; + +class GameScript; + +class GameScriptMarker : public Class + { + public: + CLASS_PROTOTYPE( GameScriptMarker ); + + str filename; + scriptmarker_t scriptmarker; + virtual void Archive( Archiver &arc ); + }; + +inline void GameScriptMarker::Archive + ( + Archiver &arc + ) + + { + // Game scripts are unique in that we don't call our superclass to archive it's data. + // Instead, we only read enough info to then initialize the script ourselves. + arc.ArchiveString( &filename ); + arc.ArchiveBoolean( &scriptmarker.tokenready ); + arc.ArchiveInteger( &scriptmarker.offset ); + arc.ArchiveInteger( &scriptmarker.line ); + arc.ArchiveRaw( scriptmarker.token, sizeof( scriptmarker.token ) ); + } + +class GameScript : public Script + { + protected: + Container *labelList; + GameScript *sourcescript; + unsigned crc; + + public: + CLASS_PROTOTYPE( GameScript ); + + GameScript(); + GameScript( GameScript *scr ); + ~GameScript(); + void Close( void ); + void SetSourceScript( GameScript *scr ); + void LoadFile( const char *filename ); + + void Mark( GameScriptMarker *mark ); + void Restore( GameScriptMarker *mark ); + + void FreeLabels( void ); + void FindLabels( void ); + qboolean labelExists( const char *name ); + qboolean Goto( const char *name ); + virtual void Archive( Archiver &arc ); + }; + +class ScriptLibrarian : public Class + { + protected: + Container scripts; + str dialog_script; + str game_script; + + public: + CLASS_PROTOTYPE( ScriptLibrarian ); + + ~ScriptLibrarian(); + + void CloseScripts( void ); + void SetDialogScript( str scriptname ); + void SetGameScript( str scriptname ); + const char *GetGameScript( void ); + GameScript *FindScript( const char *name ); + GameScript *GetScript( const char *name ); + qboolean Goto( GameScript *scr, const char *name ); + qboolean labelExists( GameScript *scr, const char *name ); + virtual void Archive( Archiver &arc ); + }; + +inline void ScriptLibrarian::Archive + ( + Archiver &arc + ) + { + GameScript * scr; + int i, num; + + Class::Archive( arc ); + + if ( arc.Loading() ) + { + scripts.FreeObjectList(); + } + else + { + num = scripts.NumObjects(); + } + arc.ArchiveInteger( &num ); + + for ( i = 1; i <= num; i++ ) + { + if ( arc.Saving() ) + { + scr = scripts.ObjectAt( i ); + } + else + { + scr = new GameScript; + } + arc.ArchiveObject( scr ); + if ( arc.Loading() ) + { + scripts.AddObject( scr ); + } + } + arc.ArchiveString( &dialog_script ); + arc.ArchiveString( &game_script ); + } + +extern ScriptLibrarian ScriptLib; + +inline void GameScript::Archive + ( + Archiver &arc + ) + + { + // Game scripts are unique in that we don't call our superclass to archive it's data. + // Instead, we only read enough info to then initialize the script ourselves. + GameScriptMarker mark; + + if ( arc.Saving() ) + { + arc.ArchiveUnsigned( &crc ); + Mark( &mark ); + arc.ArchiveObject( &mark ); + } + else + { + unsigned filecrc; + GameScript *scr; + + arc.ArchiveUnsigned( &filecrc ); + arc.ArchiveObject( &mark ); + scr = ScriptLib.FindScript( mark.filename.c_str() ); + if ( scr ) + { + SetSourceScript( scr ); + } + else + { + LoadFile( mark.filename.c_str() ); + } + + // Error out if CRCs have changed + if ( filecrc != crc ) + { + gi.Error( ERR_DROP, "File '%s' has changed from when this savegame was written. Load cancelled.\n", filename.c_str() ); + } + + RestorePosition( &mark.scriptmarker ); + } + } + +#endif diff --git a/source/source/fgame/gibs.cpp b/source/source/fgame/gibs.cpp new file mode 100644 index 0000000..22cedae --- /dev/null +++ b/source/source/fgame/gibs.cpp @@ -0,0 +1,390 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/gibs.cpp $ +// $Revision:: 25 $ +// $Author:: Steven $ +// $Date:: 8/10/00 5:45p $ +// +// Copyright (C) 1998 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source is may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/gibs.cpp $ +// +// 25 8/10/00 5:45p Steven +// Fixed a way for blood to stay around forever on gibs. +// +// 24 7/25/00 10:43a Steven +// Made snd_decap louder, +// +// 23 7/17/00 3:40p Steven +// Removed sv_gore stuff. +// +// 22 6/23/00 8:41p Markd +// made a lot of changes to different constructors for saved game support +// +// 21 6/22/00 5:33p Steven +// Fixed the amount of time gib blood spurts stay around. +// +// 20 6/19/00 4:53p Steven +// Added next_bleed_time to make gibs not bleed as much. +// +// 19 6/14/00 3:50p Markd +// Cleaned up more Intel Compiler warnings +// +// 18 4/15/00 11:50a Steven +// Took out default blood names. +// +// 17 4/14/00 10:36a Steven +// Added blood splat size to gibs. +// +// 16 4/08/00 3:56p Steven +// Made it so gibs could be damaged and would spurt blood. +// +// 15 4/04/00 6:54p Steven +// Added random radius to the blood splats. +// +// 14 4/01/00 1:20p Steven +// Some clean up. +// +// 13 3/31/00 1:02p Steven +// Fixed a bug in the bloodsplats. +// +// 12 3/30/00 2:04p Steven +// Added blood splats back in. +// +// 11 3/22/00 10:36a Steven +// Made blood optional in gibs (started using blood_trail variable). +// +// 10 3/02/00 6:40p Steven +// Made which blood model to use a parameter to gib. +// +// 9 1/20/00 6:54p Aldie +// Removed bloodsplats until we do them the right way +// +// 8 1/12/00 4:31p Steven +// Added new movetype MOVETYPE_GIB. +// +// 7 1/06/00 7:00p Steven +// Made it so gibs did not have to have a model. +// +// 6 1/06/00 4:39p Markd +// fixed tiki file name +// +// 5 1/05/00 6:44p Steven +// Fixed gib blood splats (their origin was being miscalculated). +// +// 4 9/29/99 5:18p Steven +// Event formatting. +// +// 3 9/27/99 5:44p Markd +// began documentation and cleanup phase after merge +// +// 2 9/16/99 11:18a Markd +// Continuing merge of code, not functional yet but closer +// +// 1 9/10/99 10:54a Jimdose +// +// 1 9/08/99 3:16p Aldie +// +// 14 9/01/99 8:17p Steven +// Changed gibs to use bspurt2.tik. +// +// 13 8/28/99 11:44a Steven +// Removed global from sound function calls. +// +// DESCRIPTION: +// Gibs - nuff said + +#include "gibs.h" +#include "decals.h" + +Event EV_ThrowGib + ( + "throwgib", + EV_DEFAULT, + "eif", + "ent velocity scale", + "Throw a gib." + ); + +CLASS_DECLARATION( Mover, Gib, "gib" ) + { + { &EV_ThrowGib, Throw }, + { &EV_Touch, Splat }, + { &EV_Stop, Stop }, + { &EV_Damage, Damage }, + { NULL, NULL } + }; + +Gib::Gib + ( + str name, + qboolean blood_trail, + str bloodtrailname, + str bloodspurtname, + str bloodsplatname, + float bloodsplatsize, + float pitch + ) + + { + setSize("0 0 0", "0 0 0"); + + if ( name.length() ) + setModel( name.c_str() ); + + setMoveType( MOVETYPE_GIB ); + setSolidType( SOLID_BBOX ); + takedamage = DAMAGE_YES; + sprayed = false; + fadesplat = true; + scale = 2.0f; + + next_bleed_time = 0; + + final_pitch = pitch; + + if ( blood_trail ) + { + // Make a blood emitter and bind it to the head + blood = new Mover; + + if ( bloodtrailname.length() ) + blood->setModel( bloodtrailname.c_str() ); + + blood->setMoveType( MOVETYPE_BOUNCE ); + blood->setSolidType( SOLID_NOT ); + blood->bind( this ); + + // Save the blood spurt name + + if ( bloodspurtname.length() ) + blood_spurt_name = bloodspurtname; + + // Save the blood splat name + + if ( bloodsplatname.length() ) + blood_splat_name = bloodsplatname; + + blood_splat_size = bloodsplatsize; + } + else + { + blood = NULL; + } + + Sound( "snd_decap", CHAN_BODY, 1, 300 ); + } + +Gib::~Gib() + { + if ( blood ) + blood->PostEvent( EV_Remove, 0 ); + blood = NULL; + } + +Gib::Gib() + { + if ( LoadingSavegame ) + { + return; + } + + setSize("0 0 0", "0 0 0"); + setModel("gib1.def"); + setMoveType( MOVETYPE_GIB ); + setSolidType( SOLID_BBOX ); + sprayed = 0; + fadesplat = true; + scale = 2.0f; + } + +void Gib::Stop + ( + Event *ev + ) + + { + //setSolidType( SOLID_NOT ); + if ( blood ) + blood->PostEvent( EV_Remove, 0 ); + blood = NULL; + } + +void Gib::Splat + ( + Event *ev + ) + + { + if ( deathmatch->integer ) + return; + + if ( sprayed > 3 ) + { + //setSolidType(SOLID_NOT); + return; + } + + sprayed++; + scale -= 0.2; + + // Stop spinning / force to final pitch + + avelocity = vec_zero; + + if ( final_pitch != NO_FINAL_PITCH ) + { + angles[PITCH] = final_pitch; + setAngles( angles ); + } + + SprayBlood( origin ); + Sound( "snd_gibhit" ); + } + +void Gib::Damage + ( + Event *ev + ) + + { + Vector direction; + Entity *blood; + Vector dir; + + if ( next_bleed_time > level.time ) + return; + + direction = ev->GetVector ( 5 ); + + // Spawn a blood spurt + + if ( blood_spurt_name.length() > 0 ) + { + blood = new Animate; + blood->setModel( blood_spurt_name.c_str() ); + + dir[0] = -direction[0]; + dir[1] = -direction[1]; + dir[2] = -direction[2]; + + blood->angles = dir.toAngles(); + blood->setAngles( blood->angles ); + + blood->setOrigin( centroid ); + blood->origin.copyTo( blood->edict->s.origin2 ); + blood->setSolidType( SOLID_NOT ); + + blood->PostEvent( EV_Remove, 1 ); + + next_bleed_time = level.time + 0.5; + } + } + +void Gib::SprayBlood + ( + Vector start + ) + + { + Vector norm; + trace_t trace; + Vector trace_end; + + trace_end = velocity; + trace_end.normalize(); + trace_end *= 1000; + trace_end += start; + + trace = G_Trace( start, vec_zero, vec_zero, trace_end, this, MASK_SOLID, false, "Gib::SprayBlood" ); + + if ( HitSky( &level.impact_trace ) || ( !level.impact_trace.ent ) || ( level.impact_trace.ent->solid != SOLID_BSP ) ) + { + return; + } + + // Do a bloodsplat + if ( blood_splat_name.length() ) + { + Decal *decal = new Decal; + decal->setShader( blood_splat_name ); + decal->setOrigin( Vector( trace.endpos ) + ( Vector( level.impact_trace.plane.normal ) * 0.2 ) ); + decal->setDirection( level.impact_trace.plane.normal ); + decal->setOrientation( "random" ); + decal->setRadius( blood_splat_size + G_Random( blood_splat_size ) ); + } + } + +void Gib::ClipGibVelocity + ( + void + ) + + { + if (velocity[0] < -400) + velocity[0] = -400; + else if (velocity[0] > 400) + velocity[0] = 400; + if (velocity[1] < -400) + velocity[1] = -400; + else if (velocity[1] > 400) + velocity[1] = 400; + if (velocity[2] < 200) + velocity[2] = 200; // always some upwards + else if (velocity[2] > 600) + velocity[2] = 600; +} + +void Gib::SetVelocity + ( + float damage + ) + + { + velocity[0] = 100.0 * crandom(); + velocity[1] = 100.0 * crandom(); + velocity[2] = 200.0 + 100.0 * random(); + + avelocity = Vector( G_Random( 600 ), G_Random( 600 ), G_Random( 600 ) ); + + if ( ( damage < -150 ) && ( G_Random() > 0.95f ) ) + velocity *= 2.0f; + else if ( damage < -100 ) + velocity *= 1.5f; + + ClipGibVelocity(); + } + +void Gib::Throw + ( + Event *ev + ) + + { + Entity *ent; + + ent = ev->GetEntity(1); + setOrigin(ent->centroid); + origin.copyTo(edict->s.origin2); + SetVelocity(ev->GetInteger(2)); + edict->s.scale = ev->GetFloat(3); + PostEvent(EV_FadeOut, 10 + G_Random(5)); + } + + +void CreateGibs + ( + Entity * ent, + float damage, + float scale, + int num, + const char * modelname + ) + + { + + } diff --git a/source/source/fgame/gibs.h b/source/source/fgame/gibs.h new file mode 100644 index 0000000..46db302 --- /dev/null +++ b/source/source/fgame/gibs.h @@ -0,0 +1,120 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/gibs.h $ +// $Revision:: 11 $ +// $Author:: Steven $ +// $Date:: 8/10/00 5:45p $ +// +// Copyright (C) 1998 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source is may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/gibs.h $ +// +// 11 8/10/00 5:45p Steven +// Fixed a way for blood to stay around forever on gibs. +// +// 10 6/19/00 4:53p Steven +// Added next_bleed_time to make gibs not bleed as much. +// +// 9 6/14/00 3:50p Markd +// Cleaned up more Intel Compiler warnings +// +// 8 5/26/00 7:44p Markd +// 2nd phase save games +// +// 7 5/24/00 3:14p Markd +// first phase of save/load games +// +// 6 4/14/00 10:36a Steven +// Added blood splat size to gibs. +// +// 5 4/08/00 3:59p Steven +// Added damage event and blood spurt name. +// +// 4 4/01/00 1:20p Steven +// Some clean up. +// +// 3 3/30/00 2:04p Steven +// Added blood splats back in. +// +// 2 3/02/00 6:40p Steven +// Made which blood model to use a parameter to gib. +// +// 1 9/10/99 10:54a Jimdose +// +// 1 9/08/99 3:16p Aldie +// +// DESCRIPTION: +// Gibs - nuff said + +#ifndef __GIBS_H__ +#define __GIBS_H__ + +#include "g_local.h" +#include "mover.h" + +#define NO_FINAL_PITCH -1000 + +class Gib : public Mover + { + private: + int sprayed; + float scale; + Mover *blood; + str blood_splat_name; + float blood_splat_size; + str blood_spurt_name; + float final_pitch; + float next_bleed_time; + public: + CLASS_PROTOTYPE( Gib ); + + qboolean fadesplat; + Gib(); + ~Gib(); + Gib( str name, qboolean blood_trail, str bloodtrailname="", str bloodspurtname="", str bloodsplatname="", + float blood_splat_size = 8, float pitch=NO_FINAL_PITCH ); + void SetVelocity( float health ); + void SprayBlood( Vector start ); + void Throw( Event *ev ); + void Splat( Event *ev ); + void Stop( Event *ev ); + void Damage( Event *ev ); + void ClipGibVelocity( void ); + virtual void Archive( Archiver &arc ); + }; + +inline void Gib::Archive + ( + Archiver &arc + ) + { + Entity::Archive( arc ); + + arc.ArchiveBoolean( &sprayed ); + arc.ArchiveFloat( &scale ); + arc.ArchiveObjectPointer( ( Class ** )&blood ); + arc.ArchiveString( &blood_splat_name ); + arc.ArchiveFloat( &blood_splat_size ); + arc.ArchiveString( &blood_spurt_name ); + arc.ArchiveFloat( &final_pitch ); + arc.ArchiveBoolean( &fadesplat ); + arc.ArchiveFloat( &next_bleed_time ); + } + + +void CreateGibs + ( + Entity * ent, + float damage = -50, + float scale = 1.0f, + int num = 1, + const char * modelname = NULL + ); + +extern Event EV_ThrowGib; + +#endif // gibs.h diff --git a/source/source/fgame/goo.cpp b/source/source/fgame/goo.cpp new file mode 100644 index 0000000..4ee28a7 --- /dev/null +++ b/source/source/fgame/goo.cpp @@ -0,0 +1,278 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/goo.cpp $ +// $Revision:: 7 $ +// $Author:: Markd $ +// $Date:: 7/31/00 1:33a $ +// +// Copyright (C) 1998 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/goo.cpp $ +// +// 7 7/31/00 1:33a Markd +// fixed crash bug for goo +// +// 6 7/20/00 9:30p Aldie +// Tweak +// +// 5 7/20/00 6:21p Aldie +// More fixes to goo +// +// 4 7/20/00 3:46p Aldie +// Lots of fixes to the goo projectile +// +// 3 6/08/00 3:56p Aldie +// Fixed a comment +// +// 2 6/08/00 3:55p Aldie +// Added goo +// +// DESCRIPTION: +// Goo Gun Projectile + +#include "goo.h" + +Event EV_GooDebris_Prethink + ( + "_prethink", + EV_DEFAULT, + NULL, + NULL, + "Think function for the debris" + ); + +CLASS_DECLARATION( Projectile, GooDebris, NULL ) + { + { &EV_GooDebris_Prethink, Prethink }, + { &EV_Touch, Touch }, + { NULL, NULL } + }; + +GooDebris::GooDebris + ( + ) + + { + nexttouch = 0; + } + +void GooDebris::Prethink + ( + Event *ev + ) + + { + if ( ( velocity.length() < 30 ) && ( CurrentAnim() == gi.Anim_NumForName( edict->s.modelindex, "idle" ) ) ) + { + velocity = Vector( 0,0,0 ); + RandomAnimate( "splat" ); + } + + if ( ( level.time - this->edict->spawntime ) > 5 ) + { + edict->s.scale *= 0.95; + } + + if ( edict->s.scale < 0.1 ) + { + PostEvent( EV_Remove, 0 ); + } + else + { + Event *ev1 = new Event( ev ); + PostEvent( ev1, level.frametime ); + } + } + +void GooDebris::Touch + ( + Event *ev + ) + + { + Entity *other; + Entity *owner; + Vector ang; + + other = ev->GetEntity( 1 ); + + if ( other == world ) + { + vectoangles( level.impact_trace.plane.normal, ang ); + setAngles( ang ); + } + + if ( level.time < nexttouch ) + { + return; + } + + nexttouch = level.time + 0.5; + + if ( !other->isSubclassOf( Sentient ) ) + { + return; + } + + owner = G_GetEntity( this->owner ); + + if ( !owner ) + { + owner = world; + } + + if ( !other ) + { + return; + } + + other->Damage( this, owner, damage, origin, Vector( 0,0,0 ), Vector( 0,0,0 ), 0, 0, meansofdeath ); + } + +Event EV_Goo_DebrisModel + ( + "debrismodel", + EV_DEFAULT, + "s", + "modelname", + "Model name for the debris that is spawned on explosion" + ); +Event EV_Goo_DebrisCount + ( + "debriscount", + EV_DEFAULT, + "i", + "count", + "Number of pieces of debris to spawn" + ); + +CLASS_DECLARATION( Projectile, GooProjectile, NULL ) + { + { &EV_Goo_DebrisModel, SetDebrisModel }, + { &EV_Goo_DebrisCount, SetDebrisCount }, + { NULL, NULL } + }; + +GooProjectile::GooProjectile + ( + ) + + { + m_debrismodel = "fx_goo_debris.tik"; + m_debriscount = 3; + } + +void GooProjectile::SetDebrisModel + ( + Event *ev + ) + + { + m_debrismodel = ev->GetString( 1 ); + } + +void GooProjectile::SetDebrisCount + ( + Event *ev + ) + + { + m_debriscount = ev->GetInteger( 1 ); + } + +void GooProjectile::Explode + ( + Event *ev + ) + + { + int i; + Entity *owner; + Entity *ignoreEnt=NULL; + + if ( ev->NumArgs() == 1 ) + ignoreEnt = ev->GetEntity( 1 ); + + // Get the owner of this projectile + owner = G_GetEntity( this->owner ); + + // If the owner's not here, make the world the owner + if ( !owner ) + owner = world; + + takedamage = DAMAGE_NO; + + // Spawn an explosion model + if ( explosionmodel.length() ) + { + // Move the projectile back off the surface a bit so we can see + // explosion effects. + Vector dir, v; + v = velocity; + v.normalize(); + dir = v; + v = origin - v * 36; + setOrigin( v ); + + ExplosionAttack( v, owner, explosionmodel, dir, ignoreEnt ); + } + + CancelEventsOfType( EV_Projectile_UpdateBeam ); + + // Kill the beam + if ( m_beam ) + { + m_beam->ProcessEvent( EV_Remove ); + m_beam = NULL; + } + + // When the goo hits something, spawn debris + for ( i=0; iorigin, dir, this, m_debrismodel, 1.0 ); + + if ( !proj ) + { + warning( "GooProjectile::Explode", "Could not create debris projectile" ); + return; + } + + proj->owner = ENTITYNUM_WORLD; + proj->setSolidType( SOLID_TRIGGER ); + proj->avelocity = Vector( G_CRandom( 360 ), G_CRandom( 360 ), G_CRandom( 360 ) ); + proj->setSize( Vector( -16,-16,0 ) * proj->edict->s.scale, Vector( 16,16,32 ) * proj->edict->s.scale ); + proj->setMoveType( MOVETYPE_TOSS ); + proj->PostEvent( EV_GooDebris_Prethink, level.frametime ); + } + + // Change to the splat + if ( level.impact_trace.ent && ( level.impact_trace.ent->solid == SOLID_BSP ) ) + { + GooDebris *p; + Vector ang; + p = new GooDebris; + vectoangles( level.impact_trace.plane.normal, ang ); + p->setAngles( ang ); + p->setModel( this->model ); + p->ProcessInitCommands( p->edict->s.modelindex ); + p->setSize( Vector( -16,-16,0 ) * p->edict->s.scale, Vector( 16,16,32 ) * p->edict->s.scale ); + p->setOrigin( this->origin ); + p->velocity = Vector( 0,0,0 ); + p->setMoveType( MOVETYPE_FLY ); + p->setSolidType( SOLID_TRIGGER ); + p->RandomAnimate( "splat" ); + p->owner = this->owner; + p->PostEvent( EV_GooDebris_Prethink, level.frametime ); // shrink out + } + } + diff --git a/source/source/fgame/goo.h b/source/source/fgame/goo.h new file mode 100644 index 0000000..ca35b72 --- /dev/null +++ b/source/source/fgame/goo.h @@ -0,0 +1,89 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/goo.h $ +// $Revision:: 5 $ +// $Author:: Aldie $ +// $Date:: 7/20/00 6:21p $ +// +// Copyright (C) 1998 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/goo.h $ +// +// 5 7/20/00 6:21p Aldie +// More fixes to goo +// +// 4 7/20/00 3:46p Aldie +// Lots of fixes to the goo projectile +// +// 3 6/08/00 3:56p Aldie +// Fixed a comment +// +// 2 6/08/00 3:55p Aldie +// Added goo +// +// DESCRIPTION: +// Goo Gun Projectile + +#ifndef __GOO_H__ +#define __GOO_H__ + +#include "weapon.h" +#include "weaputils.h" + +class GooProjectile : public Projectile + { + private: + str m_debrismodel; + int m_debriscount; + + public: + CLASS_PROTOTYPE( GooProjectile ); + + GooProjectile(); + void Explode( Event *ev ); + void SetDebrisModel( Event *ev ); + void SetDebrisCount( Event *ev ); + void Archive( Archiver &arc ); + }; + +void GooProjectile::Archive + ( + Archiver &arc + ) + + { + Projectile::Archive( arc ); + arc.ArchiveString( &m_debrismodel ); + arc.ArchiveInteger( &m_debriscount ); + } + + +class GooDebris : public Projectile + { + private: + float nexttouch; + + public: + CLASS_PROTOTYPE( GooDebris ); + + GooDebris(); + void Touch( Event *ev ); + void Prethink( Event *ev ); + void Archive( Archiver &arc ); + }; + +void GooDebris::Archive + ( + Archiver &arc + ) + + { + Projectile::Archive( arc ); + arc.ArchiveFloat( &nexttouch ); + } + +#endif // __GOO_H__ \ No newline at end of file diff --git a/source/source/fgame/gravpath.cpp b/source/source/fgame/gravpath.cpp new file mode 100644 index 0000000..261ce15 --- /dev/null +++ b/source/source/fgame/gravpath.cpp @@ -0,0 +1,836 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/gravpath.cpp $ +// $Revision:: 14 $ +// $Author:: Steven $ +// $Date:: 7/21/00 8:36p $ +// +// Copyright (C) 1998 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source is may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/gravpath.cpp $ +// +// 14 7/21/00 8:36p Steven +// Got gravpaths working fairly well. +// +// 13 7/08/00 6:07p Steven +// Added a PULL_UPWARDS spawn flag to gravpaths. +// +// 12 7/06/00 12:58p Steven +// Changed gravpaths to pull you parallel to the path not towards it. +// +// 11 6/23/00 8:41p Markd +// made a lot of changes to different constructors for saved game support +// +// 10 6/14/00 2:17p Markd +// fixed compiler warnings for Intel Compiler +// +// 9 1/22/00 12:42p Jimdose +// got rid of calls to vec3() +// +// 8 1/06/00 11:08p Jimdose +// cleaning up unused code +// +// 7 12/07/99 10:33a Jimdose +// made CalculateGravityPull early exit when there are no gravpaths +// +// 6 10/26/99 5:27p Aldie +// Fix for gravpaths +// +// 5 10/04/99 10:53a Aldie +// fix warning +// +// 4 9/29/99 5:18p Steven +// Event formatting. +// +// 3 9/22/99 4:47p Markd +// fixed more G_GetEntity, G_FindClass and G_GetNextEntity bugs +// +// 2 9/21/99 7:51p Markd +// Fixed a lot of entitynum_none issues +// +// 1 9/10/99 10:54a Jimdose +// +// 1 9/08/99 3:16p Aldie +// +// 10 8/18/99 3:28p Jimdose +// added cylindrical collision detection +// +// 9 6/11/99 1:23p Phook +// +// 8 6/11/99 12:58p Phook +// Changed from SINED comments to QUAKED +// +// DESCRIPTION: +// Gravity path - Used for underwater currents and wells. + +#include "g_local.h" +#include "entity.h" +#include "gravpath.h" +#include "container.h" +#include "navigate.h" +#include "misc.h" +#include "player.h" + +GravPathManager gravPathManager; + +CLASS_DECLARATION( Class, GravPathManager, NULL ) + { + { NULL,NULL } + }; + +GravPathManager::~GravPathManager() + { + Reset(); + } + +void GravPathManager::Reset( void ) + { + while( pathList.NumObjects() > 0 ) + { + delete ( GravPath * )pathList.ObjectAt( 1 ); + } + + pathList.FreeObjectList(); + } + +void GravPathManager::AddPath(GravPath *p) + { + pathList.AddObject( p ); + } + +void GravPathManager::RemovePath(GravPath *p) + { + pathList.RemoveObject( p ); + } + +void GravPathManager::DrawGravPaths + ( + void + ) + + { + int i; + int num = pathList.NumObjects(); + + for( i = 1; i <= num; i++ ) + { + GravPath *p = ( GravPath * )pathList.ObjectAt( i ); + + p->DrawPath( 1,0,0 ); + } + } + +Vector GravPathManager::CalculateGravityPull(Entity &ent, Vector pos, qboolean *force, float *max_speed) + { + int i,num; + GravPath *p; + GravPathNode *node; + Vector point; + Vector newpoint; + Vector dir; + float bestdist = 99999; + float dist; + float speed; + float radius; + Vector velocity; + int bestpath = 0; + int entity_contents, grav_contents; + + num = pathList.NumObjects(); + if ( !num ) + { + return vec_zero; + } + + entity_contents = gi.pointcontents( ent.origin, 0 ); + + for( i = 1; i <= num; i++ ) + { + p = ( GravPath * )pathList.ObjectAt( i ); + + if ( !p ) + continue; + + // Check to see if path is active + node = p->GetNode( 1 ); + if ( !node || !node->active ) + continue; + + // Check to see if the contents are the same + grav_contents = gi.pointcontents( node->origin, 0 ); + + // If grav node is in water, make sure ent is too. + if ( ( grav_contents & CONTENTS_WATER ) && !( entity_contents & CONTENTS_WATER ) ) + continue; + + // Test to see if we are in this path's bounding box + if ( (pos.x < p->maxs.x) && (pos.y < p->maxs.y) && (pos.z < p->maxs.z) && + (pos.x > p->mins.x) && (pos.y > p->mins.y) && (pos.z > p->mins.z) ) + { + point = p->ClosestPointOnPath(pos, ent, &dist, &speed, &radius); + + // If the closest distance on the path is greater than the radius, then + // do not consider this path. + + if (dist > radius) + { + continue; + } + else if (dist < bestdist) + { + bestpath = i; + bestdist = dist; + } + } + } + + if (!bestpath) + { + return vec_zero; + } + + p = ( GravPath * )pathList.ObjectAt( bestpath ); + if ( !p ) + return velocity; + *force = p->force; + dist = p->DistanceAlongPath(pos, &speed); + newpoint = p->PointAtDistance( pos, dist + speed, ent.isSubclassOf( Player ), max_speed ); + dir = newpoint-pos; + dir.normalize(); + velocity = dir * speed; + + //velocity *= .75; + return velocity; + } + +/*****************************************************************************/ +/*QUAKED info_grav_pathnode (0 0 .5) (-16 -16 0) (16 16 32) HEADNODE FORCE PULL_UPWARDS + "radius" Radius of the effect of the pull (Default is 256) + "speed" Speed of the pull (Use negative for a repulsion) (Default is 100) + + Set HEADNODE to signify the head of the path. + Set FORCE if you want un-fightable gravity ( i.e. can't go backwards ) + Set PULL_UPWARDS if you want the gravnodes to pull you upwards also +******************************************************************************/ + +#define PULL_UPWARDS ( 1 << 2 ) + +Event EV_GravPath_Create + ( + "gravpath_create", + EV_DEFAULT, + NULL, + NULL, + "Create the grav path." + ); +Event EV_GravPath_Activate + ( + "activate", + EV_DEFAULT, + NULL, + NULL, + "Activate the grav path." + ); +Event EV_GravPath_Deactivate + ( + "deactivate", + EV_DEFAULT, + NULL, + NULL, + "Deactivate the grav path." + ); +Event EV_GravPath_SetSpeed + ( + "speed", + EV_DEFAULT, + "f", + "speed", + "Set the speed of the grav path." + ); +Event EV_GravPath_SetMaxSpeed + ( + "maxspeed", + EV_DEFAULT, + "f", + "maxspeed", + "Set the max speed of the grav path." + ); +Event EV_GravPath_SetRadius + ( + "radius", + EV_DEFAULT, + "f", + "radius", + "Set the radius of the grav path." + ); + +CLASS_DECLARATION( Entity, GravPathNode, "info_grav_pathnode" ) + { + { &EV_GravPath_Create, CreatePath }, + { &EV_GravPath_Activate, Activate }, + { &EV_GravPath_Deactivate, Deactivate }, + { &EV_GravPath_SetSpeed, SetSpeed }, + { &EV_GravPath_SetMaxSpeed, SetMaxSpeed }, + { &EV_GravPath_SetRadius, SetRadius }, + { NULL, NULL } + }; + +GravPathNode::GravPathNode() + { + if ( LoadingSavegame ) + { + // all data will be setup by the archive function + return; + } + + setMoveType( MOVETYPE_NONE ); + setSolidType( SOLID_NOT ); + hideModel(); + + speed = 100.0f; + max_speed = 200.0f; + radius = 256.0f; + headnode = spawnflags & 1; + active = true; + + // This is the head of a new path, post an event to create the path + if ( headnode ) + { + PostEvent( EV_GravPath_Create, 0 ); + } + } + +void GravPathNode::SetSpeed + ( + Event *ev + ) + + { + speed = ev->GetFloat( 1 ); + } + +void GravPathNode::SetMaxSpeed + ( + Event *ev + ) + + { + max_speed = ev->GetFloat( 1 ); + } + +void GravPathNode::SetRadius + ( + Event *ev + ) + + { + radius = ev->GetFloat( 1 ); + } + +float GravPathNode::Speed + ( + void + ) + + { + if ( active ) + return speed; + else + return 0; + } + +float GravPathNode::MaxSpeed + ( + void + ) + + { + return max_speed; + } + +void GravPathNode::Activate + ( + Event *ev + ) + + { + GravPathNode *node; + Entity *ent; + const char *target; + + active = true; + node = this; + // Go through the entire path and activate it + target = node->Target(); + while (target[0]) + { + ent = G_FindTarget( NULL, target ); + if ( ent ) + { + node = (GravPathNode *)ent; + assert( node ); + node->active = true; + } + else + { + gi.Error( ERR_DROP, "GravPathNode::CreatePath: target %s not found\n",target); + } + target = node->Target(); + } + } + +void GravPathNode::Deactivate(Event *ev) + { + GravPathNode *node; + Entity *ent; + const char *target; + + active = false; + node = this; + // Go through the entire path and activate it + target = node->Target(); + while (target[0]) + { + ent = G_FindTarget( NULL, target); + if ( ent ) + { + node = (GravPathNode *)ent; + assert( node ); + node->active = false; + } + else + { + gi.Error( ERR_DROP, "GravPathNode::CreatePath: target %s not found\n",target); + } + target = node->Target(); + } + } + +void GravPathNode::CreatePath(Event *ev) + { + const char *target; + GravPath *path = new GravPath; + GravPathNode *node; + Entity *ent; + + ClearBounds( path->mins, path->maxs ); + + // This node is the head of a path, create a new path in the path manager. + // and add it in, then add all of it's children in the path. + node = this; + path->AddNode(node); + path->force = spawnflags & 2; + + // Make the path from the targetlist. + target = node->Target(); + while (target[0]) + { + ent = G_FindTarget( NULL, target ); + if ( ent ) + { + node = (GravPathNode *)ent; + assert( node ); + path->AddNode(node); + } + else + { + gi.Error( ERR_DROP, "GravPathNode::CreatePath: target %s not found\n",target); + } + target = node->Target(); + } + + // Set the origin. + path->origin = path->mins + path->maxs; + path->origin *= 0.5f; + } + +CLASS_DECLARATION( Listener, GravPath, NULL ) + { + { NULL, NULL } + }; + +GravPath::GravPath() + { + pathlength = 0; + from = NULL; + to = NULL; + nextnode = 1; + + if ( !LoadingSavegame ) + { + gravPathManager.AddPath(this); + } + } + +GravPath::~GravPath() + { + pathlength = 0; + from = NULL; + to = NULL; + nextnode = 1; + gravPathManager.RemovePath(this); + } + +void GravPath::Clear + ( + void + ) + + { + nextnode = 1; + pathlength = 0; + from = NULL; + to = NULL; + pathlist.FreeObjectList(); + } + +void GravPath::Reset + ( + void + ) + + { + nextnode = 1; + } + +GravPathNode *GravPath::Start + ( + void + ) + + { + return from; + } + +GravPathNode *GravPath::End + ( + void + ) + + { + return to; + } + +void GravPath::AddNode + ( + GravPathNode *node + ) + + { + int num; + Vector r,addp; + + if ( !from ) + { + from = node; + } + + to = node; + pathlist.AddObject( GravPathNodePtr( node ) ); + + num = NumNodes(); + if ( num > 1 ) + { + pathlength += ( node->origin - GetNode( num )->origin ).length(); + } + + r.setXYZ(node->Radius(),node->Radius(),node->Radius()); + addp = node->origin + r; + AddPointToBounds(addp,mins,maxs); + addp = node->origin - r; + AddPointToBounds(addp,mins,maxs); + } + +GravPathNode *GravPath::GetNode + ( + int num + ) + + { + return pathlist.ObjectAt( num ); + } + +GravPathNode *GravPath::NextNode + ( + void + ) + + { + if ( nextnode <= NumNodes() ) + { + return pathlist.ObjectAt( nextnode++ ); + } + return NULL; + } + +Vector GravPath::ClosestPointOnPath + ( + Vector pos, + Entity &ent, + float *ret_dist, + float *speed, + float *radius + ) + + { + GravPathNode *s; + GravPathNode *e; + int num; + int i; + float bestdist; + Vector bestpoint; + float dist; + float segmentlength; + Vector delta; + Vector p1; + Vector p2; + Vector p3; + float t; + trace_t trace; + + num = NumNodes(); + s = GetNode( 1 ); + trace = G_Trace( pos, ent.mins, ent.maxs, s->origin, &ent, MASK_PLAYERSOLID, false, "GravPath::ClosestPointOnPath 1" ); + bestpoint = s->origin; + delta = bestpoint - pos; + bestdist = delta.length(); + *speed = s->Speed(); + *radius = s->Radius(); + + for( i = 2; i <= num; i++ ) + { + e = GetNode( i ); + + // check if we're closest to the endpoint + delta = e->origin - pos; + dist = delta.length(); + + if ( dist < bestdist ) + { + trace = G_Trace( pos, ent.mins, ent.maxs, e->origin, &ent, MASK_PLAYERSOLID, false, "GravPath::ClosestPointOnPath 2" ); + bestdist = dist; + bestpoint = e->origin; + *speed = e->Speed(); + *radius = e->Radius(); + } + + // check if we're closest to the segment + p1 = e->origin - s->origin; + segmentlength = p1.length(); + p1 *= 1 / segmentlength; + p2 = pos - s->origin; + + t = p1 * p2; + if ( ( t > 0 ) && ( t < segmentlength ) ) + { + p3 = ( p1 * t ) + s->origin; + + delta = p3 - pos; + dist = delta.length(); + if ( dist < bestdist ) + { + trace = G_Trace( pos, ent.mins, ent.maxs, p3, &ent, MASK_PLAYERSOLID, false, "GravPath::ClosestPointOnPath 3" ); + bestdist = dist; + bestpoint = p3; + *speed = (e->Speed() * t) + (s->Speed() * (1.0f - t)); + *radius = (e->Radius() * t) + (s->Radius() * (1.0f - t)); + } + } + + s = e; + } + *ret_dist = bestdist; + return bestpoint; + } + +float GravPath::DistanceAlongPath + ( + Vector pos, + float *speed + ) + + { + GravPathNode *s; + GravPathNode *e; + int num; + int i; + float bestdist; + float dist; + float segmentlength; + Vector delta; + Vector segment; + Vector p1; + Vector p2; + Vector p3; + float t; + float pathdist; + float bestdistalongpath; + float oosl; + pathdist = 0; + + num = NumNodes(); + s = GetNode( 1 ); + delta = s->origin - pos; + bestdist = delta.length(); + bestdistalongpath = 0; + *speed = s->Speed(); + + for( i = 2; i <= num; i++ ) + { + e = GetNode( i ); + + segment = e->origin - s->origin; + segmentlength = segment.length(); + + // check if we're closest to the endpoint + delta = e->origin - pos; + dist = delta.length(); + + if ( dist < bestdist ) + { + bestdist = dist; + bestdistalongpath = pathdist + segmentlength; + *speed = e->Speed(); + } + + // check if we're closest to the segment + oosl = ( 1 / segmentlength ); + p1 = segment * oosl; + p1.normalize(); + p2 = pos - s->origin; + + t = p1 * p2; + if ( ( t > 0 ) && ( t < segmentlength ) ) + { + p3 = ( p1 * t ) + s->origin; + + delta = p3 - pos; + dist = delta.length(); + if ( dist < bestdist ) + { + bestdist = dist; + bestdistalongpath = pathdist + t; + + t *= oosl; + *speed = (e->Speed() * t) + (s->Speed() * (1.0f - t)); + } + } + + s = e; + pathdist += segmentlength; + } + + return bestdistalongpath; + } + +Vector GravPath::PointAtDistance + ( + Vector pos, + float dist, + qboolean is_player, + float *max_speed + ) + + { + GravPathNode *s; + GravPathNode *e; + int num; + int i; + Vector delta; + Vector p1; + float t; + float pathdist; + float segmentlength; + + num = NumNodes(); + s = GetNode( 1 ); + pathdist = 0; + + for( i = 2; i <= num; i++ ) + { + e = GetNode( i ); + + delta = e->origin - s->origin; + segmentlength = delta.length(); + + if ( ( pathdist + segmentlength ) > dist ) + { + t = dist - pathdist; + + p1 = delta * ( t / segmentlength ); +// return p1 + s->origin; + + if ( e->spawnflags & PULL_UPWARDS && is_player ) + p1.z = p1.length() / 2; + + *max_speed = e->MaxSpeed(); + + return p1 + pos; + } + + s = e; + pathdist += segmentlength; + } + + *max_speed = s->MaxSpeed(); + + // cap it off at start or end of path + return s->origin; + } + +void GravPath::DrawPath + ( + float r, + float g, + float b + ) + + { + Vector s; + Vector e; + Vector offset; + GravPathNode *node; + int num; + int i; + + num = NumNodes(); + node = GetNode( 1 ); + s = node->origin; + G_DebugBBox( s, Vector(8,8,8), Vector(-8,-8,-8), 0,1,0,1 ); + offset = Vector( r, g, b ) * 4 + Vector( 0, 0, 0 ); + offset = Vector(0, 0, 0); + + for( i = 2; i <= num; i++ ) + { + node = GetNode( i ); + e = node->origin; + + G_DebugLine( s + offset, e + offset, r, g, b, 1 ); + G_DebugBBox( e, Vector(8,8,8), Vector(-8,-8,-8), 0,1,0,1 ); + s = e; + } + + G_DebugBBox(origin,mins-origin,maxs-origin,1,0,0,1); + } + +int GravPath::NumNodes + ( + void + ) + + { + return pathlist.NumObjects(); + } + +float GravPath::Length + ( + void + ) + + { + return pathlength; + } diff --git a/source/source/fgame/gravpath.h b/source/source/fgame/gravpath.h new file mode 100644 index 0000000..433cd33 --- /dev/null +++ b/source/source/fgame/gravpath.h @@ -0,0 +1,222 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/gravpath.h $ +// $Revision:: 7 $ +// $Author:: Steven $ +// $Date:: 7/21/00 8:36p $ +// +// Copyright (C) 1998 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source is may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/gravpath.h $ +// +// 7 7/21/00 8:36p Steven +// Got gravpaths working fairly well. +// +// 6 7/06/00 12:58p Steven +// Changed gravpaths to pull you parallel to the path not towards it. +// +// 5 6/22/00 3:45p Markd +// fixed a bunch of saved game issues +// +// 4 5/26/00 7:44p Markd +// 2nd phase save games +// +// 3 5/24/00 3:14p Markd +// first phase of save/load games +// +// 2 10/26/99 5:28p Aldie +// Fix for gravpaths +// +// 1 9/10/99 10:54a Jimdose +// +// 1 9/08/99 3:16p Aldie +// +// DESCRIPTION: +// Gravity path - Used for underwater currents and wells. + +#ifndef __GRAVPATH_H__ +#define __GRAVPATH_H__ + +#include "g_local.h" +#include "class.h" +#include "container.h" + + +class GravPathNode : public Entity + { + private: + float speed; + float radius; + qboolean headnode; + float max_speed; + + public: + qboolean active; + + CLASS_PROTOTYPE(GravPathNode); + GravPathNode(); + void SetSpeed( Event *ev ); + void SetMaxSpeed( Event *ev ); + void SetRadius( Event *ev ); + void CreatePath( Event *ev ); + void Activate( Event *ev ); + void Deactivate( Event *ev ); + float Speed( void ); + float MaxSpeed( void ); + float Radius( void ) { return radius; }; + virtual void Archive( Archiver &arc ); + }; + +inline void GravPathNode::Archive + ( + Archiver &arc + ) + { + Entity::Archive( arc ); + + arc.ArchiveFloat( &speed ); + arc.ArchiveFloat( &radius ); + arc.ArchiveBoolean( &headnode ); + arc.ArchiveBoolean( &active ); + arc.ArchiveFloat( &max_speed ); + } + +typedef SafePtr GravPathNodePtr; + +class GravPath : public Listener + { + private: + Container pathlist; + float pathlength; + + GravPathNodePtr from; + GravPathNodePtr to; + int nextnode; + + public: + CLASS_PROTOTYPE( GravPath ); + + GravPath(); + ~GravPath(); + void Clear(void); + void Reset(void); + void AddNode(GravPathNode *node); + GravPathNode *GetNode(int num); + GravPathNode *NextNode(void); + Vector ClosestPointOnPath(Vector pos, Entity &ent,float *bestdist,float *speed,float *radius); + float DistanceAlongPath(Vector pos, float *speed); + Vector PointAtDistance( Vector pos, float dist, qboolean is_player, float *max_distance ); + void DrawPath(float r, float g, float b); + int NumNodes(void); + float Length(void); + GravPathNode *Start(void); + GravPathNode *End(void); + virtual void Archive( Archiver &arc ); + + Vector mins; + Vector maxs; + Vector origin; + qboolean force; + }; + +inline void GravPath::Archive + ( + Archiver &arc + ) + + { + GravPathNodePtr *tempPtr; + int i, num; + + Listener::Archive( arc ); + + if ( arc.Loading() ) + { + Reset(); + } + else + { + num = pathlist.NumObjects(); + } + arc.ArchiveInteger( &num ); + if ( arc.Loading() ) + { + pathlist.Resize( num ); + } + + for ( i = 1; i <= num; i++ ) + { + tempPtr = pathlist.AddressOfObjectAt( i ); + arc.ArchiveSafePointer( tempPtr ); + } + + arc.ArchiveFloat( &pathlength ); + arc.ArchiveSafePointer( &from ); + arc.ArchiveSafePointer( &to ); + arc.ArchiveInteger( &nextnode ); + arc.ArchiveVector( &mins ); + arc.ArchiveVector( &maxs ); + arc.ArchiveVector( &origin ); + arc.ArchiveBoolean( &force ); + } + +class GravPathManager : public Class + { + private: + Container pathList; + + public: + CLASS_PROTOTYPE( GravPathManager ); + ~GravPathManager(); + void Reset( void ); + void AddPath(GravPath *p); + void RemovePath(GravPath *p); + Vector CalculateGravityPull(Entity &ent, Vector position, qboolean *force, float *max_speed); + void DrawGravPaths( void ); + virtual void Archive( Archiver &arc ); + }; + +inline void GravPathManager::Archive + ( + Archiver &arc + ) + { + GravPath * ptr; + int i, num; + + Class::Archive( arc ); + + if ( arc.Saving() ) + { + num = pathList.NumObjects(); + } + else + { + Reset(); + } + arc.ArchiveInteger( &num ); + for ( i = 1; i <= num; i++ ) + { + if ( arc.Saving() ) + { + ptr = pathList.ObjectAt( i ); + } + else + { + ptr = new GravPath; + } + arc.ArchiveObject( ptr ); + if ( arc.Loading() ) + { + pathList.AddObject( ptr ); + } + } + } + +extern GravPathManager gravPathManager; + +#endif /* gravpath.h */ diff --git a/source/source/fgame/health.cpp b/source/source/fgame/health.cpp new file mode 100644 index 0000000..14c7339 --- /dev/null +++ b/source/source/fgame/health.cpp @@ -0,0 +1,393 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/health.cpp $ +// $Revision:: 22 $ +// $Author:: Steven $ +// $Date:: 7/23/00 7:22p $ +// +// Copyright (C) 1997 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source is may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/health.cpp $ +// +// 22 7/23/00 7:22p Steven +// Fixed a couple sounds. +// +// 21 7/22/00 8:35p Steven +// Fixed the health and water vial use sounds. +// +// 20 7/22/00 11:17a Steven +// Make health that falls from a healthplant give the same amount of health. +// +// 19 7/13/00 7:28p Steven +// Fixed some targetname stuff. +// +// 18 7/13/00 4:13p Steven +// Made fruit that is knocked off of the healthplants have a targetname = +// parent targetname + "_spawned". +// +// 17 7/13/00 12:30p Steven +// Made it so using a health item puts out fires on your body. +// +// 16 7/10/00 6:50p Markd +// fixed some issues with water running +// +// 15 7/10/00 5:09p Markd +// forgot to include player +// +// 14 7/10/00 5:07p Markd +// Added WaterInventoryItem +// +// 13 6/27/00 5:47p Steven +// Made it so player's health will not go above 100 and health items will not +// be picked up if player already has 100 health. +// +// 12 6/24/00 11:20a Steven +// Made health plants be able to be shot be any projectile. Everything but a +// sling just knocks it straight down. +// +// 11 6/05/00 11:48a Steven +// Fixed a crash in healthplant::touch. +// +// 10 5/25/00 9:59a Steven +// Made it so when a health vial is used a special effect surrounds player and +// made it so if no fall velocity is set for a health plant the fruit falls +// towards the player. +// +// 9 5/23/00 10:19a Steven +// Added healthplant. +// +// 8 4/12/00 10:01a Markd +// removed unused variables +// +// 7 4/11/00 5:31p Markd +// reworked pickup code +// +// 6 4/05/00 8:50p Markd +// got rid of damage skin support +// +// 5 4/04/00 3:28p Aldie +// Fix use code for health inventory item +// +// 4 3/13/00 5:18p Aldie +// Made some changes for usable inventory item stuff +// +// 3 1/26/00 3:33p Aldie +// Change Amount to getAmount. Added some 'listinventory' command. Added give +// all cheat to execute the script in global/giveall.txt +// +// 2 1/06/00 11:30p Jimdose +// removed unused health items +// +// 1 9/10/99 10:54a Jimdose +// +// 1 9/08/99 3:16p Aldie +// +// 6 8/28/99 2:41p Steven +// Took out some old references to def files. +// +// DESCRIPTION: +// Health powerup +// + +#include "g_local.h" +#include "item.h" +#include "inventoryitem.h" +#include "sentient.h" +#include "health.h" +#include "weaputils.h" +#include "player.h" + +CLASS_DECLARATION( InventoryItem, HealthInventoryItem, "" ) + { + { &EV_InventoryItem_Use, Use }, + { NULL, NULL } + }; + + +void HealthInventoryItem::Use + ( + Event *ev + ) + + { + Entity *other; + Sentient *sen; + Event *event; + str sound_name; + + + other = ev->GetEntity( 1 ); + if ( !other || !other->isSubclassOf( Sentient ) ) + { + return; + } + + sen = ( Sentient * )other; + sen->health += amount; + + if ( sen->health > sen->max_health ) + { + sen->health = sen->max_health; + } + + // If we are on fire stop it + + sen->ProcessEvent( EV_Sentient_StopOnFire ); + + // Spawn special effect around sentient + + sound_name = GetRandomAlias( "snd_use" ); + + if ( sound_name ) + other->Sound( sound_name.c_str(), 0 ); + + event = new Event( EV_AttachModel ); + event->AddString( "models/fx_tikifx2.tik" ); + event->AddString( "Bip01 Spine" ); + // set scale + event->AddFloat( 1 ); + // set targetname + event->AddString( "regen" ); + // set detach_at_death + event->AddInteger( 1 ); + // set remove_time + event->AddFloat( 2 ); + other->ProcessEvent( event ); + + PostEvent( EV_Remove, 0 ); + } + +CLASS_DECLARATION( InventoryItem, WaterInventoryItem, "" ) + { + { &EV_InventoryItem_Use, Use }, + { NULL, NULL } + }; + + +void WaterInventoryItem::Use + ( + Event *ev + ) + + { + Event *event; + Entity *other; + str sound_name; + + other = ev->GetEntity( 1 ); + if ( !other || !other->isSubclassOf( Player ) ) + { + return; + } + + sound_name = GetRandomAlias( "snd_use" ); + + if ( sound_name ) + other->Sound( sound_name.c_str(), 0 ); + + ( ( Player * )other )->SetWaterPower( amount ); + + event = new Event( EV_AttachModel ); + event->AddString( "models/fx_watervial.tik" ); + event->AddString( "Bip01 Spine" ); + // set scale + event->AddFloat( 1 ); + // set targetname + event->AddString( "regen" ); + // set detach_at_death + event->AddInteger( 1 ); + // set remove_time + event->AddFloat( 2 ); + other->ProcessEvent( event ); + + PostEvent( EV_Remove, 0 ); + } + + +CLASS_DECLARATION( Item, Health, "health_020" ) + { + { &EV_Item_Pickup, PickupHealth }, + { NULL, NULL } + }; + +Health::Health() + { + if ( DM_FLAG( DF_NO_HEALTH ) ) + { + PostEvent( EV_Remove, EV_REMOVE ); + return; + } + + setAmount( 20 ); + } + +void Health::PickupHealth + ( + Event *ev + ) + + { + Sentient *sen; + Entity *other; + + other = ev->GetEntity( 1 ); + if ( !other || !other->isSubclassOf( Sentient ) ) + { + return; + } + + sen = ( Sentient * )other; + + if ( sen->health >= sen->max_health ) + return; + + if ( !ItemPickup( other, qfalse ) ) + { + return; + } + + sen->health += amount; + + if ( sen->health > sen->max_health ) + { + sen->health = sen->max_health; + } + + // If we are on fire stop it + + sen->ProcessEvent( EV_Sentient_StopOnFire ); + } + +Event EV_HealthPlant_SetFallVelocity + ( + "fallvelocity", + EV_DEFAULT, + "v", + "fall_velocity", + "Sets the fall velocity for this health plant." + ); + +CLASS_DECLARATION( Health, HealthPlant, NULL ) + { + { &EV_Trigger_Effect, Touch }, + { &EV_HealthPlant_SetFallVelocity, SetFallVelocity }, + { NULL, NULL } + }; + +HealthPlant::HealthPlant() + { + respondto = (TRIGGER_PLAYERS | TRIGGER_PROJECTILES); + edict->s.eType = ET_MODELANIM; + } + +void HealthPlant::Touch + ( + Event *ev + ) + + { + Entity *other; + Event *e; + + if ( owner ) + { + // Don't respond to trigger events after item is picked up. + // we really don't need to see this. + //gi.DPrintf( "%s with targetname of %s was triggered unexpectedly.\n", getClassID(), TargetName() ); + return; + } + + other = ev->GetEntity( 1 ); + + if ( !other ) + return; + + if ( other->isSubclassOf( Projectile ) ) + { + Projectile *proj = (Projectile *)other; + + if ( proj->meansofdeath == MOD_SLING ) + Hit( proj->velocity, false ); + else + Hit( proj->velocity, true ); + } + else + { + e = new Event( EV_Item_Pickup ); + e->AddEntity( other ); + ProcessEvent( e ); + } + } + +void HealthPlant::SetFallVelocity + ( + Event *ev + ) + + { + fall_velocity = ev->GetVector( 1 ); + } + +void HealthPlant::Hit + ( + Vector velocity, + qboolean fall_straight_down + ) + + { + Health *health; + Vector orig; + + // Spawn in a health fruit + + health = new Health; + + health->setModel( "item_healthfruit1.tik" ); + + GetTag( "tag_healthfruit1", &orig ); + + health->setOrigin( orig ); + + health->ProcessPendingEvents(); + + health->PlaceItem(); + health->setOrigin( orig ); + + health->setAmount( amount ); + + // Make new health fruit have the same target name of the healthplant with "_spawned" on the end + + health->targetname = targetname; + health->targetname += "_spawned"; + + health->SetTargetName( health->targetname ); + + if ( fall_straight_down ) + { + health->velocity = vec_zero; + } + else if ( fall_velocity != vec_zero ) + { + health->velocity = fall_velocity; + } + else + { + health->velocity = velocity * -1; + health->velocity.z = 0; + health->velocity.normalize(); + health->velocity *= 150; + health->velocity.z = 200; + } + + setSolidType( SOLID_NOT ); + + RandomAnimate( "pickup", EV_Item_PickupDone ); + + if ( Respawnable() ) + PostEvent( EV_Item_Respawn, RespawnTime() ); + } + diff --git a/source/source/fgame/health.h b/source/source/fgame/health.h new file mode 100644 index 0000000..c789d60 --- /dev/null +++ b/source/source/fgame/health.h @@ -0,0 +1,110 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/health.h $ +// $Revision:: 10 $ +// $Author:: Markd $ +// $Date:: 7/10/00 5:09p $ +// +// Copyright (C) 1997 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source is may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/health.h $ +// +// 10 7/10/00 5:09p Markd +// Added waterInventoryItem +// +// 9 6/24/00 7:02p Steven +// Added fall_straight_down parm to hit in healthplant. +// +// 8 6/14/00 2:17p Markd +// fixed compiler warnings for Intel Compiler +// +// 7 5/26/00 7:44p Markd +// 2nd phase save games +// +// 6 5/25/00 10:01a Steven +// Added velociity to the hit proc. +// +// 5 5/24/00 3:14p Markd +// first phase of save/load games +// +// 4 5/23/00 10:19a Steven +// Added healthplant. +// +// 3 3/13/00 5:18p Aldie +// Made some changes for usable inventory item stuff +// +// 2 1/06/00 11:30p Jimdose +// removed unused health items +// +// 1 9/10/99 10:54a Jimdose +// +// 1 9/08/99 3:16p Aldie +// +// DESCRIPTION: +// Health powerup +// + +#ifndef __HEALTH_H__ +#define __HEALTH_H__ + +#include "g_local.h" +#include "item.h" +#include "sentient.h" +#include "item.h" + +class Health : public Item + { + public: + CLASS_PROTOTYPE( Health ); + + Health(); + virtual void PickupHealth( Event *ev ); + }; + +class HealthPlant : public Health + { + public: + Vector fall_velocity; + + CLASS_PROTOTYPE( HealthPlant ); + + HealthPlant(); + void Hit( Vector velocity, qboolean fall_straight_down ); + void SetFallVelocity( Event *ev ); + void Touch( Event *ev ); + virtual void Archive( Archiver &arc ); + }; + +inline void HealthPlant::Archive + ( + Archiver &arc + ) + { + Health::Archive( arc ); + + arc.ArchiveVector( &fall_velocity ); + } + +class HealthInventoryItem : public Item + { + public: + CLASS_PROTOTYPE( HealthInventoryItem ); + + void Use( Event *ev ); + + }; + +class WaterInventoryItem : public Item + { + public: + CLASS_PROTOTYPE( WaterInventoryItem ); + + void Use( Event *ev ); + + }; + +#endif /* health.h */ diff --git a/source/source/fgame/hornofconjuring.cpp b/source/source/fgame/hornofconjuring.cpp new file mode 100644 index 0000000..a614f9b --- /dev/null +++ b/source/source/fgame/hornofconjuring.cpp @@ -0,0 +1,84 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/hornofconjuring.cpp $ +// $Revision:: 4 $ +// $Author:: Markd $ +// $Date:: 6/14/00 2:17p $ +// +// Copyright (C) 1998 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/hornofconjuring.cpp $ +// +// 4 6/14/00 2:17p Markd +// fixed compiler warnings for Intel Compiler +// +// 3 5/31/00 2:47p Aldie +// Added first vymish +// +// 2 5/30/00 7:33p Aldie +// First version +// +// DESCRIPTION: +// Horn of Conjuring Weapon + +#include "hornofconjuring.h" + +CLASS_DECLARATION( Weapon, HornOfConjuring, NULL ) + { + { NULL, NULL } + }; + +HornOfConjuring::HornOfConjuring + ( + ) + + { + } + +void HornOfConjuring::Shoot + ( + Event *ev + ) + + { + firemode_t mode = FIRE_PRIMARY; + Vector pos,forward,right,up; + + if ( ev->NumArgs() > 0 ) + { + mode = WeaponModeNameToNum( ev->GetString( 1 ) ); + + if ( mode == FIRE_ERROR ) + return; + } + + if ( !MuzzleClear() ) + { + RandomAnimate( "clear", NULL ); + weaponstate = WEAPON_READY; + return; + } + + GetMuzzlePosition( &pos, &forward, &right, &up ); + + ActorPtr actor; + actor = new Actor; + actor->setModel( "vymish_conjured.tik" ); + actor->setOrigin( pos ); + + m_creatureList.AddObject( actor ); + + if ( !quiet ) + { + if ( next_noise_time <= level.time ) + { + BroadcastSound(); + next_noise_time = level.time + 1; + } + } + } + diff --git a/source/source/fgame/hornofconjuring.h b/source/source/fgame/hornofconjuring.h new file mode 100644 index 0000000..47e9f2e --- /dev/null +++ b/source/source/fgame/hornofconjuring.h @@ -0,0 +1,46 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/hornofconjuring.h $ +// $Revision:: 3 $ +// $Author:: Aldie $ +// $Date:: 5/31/00 3:02p $ +// +// Copyright (C) 1998 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/hornofconjuring.h $ +// +// 3 5/31/00 3:02p Aldie +// Added vymish +// +// 2 5/30/00 7:33p Aldie +// First version +// +// DESCRIPTION: +// Horn of Conjruing Weapon + +#ifndef __HORNOFCONJURING_H__ +#define __HORNOFCONJURING_H__ + +#include "weapon.h" +#include "weaputils.h" +#include "actor.h" + +typedef SafePtr ActorPtr; + +class HornOfConjuring : public Weapon + { + private: + Container m_creatureList; + + public: + CLASS_PROTOTYPE( HornOfConjuring ); + + HornOfConjuring(); + virtual void Shoot( Event *ev ); + }; + +#endif // __HORNOFCONJURING_H__ diff --git a/source/source/fgame/inventoryitem.cpp b/source/source/fgame/inventoryitem.cpp new file mode 100644 index 0000000..68d2ee9 --- /dev/null +++ b/source/source/fgame/inventoryitem.cpp @@ -0,0 +1,149 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/inventoryitem.cpp $ +// $Revision:: 7 $ +// $Author:: Steven $ +// $Date:: 7/01/00 7:02p $ +// +// Copyright (C) 1998 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source is may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/inventoryitem.cpp $ +// +// 7 7/01/00 7:02p Steven +// Fixed the antisucknblaugh name so it would match the classname. +// +// 6 6/26/00 5:50p Markd +// re-did some renderfx commands, fixed anti-sb juice stuff +// +// 5 6/24/00 11:19a Steven +// Made the anti sucknblaugh juice item set its item name. +// +// 4 6/23/00 8:41p Markd +// made a lot of changes to different constructors for saved game support +// +// 3 6/14/00 3:50p Markd +// Cleaned up more Intel Compiler warnings +// +// 2 9/29/99 5:18p Steven +// Event formatting. +// +// 1 9/10/99 10:54a Jimdose +// +// 1 9/08/99 3:16p Aldie +// +// 6 9/01/99 8:17p Steven +// Fixed some typos. +// +// 5 8/27/99 5:06p Steven +// Added anit Sucknblaugh juice powerup. +// +// DESCRIPTION: +// Inventory items + +#include "inventoryitem.h" + +Event EV_InventoryItem_Use + ( + "useinvitem", + EV_DEFAULT, + NULL, + NULL, + "Use this inventory item." + ); + +CLASS_DECLARATION( Item, InventoryItem, NULL ) + { + { &EV_InventoryItem_Use, UseEvent }, + { NULL, NULL } + }; + +InventoryItem::InventoryItem + ( + ) + + { + if ( LoadingSavegame ) + { + return; + } + + // All powerups are inventory items + if ( DM_FLAG( DF_NO_POWERUPS ) ) + { + PostEvent( EV_Remove, EV_REMOVE ); + return; + } + } + +void InventoryItem::UseEvent + ( + Event *ev + ) + + { + } + +Event EV_AntiSBJuice_Wearoff + ( + "antiSBjuice_wearoff", + EV_DEFAULT, + NULL, + NULL, + "Is called when the effect wears off." + ); + +CLASS_DECLARATION( InventoryItem, AntiSBJuice, "AntiSBJuice" ) + { + { &EV_AntiSBJuice_Wearoff, Wearoff }, + { &EV_Use, UseEvent }, + { NULL, NULL } + }; + +AntiSBJuice::AntiSBJuice + ( + ) + + { + PostEvent( EV_Use, 0 ); + item_name = "AntiSBJuice"; + } + +void AntiSBJuice::UseEvent + ( + Event *ev + ) + { + if ( !owner ) + { + CancelPendingEvents(); + PostEvent( EV_Remove, 0 ); + return; + } + + owner->edict->s.eFlags |= EF_ANTISBJUICE; + + PostEvent( EV_AntiSBJuice_Wearoff, 30.0 ); + } + +void AntiSBJuice::Wearoff + ( + Event *ev + ) + + { + if ( !owner ) + { + CancelPendingEvents(); + PostEvent( EV_Remove, 0 ); + return; + } + + owner->edict->s.eFlags &= ~EF_ANTISBJUICE; + + CancelPendingEvents(); + PostEvent( EV_Remove, 0 ); + } diff --git a/source/source/fgame/inventoryitem.h b/source/source/fgame/inventoryitem.h new file mode 100644 index 0000000..f4ff842 --- /dev/null +++ b/source/source/fgame/inventoryitem.h @@ -0,0 +1,56 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/inventoryitem.h $ +// $Revision:: 2 $ +// $Author:: Markd $ +// $Date:: 6/14/00 3:50p $ +// +// Copyright (C) 1998 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source is may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/inventoryitem.h $ +// +// 2 6/14/00 3:50p Markd +// Cleaned up more Intel Compiler warnings +// +// 1 9/10/99 10:54a Jimdose +// +// 1 9/08/99 3:16p Aldie +// +// 4 8/27/99 5:06p Steven +// Added anti Sucknblaugh juice powerup. +// +// DESCRIPTION: +// Items that are visible in the player's inventory + + +#ifndef __INVITEM_H__ +#define __INVITEM_H__ + +#include "item.h" + +class InventoryItem : public Item + { + public: + CLASS_PROTOTYPE( InventoryItem ); + + InventoryItem(); + virtual void UseEvent( Event *ev ); + }; + +extern Event EV_InventoryItem_Use; + +class AntiSBJuice : public InventoryItem + { + public: + CLASS_PROTOTYPE( AntiSBJuice ); + AntiSBJuice(); + void Wearoff( Event *ev ); + void UseEvent( Event *ev ); + }; + + +#endif /* inventoryitem.h */ diff --git a/source/source/fgame/ipfilter.cpp b/source/source/fgame/ipfilter.cpp new file mode 100644 index 0000000..05a0a60 --- /dev/null +++ b/source/source/fgame/ipfilter.cpp @@ -0,0 +1,356 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/ipfilter.cpp $ +// $Revision:: 2 $ +// $Date:: 1/06/00 11:10p $ +// +// Copyright (C) 1999 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source is may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/ipfilter.cpp $ +// +// 2 1/06/00 11:10p Jimdose +// cleaning up unused code +// +// DESCRIPTION: +// 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. +// + +#include "ipfilter.h" +#include "g_local.h" + +typedef struct + { + unsigned mask; + unsigned compare; + } ipfilter_t; + +#define MAX_IPFILTERS 1024 + +ipfilter_t ipfilters[ MAX_IPFILTERS ]; +int numipfilters; + +/* +================= +StringToFilter +================= +*/ +static qboolean StringToFilter + ( + const char *s, + ipfilter_t *f + ) + + { + char num[ 128 ]; + int i; + int 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.SendServerCommand( NULL, "print \"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 + ( + const char *from + ) + + { + int i; + unsigned in; + byte m[ 4 ]; + const 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; i < numipfilters; i++ ) + { + if ( ( in & ipfilters[ i ].mask ) == ipfilters[ i ].compare ) + { + return ( int )filterban->integer; + } + } + + return !( int )filterban->integer; + } + + +/* +================= +SV_AddIP_f +================= +*/ +void SVCmd_AddIP_f + ( + void + ) + + { + int i; + + if ( gi.argc() < 3 ) + { + gi.SendServerCommand( NULL, "print \"Usage: addip \n\"" ); + return; + } + + for( i = 0; i < numipfilters; i++ ) + { + if ( ipfilters[ i ].compare == 0xffffffff ) + { + // free spot + break; + } + } + + if ( i == numipfilters ) + { + if ( numipfilters == MAX_IPFILTERS ) + { + gi.SendServerCommand( NULL, "print \"IP filter list is full\n\"" ); + return; + } + numipfilters++; + } + + if ( !StringToFilter( gi.argv( 2 ), &ipfilters[ i ] ) ) + { + ipfilters[ i ].compare = 0xffffffff; + } + } + +/* +================= +SV_RemoveIP_f +================= +*/ +void SVCmd_RemoveIP_f + ( + void + ) + + { + ipfilter_t f; + int i; + int j; + + if ( gi.argc() < 3 ) + { + gi.SendServerCommand( NULL, "print \"Usage: sv removeip \n\"" ); + return; + } + + if ( !StringToFilter( gi.argv( 2 ), &f ) ) + { + return; + } + + for( i = 0; i < numipfilters; i++ ) + { + if ( ( ipfilters[ i ].mask == f.mask ) && ( ipfilters[ i ].compare == f.compare ) ) + { + for ( j = i + 1; j < numipfilters; j++ ) + { + ipfilters[ j - 1 ] = ipfilters[ j ]; + } + + numipfilters--; + gi.SendServerCommand( NULL, "print \"Removed.\n\"" ); + return; + } + } + + gi.SendServerCommand( NULL, "print \"Didn't find %s.\n\"", gi.argv( 2 ) ); + } + +/* +================= +SV_ListIP_f +================= +*/ +void SVCmd_ListIP_f + ( + void + ) + + { + int i; + byte b[ 4 ]; + + gi.SendServerCommand( NULL, "print \"Filter list:\n\"", gi.argv( 2 ) ); + for( i = 0; i < numipfilters; i++ ) + { + *( unsigned * )b = ipfilters[ i ].compare; + gi.SendServerCommand( NULL, "print \"%3i.%3i.%3i.%3i\n\"", b[ 0 ], b[ 1 ], b[ 2 ], b[ 3 ] ); + } + } + +/* +================= +SV_WriteIP_f +================= +*/ +void SVCmd_WriteIP_f + ( + void + ) + + { + FILE *f; + char name[ MAX_OSPATH ]; + byte b[ 4 ]; + int i; + + sprintf( name, "%s/listip.cfg", GAMEVERSION ); + gi.SendServerCommand( NULL, "print \"Writing %s.\n\"", name ); + + f = fopen( name, "wb" ); + if ( !f ) + { + gi.SendServerCommand( NULL, "print \"Couldn't open %s.\n\"", name ); + return; + } + + fprintf( f, "set filterban %d\n", ( int )filterban->integer ); + + for( i = 0; i < numipfilters; i++ ) + { + *( unsigned * )b = ipfilters[ i ].compare; + fprintf( f, "sv addip %i.%i.%i.%i\n", b[ 0 ], b[ 1 ], b[ 2 ], b[ 3 ] ); + } + + fclose( f ); + } + +/* +================= +G_ServerCommand + +G_ServerCommand will be called when an "sv" command is issued. +The game can issue gi.argc() / gi.argv() commands to get the rest +of the parameters +================= +*/ +void G_ServerCommand + ( + void + ) + + { + const char *cmd; + + cmd = gi.argv(1); + if ( Q_stricmp( cmd, "addip" ) == 0 ) + { + SVCmd_AddIP_f(); + } + else if ( Q_stricmp( cmd, "removeip" ) == 0 ) + { + SVCmd_RemoveIP_f(); + } + else if ( Q_stricmp( cmd, "listip" ) == 0 ) + { + SVCmd_ListIP_f(); + } + else if ( Q_stricmp( cmd, "writeip" ) == 0 ) + { + SVCmd_WriteIP_f(); + } + else + { + gi.SendServerCommand( NULL, "print \"Unknown server command %s.\n\"", cmd ); + } + } diff --git a/source/source/fgame/ipfilter.h b/source/source/fgame/ipfilter.h new file mode 100644 index 0000000..3139240 --- /dev/null +++ b/source/source/fgame/ipfilter.h @@ -0,0 +1,28 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/ipfilter.h $ +// $Revision:: 2 $ +// $Date:: 1/06/00 11:10p $ +// +// Copyright (C) 1999 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source is may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/ipfilter.h $ +// +// 2 1/06/00 11:10p Jimdose +// cleaning up unused code +// +// DESCRIPTION: +// + +#ifndef __IPFILTER_H__ +#define __IPFILTER_H__ + +#include "g_local.h" + +qboolean SV_FilterPacket( const char *from ); + +#endif /* !__IPFILTER_H__ */ diff --git a/source/source/fgame/item.cpp b/source/source/fgame/item.cpp new file mode 100644 index 0000000..0fcc32d --- /dev/null +++ b/source/source/fgame/item.cpp @@ -0,0 +1,1068 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/item.cpp $ +// $Revision:: 31 $ +// $Author:: Steven $ +// $Date:: 7/19/00 5:08p $ +// +// Copyright (C) 1997 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source is may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/item.cpp $ +// +// 31 7/19/00 5:08p Steven +// Added some caching stuff for cool item. +// +// 30 7/16/00 10:44a Steven +// Added has_been_looked_at stuff. +// +// 29 7/10/00 8:09p Markd +// fixed cool item pickup problems +// +// 28 7/04/00 6:45p Markd +// enhanced cool item features +// +// 27 7/04/00 2:25p Markd +// added cool cinematic for new objects +// +// 26 6/26/00 12:21p Steven +// Printing out better info on stuck warning. +// +// 25 6/23/00 8:41p Markd +// made a lot of changes to different constructors for saved game support +// +// 24 6/17/00 12:05p Steven +// Made it so the player would not look at items that have been picked up and +// not yet respawned. +// +// 23 6/03/00 5:23p Markd +// fixed bug in saved games, made items have playersolid as their default +// clipmask +// +// 22 6/01/00 3:18p Markd +// rewrote giveItem and item management in sentient +// +// 21 5/31/00 5:32p Steven +// Marked these as things for Julie to look at. +// +// 20 5/30/00 7:06p Markd +// saved games 4th pass +// +// 19 5/27/00 5:06p Steven +// Added a GetOwner function. +// +// 18 5/25/00 9:59a Steven +// Fixed some item name stuff. +// +// 17 5/20/00 5:14p Markd +// Added ITEM special effects +// +// 16 5/07/00 5:00p Markd +// fixed weapon pickup code +// +// 15 4/11/00 5:32p Markd +// reworked PickupItem code +// +// 14 4/06/00 12:14p Aldie +// Added a default name to Item +// +// 13 4/01/00 2:03p Markd +// overrode use of EV_SetAngle event from trigger +// +// 12 3/27/00 4:47p Markd +// added pickup_thread capability to all items +// +// 11 3/13/00 5:18p Aldie +// Made some changes for usable inventory item stuff +// +// 10 1/26/00 3:33p Aldie +// Change Amount to getAmount. Added some 'listinventory' command. Added give +// all cheat to execute the script in global/giveall.txt +// +// 9 1/15/00 3:57p Markd +// Eliminated multiple "angle" events and replaced them with EV_SetAngle +// +// 8 12/17/99 6:35p Jimdose +// changed spawnarg code +// added Level class for spawning and map control +// got rid of unused or superflous variables +// changed setjmp/longjmp calls to try/throw/catch exception handling +// +// 7 12/03/99 7:02p Aldie +// More ammo joy +// +// 6 12/02/99 6:53p Aldie +// Changed naming conventions from "both" to "dualhanded" Also put in the +// inventory renderer for the hud file +// +// 5 12/01/99 4:56p Markd +// fixed some reference versus pointer issues with RandomAnimate and NewAnim +// +// 4 9/29/99 7:43p Markd +// Made items behave better when dropping to floor +// +// 3 9/29/99 5:17p Steven +// Event formatting. +// +// 2 9/27/99 5:44p Markd +// began documentation and cleanup phase after merge +// +// 1 9/10/99 10:54a Jimdose +// +// 1 9/08/99 3:16p Aldie +// +// 15 9/02/99 6:44p Jimdose +// removed message when owned item is triggered +// +// 14 8/28/99 6:40p Steven +// Added more pickup animation and respawn animation stuff. +// +// 13 8/28/99 11:44a Steven +// Removed global from sound function calls. +// +// 12 8/27/99 5:07p Steven +// General item work. +// +// DESCRIPTION: +// Base class for respawnable, carryable objects. +// + +#include "g_local.h" +#include "entity.h" +#include "trigger.h" +#include "item.h" +#include "inventoryitem.h" +#include "scriptmaster.h" +#include "health.h" + +Event EV_Item_Pickup + ( + "item_pickup", + EV_DEFAULT, + "e", + "item", + "Pickup the specified item." + ); +Event EV_Item_DropToFloor + ( + "item_droptofloor", + EV_DEFAULT, + NULL, + NULL, + "Drops the item to the ground." + ); +Event EV_Item_Respawn + ( + "respawn", + EV_DEFAULT, + NULL, + NULL, + "Respawns the item." + ); +Event EV_Item_SetRespawn + ( + "set_respawn", + EV_DEFAULT, + "i", + "respawn", + "Turns respawn on or off." + ); +Event EV_Item_SetRespawnTime + ( + "set_respawn_time", + EV_DEFAULT, + "f", + "respawn_time", + "Sets the respawn time." + ); +Event EV_Item_SetAmount + ( + "amount", + EV_DEFAULT, + "i", + "amount", + "Sets the amount of the item." + ); +Event EV_Item_SetMaxAmount + ( + "maxamount", + EV_DEFAULT, + "i", + "max_amount", + "Sets the max amount of the item." + ); +Event EV_Item_SetItemName + ( + "name", + EV_DEFAULT, + "s", + "item_name", + "Sets the item name." + ); +Event EV_Item_RespawnSound + ( + "respawnsound", + EV_DEFAULT, + NULL, + NULL, + "Turns on the respawn sound for this item." + ); +Event EV_Item_DialogNeeded + ( + "dialogneeded", + EV_DEFAULT, + "s", + "dialog_needed", + "Sets the dialog needed string." + ); +Event EV_Item_NoRemove + ( + "no_remove", + EV_DEFAULT, + NULL, + NULL, + "Makes it so the item is not removed from the world when it is picked up." + ); +Event EV_Item_RespawnDone + ( + "respawn_done", + EV_DEFAULT, + NULL, + NULL, + "Called when the item respawn is done." + ); +Event EV_Item_PickupDone + ( + "pickup_done", + EV_DEFAULT, + NULL, + NULL, + "Called when the item pickup is done." + ); + +Event EV_Item_SetPickupThread + ( + "pickup_thread", + EV_DEFAULT, + "s", + "labelName", + "A thread that is called when an item is picked up." + ); + +Event EV_Item_CoolItem + ( + "coolitem", + EV_DEFAULT, + "SS", + "dialog anim_to_play", + "Specify that this is a cool item when we pick it up for the first time.\n" + "If dialog is specified, than the dialog will be played during the pickup.\n" + "If anim_to_play is specified, than the specified anim will be played after\n" + "the initial cinematic." + ); + +Event EV_Item_ForceCoolItem + ( + "forcecoolitem", + EV_DEFAULT, + "SS", + "dialog anim_to_play", + "Specify that this is a cool item when we pick it up regardless of whether or not we have it.\n" + "If dialog is specified, than the dialog will be played during the pickup.\n" + "If anim_to_play is specified, than the specified anim will be played after\n" + "the initial cinematic." + ); + +CLASS_DECLARATION( Trigger, Item, NULL ) + { + { &EV_Trigger_Effect, ItemTouch }, + { &EV_Item_DropToFloor, DropToFloor }, + { &EV_Item_Respawn, Respawn }, + { &EV_Item_SetAmount, SetAmountEvent }, + { &EV_Item_SetMaxAmount, SetMaxAmount }, + { &EV_Item_SetItemName, SetItemName }, + { &EV_Item_Pickup, Pickup }, + { &EV_Use, TriggerStuff }, + { &EV_Item_RespawnSound, RespawnSound }, + { &EV_Item_DialogNeeded, DialogNeeded }, + { &EV_Item_NoRemove, SetNoRemove }, + { &EV_Item_RespawnDone, RespawnDone }, + { &EV_Item_PickupDone, PickupDone }, + { &EV_Item_SetRespawn, setRespawn }, + { &EV_Item_SetRespawnTime, setRespawnTime }, + { &EV_Item_SetPickupThread, SetPickupThread }, + { &EV_Item_CoolItem, CoolItemEvent }, + { &EV_Item_ForceCoolItem, ForceCoolItemEvent }, + { &EV_Stop, Landed }, + { &EV_SetAngle, SetAngleEvent }, + { NULL, NULL } + }; + +Item::Item() + { + str fullname; + + if ( LoadingSavegame ) + { + return; + } + + setSolidType( SOLID_NOT ); + + // Set default respawn behavior + // Derived classes should use setRespawn + // if they want to override the default behavior + setRespawn( deathmatch->integer ? true : false ); + setRespawnTime( 20 ); + + // + // we want the bounds of this model auto-rotated + // + flags |= FL_ROTATEDBOUNDS; + + // + // set a minimum mins and maxs for the model + // + if ( size.length() < 10 ) + { + mins = "-10 -10 0"; + maxs = "10 10 20"; + } + + // + // reset the mins and maxs to pickup the FL_ROTATEDBOUNDS flag + // + setSize( mins, maxs ); + + if ( !LoadingSavegame ) + { + // Items can't be immediately dropped to floor, because they might + // be on an entity that hasn't spawned yet. + PostEvent( EV_Item_DropToFloor, EV_POSTSPAWN ); + } + + respondto = TRIGGER_PLAYERS; + + // items should collide with everything that the player does + edict->clipmask = MASK_PLAYERSOLID; + + item_index = 0; + maximum_amount = 1; + playrespawn = false; + + // this is an item entity + edict->s.eType = ET_ITEM; + + amount = 1; + no_remove = false; + setName( "Unknown Item" ); + + look_at_me = true; + coolitem = qfalse; + coolitemforced = qfalse; + + has_been_looked_at = false; + } + +Item::~Item() + { + if ( owner ) + { + owner->RemoveItem( this ); + owner = NULL; + } + } + +void Item::SetNoRemove + ( + Event *ev + ) + { + no_remove = true; + } + +/* +============ +PlaceItem + +Puts an item back in the world +============ +*/ +void Item::PlaceItem + ( + void + ) + + { + setSolidType( SOLID_TRIGGER ); + setMoveType( MOVETYPE_TOSS ); + showModel(); + + groundentity = NULL; + } + +/* +============ +DropToFloor + +plants the object on the floor +============ +*/ +void Item::DropToFloor + ( + Event *ev + ) + + { + str fullname; + Vector save; + + PlaceItem(); + + addOrigin( "0 0 1" ); + + save = origin; + if ( !droptofloor( 8192 ) ) + { + gi.DPrintf( "%s (%d) stuck in world at '%5.1f %5.1f %5.1f'\n", + getClassID(), entnum, origin.x, origin.y, origin.z ); + setOrigin( save ); + setMoveType( MOVETYPE_NONE ); + } + else + { + setMoveType( MOVETYPE_NONE ); + } + // + // if the our global variable doesn't exist, lets zero it out + // + fullname = str( "playeritem_" ) + getName(); + if ( !gameVars.VariableExists( fullname.c_str() ) ) + { + gameVars.SetVariable( fullname.c_str(), 0 ); + } + + if ( !levelVars.VariableExists( fullname.c_str() ) ) + { + levelVars.SetVariable( fullname.c_str(), 0 ); + } + + } + +qboolean Item::Drop + ( + void + ) + + { + if ( !owner ) + { + return false; + } + + setOrigin( owner->origin + "0 0 40" ); + + // drop the item + PlaceItem(); + velocity = owner->velocity * 0.5 + Vector( G_CRandom( 50 ), G_CRandom( 50 ), 100 ); + setAngles( owner->angles ); + avelocity = Vector( 0, G_CRandom( 360 ), 0 ); + + trigger_time = level.time + 1; + + if ( owner->isClient() ) + { + spawnflags |= DROPPED_PLAYER_ITEM; + } + else + { + spawnflags |= DROPPED_ITEM; + } + + // Remove this from the owner's item list + owner->RemoveItem( this ); + owner = NULL; + + return true; + } + + +void Item::ItemTouch + ( + Event *ev + ) + + { + Entity *other; + Event *e; + + if ( owner ) + { + // Don't respond to trigger events after item is picked up. + // we really don't need to see this. + //gi.DPrintf( "%s with targetname of %s was triggered unexpectedly.\n", getClassID(), TargetName() ); + return; + } + + other = ev->GetEntity( 1 ); + + e = new Event( EV_Item_Pickup ); + e->AddEntity( other ); + ProcessEvent( e ); + } + +void Item::SetOwner + ( + Sentient *ent + ) + + { + assert( ent ); + if ( !ent ) + { + // return to avoid any buggy behaviour + return; + } + + owner = ent; + setRespawn( false ); + + setSolidType( SOLID_NOT ); + hideModel(); + CancelEventsOfType( EV_Touch ); + CancelEventsOfType( EV_Item_DropToFloor ); + CancelEventsOfType( EV_Remove ); +// ItemPickup( ent ); + } + +Sentient *Item::GetOwner + ( + void + ) + + { + return owner; + } + +Item * Item::ItemPickup + ( + Entity *other, + qboolean add_to_inventory + ) + + { + Sentient * sent; + Item * item = NULL; + str realname; + + if ( !Pickupable( other ) ) + { + return NULL; + } + + sent = ( Sentient * )other; + + if ( add_to_inventory ) + { + item = sent->giveItem( model, getAmount() ); + + if ( !item ) + return NULL; + } + else + { + item = this; + } + + // + // make sure to copy over the coolness factor :) + // + item->coolitem = coolitem; + item->cool_dialog = cool_dialog; + item->cool_anim = cool_anim; + item->coolitemforced = coolitemforced; + + // + // let our sent know they received it + // we put this here so we can transfer information from the original item we picked up + // + sent->ReceivedItem( item ); + + realname = GetRandomAlias( "snd_pickup" ); + if ( realname.length() > 1 ) + sent->Sound( realname, CHAN_ITEM ); + + if ( !Removable() ) + { + // leave the item for others to pickup + return item; + } + + look_at_me = false; + + CancelEventsOfType( EV_Item_DropToFloor ); + CancelEventsOfType( EV_Item_Respawn ); + CancelEventsOfType( EV_FadeOut ); + + setSolidType( SOLID_NOT ); + + if ( HasAnim( "pickup" ) ) + RandomAnimate( "pickup", EV_Item_PickupDone ); + else + { + if ( !no_remove ) + { + hideModel(); + + if ( !Respawnable() ) + PostEvent( EV_Remove, FRAMETIME ); + } + } + + if ( Respawnable() ) + PostEvent( EV_Item_Respawn, RespawnTime() ); + + // fire off any pickup_thread's + if ( pickup_thread.length() ) + { + ExecuteThread( pickup_thread ); + } + + + if ( item && DM_FLAG( DF_INSTANT_ITEMS ) ) + { + Event *ev; + + ev = new Event( EV_InventoryItem_Use ); + ev->AddEntity( other ); + + item->ProcessEvent( ev ); + } + + return item; + } + +void Item::Respawn + ( + Event *ev + ) + + { + showModel(); + + // allow it to be touched again + setSolidType( SOLID_TRIGGER ); + + // play respawn sound + if ( playrespawn ) + { + Sound( "snd_itemspawn" ); + } + + setOrigin(); + + if ( HasAnim( "respawn" ) ) + RandomAnimate( "respawn", EV_Item_RespawnDone ); + + look_at_me = true; + has_been_looked_at = false; + } + +void Item::setRespawn + ( + Event *ev + ) + + { + if ( ev->NumArgs() < 1 ) + return; + + setRespawn( ev->GetInteger( 1 ) ); + } + +void Item::setRespawnTime + ( + Event *ev + ) + + { + if ( ev->NumArgs() < 1 ) + return; + + setRespawnTime( ev->GetFloat( 1 ) ); + } + +void Item::RespawnDone + ( + Event *ev + ) + + { + RandomAnimate( "idle" ); + } + +void Item::PickupDone + ( + Event *ev + ) + + { + if ( !no_remove ) + { + hideModel(); + + if ( !Respawnable() ) + PostEvent( EV_Remove, FRAMETIME ); + } + else + { + if ( HasAnim( "pickup_idle" ) ) + RandomAnimate( "pickup_idle" ); + else + RandomAnimate( "pickup" ); + } + } + +void Item::setRespawn + ( + qboolean flag + ) + + { + respawnable = flag; + } + +qboolean Item::Respawnable + ( + void + ) + + { + return respawnable; + } + +void Item::setRespawnTime + ( + float time + ) + + { + respawntime = time; + } + +float Item::RespawnTime + ( + void + ) + + { + return respawntime; + } + +int Item::getAmount + ( + void + ) + + { + return amount; + } + +int Item::MaxAmount + ( + void + ) + + { + return maximum_amount; + } + +qboolean Item::Pickupable + ( + Entity *other + ) + + { + if ( !other->isSubclassOf( Sentient ) ) + { + return false; + } + else + { + Sentient * sent; + Item * item; + + sent = ( Sentient * )other; + + item = sent->FindItem( getName() ); + + if ( item && ( item->getAmount() >= item->MaxAmount() ) ) + { + return false; + } + + // If deathmatch and already in a powerup, don't pickup anymore when DF_INSTANT_ITEMS is on + if ( DM_FLAG( DF_INSTANT_ITEMS ) && + this->isSubclassOf( InventoryItem ) && + sent->PowerupActive() + ) + { + return false; + } + } + return true; + } + +void Item::Pickup + ( + Event * ev + ) + + { + ItemPickup( ev->GetEntity( 1 ) ); + } + +void Item::setName + ( + const char *i + ) + + { + item_name = i; + item_index = gi.itemindex( i ); + strcpy( edict->entname, i ); + } + +str Item::getName + ( + void + ) + + { + return( item_name ); + } + +int Item::getIndex + ( + void + ) + + { + return item_index; + } + +void Item::setAmount + ( + int startamount + ) + + { + amount = startamount; + if ( amount >= MaxAmount() ) + { + SetMax( amount ); + } + } + +void Item::SetMax + ( + int maxamount + ) + + { + maximum_amount = maxamount; + } + +void Item::SetAmountEvent + ( + Event *ev + ) + + { + setAmount( ev->GetInteger( 1 ) ); + } + +void Item::SetMaxAmount + ( + Event *ev + ) + + { + SetMax( ev->GetInteger( 1 ) ); + } + +void Item::SetItemName + ( + Event *ev + ) + + { + setName( ev->GetString( 1 ) ); + } + +void Item::Add + ( + int num + ) + + { + amount += num; + if ( amount >= MaxAmount() ) + amount = MaxAmount(); + } + +void Item::Remove + ( + int num + ) + { + amount -= num; + if (amount < 0) + amount = 0; + } + + +qboolean Item::Use + ( + int num + ) + + { + if ( num > amount ) + { + return false; + } + + amount -= num; + return true; + } + +qboolean Item::Removable + ( + void + ) + + { + return true; + } + +void Item::RespawnSound + ( + Event *ev + ) + + { + playrespawn = true; + } + +void Item::DialogNeeded + ( + Event *ev + ) + + { + // + // if this item is needed for a trigger, play this dialog + // + dialog_needed = ev->GetString( 1 ); + } + +str Item::GetDialogNeeded + ( + void + ) + + { + return dialog_needed; + } + +// +// once item has landed on the floor, go to movetype none +// +void Item::Landed + ( + Event *ev + ) + { + if ( groundentity && ( groundentity->entity != world ) ) + { + warning( "Item::Landed", "Item %d has landed on an entity that might move\n", entnum ); + } + setMoveType( MOVETYPE_NONE ); + } + +void Item::SetPickupThread + ( + Event *ev + ) + + { + pickup_thread = ev->GetString( 1 ); + } + +void Item::SetCoolItem + ( + qboolean cool, + str &dialog, + str &anim + ) + { + coolitem = cool; + cool_dialog = dialog; + if ( cool_dialog.length() ) + { + CacheResource( cool_dialog, this ); + } + + CacheResource( "models/fx_coolitem.tik", this ); + CacheResource( "models/fx_coolitem_reverse.tik", this ); + + cool_anim = anim; + } + +void Item::CoolItemEvent + ( + Event *ev + ) + + { + qboolean cool; + str dialog, anim; + + cool = qtrue; + if ( ev->NumArgs() > 0 ) + { + dialog = ev->GetString( 1 ); + } + if ( ev->NumArgs() > 1 ) + { + anim = ev->GetString( 2 ); + } + SetCoolItem( cool, dialog, anim ); + } + +void Item::ForceCoolItemEvent + ( + Event *ev + ) + + { + coolitemforced = qtrue; + CoolItemEvent( ev ); + } + +qboolean Item::IsItemCool + ( + str * dialog, + str * anim, + qboolean * forced + ) + { + *dialog = cool_dialog; + *anim = cool_anim; + *forced = coolitemforced; + return coolitem; + } diff --git a/source/source/fgame/item.h b/source/source/fgame/item.h new file mode 100644 index 0000000..e637a48 --- /dev/null +++ b/source/source/fgame/item.h @@ -0,0 +1,217 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/item.h $ +// $Revision:: 20 $ +// $Author:: Steven $ +// $Date:: 7/16/00 10:46a $ +// +// Copyright (C) 1997 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source is may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/item.h $ +// +// 20 7/16/00 10:46a Steven +// Added has_been_looked_at stuff. +// +// 19 7/10/00 8:09p Markd +// fixed cool item pickup problems +// +// 18 7/04/00 6:45p Markd +// enhanced cool item features +// +// 17 7/04/00 2:25p Markd +// added cool cinematic for new objects +// +// 16 6/14/00 2:17p Markd +// fixed compiler warnings for Intel Compiler +// +// 15 6/01/00 3:18p Markd +// rewrote giveItem and item management in sentient +// +// 14 5/30/00 7:06p Markd +// saved games 4th pass +// +// 13 5/27/00 5:06p Steven +// Added a GetOwner function. +// +// 12 5/26/00 7:44p Markd +// 2nd phase save games +// +// 11 5/24/00 3:14p Markd +// first phase of save/load games +// +// 10 5/23/00 10:19a Steven +// Made EV_Item_PickupDone visible externally. +// +// 9 4/11/00 5:32p Markd +// reworked PickupItem code +// +// 8 3/27/00 4:47p Markd +// added pickup_thread capability to all items +// +// 7 3/13/00 5:18p Aldie +// Made some changes for usable inventory item stuff +// +// 6 1/26/00 3:33p Aldie +// Change Amount to getAmount. Added some 'listinventory' command. Added give +// all cheat to execute the script in global/giveall.txt +// +// 5 1/15/00 3:57p Markd +// Eliminated multiple "angle" events and replaced them with EV_SetAngle +// +// 4 12/17/99 6:35p Jimdose +// changed spawnarg code +// added Level class for spawning and map control +// got rid of unused or superflous variables +// changed setjmp/longjmp calls to try/throw/catch exception handling +// +// 3 12/02/99 6:53p Aldie +// Changed naming conventions from "both" to "dualhanded" Also put in the +// inventory renderer for the hud file +// +// 2 9/29/99 7:43p Markd +// Made items behave better when dropping to floor +// +// 1 9/10/99 10:54a Jimdose +// +// 1 9/08/99 3:16p Aldie +// +// 5 8/27/99 5:07p Steven +// General item work. +// +// DESCRIPTION: +// Base class for respawnable, carryable objects. +// + +#ifndef __ITEM_H__ +#define __ITEM_H__ + +#include "g_local.h" +#include "entity.h" +#include "trigger.h" +#include "sentient.h" + +extern Event EV_Item_Pickup; +extern Event EV_Item_DropToFloor; +extern Event EV_Item_Respawn; +extern Event EV_Item_SetAmount; +extern Event EV_Item_SetMaxAmount; +extern Event EV_Item_RespawnSound; +extern Event EV_Item_DialogNeeded; +extern Event EV_Item_PickupDone; + +#define DROPPED_ITEM 0x00008000 +#define DROPPED_PLAYER_ITEM 0x00010000 + +class Item : public Trigger + { + protected: + SentientPtr owner; + qboolean respawnable; + qboolean playrespawn; + qboolean coolitem; + qboolean coolitemforced; + str cool_dialog; + str cool_anim; + float respawntime; + str dialog_needed; + int item_index; + str item_name; + int maximum_amount; + int amount; + str pickup_thread; + + qboolean no_remove; + + void ItemTouch( Event *ev ); + + public: + + qboolean has_been_looked_at; + + CLASS_PROTOTYPE( Item ); + + Item(); + ~Item(); + virtual void PlaceItem( void ); + virtual void SetOwner( Sentient *ent ); + virtual Sentient* GetOwner( void ); + void SetNoRemove( Event *ev ); + virtual void DropToFloor( Event *ev ); + virtual Item *ItemPickup( Entity *other, qboolean add_to_inventory = qtrue ); + virtual void Respawn( Event *ev ); + virtual void setRespawn( qboolean flag ); + void setRespawn( Event *ev ); + virtual qboolean Respawnable( void ); + virtual void setRespawnTime( float time ); + void setRespawnTime( Event *ev ); + virtual float RespawnTime( void ); + void RespawnDone( Event *ev ); + void PickupDone( Event *ev ); + virtual int GetItemIndex( void ) { return item_index; }; + virtual int getAmount( void ); + virtual void setAmount( int startamount ); + + virtual int MaxAmount( void ); + virtual qboolean Pickupable( Entity *other ); + + virtual void setName( const char *i ); + virtual str getName( void ); + virtual int getIndex( void ); + virtual void SetAmountEvent( Event *ev ); + virtual void SetMaxAmount( Event *ev ); + virtual void SetItemName( Event *ev ); + virtual void SetPickupThread( Event *ev ); + + virtual void SetMax( int maxamount ); + virtual void Add( int num ); + virtual void Remove( int num ); + virtual qboolean Use( int amount ); + virtual qboolean Removable( void ); + virtual void Pickup( Event *ev ); + virtual qboolean Drop( void ); + virtual void RespawnSound( Event *ev ); + virtual void DialogNeeded( Event *ev ); + virtual str GetDialogNeeded( void ); + void Landed( Event *ev ); + void CoolItemEvent( Event *ev ); + void ForceCoolItemEvent( Event *ev ); + qboolean IsItemCool( str * dialog, str * anim, qboolean *force ); + void SetCoolItem( qboolean cool, str &dialog, str &anim ); + virtual void Archive( Archiver &arc ); + }; + +inline void Item::Archive + ( + Archiver &arc + ) + { + Trigger::Archive( arc ); + + arc.ArchiveSafePointer( &owner ); + arc.ArchiveBoolean( &respawnable ); + arc.ArchiveBoolean( &playrespawn ); + arc.ArchiveBoolean( &coolitem ); + arc.ArchiveBoolean( &coolitemforced ); + arc.ArchiveString( &cool_dialog ); + arc.ArchiveString( &cool_anim ); + arc.ArchiveFloat( &respawntime ); + arc.ArchiveString( &dialog_needed ); + arc.ArchiveString( &item_name ); + if ( arc.Loading() ) + { + setName( item_name.c_str() ); + } + arc.ArchiveInteger( &maximum_amount ); + arc.ArchiveInteger( &amount ); + arc.ArchiveString( &pickup_thread ); + arc.ArchiveBoolean( &no_remove ); + + arc.ArchiveBoolean( &has_been_looked_at ); + } + + +#endif /* item.h */ diff --git a/source/source/fgame/level.cpp b/source/source/fgame/level.cpp new file mode 100644 index 0000000..81f202b --- /dev/null +++ b/source/source/fgame/level.cpp @@ -0,0 +1,1022 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/level.cpp $ +// $Revision:: 37 $ +// $Date:: 8/11/00 2:34p $ +// +// Copyright (C) 1999 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source is may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/level.cpp $ +// +// 37 8/11/00 2:34p Markd +// Added pre-release demo specific code +// +// 36 7/30/00 2:55p Markd +// initialized more variables on cleanup +// +// 35 7/28/00 6:57p Steven +// Added some player died stuff. +// +// 34 7/27/00 3:52p Aldie +// Changed over letterboxing and fades to the game code. They are sent over in +// player stats and fields now. +// +// 33 7/25/00 11:32p Aldie +// Made some changes to the memory system and fixed a memory allocation bug in +// Z_TagMalloc. Also changed a lot of classes to subclass from Class. +// +// 32 7/23/00 7:58p Steven +// Fixed some boss health stuff. +// +// 31 7/23/00 2:35p Markd +// added precache support +// +// 30 7/21/00 10:44p Aldie +// Added a carriage return to the restart command +// +// 29 7/21/00 2:32p Markd +// changed default value of detail +// +// 28 7/17/00 3:26p Aldie +// Fix for flashbangs, changed detail variable, and added forcetorsostate +// +// 27 7/16/00 11:09p Markd +// fixed potential va bugs +// +// 26 7/10/00 11:54p Markd +// added exit level code +// +// 25 7/07/00 6:34p Steven +// Added mission failed stuff. +// +// 24 7/04/00 2:25p Markd +// added cool cinematic for new objects +// +// 23 6/28/00 3:26p Steven +// Added level wide ai_on. +// +// 22 6/24/00 1:06p Steven +// Fixed some soundtrack problems. +// +// 21 6/23/00 8:41p Markd +// made a lot of changes to different constructors for saved game support +// +// 20 6/10/00 4:23p Markd +// rewrote map restarting and loading out of date save games +// +// 19 6/10/00 1:50p Steven +// Added statemap caching. +// +// 18 6/02/00 2:01p Markd +// Fixed client persistant data issues +// +// 17 5/29/00 1:16p Markd +// 3rd round of saved games +// +// 16 5/26/00 7:44p Markd +// 2nd phase save games +// +// 15 5/24/00 3:14p Markd +// first phase of save/load games +// +// 14 4/11/00 2:46p Markd +// Implemented Automatic camera support +// +// 13 3/21/00 5:05p Markd +// improved earthquakes a lot with a visual effect +// +// 12 2/29/00 5:51p Jimdose +// added alternate spawnpoint support +// +// 11 2/26/00 12:58p Jimdose +// added PlayerRestart +// +// 10 2/15/00 5:17p Aldie +// Increased eventlimit and also added a count to print out the number of +// entities spawned +// +// 9 2/04/00 11:18a Markd +// Fixed memory leak with AI_PathNodes +// +// 8 1/28/00 5:43p Markd +// Added script command to the game +// +// 7 1/19/00 5:15p Aldie +// Fix for fixedframetime +// +// 6 1/13/00 5:19p Jimdose +// removed clearsavegames +// +// 5 1/12/00 6:14p Jimdose +// added spawnflags to level +// +// 4 1/10/00 12:42p Markd +// fixed entity spawing at the beginng of a map +// +// 3 1/06/00 11:08p Jimdose +// cleaning up unused code +// +// 2 12/17/99 7:32p Markd +// made various warnings developer 2 instead of developer 1 +// +// 1 12/17/99 6:33p Jimdose +// +// DESCRIPTION: +// + +#include "level.h" +#include "scriptmaster.h" +#include "navigate.h" +#include "gravpath.h" +#include "g_spawn.h" +#include "player.h" +#include "characterstate.h" + +Level level; + +CLASS_DECLARATION( Class, Level, NULL ) + { + { NULL, NULL } + }; + +Level::Level() + { + Init(); + } + +void Level::Init + ( + void + ) + + { + spawn_entnum = -1; + + restart = qfalse;; + + framenum = 0; + time = 0; + frametime = 0; + + level_name = ""; + mapname = ""; + spawnpoint = ""; + nextmap = ""; + + playerfrozen = false; + intermissiontime = 0; + exitintermission = 0; + + next_edict = NULL; + + total_secrets = 0; + found_secrets = 0; + + memset( &impact_trace, 0, sizeof( impact_trace ) ); + + earthquake = 0; + + cinematic = false; + ai_on = true; + + mission_failed = false; + died_already = false; + near_exit = false; + + water_color = vec_zero; + lava_color = vec_zero; + water_alpha = lava_alpha = 0; + + saved_soundtrack = ""; + current_soundtrack = ""; + + consoleThread = NULL; + + // clear out automatic cameras + automatic_cameras.ClearObjectList(); + + // init level script variables + levelVars.ClearList(); + + m_fade_time_start = 0; + m_fade_time = -1; + m_fade_color = vec_zero; + m_fade_alpha = 0; + m_fade_style = additive; + m_fade_type = fadein; + m_letterbox_fraction = 0; + m_letterbox_time = -1; + m_letterbox_time_start = 0; + m_letterbox_dir = letterbox_out; + } + +void Level::CleanUp + ( + void + ) + + { + ClearCachedStatemaps(); + + PathManager.SavePaths(); + + assert( active_edicts.next ); + assert( active_edicts.next->prev == &active_edicts ); + assert( active_edicts.prev ); + assert( active_edicts.prev->next == &active_edicts ); + assert( free_edicts.next ); + assert( free_edicts.next->prev == &free_edicts ); + assert( free_edicts.prev ); + assert( free_edicts.prev->next == &free_edicts ); + + while( active_edicts.next != &active_edicts ) + { + assert( active_edicts.next != &free_edicts ); + assert( active_edicts.prev != &free_edicts ); + + assert( active_edicts.next ); + assert( active_edicts.next->prev == &active_edicts ); + assert( active_edicts.prev ); + assert( active_edicts.prev->next == &active_edicts ); + assert( free_edicts.next ); + assert( free_edicts.next->prev == &free_edicts ); + assert( free_edicts.prev ); + assert( free_edicts.prev->next == &free_edicts ); + + if ( active_edicts.next->entity ) + { + delete active_edicts.next->entity; + } + else + { + FreeEdict( active_edicts.next ); + } + } + earthquake = 0; + + cinematic = false; + ai_on = true; + + mission_failed = false; + died_already = false; + near_exit = false; + + globals.num_entities = game.maxclients + 1; + + // clear up all AI node information + AI_ResetNodes(); + + // Reset the gravity paths + gravPathManager.Reset(); + + if ( consoleThread ) + { + Director.KillThread( consoleThread->ThreadNum() ); + consoleThread = NULL; + } + + // close all the scripts + Director.CloseScript(); + + // invalidate player readiness + Director.PlayerNotReady(); + + // clear out automatic cameras + automatic_cameras.ClearObjectList(); + + // clear out level script variables + levelVars.ClearList(); + + // Clear out parm vars + parmVars.ClearList(); + + // initialize the game variables + // these get restored by the persistant data, so we can safely clear them here + gameVars.ClearList(); + + // clearout any waiting events + L_ClearEventList(); + + ResetEdicts(); + + // Reset the boss health cvar + + gi.cvar_set( "bosshealth", "0" ); + } + +/* +============== +ResetEdicts +============== +*/ +void Level::ResetEdicts + ( + void + ) + + { + int i; + + memset( g_entities, 0, game.maxentities * sizeof( g_entities[ 0 ] ) ); + + // Add all the edicts to the free list + LL_Reset( &free_edicts, next, prev ); + LL_Reset( &active_edicts, next, prev ); + for( i = 0; i < game.maxentities; i++ ) + { + LL_Add( &free_edicts, &g_entities[ i ], next, prev ); + } + + for( i = 0; i < game.maxclients; i++ ) + { + // set client fields on player ents + g_entities[ i ].client = game.clients + i; + + G_InitClientPersistant (&game.clients[i]); + } + + globals.num_entities = game.maxclients; + } + +/* +============== +Start + +Does all post-spawning setup. This is NOT called for savegames. +============== +*/ +void Level::Start + ( + void + ) + + { + ScriptThread *gamescript; + const char *scriptname; + + // initialize secrets + levelVars.SetVariable( "total_secrets", total_secrets ); + levelVars.SetVariable( "found_secrets", found_secrets ); + + FindTeams(); + + // call the precache scripts + Precache(); + + // + // create the console thread + // + consoleThread = Director.CreateThread( CONSOLE_SCRIPT ); + + // + // start executing the game script + // + scriptname = ScriptLib.GetGameScript(); + if ( scriptname && scriptname[ 0 ] ) + { + gamescript = Director.CreateThread( scriptname, LEVEL_SCRIPT ); + if ( gamescript ) + { + // start at the end of this frame + gamescript->Start( 0 ); + } + } + } + +qboolean Level::inhibitEntity + ( + int spawnflags + ) + + { + if ( !developer->integer && ( spawnflags & SPAWNFLAG_DEVELOPMENT ) ) + { + return qtrue; + } + + if ( !detail->integer && ( spawnflags & SPAWNFLAG_DETAIL ) ) + { + return qtrue; + } + + if ( deathmatch->integer ) + { + if ( spawnflags & SPAWNFLAG_NOT_DEATHMATCH ) + { + return qtrue; + } + + return qfalse; + } + + switch( skill->integer ) + { + case 0 : + return ( spawnflags & SPAWNFLAG_NOT_EASY ) != 0; + break; + + case 1 : + return ( spawnflags & SPAWNFLAG_NOT_MEDIUM ) != 0; + break; + + case 2 : + case 3 : + return ( spawnflags & SPAWNFLAG_NOT_HARD ); + break; + } + + return qfalse; + } + +void Level::setSkill + ( + int value + ) + + { + int skill_level; + + skill_level = floor( value ); + skill_level = bound( skill_level, 0, 3 ); + + gi.cvar_set( "skill", va( "%d", skill_level ) ); + + gameVars.SetVariable( "skill", skill_level ); + } + +void Level::setTime + ( + int levelTime, + int frameTime + ) + + { + inttime = levelTime; + fixedframetime = 1.0f / sv_fps->value; + time = ( ( float )levelTime / 1000.0f ); + frametime = ( ( float )frameTime / 1000.0f ); + } + +/* +============== +SpawnEntities + +Creates a server's entity / program execution context by +parsing textual entity definitions out of an ent file. +============== +*/ +void Level::SpawnEntities + ( + const char *themapname, + const char *entities, + int levelTime + ) + + { + int inhibit,count=0; + const char *value; + SpawnArgs args; + char *spawnpos; + + // Init the level variables + Init(); + + spawnpos = strchr( themapname, '$' ); + if ( spawnpos ) + { + mapname = str( themapname, 0, spawnpos - themapname ); + spawnpoint = spawnpos + 1; + } + else + { + mapname = themapname; + spawnpoint = ""; + } + + // set up time so functions still have valid times + setTime( levelTime, 1000 / 20 ); + + if ( !LoadingServer ) + { + // Get rid of anything left over from the last level + CleanUp(); + + // Set up for a new map + PathManager.Init( mapname ); + } + + setSkill( skill->integer ); + + // reset out count of the number of game traces + sv_numtraces = 0; + + // parse world + entities = args.Parse( entities ); + spawn_entnum = ENTITYNUM_WORLD; + args.Spawn(); + + // parse ents + inhibit = 0; + for( entities = args.Parse( entities ); entities != NULL; entities = args.Parse( entities ) ) + { + // remove things (except the world) from different skill levels or deathmatch + spawnflags = 0; + value = args.getArg( "spawnflags" ); + if ( value ) + { + spawnflags = atoi( value ); + if ( inhibitEntity( spawnflags ) ) + { + inhibit++; + continue; + } + } + + args.Spawn(); + count++; + } + + gi.DPrintf( "%i entities spawned\n", count ); + gi.DPrintf( "%i entities inhibited\n", inhibit ); + + // Process the spawn events + L_ProcessPendingEvents(); + + if ( !LoadingServer || game.autosaved ) + { + Start(); + } + + // + // if this is a single player game, spawn the single player in now + // this allows us to read persistant data into the player before the client + // is completely ready + // + if ( game.maxclients == 1 ) + { + spawn_entnum = 0; + new Player; + } + } + +void Level::NewMap + ( + const char *mapname, + const char *entities, + int levelTime + ) + + { + current_map = mapname; + current_entities = entities; + + SpawnEntities( current_map, current_entities, levelTime ); + } + +void Level::Restart + ( + void + ) + + { + SpawnEntities( current_map, current_entities, inttime ); + + L_ProcessPendingEvents(); + + G_ClientConnect( 0, qtrue ); + G_ClientBegin( &g_entities[ 0 ], NULL ); + } + +void Level::PlayerRestart + ( + void + ) + + { + // we need to restart through the server code + gi.SendConsoleCommand( "restart\n" ); + //restart = qtrue; + level.mission_failed = false; + } + +void Level::Archive + ( + Archiver &arc + ) + + { + Class::Archive( arc ); + + arc.ArchiveInteger( &framenum ); + arc.ArchiveInteger( &inttime ); + arc.ArchiveFloat( &time ); + arc.ArchiveFloat( &frametime ); + arc.ArchiveFloat( &fixedframetime ); + arc.ArchiveInteger( &startTime ); + + arc.ArchiveString( &level_name ); + arc.ArchiveString( &mapname ); + arc.ArchiveString( &spawnpoint ); + arc.ArchiveString( &nextmap ); + + arc.ArchiveBoolean( &restart ); + + arc.ArchiveBoolean( &playerfrozen ); + arc.ArchiveFloat( &intermissiontime ); + arc.ArchiveInteger( &exitintermission ); + + arc.ArchiveInteger( &total_secrets ); + arc.ArchiveInteger( &found_secrets ); + + arc.ArchiveFloat( &earthquake ); + arc.ArchiveFloat( &earthquake_magnitude ); + + arc.ArchiveBoolean( &cinematic ); + arc.ArchiveBoolean( &ai_on ); + + arc.ArchiveBoolean( &mission_failed ); + arc.ArchiveBoolean( &died_already ); + + arc.ArchiveVector( &water_color ); + arc.ArchiveVector( &lava_color ); + arc.ArchiveFloat( &water_alpha ); + arc.ArchiveFloat( &lava_alpha ); + + arc.ArchiveString( &saved_soundtrack ); + arc.ArchiveString( ¤t_soundtrack ); + + arc.ArchiveVector( &m_fade_color ); + arc.ArchiveFloat( &m_fade_alpha ); + arc.ArchiveFloat( &m_fade_time ); + arc.ArchiveFloat( & m_fade_time_start ); + arc.ArchiveInteger( (int *)&m_fade_style ); + arc.ArchiveInteger( (int *)&m_fade_type ); + + arc.ArchiveFloat( &m_letterbox_fraction ); + arc.ArchiveFloat( &m_letterbox_time ); + arc.ArchiveFloat( &m_letterbox_time_start ); + arc.ArchiveInteger( (int *)&m_letterbox_dir ); + + if ( arc.Loading() ) + { + str temp_soundtrack; + + // Change the sound track to the one just loaded + + temp_soundtrack = saved_soundtrack; + ChangeSoundtrack( current_soundtrack.c_str() ); + saved_soundtrack = temp_soundtrack; + + // + // create the console thread + // + consoleThread = Director.CreateThread( CONSOLE_SCRIPT ); + // not archived since we can't save mid-frame + next_edict = NULL; + // not archived since we can't save mid-frame + memset( &impact_trace, 0, sizeof( impact_trace ) ); + } + } + +/* +============== +Precache + +Calls precache scripts +============== +*/ +void Level::Precache + ( + void + ) + + { + str filename; + const char *scriptname; + int i; + + // + // load in global0-9.scr + // + for( i = 0; i < 100; i++ ) + { + filename = va( "global/global%i.scr", i ); + if ( !G_LoadAndExecScript( filename.c_str(), NULL, qtrue ) ) + { + break; + } + } + + // + // load in precache0-9.scr + // + if ( precache->integer ) + { + for( i = 0; i < 100; i++ ) + { +#ifdef PRE_RELEASE_DEMO + filename = va( "global/precache_demo%i.scr", i ); +#else + filename = va( "global/precache%i.scr", i ); +#endif + if ( !G_LoadAndExecScript( filename.c_str(), NULL, qtrue ) ) + { + break; + } + } + } + + // + // load in players0-9.scr + // + for( i = 0; i< 100; i++ ) + { + filename = va( "global/players%i.scr", i ); + if ( !G_LoadAndExecScript( filename.c_str(), NULL, qtrue ) ) + { + break; + } + } + + // + // load in universal_script.scr + // + G_LoadAndExecScript( "global/universal_script.scr", "precache:", qtrue ); + + // + // precache for the game script + // + scriptname = ScriptLib.GetGameScript(); + if ( scriptname && scriptname[ 0 ] ) + { + char stripped[ MAX_QPATH ]; + char precache_script[ MAX_QPATH ]; + + COM_StripExtension( scriptname, stripped ); + Com_sprintf( precache_script, sizeof( precache_script ), "%s_precache.scr", stripped ); + G_LoadAndExecScript( precache_script, "precache:" ); + + // also try to call the preache in the normal script itself + G_LoadAndExecScript( scriptname, "precache:", qtrue ); + } + } + +/* +================ +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 Level::FindTeams + ( + void + ) + + { + gentity_t *e; + gentity_t *e2; + gentity_t *next; + gentity_t *next2; + Entity *chain; + Entity *ent; + Entity *ent2; + int c; + int c2; + + c = 0; + c2 = 0; + + for( e = active_edicts.next; e != &active_edicts; e = next ) + { + assert( e ); + assert( e->inuse ); + assert( e->entity ); + + next = e->next; + + ent = e->entity; + if ( !ent->moveteam.length() ) + { + continue; + } + + if ( ent->flags & FL_TEAMSLAVE ) + { + continue; + } + + chain = ent; + ent->teammaster = ent; + c++; + c2++; + for( e2 = next; e2 != &active_edicts; e2 = next2 ) + { + assert( e2 ); + assert( e2->inuse ); + assert( e2->entity ); + + next2 = e2->next; + + ent2 = e2->entity; + if ( !ent2->moveteam.length() ) + { + continue; + } + + if ( ent2->flags & FL_TEAMSLAVE ) + { + continue; + } + + if ( ent->moveteam == ent2->moveteam ) + { + c2++; + chain->teamchain = ent2; + ent2->teammaster = ent; + chain = ent2; + ent2->flags |= FL_TEAMSLAVE; + } + } + } + + gi.DPrintf( "%i teams with %i entities\n", c, c2 ); + } + +/* +================= +AllocEdict + +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. +================= +*/ +gentity_t *Level::AllocEdict + ( + Entity *ent + ) + + { + int i; + gentity_t *edict; + + if ( spawn_entnum >= 0 ) + { + edict = &g_entities[ spawn_entnum ]; + spawn_entnum = -1; + + assert( !edict->inuse && !edict->entity ); + + // free up the entity pointer in case we took one that still exists + if ( edict->inuse && edict->entity ) + { + delete edict->entity; + } + } + else + { + edict = &g_entities[ maxclients->integer ]; + for ( i = maxclients->integer; i < globals.num_entities; i++, edict++ ) + { + // the first couple seconds of server time can involve a lot of + // freeing and allocating, so relax the replacement policy + if ( + !edict->inuse && + ( + ( edict->freetime < ( 2 + startTime ) ) || + ( time - edict->freetime > 0.5 ) + ) + ) + { + break; + } + } + + // allow two spots for none and world + if ( i == game.maxentities - 2 ) + { + gi.Error( ERR_DROP, "Level::AllocEdict: no free edicts" ); + } + } + + assert( edict->next ); + assert( edict->prev ); + LL_Remove( edict, next, prev ); + InitEdict( edict ); + assert( active_edicts.next ); + assert( active_edicts.prev ); + LL_Add( &active_edicts, edict, next, prev ); + assert( edict->next ); + assert( edict->prev ); + + assert( edict->next != &free_edicts ); + assert( edict->prev != &free_edicts ); + + // Tell the server about our data since we just spawned something + if ( ( edict->s.number < ENTITYNUM_WORLD ) && ( globals.num_entities <= edict->s.number ) ) + { + globals.num_entities = edict->s.number + 1; + gi.LocateGameData( g_entities, globals.num_entities, sizeof( gentity_t ), &game.clients[ 0 ].ps, sizeof( game.clients[ 0 ] ) ); + } + + edict->entity = ent; + + return edict; + } + +/* +================= +FreeEdict + +Marks the edict as free +================= +*/ +void Level::FreeEdict + ( + gentity_t *ed + ) + + { + gclient_t *client; + + assert( ed != &free_edicts ); + + // unlink from world + gi.unlinkentity ( ed ); + + assert( ed->next ); + assert( ed->prev ); + + if ( next_edict == ed ) + { + next_edict = ed->next; + } + + LL_Remove( ed, next, prev ); + + assert( ed->next == ed ); + assert( ed->prev == ed ); + assert( free_edicts.next ); + assert( free_edicts.prev ); + + client = ed->client; + memset( ed, 0, sizeof( *ed ) ); + ed->client = client; + ed->freetime = time; + ed->inuse = false; + ed->s.number = ed - g_entities; + + assert( free_edicts.next ); + assert( free_edicts.prev ); + + LL_Add( &free_edicts, ed, next, prev ); + + assert( ed->next ); + assert( ed->prev ); + } + +void Level::InitEdict + ( + gentity_t *e + ) + + { + int i; + + e->inuse = true; + e->s.number = e - g_entities; + + // make sure a default scale gets set + e->s.scale = 1.0f; + // make sure the default constantlight gets set, initalize to r 1.0, g 1.0, b 1.0, r 0 + e->s.constantLight = 0xffffff; + e->s.renderfx |= RF_FRAMELERP; + e->spawntime = time; + e->s.frame = 0; + + for( i = 0; i < NUM_BONE_CONTROLLERS; i++ ) + { + e->s.bone_tag[ i ] = -1; + VectorClear( e->s.bone_angles[ i ] ); + EulerToQuat( e->s.bone_angles[ i ], e->s.bone_quat[ i ] ); + } + } + +void Level::AddAutomaticCamera + ( + Camera *cam + ) + + { + automatic_cameras.AddUniqueObject( cam ); + } diff --git a/source/source/fgame/level.h b/source/source/fgame/level.h new file mode 100644 index 0000000..ae32b4e --- /dev/null +++ b/source/source/fgame/level.h @@ -0,0 +1,190 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/level.h $ +// $Revision:: 15 $ +// $Date:: 7/28/00 6:59p $ +// +// Copyright (C) 1999 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source is may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/level.h $ +// +// 15 7/28/00 6:59p Steven +// Added some player died stuff. +// +// 14 7/27/00 3:52p Aldie +// Changed over letterboxing and fades to the game code. They are sent over in +// player stats and fields now. +// +// 13 7/10/00 11:54p Markd +// added exit level code +// +// 12 7/07/00 6:35p Steven +// Added mission failed stuff. +// +// 11 6/28/00 3:27p Steven +// Added level wide ai_on. +// +// 10 5/24/00 3:14p Markd +// first phase of save/load games +// +// 9 4/11/00 2:46p Markd +// Implemented Automatic camera support +// +// 8 3/21/00 5:05p Markd +// improved earthquakes a lot with a visual effect +// +// 7 2/29/00 5:51p Jimdose +// added alternate spawnpoint support +// +// 6 2/26/00 12:58p Jimdose +// added PlayerRestart +// +// 5 1/28/00 5:43p Markd +// Added script command to the game +// +// 4 1/13/00 5:19p Jimdose +// removed clearsavegames +// +// 3 1/12/00 6:14p Jimdose +// added spawnflags to Level +// +// 2 1/06/00 11:08p Jimdose +// cleaning up unused code +// +// 1 12/17/99 6:33p Jimdose +// +// DESCRIPTION: +// + +#ifndef __LEVEL_H__ +#define __LEVEL_H__ + +#include "g_local.h" +#include "container.h" + +class ScriptThread; +class Camera; +// +// this structure is cleared as each map is entered +// it is read/written to the level.sav file for savegames +// +enum fadetype_t { fadein, fadeout }; +enum fadestyle_t { alphablend, additive }; +enum letterboxdir_t { letterbox_in, letterbox_out }; + +class Level : public Class + { + public: + const char *current_map; + const char *current_entities; + + int spawn_entnum; + int spawnflags; + + int framenum; + int inttime; // level time in millisecond integer form + float time; + float frametime; + float fixedframetime; // preset frame time based on sv_fps + int startTime; // level.time the map was started + + str level_name; // the descriptive name (Outer Base, etc) + str mapname; // the server name (base1, etc) + str spawnpoint; // targetname of spawnpoint + str nextmap; // go here when fraglimit is hit + + qboolean restart; // set true when game loop should restart + + // used for cinematics + qboolean playerfrozen; + + // intermission state + float intermissiontime; // time the intermission was started + int exitintermission; + + gentity_s *next_edict; // Used to keep track of the next edict to process in G_RunFrame + + int total_secrets; + int found_secrets; + + // FIXME - remove this later when it is passed in the event. + trace_t impact_trace; + + float earthquake; + float earthquake_magnitude; + + qboolean cinematic; + + qboolean ai_on; + + qboolean mission_failed; + qboolean died_already; + + qboolean near_exit; + + // Blending color for water, light volumes,lava + Vector water_color; + Vector lava_color; + float water_alpha; + float lava_alpha; + + str current_soundtrack; + str saved_soundtrack; + + ScriptThread *consoleThread; + + Vector m_fade_color; + float m_fade_alpha; + float m_fade_time; + float m_fade_time_start; + fadetype_t m_fade_type; + fadestyle_t m_fade_style; + + float m_letterbox_fraction; + float m_letterbox_time; + float m_letterbox_time_start; + letterboxdir_t m_letterbox_dir; + + // + // list of automatic_cameras on the level + // + Container automatic_cameras; + + + + CLASS_PROTOTYPE( Level ); + + Level(); + + void Init( void ); + void CleanUp( void ); + + void ResetEdicts( void ); + gentity_t *AllocEdict( Entity *ent ); + void FreeEdict( gentity_t *ed ); + void InitEdict( gentity_t *e ); + + void Start( void ); + void Restart( void ); + void PlayerRestart( void ); + void Precache( void ); + void FindTeams( void ); + + void SpawnEntities( const char *mapname, const char *entities, int levelTime ); + void NewMap( const char *mapname, const char *entities, int levelTime ); + + qboolean inhibitEntity( int spawnflags ); + void setSkill( int value ); + void setTime( int levelTime, int frameTime ); + void AddAutomaticCamera( Camera * cam ); + + virtual void Archive( Archiver &arc ); + }; + +extern Level level; + +#endif /* !__LEVEL_H__ */ diff --git a/source/source/fgame/light.cpp b/source/source/fgame/light.cpp new file mode 100644 index 0000000..da9fbc2 --- /dev/null +++ b/source/source/fgame/light.cpp @@ -0,0 +1,170 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/light.cpp $ +// $Revision:: 7 $ +// $Author:: Markd $ +// $Date:: 6/14/00 3:50p $ +// +// Copyright (C) 1997 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source is may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/light.cpp $ +// +// 7 6/14/00 3:50p Markd +// Cleaned up more Intel Compiler warnings +// +// 6 10/18/99 7:14p Markd +// Fixed fulcrum stuff +// +// 5 10/11/99 1:08p Markd +// Added angles and spot_angle support to lights +// +// 4 10/05/99 8:05p Markd +// Forgot to add light handling behavior +// +// 3 10/05/99 7:58p Markd +// Rewrote light documentation +// +// 2 9/29/99 5:18p Steven +// Event formatting. +// +// 1 9/10/99 10:54a Jimdose +// +// 1 9/08/99 3:16p Aldie +// +// 9 7/08/99 4:28p Markd +// Removed obsolete QUAKED functions +// +// 8 6/11/99 1:23p Phook +// +// 7 6/11/99 12:58p Phook +// Changed from SINED comments to QUAKED +// +// 6 6/11/99 12:46p Phook +// EClass color changes +// +// DESCRIPTION: +// Classes for creating and controlling lights. +// + +#include "g_local.h" +#include "entity.h" +#include "trigger.h" +#include "light.h" +#include "scriptmaster.h" + +/*****************************************************************************/ +/*QUAKED light (0.75 0.5 0) (-8 -8 -8) (8 8 8) LINEAR NO_ENTITIES ENTITY_TRACE + +Non-displayed light. If it targets another entity it will become a spot light +if "LINEAR" is set, it will be a linear light +if "NO_ENTITIES" is set, this light will only effect the world, not entities +if "ENTITY_TRACE" is set, a trace is done betwee the light and the entity.\ +The light is only added if the trace is clear + +"no_entity_light" - this light will not effect entities, just the world +"light" - the intensity of the light, default 300 +"color" - the color of the light +"falloff" - if linear, specify the linear falloff (defaults to 1) +"radius" - make this a spot light of the given radius +"angles" - make this a spot light centered on angles +"spot_angle" - if this is a spot light, what angle to use (default 45) +"entity_trace" - trace between the entity and the light + +******************************************************************************/ + +Event EV_Light_SetLight + ( + "light", + EV_DEFAULT, + NULL, + NULL, + "Set the intensity of the light" + ); + +Event EV_Light_SetColor + ( + "color", + EV_DEFAULT, + NULL, + NULL, + "" + ); + +Event EV_Light_SetFalloff + ( + "falloff", + EV_HIDE, + NULL, + NULL, + "" + ); + +Event EV_Light_SetRadius + ( + "falloff", + EV_HIDE, + NULL, + NULL, + "" + ); + +Event EV_Light_SpotDir + ( + "spot_dir", + EV_HIDE, + NULL, + NULL, + "" + ); + +Event EV_Light_SpotRadiusByDistance + ( + "spot_radiusbydistance", + EV_HIDE, + NULL, + NULL, + "" + ); + +Event EV_Light_NoEntityLight + ( + "no_entity_light", + EV_HIDE, + NULL, + NULL, + "" + ); + +Event EV_Light_EntityTrace + ( + "entity_trace", + EV_HIDE, + NULL, + NULL, + "" + ); + +Event EV_Light_SpotAngle + ( + "spot_angle", + EV_HIDE, + NULL, + NULL, + "" + ); + +CLASS_DECLARATION( Entity, Light, "light" ) + { + { &EV_Light_SetLight, NULL }, + { NULL, NULL } + }; + +Light::Light() + { + PostEvent( EV_Remove, 0 ); + } + diff --git a/source/source/fgame/light.h b/source/source/fgame/light.h new file mode 100644 index 0000000..94eacbd --- /dev/null +++ b/source/source/fgame/light.h @@ -0,0 +1,41 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/light.h $ +// $Revision:: 2 $ +// $Author:: Markd $ +// $Date:: 10/05/99 7:58p $ +// +// Copyright (C) 1997 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source is may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/light.h $ +// +// 2 10/05/99 7:58p Markd +// Rewrote light documentation +// +// 1 9/10/99 10:54a Jimdose +// +// 1 9/08/99 3:16p Aldie +// +// DESCRIPTION: +// Classes for creating and controlling lights. +// + +#ifndef __LIGHT_H__ +#define __LIGHT_H__ + +#include "g_local.h" +#include "entity.h" + +class Light : public Entity + { + public: + CLASS_PROTOTYPE( Light ); + + Light(); + }; + +#endif /* light.h */ diff --git a/source/source/fgame/linklist.h b/source/source/fgame/linklist.h new file mode 100644 index 0000000..dc46b5c --- /dev/null +++ b/source/source/fgame/linklist.h @@ -0,0 +1,129 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/Linklist.h $ +// $Revision:: 3 $ +// $Author:: Markd $ +// $Date:: 6/14/00 11:18a $ +// +// Copyright (C) 1997 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source is may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/Linklist.h $ +// +// 3 6/14/00 11:18a Markd +// cleaned up code using Intel compiler +// +// 2 10/05/99 2:03p Markd +// Added warning about files being in multiple projects +// +// 1 9/10/99 10:54a Jimdose +// +// 1 9/08/99 3:16p Aldie +// +// DESCRIPTION: +// +// WARNING: This file is shared between fgame, cgame and possibly the user interface. +// It is instanced in each one of these directories because of the way that SourceSafe works. +// + +#ifndef __linklist_h +#define __linklist_h +#ifdef __cplusplus +extern "C" { +#endif + + +#define NewNode(type) ((type *)Z_Malloc(sizeof(type))) + +#define LL_New(rootnode,type,next,prev) \ + { \ + (rootnode) = NewNode(type); \ + (rootnode)->prev = (rootnode); \ + (rootnode)->next = (rootnode); \ + } + +#define LL_Add(rootnode, newnode, next, prev) \ + { \ + (newnode)->next = (rootnode); \ + (newnode)->prev = (rootnode)->prev; \ + (rootnode)->prev->next = (newnode); \ + (rootnode)->prev = (newnode); \ + } +//MED +#define LL_AddFirst(rootnode, newnode, next, prev) \ + { \ + (newnode)->prev = (rootnode); \ + (newnode)->next = (rootnode)->next; \ + (rootnode)->next->prev = (newnode); \ + (rootnode)->next = (newnode); \ + } + +#define LL_Transfer(oldroot,newroot,next,prev) \ + { \ + if (oldroot->prev != oldroot) \ + { \ + oldroot->prev->next = newroot; \ + oldroot->next->prev = newroot->prev; \ + newroot->prev->next = oldroot->next; \ + newroot->prev = oldroot->prev; \ + oldroot->next = oldroot; \ + oldroot->prev = oldroot; \ + } \ + } + +#define LL_Reverse(root,type,next,prev) \ + { \ + type *newend,*trav,*tprev; \ + \ + newend = root->next; \ + for(trav = root->prev; trav != newend; trav = tprev) \ + { \ + tprev = trav->prev; \ + LL_Move(trav,newend,next,prev); \ + } \ + } + + +#define LL_Remove(node,next,prev) \ + { \ + node->prev->next = node->next; \ + node->next->prev = node->prev; \ + node->next = node; \ + node->prev = node; \ + } + +#define LL_SortedInsertion(rootnode,insertnode,next,prev,type,sortparm) \ + { \ + type *hoya; \ + \ + hoya = rootnode->next; \ + while((hoya != rootnode) && (insertnode->sortparm > hoya->sortparm)) \ + { \ + hoya = hoya->next; \ + } \ + LL_Add(hoya,insertnode,next,prev); \ + } + +#define LL_Move(node,newroot,next,prev) \ + { \ + LL_Remove(node,next,prev); \ + LL_Add(newroot,node,next,prev); \ + } + +#define LL_Empty(list,next,prev) \ + ( \ + ((list)->next == (list)) && \ + ((list)->prev == (list)) \ + ) + +#define LL_Free(list) Z_Free(list) +#define LL_Reset(list,next,prev) (list)->next = (list)->prev = (list) + +#ifdef __cplusplus +} + +#endif +#endif diff --git a/source/source/fgame/listener.cpp b/source/source/fgame/listener.cpp new file mode 100644 index 0000000..e485689 --- /dev/null +++ b/source/source/fgame/listener.cpp @@ -0,0 +1,3435 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/listener.cpp $ +// $Revision:: 61 $ +// $Author:: Aldie $ +// $Date:: 8/10/00 7:38p $ +// +// Copyright (C) 1998 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source is may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/listener.cpp $ +// +// 61 8/10/00 7:38p Aldie +// Working on cleaning stuff +// +// 60 8/10/00 7:34p Aldie +// +// 59 8/10/00 7:21p Aldie +// Added some cleanup to events +// +// 58 8/10/00 7:04p Aldie +// Changed a string allocation +// +// 57 7/14/00 11:30a Markd +// changed initial number of allocated events +// +// 56 7/13/00 12:31p Steven +// Check to see if event is equal to EV_Remove before trying to use it to print +// out info on it. +// +// 55 7/03/00 2:12p Steven +// fixed a crash bug in EventVar::GetVector +// +// 54 6/27/00 2:35p Markd +// allowed vectors to be set to entities to get their origins +// +// 53 6/23/00 9:12p Markd +// fixed some loading of events at spawn time +// +// 52 6/22/00 3:45p Markd +// fixed a bunch of saved game issues +// +// 51 6/14/00 12:14p Markd +// more intel compiler bug fixes +// +// 50 6/06/00 10:57a Steven +// Fixed a compiler issue with g_timeevents change. +// +// 49 6/06/00 10:38a Steven +// Improved g_timeevents. +// +// 48 5/27/00 8:07p Markd +// Saved games 3rd pass +// +// 47 5/26/00 7:44p Markd +// 2nd phase save games +// +// 46 5/25/00 4:28p Markd +// fixed up archive functions +// +// 45 5/24/00 3:14p Markd +// first phase of save/load games +// +// 44 4/29/00 3:26p Markd +// fleshed out the rest of the event/class documentation +// +// 43 4/26/00 7:55p Markd +// Added more documentation code into various systems +// +// 42 4/08/00 3:57p Steven +// Made it so in EventVar( Entity *ent ) if ent was NULL it would save the +// entnum as ENTITYNUM_NONE instead of 0. +// +// 41 3/16/00 7:04p Markd +// Increased number of events allocated at startup +// +// 40 3/06/00 8:07p Markd +// cleaned up unused cvar's +// +// 39 2/24/00 3:16p Jimdose +// changed asserts when Event is unknown into dprintfs +// +// 38 2/23/00 10:07a Markd +// fixed center print and event system crash +// +// 37 2/15/00 5:17p Aldie +// Increased eventlimit and also added a count to print out the number of +// entities spawned +// +// 36 1/06/00 11:10p Jimdose +// cleaning up unused code +// +// 35 12/15/99 3:26p Markd +// fixed listener up a bit, but deleting events instead of realDeallocating +// them right away. +// +// 34 12/15/99 2:08p Markd +// undid test from before +// +// 33 12/15/99 12:11p Markd +// testing undoing my fix +// +// 32 12/15/99 11:45a Markd +// made Event's Classes and also freed up safe pointers at the appropriate +// times +// +// 31 12/13/99 11:14a Markd +// Incremental checkin +// +// 30 12/11/99 5:51p Markd +// First wave of bug fixes after q3a gold merge +// +// 29 12/11/99 3:37p Markd +// q3a gold checkin, first time +// +// 28 10/21/99 2:19p Markd +// Changed range to use ..., fixed fadein and fadeout some more +// +// 27 10/21/99 10:57a Markd +// fixed suppression of _events +// +// 26 10/20/99 7:04p Markd +// suppress commands starting with '_' +// +// 25 10/18/99 2:54p Aldie +// Upped the number of client events +// +// 24 10/11/99 12:01p Steven +// Added some more tabing support when printing out event documentation. +// +// 23 10/11/99 10:05a Markd +// Added some tabbing support to event documentation +// +// 22 10/09/99 6:04p Markd +// changed up documentation a bit +// +// 21 10/07/99 7:14p Aldie +// More beam stuff +// +// 20 10/07/99 3:03p Steven +// Added a new event constructor that only takes a const char * as a parm. +// +// 19 10/06/99 3:09p Steven +// Added dumpevents command. +// +// 18 10/05/99 2:03p Markd +// Added warning about files being in multiple projects +// +// 17 10/03/99 4:50p Markd +// removed str& constructor from listener +// +// 16 10/02/99 6:51p Markd +// Put in backend work for event documentation and fixed a lot of event +// documentation bugs +// +// 15 10/01/99 3:50p Markd +// fixed some level 4 warnings +// +// 14 9/30/99 10:50a Markd +// put in different warning printing depending on which module is used +// +// 13 9/29/99 7:43p Markd +// Made items behave better when dropping to floor +// +// 12 9/29/99 3:36p Steven +// Event formatting. +// +// 11 9/28/99 7:15p Morbid +// +// 10 9/28/99 5:31p Markd +// Successfully merged class.h, listener.h and vector.h into all three modules, +// cgame, fgame and client +// +// 9 9/28/99 5:15p Markd +// Fixed more merge bugs with sharing class, vector and listener between three +// modules +// +// 8 9/28/99 4:26p Markd +// merged listener, class and vector between 3 projects +// +// 7 9/28/99 10:12a Markd +// fixed some event issues +// +// 6 9/27/99 5:44p Markd +// began documentation and cleanup phase after merge +// +// 5 9/22/99 4:48p Markd +// fixed more G_GetEntity, G_FindClass and G_GetNextEntity bugs +// +// 4 9/21/99 7:51p Markd +// Fixed a lot of entitynum_none issues +// +// 3 9/15/99 6:57p Aldie +// Update to get game working +// +// 2 9/10/99 5:45p Jimdose +// merge +// +// 1 9/10/99 10:54a Jimdose +// +// 1 9/08/99 3:16p Aldie +// +// 17 9/02/99 2:33p Markd +// Added cache ability to entities +// +// 16 8/28/99 3:33p Jimdose +// Added EventVar +// All event args now have type information and use lazy evaluation +// +// 15 8/27/99 8:25p Markd +// added pengingevents and fixed some event holes +// +// 14 8/27/99 3:30p Markd +// put in event caching system so that events are reused +// +// 13 8/19/99 12:16p Jimdose +// added event stats +// added lru check to FindEvent +// +// DESCRIPTION: +// +// WARNING: This file is shared between fgame, cgame and possibly the user interface. +// It is instanced in each one of these directories because of the way that SourceSafe works. +// + +#include "listener.h" + +#if defined( GAME_DLL ) + +#include "scriptvariable.h" +#include "worldspawn.h" +#include "scriptmaster.h" + +#elif defined( CGAME_DLL ) + +#elif defined( UI_LIB ) + +#else + +#include "client.h" + +#endif + +Event EV_Remove + ( + "immediateremove", + EV_DEFAULT, + NULL, + NULL, + "Removes this listener immediately." + ); +Event EV_ScriptRemove + ( + "remove", + EV_DEFAULT, + NULL, + NULL, + "Removes this listener the next time events are processed." + ); + +extern "C" + { + int numEvents = 0; + int numFreeEvents = 0; + } + +cvar_t *g_showevents; +cvar_t *g_eventlimit; +cvar_t *g_timeevents; +cvar_t *g_watch; +cvar_t *g_eventstats; + +Event FreeEventHead; +Event *FreeEvents = &FreeEventHead; +Event EventQueueHead; +Event *EventQueue = &EventQueueHead; +Event ActiveEventHead; +Event *ActiveEvents = &ActiveEventHead; + +Container *Event::commandList = NULL; +Container *Event::flagList = NULL; +Container *Event::sortedList = NULL; +Container *Event::eventDefList = NULL; +qboolean Event::dirtylist = false; + +int Event::numfinds; +int Event::numfirstsearch; +int Event::numcompares; +int Event::lastevent; +bool Event::EventSystemStarted; + +int Event_totalmemallocated; + +Event NullEvent; + +void EV_Print( FILE *event_file, const char *fmt, ... ) + { + va_list argptr; + char text[ 1024 ]; + + va_start( argptr, fmt ); + vsprintf( text, fmt, argptr ); + va_end( argptr ); + + if ( event_file ) + fprintf( event_file, text ); + else + EVENT_Printf( text ); + } + +EventVar::EventVar + ( + const char *text + ) + + { + assert( text ); + if ( !text ) + { + text = ""; + } + + dirtyFlags = DIRTY_ALL & ~DIRTY_STRING; + stringValue = text; +#ifdef GAME_DLL + type = Director.isVarGroup( text ) ? IS_SCRIPTVARIABLE : IS_STRING; +#else + type = IS_STRING; +#endif + } + +EventVar::EventVar + ( + str &text + ) + + { + dirtyFlags = DIRTY_ALL & ~DIRTY_STRING; + stringValue = text; +#ifdef GAME_DLL + type = Director.isVarGroup( text.c_str() ) ? IS_SCRIPTVARIABLE : IS_STRING; +#else + type = IS_STRING; +#endif + } + +#ifdef GAME_DLL + +EventVar::EventVar + ( + Entity *ent + ) + + { + type = IS_ENTITY; + dirtyFlags = DIRTY_ALL & ~DIRTY_INTEGER; + if ( ent ) + { + intValue = ent->entnum; + } + else + { + intValue = ENTITYNUM_NONE; + } + } + +void EventVar::Archive + ( + Archiver &arc + ) + + { + arc.ArchiveShort( &type ); + arc.ArchiveShort( &dirtyFlags ); + arc.ArchiveString( &stringValue ); + arc.ArchiveVector( &vectorValue ); + arc.ArchiveInteger( &intValue ); + arc.ArchiveFloat( &floatValue ); + } + +#endif + +const char *EventVar::GetToken + ( + Event &ev + ) + + { + if ( dirtyFlags & DIRTY_STRING ) + { + switch( type ) + { + case IS_VECTOR : + stringValue = va( "(%f %f %f)", vectorValue.x, vectorValue.y, vectorValue.z ); + break; + + case IS_INTEGER : + stringValue = va( "%d", intValue ); + break; + + case IS_FLOAT : + stringValue = va( "%f", floatValue ); + break; + + case IS_ENTITY : + stringValue = va( "*%d", intValue ); + break; + } + + dirtyFlags &= ~DIRTY_STRING; + } + + return stringValue.c_str(); + } + +const char *EventVar::GetString + ( + Event &ev + ) + + { + if ( dirtyFlags & DIRTY_STRING ) + { + switch( type ) + { + case IS_VECTOR : + stringValue = va( "(%f %f %f)", vectorValue.x, vectorValue.y, vectorValue.z ); + break; + + case IS_INTEGER : + stringValue = va( "%d", intValue ); + break; + + case IS_FLOAT : + stringValue = va( "%f", floatValue ); + break; + + case IS_ENTITY : + stringValue = va( "*%d", intValue ); + break; + } + + dirtyFlags &= ~DIRTY_STRING; + } + +#ifdef GAME_DLL + if ( type == IS_SCRIPTVARIABLE ) + { + ScriptVariable *var; + + var = Director.GetExistingVariable( stringValue.c_str() ); + if ( var ) + { + return var->stringValue(); + } + else + { + ev.Error( "Variable %s does not exist.", stringValue.c_str() ); + return ""; + } + } +#endif + + return stringValue.c_str(); + } + +int EventVar::GetInteger + ( + Event &ev + ) + + { + if ( dirtyFlags & DIRTY_INTEGER ) + { + switch( type ) + { + case IS_STRING : + intValue = atoi( stringValue.c_str() ); + break; + + case IS_VECTOR : + intValue = 0; + break; + + case IS_FLOAT : + intValue = int( floatValue ); + break; + + case IS_SCRIPTVARIABLE : +#ifdef GAME_DLL + ScriptVariable *var; + + var = Director.GetExistingVariable( stringValue.c_str() ); + if ( var ) + { + if ( !::IsNumeric( var->stringValue() ) ) + { + ev.Error( "Variable %s contains non-numeric value '%s'", stringValue.c_str(), + var->stringValue() ); + } + + // don't change the dirty flag since the variable may change in the future + return var->intValue(); + } + else + { + ev.Error( "Variable %s does not exist.", stringValue.c_str() ); + // don't change the dirty flag since the variable may exist in the future + //FIXME + // someday, missing variable names should be an error... + return 0; + } +#endif + break; + } + + dirtyFlags &= ~DIRTY_INTEGER; + } + + return intValue; + } + +float EventVar::GetFloat + ( + Event &ev + ) + + { + if ( dirtyFlags & DIRTY_FLOAT ) + { + switch( type ) + { + case IS_STRING : + floatValue = atof( stringValue.c_str() ); + break; + + case IS_VECTOR : + floatValue = 0; + break; + + case IS_ENTITY : + case IS_INTEGER : + floatValue = float( intValue ); + break; + + case IS_SCRIPTVARIABLE : +#ifdef GAME_DLL + ScriptVariable *var; + + var = Director.GetExistingVariable( stringValue.c_str() ); + if ( var ) + { + if ( !::IsNumeric( var->stringValue() ) ) + { + ev.Error( "Variable %s contains non-numeric value '%s'", stringValue.c_str(), + var->stringValue() ); + } + + // don't change the dirty flag since the variable may change in the future + return var->floatValue(); + } + else + { + ev.Error( "Variable %s does not exist.", stringValue.c_str() ); + // don't change the dirty flag since the variable may exist in the future + //FIXME + // someday, missing variable names should be an error... + return 0.0f; + } +#endif + break; + } + + dirtyFlags &= ~DIRTY_FLOAT; + } + + return floatValue; + } + +Vector EventVar::GetVector + ( + Event &ev + ) + + { + if ( dirtyFlags & DIRTY_VECTOR ) + { + switch( type ) + { + case IS_STRING : + const char *text; + + text = stringValue.c_str(); + if ( text[ 0 ] == '(' ) + { + vectorValue = &text[ 1 ]; + } +#ifdef GAME_DLL + // is it an entity + else if ( text[ 0 ] == '$' ) + { + Entity * ent; + + // allow console users to not use '$' + ent = G_FindTarget( NULL, &text[ 1 ] ); + + if ( ent ) + { + vectorValue = ent->origin; + } + else + { + vectorValue = vec_zero; + } + } +#endif + else + { + vectorValue = text; + } + break; + + case IS_FLOAT : + case IS_INTEGER : + vectorValue = vec_zero; + break; + case IS_ENTITY : +#ifdef GAME_DLL + { + Entity * ent; + + ent = G_GetEntity( intValue ); + if ( ent ) + { + vectorValue = ent->origin; + } + else + { + vectorValue = vec_zero; + } + } +#else + vectorValue = vec_zero; +#endif + break; + + case IS_SCRIPTVARIABLE : +#ifdef GAME_DLL + ScriptVariable *var; + + var = Director.GetExistingVariable( stringValue.c_str() ); + if ( !var ) + { + ev.Error( "Variable %s does not exist.", stringValue.c_str() ); + return vec_zero; + } + + // don't change the dirty flag since the variable may change in the future + return var->vectorValue(); +#endif + break; + } + + dirtyFlags &= ~DIRTY_VECTOR; + } + + return vectorValue; + } + +#ifdef GAME_DLL +Entity *EventVar::GetEntity + ( + Event &ev + ) + + { + if ( dirtyFlags & DIRTY_INTEGER ) + { + switch( type ) + { + case IS_VECTOR : + intValue = 0; + break; + + case IS_FLOAT : + intValue = int( floatValue ); + break; + + case IS_SCRIPTVARIABLE : + case IS_STRING : + const char *name; + int t; + + t = 0; + if ( type == IS_STRING ) + { + name = stringValue.c_str(); + if ( ev.GetSource() == EV_FROM_CONSOLE ) + { + Entity * ent; + + // allow console users to not use '$' + ent = G_FindTarget( NULL, name ); + intValue = ent->entnum; + break; + } + } + else + { + ScriptVariable *var; + + var = Director.GetExistingVariable( stringValue.c_str() ); + if ( !var ) + { + ev.Error( "Variable %s does not exist.", stringValue.c_str() ); + return NULL; + } + + name = var->stringValue(); + } + + if ( name[ 0 ] == '$' ) + { + Entity * ent; + + ent = G_FindTarget( NULL, &name[ 1 ] ); + if ( !ent ) + { + ev.Error( "Entity with targetname of '%s' not found", &name[ 1 ] ); + + return NULL; + } + else + { + t = ent->entnum; + } + } + else + { + if ( name[ 0 ] != '*' ) + { + if ( ev.GetSource() == EV_FROM_CONSOLE ) + { + ev.Error( "Entity with targetname of '%s' not found", name ); + } + else + { + ev.Error( "Expecting a '*'-prefixed entity number but found '%s'.", name ); + } + + return NULL; + } + + if ( !::IsNumeric( &name[ 1 ] ) ) + { + ev.Error( "Expecting a numeric value but found '%s'.", &name[ 1 ] ); + + return NULL; + } + else + { + t = atoi( &name[ 1 ] ); + } + } + + if ( type == IS_STRING ) + { + intValue = t; + } + else + { + if ( ( t < 0 ) || ( t > game.maxentities ) ) + { + ev.Error( "%d out of valid range for entity.", t ); + return NULL; + } + + // don't change the dirty flag since the variable may change in the future + return G_GetEntity( t ); + } + break; + } + + dirtyFlags &= ~DIRTY_INTEGER; + } + + if ( ( intValue < 0 ) || ( intValue > game.maxentities ) ) + { + ev.Error( "%d out of valid range for entity.", intValue ); + return NULL; + } + + return G_GetEntity( intValue ); + } + +ScriptVariable *EventVar::GetVariable + ( + Event &ev + ) + + { + if ( type != IS_SCRIPTVARIABLE ) + { + return NULL; + } + + return Director.GetExistingVariable( stringValue.c_str() ); + } +#else + +qboolean IsNumeric + ( + const char *str + ) + + { + int len; + int i; + qboolean dot; + + if ( *str == '-' ) + { + str++; + } + + dot = qfalse; + len = strlen( str ); + for( i = 0; i < len; i++ ) + { + if ( !isdigit( str[ i ] ) ) + { + if ( ( str[ i ] == '.' ) && !dot ) + { + dot = qtrue; + continue; + } + return qfalse; + } + } + + return qtrue; + } + +#endif + +qboolean EventVar::IsVector + ( + Event &ev + ) + + { + switch( type ) + { + case IS_VECTOR : + return true; + break; + + case IS_STRING : + if ( stringValue.c_str()[ 0 ] == '(' ) + { + return true; + } + break; + + case IS_SCRIPTVARIABLE : +#ifdef GAME_DLL + ScriptVariable *var; + + var = Director.GetExistingVariable( stringValue.c_str() ); + if ( var && ( var->stringValue()[ 0 ] == '(' ) ) + { + return true; + } +#endif + break; + } + + return false; + } + +qboolean EventVar::IsNumeric + ( + Event &ev + ) + + { + switch( type ) + { + case IS_STRING : + return ::IsNumeric( stringValue.c_str() ); + break; + +#ifdef GAME_DLL + case IS_SCRIPTVARIABLE : + ScriptVariable *var; + + var = Director.GetExistingVariable( stringValue.c_str() ); + if ( var ) + { + return ::IsNumeric( var->stringValue() ); + } + break; +#endif + + case IS_FLOAT : + case IS_INTEGER : + return true; + break; + } + + return false; + } + +//=========================================================================== +// EventArgDef +//=========================================================================== + +void EventArgDef::Setup + ( + const char *eventName, + const char *argName, + const char *argType, + const char *argRange + ) + { + char scratch[ 256 ]; + const char *ptr; + char *tokptr; + const char *endptr; + int index; + + // set name + name = argName; + + // set optionality + if ( isupper( argType[ 0 ] ) ) + { + optional = qtrue; + } + else + { + optional = qfalse; + } + + // grab the ranges + index = 0; + memset( minRangeDefault, qtrue, sizeof( minRangeDefault ) ); + memset( minRange, 0, sizeof( minRange ) ); + memset( maxRangeDefault, qtrue, sizeof( maxRangeDefault ) ); + memset( maxRange, 0, sizeof( maxRange ) ); + + if ( argRange && argRange[ 0 ] ) + { + ptr = argRange; + while( 1 ) + { + // find opening '[' + tokptr = strchr( ptr, '[' ); + if ( !tokptr ) + { + break; + } + // find closing ']' + endptr = strchr( tokptr, ']' ); + if ( !endptr ) + { + assert( 0 ); + EVENT_DPrintf( "Argument defintion %s, no matching ']' found for range spec in event %s.\n", name, eventName ); + break; + } + // point to the next range + ptr = endptr; + // skip the '[' + tokptr++; + // copy off the range spec + // skip the ']' + strncpy( scratch, tokptr, endptr - tokptr ); + // terminate the range + scratch[ endptr - tokptr ] = 0; + // see if there is one or two parameters here + tokptr = strchr( scratch, ',' ); + if ( !tokptr ) + { + // just one parameter + minRange[ index >> 1 ] = atof( scratch ); + minRangeDefault[ index >> 1 ] = qfalse; + index++; + // skip the second parameter + index++; + } + else if ( tokptr == scratch ) + { + // just second parameter + // skip the first paremeter + index++; + tokptr++; + maxRange[ index >> 1 ] = atof( scratch ); + maxRangeDefault[ index >> 1 ] = qfalse; + index++; + } + else + { + qboolean second; + // one or two parameters + // see if there is anything behind the ',' + if ( strlen( scratch ) > ( tokptr - scratch + 1) ) + second = qtrue; + else + second = qfalse; + // zero out the ',' + *tokptr = 0; + minRange[ index >> 1 ] = atof( scratch ); + minRangeDefault[ index >> 1 ] = qfalse; + index++; + // skip over the nul character + tokptr++; + if ( second ) + { + maxRange[ index >> 1 ] = atof( tokptr ); + maxRangeDefault[ index >> 1 ] = qfalse; + } + index++; + } + } + } + + // figure out the type of variable it is + switch( tolower( argType[ 0 ] ) ) + { + case 'e': + type = IS_ENTITY; + break; + case 'v': + type = IS_VECTOR; + break; + case 'i': + type = IS_INTEGER; + break; + case 'f': + type = IS_FLOAT; + break; + case 's': + type = IS_STRING; + break; + case 'b': + type = IS_BOOLEAN; + break; + } + } + +void EventArgDef::PrintRange + ( + FILE *event_file + ) + { + qboolean integer; + qboolean single; + int numRanges; + int i; + + single = qfalse; + integer = qtrue; + numRanges = 1; + switch( type ) + { + case IS_VECTOR: + integer = qfalse; + numRanges = 3; + break; + case IS_FLOAT: + integer = qfalse; + break; + case IS_STRING: + single = qtrue; + break; + } + for( i = 0; i < numRanges; i++ ) + { + if ( single ) + { + if ( !minRangeDefault[ i ] ) + { + if ( integer ) + { + EV_Print( event_file, "<%d>", ( int )minRange[ i ] ); + } + else + { + EV_Print( event_file, "<%.2f>", minRange[ i ] ); + } + } + } + else + { + // both non-default + if ( !minRangeDefault[ i ] && !maxRangeDefault[ i ] ) + { + if ( integer ) + { + EV_Print( event_file, "<%d...%d>", ( int )minRange[ i ], ( int )maxRange[ i ] ); + } + else + { + EV_Print( event_file, "<%.2f...%.2f>", minRange[ i ], maxRange[ i ] ); + } + } + // max default + else if ( !minRangeDefault[ i ] && maxRangeDefault[ i ] ) + { + if ( integer ) + { + EV_Print( event_file, "<%d...max_integer>", ( int )minRange[ i ] ); + } + else + { + EV_Print( event_file, "<%.2f...max_float>", minRange[ i ] ); + } + } + // min default + else if ( minRangeDefault[ i ] && !maxRangeDefault[ i ] ) + { + if ( integer ) + { + EV_Print( event_file, "", ( int )maxRange[ i ] ); + } + else + { + EV_Print( event_file, "", maxRange[ i ] ); + } + } + } + } + } + +void EventArgDef::PrintArgument + ( + FILE *event_file + ) + { + if ( optional ) + { + EV_Print( event_file, "[ " ); + } + switch( type ) + { + case IS_ENTITY: + EV_Print( event_file, "Entity " ); + break; + case IS_VECTOR: + EV_Print( event_file, "Vector " ); + break; + case IS_INTEGER: + EV_Print( event_file, "Integer " ); + break; + case IS_FLOAT: + EV_Print( event_file, "Float " ); + break; + case IS_STRING: + EV_Print( event_file, "String " ); + break; + case IS_BOOLEAN: + EV_Print( event_file, "Boolean " ); + break; + } + EV_Print( event_file, "%s", name.c_str() ); + + // print the range of the argument + PrintRange( event_file ); + + if ( optional ) + { + EV_Print( event_file, " ]" ); + } + } + + +//=========================================================================== +// EventCode +//=========================================================================== + +CLASS_DECLARATION( Class, Event, NULL ) + { + { NULL, NULL } + }; + +// Free Event Management routines +static Event *RealAllocateEvent + ( + void + ) + { + Event *event; + + event = ( Event * )::new char[ sizeof( Event ) ]; + Event_totalmemallocated += sizeof( Event ); + + return event; + } + +static void RealDeallocateEvent + ( + Event * event + ) + { + ::delete[]( ( void * )event ); + Event_totalmemallocated -= sizeof( Event ); + } + +void * Event::operator new( size_t s ) + { + Event * newevent; + + assert( sizeof( Event ) == s ); + + // if the list is empty create a new one + if ( LL_Empty( FreeEvents, next, prev ) ) + { + // this is here to let us know that it is happening + assert( 0 ); + newevent = RealAllocateEvent(); + } + else + { + newevent = FreeEvents->next; + LL_Remove( newevent, next, prev ); + numFreeEvents--; + } + + // add it to the active list of events + LL_Add( ActiveEvents, newevent, next, prev ); + + newevent->time = EVENT_time; + newevent->flags = 0; + + return newevent; + } + +void Event::operator delete( void *ptr ) + { + Event * event; + + event = ( Event * )ptr; + + // clear out any safe pointers we have setup + event->ClearSafePointers(); + + LL_Remove( event, next, prev ); + LL_Add( FreeEvents, event, next, prev ); + numFreeEvents++; + } + +#if defined( GAME_DLL ) +#define INITIALLY_ALLOCATED_EVENTS 4500 +#elif defined ( CGAME_DLL ) +#define INITIALLY_ALLOCATED_EVENTS 512 +#elif defined ( UI_LIB ) +#define INITIALLY_ALLOCATED_EVENTS 192 +#else +#define INITIALLY_ALLOCATED_EVENTS 192 +#endif + +void Event::InitializeEventLists + ( + void + ) + { + Event * newevent; + int i; + + numEvents = 0; + numFreeEvents = 0; + // + // initialize lists + // + LL_Reset( FreeEvents, next, prev ); + LL_Reset( EventQueue, next, prev ); + LL_Reset( ActiveEvents, next, prev ); + + // + // allocate the initial allottment of events + // + for( i = 0; i < INITIALLY_ALLOCATED_EVENTS; i++ ) + { + newevent = RealAllocateEvent(); + LL_Add( FreeEvents, newevent, next, prev ); + numFreeEvents++; + } + } + +void Event::ShutdownEventLists + ( + void + ) + { + Event *event, *next; + + // free queued events + for( event = EventQueue->next; event != EventQueue; event = next ) + { + next = event->next; + delete event; + } + // free active events + for( event = ActiveEvents->next; event != ActiveEvents; event = next ) + { + next = event->next; + delete event; + } + // free free events + for( event = FreeEvents->next; event != FreeEvents; event = next ) + { + next = event->next; + RealDeallocateEvent( event ); + } + + assert( Event_totalmemallocated == 0 ); + + numEvents = 0; + numFreeEvents = 0; + + // + // initialize lists + // + LL_Reset( FreeEvents, next, prev ); + LL_Reset( EventQueue, next, prev ); + LL_Reset( ActiveEvents, next, prev ); + } + +int Event::NumEventCommands + ( + void + ) + + { + if ( commandList ) + { + // Add 1 since container gives the inclusive number of objects + return commandList->NumObjects() + 1; + } + + return 0; + } + +int Event::compareEvents + ( + const void *arg1, + const void *arg2 + ) + + { + int ev1; + int ev2; + + ev1 = *( int * )arg1; + ev2 = *( int * )arg2; + + return stricmp( commandList->ObjectAt( ev1 )->c_str(), commandList->ObjectAt( ev2 )->c_str() ); + } + +void Event::SortEventList + ( + void + ) + + { + dirtylist = false; + + if ( sortedList && commandList ) + { + qsort( ( void * )sortedList->AddressOfObjectAt( 1 ), + ( size_t )sortedList->NumObjects(), + sizeof( int ), compareEvents ); + } + } + +inline int Event::FindEvent + ( + const char *name + ) + + { + int eventnum; + int index; + int l; + int r; + int diff; + + assert( name ); + if ( !name ) + { + return 0; + } + + if ( !commandList ) + { + return 0; + } + + if ( dirtylist ) + { + SortEventList(); + } + + numfinds++; + numcompares++; + if ( lastevent && !stricmp( name, commandList->ObjectAt( lastevent )->c_str() ) ) + { + numfirstsearch++; + return lastevent; + } + + l = 1; + r = sortedList->NumObjects(); + while( r >= l ) + { + index = ( l + r ) >> 1; + eventnum = sortedList->ObjectAt( index ); + diff = stricmp( name, commandList->ObjectAt( eventnum )->c_str() ); + numcompares++; + if ( diff < 0 ) + { + r = index - 1; + } + else if ( diff > 0 ) + { + l = index + 1; + } + else + { + lastevent = eventnum; + return eventnum; + } + } + + return 0; + } + +int Event::MapSortedEventIndex + ( + int index + ) + { + return sortedList->ObjectAt( index ); + } + + +int Event::FindEvent + ( + str &name + ) + + { + return FindEvent( name.c_str() ); + } + +void Event::ListCommands + ( + const char *mask + ) + + { + str name; + int flags; + int eventnum; + int num; + int i; + int n; + int l; + int p; + int hidden; + str text; + + if ( !commandList ) + { + EVENT_DPrintf( "No events.\n" ); + return; + } + + if ( dirtylist ) + { + SortEventList(); + } + + l = 0; + if ( mask ) + { + l = strlen( mask ); + } + + hidden = 0; + num = 0; + n = sortedList->NumObjects(); + for( i = 1; i <= n; i++ ) + { + eventnum = sortedList->ObjectAt( i ); + name = commandList->ObjectAt( eventnum )->c_str(); + flags = flagList->ObjectAt( eventnum ); + + if ( flags & EV_HIDE ) + { + hidden++; + continue; + } + + if ( mask && Q_stricmpn( name.c_str(), mask, l ) ) + { + continue; + } + + num++; + + text = " "; + p = 0; + if ( flags & EV_CONSOLE ) + { + text[ p++ ] = '*'; + } + if ( flags & EV_CHEAT ) + { + text[ p++ ] = 'C'; + } + if ( flags & EV_CACHE ) + { + text[ p++ ] = '%'; + } + + EVENT_Printf( "%4d : %s%s\n", eventnum, text.c_str(), name.c_str() ); + } + + EVENT_Printf( "\n* = console command.\nC = cheat command.\n% = cache command.\n\n" + "Printed %d of %d total commands.\n", num, n - hidden ); + + if ( developer->integer && hidden ) + { + EVENT_Printf( "Suppressed %d commands.\n", hidden ); + } + } + +#ifdef GAME_DLL + +void Event::PrintEvent + ( + Event * event + ) + { + int i; + int n; + Listener * obj; + str text; + + obj = event->GetSourceObject(); + + text = va( "%6.1f:%1d: %s", event->time, event->flags, obj->getClassname() ); + if ( obj->isSubclassOf( Entity ) ) + { + text += va( " (*%d) ", ( ( Entity * )obj )->entnum ); + if ( ( ( Entity * )obj )->Targeted() ) + { + text += va( "'%s'", ( ( Entity * )obj )->TargetName() ); + } + } + else if ( obj->isSubclassOf( ScriptThread ) ) + { + text += va( " #%d:'%s'", ( ( ScriptThread * )obj )->ThreadNum(), ( ( ScriptThread * )obj )->ThreadName() ); + } + else if ( obj->isSubclassOf( ScriptVariable ) ) + { + text += va( " '%s'", ( ( ScriptVariable * )obj )->getName() ); + } + + switch( event->GetSource() ) + { + default : + case EV_FROM_CODE : + text += " : Code :"; + break; + + case EV_FROM_SCRIPT : + assert( event->GetThread() ); + if ( event->GetThread() ) + { + text += va( " : %s(%d) :", event->GetThread()->Filename(), event->info.linenumber ); + } + else + { + text += " : NULL :"; + } + break; + + case EV_FROM_CONSOLE : + text += " : Console :"; + break; + } + + text += event->getName().c_str(); + n = event->NumArgs(); + for( i = 1; i <= n; i++ ) + { + text += va( " %s", event->GetToken( i ) ); + } + + text += "\n"; + + if ( !g_watch->integer || ( obj->isSubclassOf( Entity ) && ( g_watch->integer == ( ( Entity * )obj )->entnum ) ) ) + { + if ( g_showevents->integer == 2 ) + { + EVENT_DebugPrintf( text.c_str() ); + } + else + { + EVENT_DPrintf( "%s", text.c_str() ); + } + } + } + +#else + +void Event::PrintEvent + ( + Event * event + ) + { + int i; + int n; + str text; + + + text = va( "%6.1f:%1d ", event->time, event->flags ); + + switch( event->GetSource() ) + { + default : + case EV_FROM_CODE : + text += " : Code :"; + break; + + case EV_FROM_CONSOLE : + text += " : Console :"; + break; + } + + text += event->getName().c_str(); + n = event->NumArgs(); + for( i = 1; i <= n; i++ ) + { + text += va( " %s", event->GetToken( i ) ); + } + + text += "\n"; + + if ( g_showevents->integer == 2 ) + { + EVENT_DebugPrintf( text.c_str() ); + } + else + { + EVENT_DPrintf( text.c_str() ); + } + } + +#endif + +void Event::PendingEvents + ( + const char *mask + ) + + { + Event *event; + int l, num; + + l = 0; + if ( mask ) + { + l = strlen( mask ); + } + + assert( EventQueue ); + assert( EventQueue->next ); + assert( EventQueue->prev ); + + num = 0; + event = EventQueue->next; + while( event != EventQueue ) + { + assert( event ); + assert( event->m_sourceobject ); + + if ( !mask || !Q_stricmpn( event->getName().c_str(), mask, l ) ) + { + num++; + Event::PrintEvent( event ); + } + + event = event->next; + } + EVENT_Printf( "%d pending events as of %.2f\n", num, EVENT_time ); + } + +void Event::PrintDocumentation + ( + FILE *event_file, + qboolean html + ) + + { + int i; + int p; + str text; + + if ( !html ) + { + text = " "; + p = 0; + + if ( flags & EV_CONSOLE ) + { + text[ p++ ] = '*'; + } + if ( flags & EV_CHEAT ) + { + text[ p++ ] = 'C'; + } + if ( flags & EV_CACHE ) + { + text[ p++ ] = '%'; + } + } + + if ( html ) + { + EV_Print( event_file, "\n

%s", name ); + } + else + { + if ( text[ 0 ] != ' ' ) + { + EV_Print( event_file, "\n%s:%s", text.c_str(), name ); + } + else + { + EV_Print( event_file, "\n%s %s", text.c_str(), name ); + } + } + + if ( definition ) + { + if ( html ) + { + EV_Print( event_file, "( " ); + } + else + { + EV_Print( event_file, "( " ); + } + for( i = 1; i <= definition->NumObjects(); i++ ) + { + definition->ObjectAt( i ).PrintArgument( event_file ); + if ( i < definition->NumObjects() ) + { + EV_Print( event_file, ", " ); + } + } + if ( html ) + { + EV_Print( event_file, " )
\n" ); + } + else + { + EV_Print( event_file, " )\n" ); + } + } + else + { + if ( html ) + { + EV_Print( event_file, "
\n" ); + } + else + { + EV_Print( event_file, "\n" ); + } + } + if ( documentation ) + { + char new_doc[1024]; + int old_index; + int new_index = 0; + + for ( old_index = 0 ; old_index < strlen ( documentation ) ; old_index++ ) + { + if ( documentation[old_index] == '\n' ) + { + if ( html ) + { + new_doc[new_index ] = '<'; + new_doc[new_index + 1] = 'B'; + new_doc[new_index + 2] = 'R'; + new_doc[new_index + 3] = '>'; + new_doc[new_index + 4] = '\n'; + new_index += 5; + } + else + { + new_doc[new_index ] = '\n'; + new_doc[new_index + 1] = '\t'; + new_doc[new_index + 2] = '\t'; + new_index += 3; + } + } + else + { + new_doc[new_index] = documentation[old_index]; + new_index++; + } + + } + + new_doc[new_index] = 0; + + if ( html ) + { +// EV_Print( event_file, "

%s
\n", new_doc ); + EV_Print( event_file, "
    %s
\n", new_doc ); + } + else + { + EV_Print( event_file, "\t\t- %s\n", new_doc ); + } + } + } + +void Event::PrintEventDocumentation + ( + Event * ePtr, + FILE *event_file, + qboolean html + ) + + { + int flags; + + flags = ePtr->GetFlags(); + + if ( flags & EV_HIDE ) + { + return; + } + + // purposely suppressed + if ( ePtr->name[ 0 ] == '_' ) + { + return; + } + + ePtr->PrintDocumentation( event_file, html ); + } + + +void Event::ListDocumentation + ( + const char *mask, + qboolean print_to_disk + ) + + { + Event * ePtr; + int num; + int i; + int n; + int l; + int flags; + int hidden; + str name; + str text; + FILE *event_file = NULL; + str event_filename; + + if ( !eventDefList ) + { + EVENT_DPrintf( "No events.\n" ); + return; + } + + if ( print_to_disk ) + { + if ( !mask || !mask[0] ) + event_filename = EVENT_FILENAME; + else + event_filename = str ( mask ) + ".txt"; + + event_file = fopen( event_filename.c_str(), "w" ); + + if ( event_file == NULL ) + return; + } + + l = 0; + if ( mask ) + { + l = strlen( mask ); + } + + + EV_Print( event_file, "\nCommand Documentation\n" ); + EV_Print( event_file, "=====================\n" ); + + hidden = 0; + num = 0; + n = eventDefList->NumObjects(); + for( i = 1; i <= n; i++ ) + { + ePtr = eventDefList->ObjectAt( i ); + flags = ePtr->GetFlags(); + name = ePtr->getName(); + + if ( flags & EV_HIDE ) + { + hidden++; + continue; + } + + if ( mask && Q_stricmpn( name, mask, l ) ) + { + continue; + } + + num++; + + ePtr->PrintDocumentation( event_file ); + } + + + EV_Print( event_file, "\n* = console command.\nC = cheat command.\n% = cache command.\n\n" + "Printed %d of %d total commands.\n", num, n - hidden ); + + if ( developer->integer && hidden ) + { + EV_Print( event_file, "Suppressed %d commands.\n", hidden ); + } + + if ( event_file != NULL ) + { + EVENT_Printf( "Printed event info to file %s\n", event_filename.c_str() ); + fclose( event_file ); + } + } + + +void Event::initCommandList + ( + void + ) + + { + int flags; + str *n; + + flags = 0; + commandList = new Container; + + n = new str( "NULL" ); + NullEvent.eventnum = commandList->AddObject( n ); + + flagList = new Container; + flagList->AddObject( flags ); + + sortedList = new Container; + sortedList->AddObject( NullEvent.eventnum ); + + eventDefList = new Container; + + dirtylist = false; + + NullEvent.data = NULL; + NullEvent.info.inuse = 0; + NullEvent.info.source = EV_FROM_CODE; + NullEvent.info.flags = 0; + NullEvent.info.linenumber = 0; + } + +Event::Event() + { + info.inuse = 0; + info.source = EV_FROM_CODE; + info.flags = 0; + info.linenumber = 0; + threadnum = -1; + eventnum = 0; + data = NULL; + definition = NULL; + name = NULL; + documentation = NULL; + } + +Event::Event + ( + int num + ) + + { + if ( !commandList ) + { + initCommandList(); + } + + assert( ( num > 0 ) && num <= commandList->NumObjects() ); + + if ( ( num <= 0 ) || ( num > commandList->NumObjects() ) ) + { + EVENT_DPrintf( "Event %d out of range.\n", num ); + num = 0; + name = NULL; + info.flags = 0; + } + else + { + name = commandList->ObjectAt( num )->c_str(); + info.flags = flagList->ObjectAt( num ); + } + + eventnum = num; + data = NULL; + definition = NULL; + documentation = NULL; + info.inuse = 0; + info.source = EV_FROM_CODE; + info.linenumber = 0; + threadnum = -1; + } + +Event::Event + ( + Event &ev + ) + + { + int num; + int i; + + eventnum = ( int )ev; + assert( ( eventnum > 0 ) && eventnum <= commandList->NumObjects() ); + data = NULL; + definition = NULL; + documentation = NULL; + + name = commandList->ObjectAt( eventnum )->c_str(); + info.inuse = 0; + info.source = ev.info.source; + info.flags = ev.info.flags; + info.linenumber = ev.info.linenumber; + threadnum = ev.threadnum; + + if ( ev.data ) + { + num = ev.data->NumObjects(); + + data = new Container; + data->Resize( num ); + + for( i = 1; i <= num; i++ ) + { + data->AddObject( ev.data->ObjectAt( i ) ); + } + } + } + +Event::Event + ( + Event *ev + ) + + { + int num; + int i; + + assert( ev ); + if ( !ev ) + { + EVENT_Error( ERR_DROP, "NULL Event\n" ); + } + + eventnum = ( int )*ev; + assert( ( eventnum > 0 ) && eventnum <= commandList->NumObjects() ); + data = NULL; + definition = NULL; + documentation = NULL; + name = commandList->ObjectAt( eventnum )->c_str(); + info.inuse = 0; + info.source = ev->info.source; + info.flags = ev->info.flags; + info.linenumber = ev->info.linenumber; + threadnum = ev->threadnum; + if ( ev->data ) + { + num = ev->data->NumObjects(); + + data = new Container; + data->Resize( num ); + + for( i = 1; i <= num; i++ ) + { + data->AddObject( ev->data->ObjectAt( i ) ); + } + } + } + +Event::Event + ( + const char *command, + int flags, + const char *theFormatspec, + const char *theArgument_names, + const char *theDocumentation + ) + + { + str *t; + + if ( !commandList ) + { + initCommandList(); + } + + eventnum = FindEvent( command ); + if ( !eventnum ) + { + t = new str( command ); + eventnum = commandList->AddObject( t ); + // check for default flags + if ( flags == EV_DEFAULT ) + { + flags = 0; + } + flagList->AddObject( ( int )flags ); + sortedList->AddObject( eventnum ); + dirtylist = true; + } + + // Use the name stored in the command list in case the string passed in + // is not in static memory. + name = commandList->ObjectAt( eventnum )->c_str(); + + data = NULL; + info.inuse = 0; + info.source = EV_FROM_CODE; + info.linenumber = 0; + threadnum = -1; + formatspec = theFormatspec; + argument_names = theArgument_names; + documentation = theDocumentation; + definition = NULL; + + // If flags have changed, let the user know. It's probably a development bug. + int &flagobj = flagList->ObjectAt( eventnum ); + + // check for default flags + if ( flags == EV_DEFAULT ) + { + flags = flagobj; + } + + assert( flags == flagobj ); + if ( flags != flagobj ) + { + // Flags not equal. Use combined value. + flagobj |= flags; + } + + info.flags = flagobj; + + // add it to the list for Documentation + // suppress it if it starts with '_' + if ( documentation && ( command[ 0 ] != '_' ) ) + { + eventDefList->AddObject( ( Event * )this ); + } + else + { + // purposely suppressed + if ( command[ 0 ] != '_' ) + { + // empty documentation! + assert( 0 ); + } + } + } + +Event::Event + ( + const char *command + ) + + { + if ( !commandList ) + { + initCommandList(); + } + + eventnum = FindEvent( command ); + if ( !eventnum ) + { + EVENT_DPrintf( "Event '%s' does not exist.\n", command ); + name = NULL; + info.flags = 0; + } + else + { + name = commandList->ObjectAt( eventnum )->c_str(); + info.flags = flagList->ObjectAt( eventnum ); + } + + data = NULL; + definition = NULL; + documentation = NULL; + info.inuse = 0; + info.source = EV_FROM_CODE; + info.linenumber = 0; + threadnum = -1; + } + +Event::Event + ( + str &command + ) + + { + if ( !commandList ) + { + initCommandList(); + } + + eventnum = FindEvent( command ); + if ( !eventnum ) + { + EVENT_DPrintf( "Event '%s' does not exist.\n", command.c_str() ); + name = NULL; + info.flags = 0; + } + else + { + name = commandList->ObjectAt( eventnum )->c_str(); + info.flags = flagList->ObjectAt( eventnum ); + } + + data = NULL; + definition = NULL; + documentation = NULL; + info.inuse = 0; + info.source = EV_FROM_CODE; + info.linenumber = 0; + threadnum = -1; + } + +Event::~Event() + { + if ( data ) + { + delete data; + data = NULL; + } + if ( definition ) + { + delete definition; + definition = NULL; + } + } + +void Event::SetupDocumentation + ( + void + ) + + { + // setup documentation + if ( formatspec ) + { + if ( argument_names ) + { + char argumentNames[ 256 ]; + str argSpec; + str rangeSpec; + str argName; + EventArgDef argDef; + const char *namePtr; + const char *specPtr; + int specLength, index; + Container argNames; + + specLength = strlen( formatspec ); + specPtr = formatspec; + // + // store off all the names + // + strcpy( argumentNames, argument_names ); + namePtr = strtok( argumentNames, " " ); + while ( namePtr != NULL ) + { + argNames.AddObject( str( namePtr ) ); + namePtr = strtok( NULL, " " ); + } + // + // create the definition container + // + definition = new Container; + definition->Resize( argNames.NumObjects() ); + index = 0; + // go throught he formatspec + while( specLength ) + { + // clear the rangeSpec + rangeSpec = ""; + // get the argSpec + argSpec = ""; + argSpec += *specPtr; + specPtr++; + specLength--; + // see if there is a range specified + while ( *specPtr == '[' ) + { + // add in all the characters until NULL or ']' + while( specLength && ( *specPtr != ']' ) ) + { + rangeSpec += *specPtr; + specPtr++; + specLength--; + } + if ( specLength && *specPtr == ']' ) + { + rangeSpec += *specPtr; + specPtr++; + specLength--; + } + } + if ( index < argNames.NumObjects() ) + { + argName = argNames.ObjectAt( index + 1 ); + argDef.Setup( name, argName, argSpec, rangeSpec ); + definition->AddObject( argDef ); + } + else + { + assert( 0 ); + Error( "More format specifiers than argument names for event %s\n", name ); + } + index++; + } + if ( index < argNames.NumObjects() ) + { + assert( 0 ); + Error( "More argument names than format specifiers for event %s\n", name ); + } + } + } + } + +void Event::DeleteDocumentation + ( + void + ) + + { + // setup documentation + if ( formatspec ) + { + if ( argument_names ) + { + definition->FreeObjectList(); + delete definition; + definition = NULL; + } + } + } + +#ifdef GAME_DLL + +void Event::SetThread + ( + ScriptThread *thread + ) + + { + if ( thread ) + { + threadnum = thread->ThreadNum(); + } + else + { + threadnum = -1; + } + } + +ScriptThread *Event::GetThread + ( + void + ) + + { + if ( threadnum != -1 ) + { + return Director.GetThread( threadnum ); + } + + return NULL; + } +#endif + +void Event::Error + ( + const char *fmt, + ... + ) + + { + va_list argptr; + char text[ 1024 ]; + + va_start( argptr, fmt ); + vsprintf( text, fmt, argptr ); + va_end( argptr ); + + switch( GetSource() ) + { + default : + case EV_FROM_CODE : +#if defined( GAME_DLL ) + EVENT_DPrintf( "Game: '%s' : %s\n", getName().c_str(), text ); +#elif defined( CGAME_DLL ) + EVENT_DPrintf( "CGame: '%s' : %s\n", getName().c_str(), text ); +#elif defined( UI_LIB ) + EVENT_DPrintf( "UI_Lib: '%s' : %s\n", getName().c_str(), text ); +#else + EVENT_DPrintf( "Client: '%s' : %s\n", getName().c_str(), text ); +#endif + break; +#ifdef GAME_DLL + case EV_FROM_SCRIPT : + { + ScriptThread *thread = GetThread(); + const char *filename = "Dead script"; + if ( thread ) + { + filename = thread->Filename(); + } + EVENT_DPrintf( "%s(%d): '%s' :\n%s\n", filename, info.linenumber, getName().c_str(), text ); + } + break; + + case EV_FROM_CONSOLE : + gi.SendServerCommand( GetConsoleEdict()-g_entities, "print \"Console: '%s' : %s\n\"", getName().c_str(), text ); + break; +#endif + } + } + +qboolean Event::IsVectorAt + ( + int pos + ) + + { + if ( !data || ( pos < 1 ) || ( data->NumObjects() < pos ) ) + { + Error( "Index %d out of range.", pos ); + return false; + } + + return data->ObjectAt( pos ).IsVector( *this ); + } + +#ifdef GAME_DLL +qboolean Event::IsEntityAt + ( + int pos + ) + + { + if ( !data || ( pos < 1 ) || ( data->NumObjects() < pos ) ) + { + Error( "Index %d out of range.", pos ); + return false; + } + + return data->ObjectAt( pos ).GetEntity( *this ) != NULL; + } +#endif + +qboolean Event::IsNumericAt + ( + int pos + ) + + { + if ( !data || ( pos < 1 ) || ( data->NumObjects() < pos ) ) + { + Error( "Index %d out of range.", pos ); + return false; + } + + return data->ObjectAt( pos ).IsNumeric( *this ); + } + +#ifdef GAME_DLL +void Event::Archive + ( + Archiver &arc + ) + + { + str name; + int num; + int i; + EventVar var; + + if ( arc.Saving() ) + { + name = getName(); + } + arc.ArchiveString( &name ); + if ( arc.Loading() ) + { + if ( data ) + { + delete data; + data = NULL; + } + *this = Event( name ); + } + + arc.ArchiveRaw( &info, sizeof( info ) ); + arc.ArchiveInteger( &threadnum ); + arc.ArchiveShort( &anim_number ); + arc.ArchiveShort( &anim_frame ); + arc.ArchiveSafePointer( &m_sourceobject ); + arc.ArchiveFloat( &time ); + arc.ArchiveInteger( &flags ); + + if ( arc.Saving() ) + { + if ( !data ) + { + num = 0; + } + else + { + num = data->NumObjects(); + } + } + arc.ArchiveInteger( &num ); + if ( arc.Loading() && num ) + { + data = new Container; + data->Resize( num ); + } + + for( i = 1; i <= num; i++ ) + { + if ( arc.Saving() ) + { + var = data->ObjectAt( i ); + } + var.Archive( arc ); + if ( arc.Loading() ) + { + data->AddObject( var ); + } + } + } +#endif + +CLASS_DECLARATION( Class, Listener, NULL ) + { + { &EV_Remove, Listener::Remove }, + { &EV_ScriptRemove, Listener::ScriptRemove }, + { NULL, NULL } + }; + +void Listener::Remove + ( + Event *e + ) + + { + delete this; + } + +void Listener::ScriptRemove + ( + Event *e + ) + + { + // Forces the remove to be done at a safe time + PostEvent( EV_Remove, 0 ); + } + +qboolean Listener::ValidEvent + ( + Event &e + ) + + { + ClassDef *c; + int ev; + + ev = ( int )e; + + c = this->classinfo(); + assert( ( ev >= 0 ) && ( ev < c->numEvents ) ); + if ( ( ev < 0 ) || ( ev >= c->numEvents ) ) + { + warning( "ValidEvent", "Event '%s' out of response range for class '%s'. " + "Event probably invalid or allocated late.\n", e.getName().c_str(), getClassname() ); + return false; + } + + return ( c->responseLookup[ ev ] != NULL ); + } + +qboolean Listener::ValidEvent + ( + const char *name + ) + + { + ClassDef *c; + int ev; + + ev = Event::FindEvent( name ); + + c = this->classinfo(); + assert( ( ev >= 0 ) && ( ev < c->numEvents ) ); + if ( ( ev < 0 ) || ( ev >= c->numEvents ) ) + { + warning( "ValidEvent", "Event '%s' out of response range for class '%s'. " + "Event probably invalid or allocated late.\n", name, getClassname() ); + return false; + } + + return ( c->responseLookup[ ev ] != NULL ); + } + +qboolean Listener::EventPending + ( + Event &ev + ) + + { + Event *event; + int eventnum; + + assert( EventQueue ); + assert( EventQueue->next ); + + event = EventQueue->next; + + eventnum = ( int )ev; + while( event != EventQueue ) + { + if ( ( event->m_sourceobject == this ) && ( (int)*event == eventnum ) ) + { + return true; + } + event = event->next; + } + + return false; + } + +inline qboolean Listener::CheckEventFlags + ( + Event *event + ) + + { +#ifdef GAME_DLL + // Special handling of console events + if ( event->GetSource() == EV_FROM_CONSOLE ) + { + if ( !( event->info.flags & (EV_CONSOLE|EV_CHEAT) ) ) + { + if ( isSubclassOf( Entity ) ) + { + Entity *ent; + + ent = ( Entity * )this; + gi.SendServerCommand( ent->edict-g_entities, "print \"Command not available from console.\n\"" ); + } + + // don't process + return false; + } + + // don't allow console cheats during deathmatch unless the server says it's ok. + if ( ( event->info.flags & EV_CHEAT ) && deathmatch->integer && !sv_cheats->integer ) + { + if ( isSubclassOf( Entity ) ) + { + Entity *ent; + + ent = ( Entity * )this; + gi.SendServerCommand( ent->edict-g_entities, "print \"You must run the server with '+set cheats 1' to enable this command.\n\"" ); + } + + // don't process + return false; + } + } +#endif + + // ok to process + return true; + } + +qboolean Listener::ProcessEvent + ( + Event *event + ) + + { + ClassDef *c; + int ev; + + if ( !Event::EventSystemStarted ) + { + assert( 0 ); + return false; + } + + // make sure the event has only been used once + if ( event->info.inuse ) + { + EVENT_Error( ERR_DROP, "ProcessEvent : Event '%s' has already been posted.\n", event->getName().c_str() ); + } + + if ( g_showevents->integer ) + { + Listener *obj; + + obj = event->GetSourceObject(); + if ( !obj ) + { + event->SetSourceObject( this ); + } + Event::PrintEvent( event ); + } + + ev = ( int )*event; + c = this->classinfo(); + if ( ev >= c->numEvents ) + { + event->Error( "Event out of response range for class '%s'. Event probably invalid or allocated late.\n", getClassname() ); + return false; + } + + if ( c->responseLookup[ ev ] ) + { + int start; + int end; + + event->info.inuse++; + + if ( !g_timeevents->integer ) + { + // only process the event if we allow it + if ( CheckEventFlags( event ) ) + { + ( this->**c->responseLookup[ ev ] )( event ); + } + } + else + { + start = EVENT_realtime; + + // only process the event if we allow it + if ( CheckEventFlags( event ) ) + { + ( this->**c->responseLookup[ ev ] )( event ); + } + + end = EVENT_realtime; + + if ( end - start >= g_timeevents->integer ) + { +#ifdef GAME_DLL + if ( event != EV_Remove && this->isSubclassOf( Entity ) ) + { + Entity *ent = (Entity *)this; + + EVENT_DebugPrintf( "(%d) ", ent->entnum ); + } +#endif + + EVENT_DebugPrintf( "'%s' : %d\n", event->getName().c_str(), end - start ); + } + } + + // Prevent an event from being freed twice, in case it's been re-used + event->info.inuse--; + if ( !event->info.inuse ) + { + delete event; + } + else + { + EVENT_Error( ERR_DROP, "ProcessEvent : Event '%s' is still in use after being processed.\n", event->getName().c_str() ); + } + + return true; + } + + if ( !event->info.inuse ) + { + delete event; + } + else + { + EVENT_Error( ERR_DROP, "ProcessEvent : Event '%s' is still in use after being processed.\n", event->getName().c_str() ); + } + + return false; + } + +void Listener::PostEvent + ( + Event *ev, + float time, + int flags + ) + + { + int evnum; + ClassDef *c; + Event *event; + +#ifdef GAME_DLL + if ( LoadingSavegame ) + { + // while technically not bad, if we got here we have an event that is being posted while loading which is a bad thing + assert( 0 ); + if ( !ev->info.inuse ) + { + delete ev; + } + else + { + EVENT_Error( ERR_DROP, "PostEvent : Event '%s' is still in use during loading.\n", ev->getName().c_str() ); + } + + return; + } +#endif + + if ( !Event::EventSystemStarted ) + { + assert( 0 ); + return; + } + + evnum = ( int )*ev; + c = this->classinfo(); + if ( evnum >= c->numEvents ) + { + ev->Error( "Event out of response range for class '%s'. Event probably invalid or allocated late.\n", getClassname() ); + return; + } + + if ( !c->responseLookup[ evnum ] ) + { + // we don't need it so lets delete it + delete ev; + return; + } + + LL_Remove( ev, next, prev ); + + ev->SetSourceObject( this ); + ev->time = EVENT_time + time; + ev->flags = flags; + + event = EventQueue->next; + while( ( event != EventQueue ) && ( ev->time >= event->time ) ) + { + event = event->next; + } + + LL_Add( event, ev, next, prev ); + numEvents++; + } + +qboolean Listener::PostponeEvent + ( + Event &ev, + float time + ) + + { + Event *event; + Event *node; + int eventnum; + + assert( EventQueue ); + assert( EventQueue->next ); + + eventnum = ( int )ev; + + event = EventQueue->next; + while( event != EventQueue ) + { + if ( ( event->GetSourceObject() == this ) && ( ( int )*event == eventnum ) ) + { + event->time += time; + + node = event->next; + while( ( node != EventQueue ) && ( event->time >= node->time ) ) + { + node = node->next; + } + + LL_Remove( event, next, prev ); + LL_Add( node, event, next, prev ); + + return true; + } + event = event->next; + } + + return false; + } + +void Listener::CancelEventsOfType + ( + Event *ev + ) + + { + Event *event; + Event *next; + int eventnum; + + assert( EventQueue ); + assert( EventQueue->next ); + + event = EventQueue->next; + + eventnum = (int)*ev; + while( event != EventQueue ) + { + next = event->next; + if ( ( event->GetSourceObject() == this ) && ( (int)*event == eventnum ) ) + { + LL_Remove( event, next, prev ); + numEvents--; + delete event; + } + event = next; + } + } + +void Listener::CancelFlaggedEvents + ( + int flags + ) + + { + Event *event; + Event *next; + + assert( EventQueue ); + assert( EventQueue->next ); + + event = EventQueue->next; + + while( event != EventQueue ) + { + next = event->next; + if ( ( event->GetSourceObject() == this ) && ( event->flags & flags ) ) + { + LL_Remove( event, next, prev ); + numEvents--; + delete event; + } + event = next; + } + } + + +void Listener::CancelPendingEvents + ( + void + ) + + { + Event *event; + Event *next; + + assert( EventQueue ); + assert( EventQueue->next ); + + event = EventQueue->next; + + while( event != EventQueue ) + { + next = event->next; + if ( event->GetSourceObject() == this ) + { + LL_Remove( event, next, prev ); + numEvents--; + delete event; + } + event = next; + } + } + +qboolean Listener::ProcessPendingEvents + ( + void + ) + + { + Event *event; + qboolean processedEvents; + float t; + + assert( EventQueue ); + assert( EventQueue->next ); + assert( EventQueue->prev ); + + processedEvents = false; + + t = EVENT_time + 0.001; + + event = EventQueue->next; + while( event != EventQueue ) + { + Listener * obj; + + assert( event ); + + obj = event->GetSourceObject(); + + if ( event->time > t ) + { + break; + } + + if ( obj != this ) + { + // traverse normally + event = event->next; + } + else + { + // the event is removed from its list and temporarily added to the active list + LL_Remove( event, next, prev ); + numEvents--; + LL_Add( ActiveEvents, event, next, prev ); + + + // ProcessEvent will dispose of this event when it is done + obj->ProcessEvent( event ); + + // start over, since can't guarantee that we didn't process any previous or following events + event = EventQueue->next; + + processedEvents = true; + } + } + + return processedEvents; + } + +Listener::~Listener() + { + if ( Event::EventSystemStarted ) + CancelPendingEvents(); + } + +void L_ClearEventList + ( + void + ) + + { + Event *event; + + // go through active and event queue lists + while( !LL_Empty( EventQueue, next, prev ) ) + { + event = EventQueue->next; + numEvents--; + LL_Remove( event, next, prev ); + delete event; + } + + while( !LL_Empty( ActiveEvents, next, prev ) ) + { + event = ActiveEvents->next; + LL_Remove( event, next, prev ); + delete event; + } + + numEvents = 0; + } + +void L_ProcessPendingEvents + ( + void + ) + + { + Event *event; + float t; + int num; + int maxevents; + + assert( EventQueue ); + assert( EventQueue->next ); + assert( EventQueue->prev ); + + maxevents = ( int )g_eventlimit->integer; + + num = 0; + t = EVENT_time + 0.001; + while( !LL_Empty( EventQueue, next, prev ) ) + { + Listener * obj; + + event = EventQueue->next; + + assert( event ); + + obj = event->GetSourceObject(); + + assert( obj ); + + if ( event->time > t ) + { + break; + } + + // the event is removed from its list and temporarily added to the active list + LL_Remove( event, next, prev ); + numEvents--; + LL_Add( ActiveEvents, event, next, prev ); + + + // ProcessEvent will dispose of this event when it is done + obj->ProcessEvent( event ); + + // Don't allow ourselves to stay in here too long. An abnormally high number + // of events being processed is evidence of an infinite loop of events. + num++; + if ( num > maxevents ) + { + EVENT_Printf( "Event overflow. Possible infinite loop in script. " + "Enable g_showevents to trace. Aborting frame.\n" ); + break; + } + } + + if ( g_eventstats->integer ) + { + if ( g_eventstats->integer == 1 ) + { + EVENT_Printf( "finds %d, searches %d, num first search %d, avg %f\n", + Event::numfinds, Event::numcompares, Event::numfirstsearch, + ( float )Event::numcompares / ( float )Event::numfinds ); + } + else if ( g_eventstats->integer == 2 ) + { + EVENT_Printf( "pending %5d free %5d active+pending %4d\n", + numEvents, numFreeEvents, numFreeEvents + numEvents ); + } + } + } + +#ifdef GAME_DLL + +void Event::SetConsoleEdict + ( + gentity_t *consoleedict + ) + + { + // linenumber does double duty in the case of the console commands + if ( consoleedict ) + { + info.linenumber = consoleedict->s.number; + } + else + { + // default to player 1 + info.linenumber = 0; + } + } + +gentity_t *Event::GetConsoleEdict + ( + void + ) + + { + // linenumber does double duty in the case of the console commands + if ( ( info.source != EV_FROM_CONSOLE ) || ( info.linenumber < 0 ) || ( info.linenumber >= game.maxclients ) ) + { + // default to player 1 for release + return &g_entities[ 0 ]; + } + + return &g_entities[ info.linenumber ]; + } + +void L_ArchiveEvents + ( + Archiver &arc + ) + + { + Event *event; + int num; + + assert( EventQueue ); + assert( EventQueue->next ); + assert( EventQueue->prev ); + + num = 0; + for( event = EventQueue->next; event != EventQueue; event = event->next ) + { + Listener * obj; + + assert( event ); + + obj = event->GetSourceObject(); + + assert( obj ); + + if ( obj->isSubclassOf( Entity ) && + ( ( ( Entity * )obj )->flags & FL_DONTSAVE ) ) + { + continue; + } + + num++; + } + + arc.ArchiveInteger( &num ); + for( event = EventQueue->next; event != EventQueue; event = event->next ) + { + Listener * obj; + + assert( event ); + + obj = event->GetSourceObject(); + + assert( obj ); + + if ( obj->isSubclassOf( Entity ) && + ( ( ( Entity * )obj )->flags & FL_DONTSAVE ) ) + { + continue; + } + + arc.ArchiveEvent( event ); + arc.ArchiveFloat( &event->time ); + arc.ArchiveInteger( &event->flags ); + } + } + +void L_UnarchiveEvents + ( + Archiver &arc + ) + + { + Event *e; + int i; + + // the FreeEvents list would already be allocated at this point + // clear out any events that may exist + L_ClearEventList(); + + arc.ArchiveInteger( &numEvents ); + for( i = 0; i < numEvents; i++ ) + { + e = new Event(); + LL_Remove( e, next, prev ); + arc.ArchiveEvent( e ); + arc.ArchiveFloat( &e->time ); + arc.ArchiveInteger( &e->flags ); + + LL_Add( EventQueue, e, next, prev ); + } + } +#endif + +void Event::InitializeDocumentation + ( + void + ) + { + Event * ePtr; + int i; + + for( i = 1; i <= eventDefList->NumObjects(); i++ ) + { + ePtr = eventDefList->ObjectAt( i ); + ePtr->SetupDocumentation(); + } + } + +void Event::ShutdownDocumentation + ( + void + ) + { + Event * ePtr; + int i; + + for( i = 1; i <= eventDefList->NumObjects(); i++ ) + { + ePtr = eventDefList->ObjectAt( i ); + ePtr->DeleteDocumentation(); + } + } + + +void L_InitEvents + ( + void + ) + + { + if ( Event::EventSystemStarted ) + { + assert( 0 ); + L_ShutdownEvents(); + } + + Event::lastevent = 0; + Event::numfinds = 0; + Event::numcompares = 0; + Event::numfirstsearch = 0; + Event_totalmemallocated = 0; + +#if defined( GAME_DLL ) + g_showevents = gi.cvar ( "g_showevents", "0", 0 ); + g_eventlimit = gi.cvar ( "g_eventlimit", "5000", 0 ); + g_timeevents = gi.cvar ( "g_timeevents", "0", 0 ); + g_watch = gi.cvar ( "g_watch", "0", 0 ); + g_eventstats = gi.cvar ( "g_eventstats", "0", 0 ); +#elif defined( CGAME_DLL ) + g_showevents = cgi.Cvar_Get ( "cg_showevents", "0", 0 ); + g_eventlimit = cgi.Cvar_Get ( "cg_eventlimit", "500", 0 ); + g_timeevents = cgi.Cvar_Get ( "cg_timeevents", "0", 0 ); + g_eventstats = cgi.Cvar_Get ( "cg_eventstats", "0", 0 ); +#else + g_showevents = Cvar_Get ( "cl_showevents", "0", 0 ); + g_eventlimit = Cvar_Get ( "cl_eventlimit", "500", 0 ); + g_timeevents = Cvar_Get ( "cl_timeevents", "0", 0 ); + g_eventstats = Cvar_Get ( "cl_eventstats", "0", 0 ); +#endif + + BuildEventResponses(); + + Event::InitializeEventLists(); + + L_ClearEventList(); + + // setup the documentation on all the events + Event::InitializeDocumentation(); + + // Sort the list before we go on since we won't be adding any more events + Event::SortEventList(); + + // the event system has started + Event::EventSystemStarted = true; + } + +void L_ShutdownEvents + ( + void + ) + + { + int i; + + if ( !Event::EventSystemStarted ) + return; + + Event::ShutdownEventLists(); + + // deletes all the documentation + Event::ShutdownDocumentation(); + + if ( Event::commandList ) + { + for ( i=Event::commandList->NumObjects(); i>0; i-- ) + { + str *s; + + s = Event::commandList->ObjectAt( i ); + assert( s ); + if ( s ) + delete s; + } + delete Event::commandList; + Event::commandList = NULL; + } + + if ( Event::eventDefList ) + { + delete Event::eventDefList; + Event::eventDefList = NULL; + } + + if ( Event::flagList ) + { + delete Event::flagList; + Event::flagList = NULL; + } + + if ( Event::sortedList ) + { + delete Event::sortedList; + Event::sortedList = NULL; + } + + // say it is now shutdown + Event::EventSystemStarted = false; + } diff --git a/source/source/fgame/listener.h b/source/source/fgame/listener.h new file mode 100644 index 0000000..481ffb2 --- /dev/null +++ b/source/source/fgame/listener.h @@ -0,0 +1,1208 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/listener.h $ +// $Revision:: 36 $ +// $Author:: Aldie $ +// $Date:: 7/25/00 11:32p $ +// +// Copyright (C) 1998 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source is may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/listener.h $ +// +// 36 7/25/00 11:32p Aldie +// Made some changes to the memory system and fixed a memory allocation bug in +// Z_TagMalloc. Also changed a lot of classes to subclass from Class. +// +// 35 6/22/00 6:34p Markd +// fixed =operator assignment bug +// +// 34 6/22/00 3:45p Markd +// fixed a bunch of saved game issues +// +// 33 6/14/00 11:18a Markd +// cleaned up code using Intel compiler +// +// 32 5/30/00 7:06p Markd +// saved games 4th pass +// +// 31 5/24/00 3:14p Markd +// first phase of save/load games +// +// 30 4/29/00 3:26p Markd +// fleshed out the rest of the event/class documentation +// +// 29 4/26/00 7:55p Markd +// Added more documentation code into various systems +// +// 28 4/13/00 7:04p Aldie +// Fixed bug for animation events where the anim was greater than 255. Added +// animframe and animnumber to Event. +// +// 27 3/16/00 10:50a Markd +// Fixed some bad syntax in headers that exhibited itself in non-visualc +// compilers +// +// 26 1/06/00 11:10p Jimdose +// cleaning up unused code +// +// 25 12/15/99 11:45a Markd +// made Event's Classes and also freed up safe pointers at the appropriate +// times +// +// 24 12/11/99 5:51p Markd +// First wave of bug fixes after q3a gold merge +// +// 23 12/11/99 3:37p Markd +// q3a gold checkin, first time +// +// 22 11/11/99 3:54p Jimdose +// added EVENT_TORSO_ANIM +// +// 21 10/19/99 7:52p Markd +// Removed three part model system +// +// 20 10/12/99 11:09a Morbid +// UI merge back to FAKK +// +// 19 10/07/99 3:02p Steven +// Removed defaults for event constructor and added a new event constructor +// that only takes a const char * as a parm. +// +// 18 10/06/99 3:09p Steven +// Added dumpevents command. +// +// 17 10/05/99 2:03p Markd +// Added warning about files being in multiple projects +// +// 16 10/03/99 4:50p Markd +// removed str& constructor from listener +// +// 15 10/02/99 6:51p Markd +// Put in backend work for event documentation and fixed a lot of event +// documentation bugs +// +// 14 10/01/99 4:52p Markd +// Made Warning level 4 work on all projects +// +// 13 10/01/99 3:49p Markd +// fixed some level 4 warnings +// +// 12 9/29/99 3:10p Markd +// fixed listener problems +// +// 11 9/29/99 2:49p Morbid +// +// 10 9/28/99 7:13p Markd +// moved __LISTENER define up to the top of the file +// +// 9 9/28/99 5:31p Markd +// Successfully merged class.h, listener.h and vector.h into all three modules, +// cgame, fgame and client +// +// 8 9/28/99 5:15p Markd +// Fixed more merge bugs with sharing class, vector and listener between three +// modules +// +// 7 9/28/99 4:26p Markd +// merged listener, class and vector between 3 projects +// +// 6 9/28/99 10:12a Markd +// fixed some event issues +// +// 5 9/27/99 5:44p Markd +// began documentation and cleanup phase after merge +// +// 4 9/16/99 7:48p Jimdose +// made SetConsoleEdict use 0 based players +// +// 3 9/16/99 7:48p Jimdose +// fixed GetConsoleEdict to use 0 based players +// +// 2 9/16/99 11:18a Markd +// Continuing merge of code, not functional yet but closer +// +// 1 9/10/99 10:54a Jimdose +// +// 1 9/08/99 3:16p Aldie +// +// 14 9/02/99 2:33p Markd +// Added cache ability to entities +// +// 13 8/28/99 3:34p Jimdose +// Added EventVar +// All event args now have type information and use lazy evaluation +// +// 12 8/27/99 8:25p Markd +// added pengingevents and fixed some event holes +// +// 11 8/27/99 3:30p Markd +// put in event caching system so that events are reused +// +// 10 8/19/99 12:16p Jimdose +// added event stats +// added lru check to FindEvent +// +// 9 8/09/99 5:07p Aldie +// More changes to accomodate weapons system +// +// DESCRIPTION: +// +// WARNING: This file is shared between fgame, cgame and possibly the user interface. +// It is instanced in each one of these directories because of the way that SourceSafe works. +// + +// +// this has to be placed in front of the __LISTENER_H__ +// if it is not, listener.cpp will not compile +// +#if defined( GAME_DLL ) +// +// game dll specific defines +// +#include "g_local.h" + +#endif + +#ifndef __LISTENER_H__ +#define __LISTENER_H__ + +#if defined( GAME_DLL ) +// +// game dll specific defines +// +#define EVENT_DebugPrintf gi.DebugPrintf +#define EVENT_DPrintf gi.DPrintf +#define EVENT_Printf gi.Printf +#define EVENT_time level.time +#define EVENT_realtime gi.Milliseconds() +#define EVENT_Error gi.Error + +#define EVENT_FILENAME "events.txt" + +class Entity; +class ScriptVariable; +class ScriptThread; +class Archiver; + +#elif defined ( CGAME_DLL ) +// +// cgame dll specific defines +// +#include "cg_local.h" +#include "vector.h" +#include "str.h" +#include "../qcommon/qcommon.h" + +#define EVENT_DebugPrintf cgi.DebugPrintf +#define EVENT_DPrintf cgi.Printf +#define EVENT_Printf cgi.Printf +#define EVENT_time ( ( ( float )cg.time / 1000.0f ) ) +#define EVENT_realtime cgi.Milliseconds() +#define EVENT_Error cgi.Error + +#define EVENT_FILENAME "cg_events.txt" + +#elif defined ( UI_LIB ) + +#include "../fgame/q_shared.h" +#include "vector.h" +#include "str.h" +#include "../qcommon/qcommon.h" +#include "ui_local.h" + +#define EVENT_DebugPrintf Com_DebugPrintf +#define EVENT_DPrintf Com_Printf +#define EVENT_Printf Com_Printf +#define EVENT_time ( ( ( float )cls.realtime / 1000.0f ) ) +#define EVENT_realtime Sys_Milliseconds() +#define EVENT_Error Com_Error + +#define EVENT_FILENAME "ui_events.txt" + +#else + +// +// client specific defines +// +#include "../fgame/q_shared.h" +#include "vector.h" +#include "str.h" +#include "../qcommon/qcommon.h" + +#define EVENT_DebugPrintf Com_DebugPrintf +#define EVENT_DPrintf Com_Printf +#define EVENT_Printf Com_Printf +#define EVENT_time ( ( ( float )cls.realtime / 1000.0f ) ) +#define EVENT_realtime Sys_Milliseconds() +#define EVENT_Error Com_Error + +#define EVENT_FILENAME "cl_events.txt" +#endif + +#include "class.h" +#include "container.h" + +typedef enum + { + EV_FROM_CODE, + EV_FROM_CONSOLE, + EV_FROM_SCRIPT, + EV_FROM_ANIMATION + } eventsource_t; + +// Posted Event Flags +#define EVENT_LEGS_ANIM (1<<0) // this event is associated with an animation for the legs +#define EVENT_TORSO_ANIM (1<<1) // this event is associated with an animation for the torso +#define EVENT_DIALOG_ANIM (1<<2) // this event is associated with an animation for dialog lip syncing + + +// Event flags +#define EV_CONSOLE (1<<0) // Allow entry from console +#define EV_CHEAT (1<<1) // Only allow entry from console if cheats are enabled +#define EV_HIDE (1<<2) // Hide from eventlist +#define EV_CACHE (1<<3) // This event is used to cache data in + +#define EV_DEFAULT -1 // default flags + +#define INUSE_BITS 2 +#define MAX_EVENT_USE ( ( 1 << INUSE_BITS ) - 1 ) + +typedef enum + { + IS_STRING, + IS_VECTOR, + IS_BOOLEAN, + IS_INTEGER, + IS_FLOAT, + IS_ENTITY, + IS_SCRIPTVARIABLE + } vartype; + +#define DIRTY_STRING ( 1 << 0 ) +#define DIRTY_VECTOR ( 1 << 1 ) +#define DIRTY_INTEGER ( 1 << 2 ) +#define DIRTY_FLOAT ( 1 << 3 ) + +#define DIRTY_ALL ( 0x7fff ) + +class EventVar : public Class + { + private: + short type; + short dirtyFlags; + str stringValue; + Vector vectorValue; + int intValue; + float floatValue; + + public: + + EventVar() + { + type = IS_INTEGER; + dirtyFlags = DIRTY_ALL; + intValue = 0; + floatValue = 0; + }; + + EventVar( EventVar &ev ) + { + type = ev.type; + dirtyFlags = ev.dirtyFlags; + intValue = ev.intValue; + floatValue = ev.floatValue; + }; + + EventVar( const char *text ); + EventVar( str &text ); + + EventVar( int val ) + { + type = IS_INTEGER; + dirtyFlags = DIRTY_ALL & ~DIRTY_INTEGER; + intValue = val; + }; + + EventVar( float val ) + { + type = IS_FLOAT; + dirtyFlags = DIRTY_ALL & ~DIRTY_FLOAT; + floatValue = val; + }; + + EventVar( Vector &vec ) + { + type = IS_VECTOR; + dirtyFlags = DIRTY_ALL & ~DIRTY_VECTOR; + vectorValue = vec; + }; + +#ifdef GAME_DLL + EventVar( Entity *ent ); +#endif + + const char *GetToken( Event &ev ); + const char *GetString( Event &ev ); + qboolean GetBoolean( Event &ev ); + int GetInteger( Event &ev ); + float GetFloat( Event &ev ); + Vector GetVector( Event &ev ); +#ifdef GAME_DLL + Entity *GetEntity( Event &ev ); + ScriptVariable *GetVariable( Event &ev ); +#endif + + qboolean IsVector( Event &ev ); + qboolean IsNumeric( Event &ev ); + +#ifdef GAME_DLL + void Archive( Archiver &arc ); +#endif + }; + + +class EventArgDef : public Class + { + private: + int type; + str name; + float minRange[ 3 ]; + qboolean minRangeDefault[ 3 ]; + float maxRange[ 3 ]; + qboolean maxRangeDefault[ 3 ]; + qboolean optional; + public: + + EventArgDef() + { + type = IS_INTEGER; + //name = "undefined"; + optional = qfalse; + }; + void Setup( const char * eventName, const char *argName, const char *argType, const char *argRange ); + void PrintArgument( FILE *event_file = NULL ); + void PrintRange( FILE *event_file = NULL ); +#if 0 +#ifdef GAME_DLL + void Archive( Archiver &arc ); +#endif +#endif + }; + + + +#ifndef GAME_DLL +extern "C" + { + // interface functions + void L_ProcessPendingEvents( void ); + void L_ClearEventList( void ); + void L_InitEvents( void ); + void L_ShutdownEvents( void ); + } +#endif + + +class Listener; +typedef SafePtr ListenerPtr; + + +class Event : public Class + { + private: + friend class Listener; + + typedef struct EventInfo + { + unsigned inuse : INUSE_BITS; // must change MAX_EVENT_USE to reflect maximum number stored here + unsigned source : 2; + unsigned flags : 9; + unsigned linenumber : 19; // linenumber does double duty in the case of the console commands + } EventInfo_t; + + int eventnum; + EventInfo info; + const char *name; + const char *formatspec; + const char *argument_names; + const char *documentation; + Container *data; + Container *definition; + int threadnum; + short anim_number; + short anim_frame; + SafePtr m_sourceobject; + + //Listener *obj; + float time; + int flags; + + Event( int num ); + static void initCommandList( void ); + static void InitializeEventLists( void ); + static void ShutdownEventLists( void ); + static void InitializeDocumentation( void ); + static void ShutdownDocumentation( void ); + + static int numfinds; + static int numfirstsearch; + static int numcompares; + static int lastevent; + static bool EventSystemStarted; + + friend void L_ProcessPendingEvents( void ); + friend void L_ClearEventList( void ); + friend void L_InitEvents( void ); + friend void L_ShutdownEvents( void ); + +#ifdef GAME_DLL + friend void L_ArchiveEvents( Archiver &arc ); + friend void L_UnarchiveEvents( Archiver &arc ); + +#endif + + static Container *commandList; + static Container *flagList; + static Container *sortedList; + static Container *eventDefList; + static qboolean dirtylist; + + static int compareEvents( const void *arg1, const void *arg2 ); + static void SortEventList( void ); + static int FindEvent( const char *name ); + static int FindEvent( str &name ); + static void PrintEvent( Event *ev ); + + public: + CLASS_PROTOTYPE( Event ); + + Event *next; // next event in the list, used for event recycling + Event *prev; // previous event int the list, used for event recycling + + void * operator new( size_t ); + void operator delete( void * ); + + static int NumEventCommands( void ); + static void ListCommands( const char *mask = NULL ); + static void ListDocumentation( const char *mask, qboolean print_to_file = qfalse ); + static void PendingEvents( const char *mask = NULL ); + static void PrintEventDocumentation( Event * event, FILE *event_file = NULL, qboolean html = qfalse ); + static int MapSortedEventIndex( int index ); + + Event(); + Event( Event &ev ); + Event( Event *ev ); + Event + ( + const char *command, + int flags, + const char *formatspec, + const char *argument_names, + const char *documentation + ); + Event( const char *command ); + Event( str &command ); + ~Event(); + + void SetupDocumentation( void ); + void DeleteDocumentation( void ); + void PrintDocumentation( FILE *event_file = NULL, qboolean html = qfalse ); + + str getName( void ); + + void SetSource( eventsource_t source ); + void SetLineNumber( int linenumber ); + void SetSourceObject( Listener *source ); + Listener *GetSourceObject( void ); + SafePtr *GetSourceObjectPointer( void ); + + eventsource_t GetSource( void ); + int GetLineNumber( void ); + int GetAnimationNumber( void ); + int GetAnimationFrame( void ); + void SetAnimationNumber( int anim ); + void SetAnimationFrame( int frame ); + + int GetFlags( void ); + + void Error( const char *fmt, ... ); + + static Event Find( const char *command ); + static qboolean Exists( const char *command ); + static Event Find( str &command ); + + Event& printInfo(void); + + friend bool operator==( const Event &a, const Event &b ); + friend bool operator!=( const Event &a, const Event &b ); + void operator=( const Event &ev ); + + operator int(); + operator const char *(); + + int NumArgs( void ); + + qboolean IsVectorAt( int pos ); + qboolean IsEntityAt( int pos ); + qboolean IsNumericAt( int pos ); + + const char *GetToken( int pos ); + const char *GetString( int pos ); + int GetInteger( int pos ); + float GetFloat( int pos ); + Vector GetVector( int pos ); + bool GetBoolean( int pos ); + + void AddToken( const char *text ); + void AddTokens( int argc, const char **argv ); + void AddString( const char *text ); + void AddString( str &text ); + void AddInteger( int val ); + void AddFloat( float val ); + void AddVector( Vector &vec ); + +#ifdef GAME_DLL + void AddEntity( Entity *ent ); + Entity *GetEntity( int pos ); + ScriptVariable *GetVariable( int pos ); + void SetThread( ScriptThread *thread ); + ScriptThread *GetThread( void ); + void SetConsoleEdict( gentity_t *consoleedict ); + gentity_t *GetConsoleEdict( void ); + + virtual void Archive( Archiver &arc ); +#endif + }; + +extern Event NullEvent; +extern Event EV_Remove; + +class Listener; + +class Listener : public Class + { + private: + void ScriptRemove( Event *e ); + + protected: + qboolean CheckEventFlags( Event *event ); + + public: + CLASS_PROTOTYPE( Listener ); + + ~Listener(); + void Remove( Event *e ); + qboolean ValidEvent( Event &e ); + qboolean ValidEvent( const char *name ); + qboolean EventPending( Event &ev ); + qboolean ProcessEvent( Event *event ); + qboolean ProcessEvent( Event &event ); + void PostEvent( Event *event, float time, int flags = 0 ); + void PostEvent( Event &event, float time, int flags = 0 ); + qboolean PostponeEvent( Event &event, float time ); + qboolean PostponeEvent( Event *event, float time ); + void CancelEventsOfType( Event *event ); + void CancelEventsOfType( Event &event ); + void CancelFlaggedEvents( int flags ); + void CancelPendingEvents( void ); + qboolean ProcessPendingEvents( void ); + }; + +inline void Event::SetSourceObject + ( + Listener *source + ) + + { + m_sourceobject = source; + } + +inline Listener *Event::GetSourceObject + ( + void + ) + + { + return m_sourceobject; + } + +inline SafePtr *Event::GetSourceObjectPointer + ( + void + ) + + { + return &m_sourceobject; + } + +inline qboolean Event::Exists + ( + const char *command + ) + + { + int num; + str c; + + if ( !commandList ) + { + initCommandList(); + } + + c = command; + num = FindEvent( c ); + if ( num ) + { + return true; + } + + return false; + } + + +inline Event Event::Find + ( + const char *command + ) + + { + int num; + str c; + + if ( !commandList ) + { + initCommandList(); + } + + c = command; + num = FindEvent( c ); + if ( num ) + { + Event ev( num ); + return ev; + } + + return NullEvent; + } + +inline Event Event::Find + ( + str &command + ) + + { + int num; + + if ( !commandList ) + { + initCommandList(); + } + + num = FindEvent( command ); + if ( num ) + { + Event ev( num ); + return ev; + } + + return NullEvent; + } + +inline void Event::SetSource + ( + eventsource_t source + ) + + { + info.source = ( unsigned )source; + } + +inline void Event::SetLineNumber + ( + int linenumber + ) + + { + info.linenumber = linenumber; + } + +inline eventsource_t Event::GetSource + ( + void + ) + + { + return ( eventsource_t )info.source; + } + +inline int Event::GetAnimationNumber + ( + void + ) + + { + return anim_number; + } + +inline int Event::GetAnimationFrame + ( + void + ) + + { + return anim_frame; + } + +inline void Event::SetAnimationNumber + ( + int anim + ) + + { + anim_number = anim; + } + +inline void Event::SetAnimationFrame + ( + int frame + ) + + { + anim_frame = frame; + } + +inline int Event::GetLineNumber + ( + void + ) + + { + // linenumber does double duty in the case of the console commands + if ( info.source == EV_FROM_SCRIPT ) + { + return info.linenumber; + } + + return 0; + } + +inline int Event::GetFlags + ( + void + ) + + { + return info.flags; + } + +inline str Event::getName + ( + void + ) + + { + assert( name || !eventnum ); + + if ( !name ) + { + return "NULL"; + } + + return name; + } + +inline Event& Event::printInfo + ( + void + ) + + { + EVENT_DPrintf( "event '%s' is number %d\n", getName().c_str(), eventnum ); + + return *this; + } + +inline bool operator== + ( + const Event &a, + const Event &b + ) + + { + return a.eventnum == b.eventnum; + } + +inline bool operator!= + ( + const Event &a, + const Event &b + ) + + { + return a.eventnum != b.eventnum; + } + +inline void Event::operator= + ( + const Event &ev + ) + { + eventnum = ev.eventnum; + info = ev.info; + if ( ev.data ) + { + int i; + + data = new Container; + data->Resize( ev.data->NumObjects() ); + for( i = 1; i < ev.data->NumObjects(); i++ ) + { + data->AddObject( ev.data->ObjectAt( i ) ); + } + } + name = ev.name; + definition = NULL; + threadnum = ev.threadnum; + anim_number = ev.anim_number; + anim_frame = ev.anim_frame; + m_sourceobject = ev.m_sourceobject; + time = ev.time; + flags = ev.flags; + } + + +inline Event::operator int() + { + return eventnum; + } + +inline Event::operator const char *() + { + return getName().c_str(); + } + +inline int Event::NumArgs + ( + void + ) + + { + if ( !data ) + { + return 0; + } + + return ( data->NumObjects() ); + } + +#ifdef GAME_DLL +inline void Event::AddEntity + ( + Entity *ent + ) + + { + if ( !data ) + { + data = new Container; + data->Resize( 1 ); + } + + + EventVar var( ent ); + data->AddObject( var ); + } +#endif + +inline void Event::AddToken + ( + const char *text + ) + + { + if ( !data ) + { + data = new Container; + data->Resize( 1 ); + } + + EventVar var( text ); + data->AddObject( var ); + } + +inline void Event::AddTokens + ( + int argc, + const char **argv + ) + + { + int i; + + if ( !data ) + { + data = new Container; + data->Resize( argc ); + } + + for( i = 0; i < argc; i++ ) + { + assert( argv[ i ] ); + EventVar var( argv[ i ] ); + data->AddObject( var ); + } + } + +inline void Event::AddString + ( + const char *text + ) + + { + if ( !data ) + { + data = new Container; + data->Resize( 1 ); + } + + EventVar var( text ); + data->AddObject( var ); + } + +inline void Event::AddString + ( + str &text + ) + + { + if ( !data ) + { + data = new Container; + data->Resize( 1 ); + } + + EventVar var( text ); + data->AddObject( var ); + } + +inline void Event::AddInteger + ( + int val + ) + + { + if ( !data ) + { + data = new Container; + data->Resize( 1 ); + } + + EventVar var( val ); + data->AddObject( var ); + } + +inline void Event::AddFloat + ( + float val + ) + + { + if ( !data ) + { + data = new Container; + data->Resize( 1 ); + } + + EventVar var( val ); + data->AddObject( var ); + } + +inline void Event::AddVector + ( + Vector &vec + ) + + { + if ( !data ) + { + data = new Container; + data->Resize( 1 ); + } + + EventVar var( vec ); + data->AddObject( var ); + } + +inline const char *Event::GetToken + ( + int pos + ) + + { + if ( !data || ( pos < 1 ) || ( data->NumObjects() < pos ) ) + { + Error( "Index %d out of range.", pos ); + return ""; + } + + return data->ObjectAt( pos ).GetToken( *this ); + } + +inline const char *Event::GetString + ( + int pos + ) + + { + if ( !data || ( pos < 1 ) || ( data->NumObjects() < pos ) ) + { + Error( "Index %d out of range.", pos ); + return ""; + } + + return data->ObjectAt( pos ).GetString( *this ); + } + +inline int Event::GetInteger + ( + int pos + ) + + { + if ( !data || ( pos < 1 ) || ( data->NumObjects() < pos ) ) + { + Error( "Index %d out of range.", pos ); + return 0; + } + + return data->ObjectAt( pos ).GetInteger( *this ); + } + +inline float Event::GetFloat + ( + int pos + ) + + { + if ( !data || ( pos < 1 ) || ( data->NumObjects() < pos ) ) + { + Error( "Index %d out of range.", pos ); + return 0; + } + + return data->ObjectAt( pos ).GetFloat( *this ); + } + +inline Vector Event::GetVector + ( + int pos + ) + + { + if ( !data || ( pos < 1 ) || ( data->NumObjects() < pos ) ) + { + Error( "Index %d out of range.", pos ); + return vec_zero; + } + + return data->ObjectAt( pos ).GetVector( *this ); + } + +inline bool Event::GetBoolean + ( + int pos + ) + + { + int val; + + val = this->GetInteger( pos ); + + return ( val != 0 ) ? true : false; + } + +#ifdef GAME_DLL + +inline Entity *Event::GetEntity + ( + int pos + ) + + { + if ( !data || ( pos < 1 ) || ( data->NumObjects() < pos ) ) + { + Error( "Index %d out of range.", pos ); + return NULL; + } + + return data->ObjectAt( pos ).GetEntity( *this ); + } + +inline ScriptVariable *Event::GetVariable + ( + int pos + ) + + { + if ( !data || ( pos < 1 ) || ( data->NumObjects() < pos ) ) + { + Error( "Index %d out of range.", pos ); + return NULL; + } + + return data->ObjectAt( pos ).GetVariable( *this ); + } + +#endif + +inline qboolean Listener::ProcessEvent + ( + Event &event + ) + + { + Event *ev; + + ev = new Event( event ); + return ProcessEvent( ev ); + } + +inline void Listener::PostEvent + ( + Event &event, + float time, + int flags + ) + + { + Event *ev; + + ev = new Event( event ); + PostEvent( ev, time, flags ); + } + +inline qboolean Listener::PostponeEvent + ( + Event *event, + float time + ) + + { + return PostponeEvent( *event, time ); + } + +inline void Listener::CancelEventsOfType + ( + Event &event + ) + + { + CancelEventsOfType( &event ); + } + +#endif + diff --git a/source/source/fgame/misc.cpp b/source/source/fgame/misc.cpp new file mode 100644 index 0000000..5bacc89 --- /dev/null +++ b/source/source/fgame/misc.cpp @@ -0,0 +1,3757 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/misc.cpp $ +// $Revision:: 100 $ +// $Author:: Markd $ +// $Date:: 7/30/00 6:27p $ +// +// Copyright (C) 1997 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source is may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/misc.cpp $ +// +// 100 7/30/00 6:27p Markd +// changed default animation from push to stand_use +// +// 98 7/30/00 2:54p Markd +// made horizontalpipe and monkeybars notsolid for the camera +// +// 97 7/29/00 1:26p Steven +// Took out teleport sounds (are in the effect now). +// +// 96 7/27/00 9:52p Markd +// got keyed triggers to work correctly +// +// 95 7/27/00 6:31p Markd +// made useAnim's work with doors, added key ability +// +// 92 7/25/00 10:37p Markd +// fallingrocks have default bounce sounds now +// +// 91 7/24/00 11:57p Markd +// fixed edenwater sounds +// +// 90 7/21/00 12:34p Markd +// increased default code from 60 degrees to 90 +// +// 89 7/19/00 5:08p Steven +// Added some caching stuff for teleporters. +// +// 88 7/18/00 3:29p Markd +// added better caching for sounds in general +// +// 87 7/17/00 4:58p Markd +// fixed useobjects and skins +// +// 86 7/16/00 5:34p Aldie +// Fix effect for teleporters. +// +// 85 7/14/00 11:45p Markd +// Added ambient sounds to func_supllywater +// +// 84 7/14/00 5:59p Steven +// Added another good sound to the teleporter. +// +// 83 7/11/00 9:28p Markd +// Added MaxWater event to func_watersupply +// +// 82 7/11/00 7:08p Steven +// Made teleport stuff cooler. +// +// 81 7/10/00 11:54p Markd +// added exit level code +// +// 80 7/10/00 5:09p Markd +// changed water supply so that it would only give up to 50 percent water +// +// 79 7/08/00 7:09p Steven +// Made teleport sound not get played if no_effects spawnflag is set. +// +// 78 7/07/00 6:38p Steven +// Forgot to put in QUAKED comment. +// +// 77 7/07/00 4:32p Steven +// Teleporter stuff : no_effects flag, warp sentient to middle of teleporter +// and fixed some teleporting multiple times problems. +// +// 76 7/06/00 9:54p Markd +// simplified code +// +// 75 7/06/00 6:25p Steven +// Added new teleport stuff. +// +// 74 7/03/00 6:59p Steven +// Setup default pushobject sound, improved pushobject loop sounds a little, +// and setup a default falling rock sound. +// +// 73 6/28/00 4:17p Markd +// fixed small UseAnim bug +// +// 72 6/28/00 3:41p Markd +// added better documentation +// +// 71 6/25/00 3:10p Markd +// Tweaked TouchAnim's so that they would not multi-trigger +// +// 70 6/25/00 2:51p Markd +// made use objects easier to use +// +// 69 6/23/00 8:41p Markd +// made a lot of changes to different constructors for saved game support +// +// 68 6/14/00 4:13p Markd +// +// 67 6/14/00 3:50p Markd +// Cleaned up more Intel Compiler warnings +// +// 66 6/13/00 6:41p Markd +// Fixed pushing and pulling of objects +// +// 65 6/09/00 7:36p Markd +// Added activate and deactive to useobjects +// +// 64 6/09/00 2:05p Markd +// bullet proofed falling rock code +// +// 63 6/09/00 11:54a Markd +// fixed falling rock code again... +// +// 62 6/07/00 5:37p Markd +// got rid of debugging stuff +// +// 61 6/07/00 5:36p Markd +// fixed falling rock code +// +// 60 6/04/00 6:52p Markd +// Added camera support to TouchAnim's cleaned up player camera interface +// +// 59 6/04/00 6:16p Markd +// Added TouchAnim support +// +// 58 5/31/00 5:32p Steven +// Marked use objects as things for Julie to look at. +// +// 57 5/03/00 11:46a Markd +// Made PushObjects trigger stuff +// +// 56 5/03/00 10:00a Markd +// automatically kill toss objects after a preset amount of time if they don't +// come to rest +// +// 55 4/30/00 2:46p Markd +// allowed falling rocks to trigger threads at waypoints +// +// 54 4/24/00 6:20p Markd +// fixed toss objects so that they would be solid when falling +// +// 53 4/21/00 6:16p Markd +// Fixed bounce sound stuff +// +// 52 4/21/00 3:00p Markd +// fixed up TossObjects so that they would work properly +// +// 51 4/19/00 9:25a Markd +// added bouncesound to falling rock code +// +// 50 4/18/00 11:44a Markd +// Added NO_RANDOMNESS flag to falling rock code +// +// 49 4/06/00 6:18p Markd +// made UseObjects and UseAnim's not climable +// +// 48 4/06/00 5:45p Aldie +// Added func_supplywater +// +// 47 4/05/00 12:20p Markd +// added damage type +// +// 46 4/04/00 5:30p Markd +// Removed sounds from UseObject +// +// 45 3/31/00 6:07p Markd +// improved the functionality of UseObjects +// +// 44 3/31/00 3:26p Markd +// Removed options from func_useobject +// +// 43 3/31/00 3:19p Markd +// Added UseObject functionality +// +// 42 3/29/00 4:21p Markd +// Made falling rocks take into account their local gravity variable +// +// 41 3/27/00 3:45p Markd +// Hooked up UseAnim state info into the game +// +// 40 3/21/00 5:05p Markd +// Added state variable to func_useanim_destination +// +// 39 3/20/00 3:01p Markd +// added more functionality to falling rock +// +// 38 3/18/00 2:43p Aldie +// Changed some func_spawn functionality +// +// 37 3/16/00 10:20a Markd +// fixed useanim firing its targets before the animation was completed +// +// 36 3/15/00 5:52p Aldie +// Added pushsound to func_pushobject and removed a printf. +// +// 35 3/13/00 7:46p Jimdose +// added fallingrock +// +// 34 3/01/00 10:59a Jimdose +// UseAnim now sends the entity that used it as the activator instead of itself +// when triggering targets +// +// 33 2/26/00 9:51a Markd +// forgot to reset num_loops back to 1 +// +// 32 2/25/00 7:27p Markd +// Added useanim_numloop support and fixed useanim_orientation +// +// 31 2/24/00 3:17p Jimdose +// made UseAnims solid on client when not touchable +// added canBeUsed to UseAnim +// added canPush to PushObject +// +// 30 2/22/00 6:57p Jimdose +// pushobjects now do damage when blocked +// push objects are now solid_bsp +// +// 29 2/22/00 1:57p Jimdose +// added PushObject +// +// 28 2/14/00 5:43p Jimdose +// initialized dir in MonkeyBars and HorizontalPipe +// +// 27 2/02/00 7:14p Markd +// Added func_explodeobject and TossObject +// +// 26 1/31/00 4:26p Jimdose +// added dir variable to monkeybar and horizontalpipe +// +// 25 1/27/00 11:35a Markd +// Fixed solid/notsolid client side entities +// +// 24 1/22/00 12:42p Jimdose +// got rid of calls to vec3() +// added func_horizontalpipe +// +// 23 1/20/00 6:54p Aldie +// Removed bloodsplats until we do them the right way +// +// 22 1/19/00 7:46p Aldie +// Fixed func_spawns of various types and removed some unused misc classes +// +// 21 1/19/00 5:16p Markd +// Added thread and triggertarget to UseAnim +// +// 20 1/18/00 2:38p Markd +// Made UseAnim not multi-trigger by default +// +// 19 1/15/00 3:57p Markd +// Eliminated multiple "angle" events and replaced them with EV_SetAngle +// +// 18 1/15/00 1:36p Markd +// Added UseAnim and TouchUseAnim functionality to Player and game +// +// 17 1/14/00 5:07p Markd +// Removed surface num, tri_num and damage_multiplier from multiple functions +// and events +// +// 16 1/12/00 8:17p Markd +// Fixed teleporter code so that the camera cut occurred properly +// +// 15 1/12/00 6:15p Jimdose +// added base_velocity and random_velocity +// rewrote CreateExplosion +// +// 14 1/06/00 11:08p Jimdose +// cleaning up unused code +// +// 13 12/17/99 6:35p Jimdose +// changed spawnarg code +// added Level class for spawning and map control +// got rid of unused or superflous variables +// changed setjmp/longjmp calls to try/throw/catch exception handling +// +// 12 12/14/18 2:44p Jimdose +// added func_monkeybar +// +// 11 11/23/99 6:09p Markd +// fixed spawning entities which wouldn't fall automatically +// +// 10 11/08/99 10:43a Phook +// changed the color of func_group +// +// 9 11/04/99 10:03a Markd +// complete overhaul of the camera system +// +// 8 10/14/99 5:08p Markd +// removed a lot of G_GetMoveDir calls from the initialization code +// +// 7 10/07/99 3:00p Steven +// Event formatting. +// +// 6 9/29/99 5:18p Steven +// Event formatting. +// +// 5 9/23/99 7:30p Markd +// Added misc_model support and fixed shadows +// +// 4 9/22/99 4:48p Markd +// fixed more G_GetEntity, G_FindClass and G_GetNextEntity bugs +// +// 3 9/21/99 7:51p Markd +// Fixed a lot of entitynum_none issues +// +// 2 9/16/99 11:18a Markd +// Continuing merge of code, not functional yet but closer +// +// 1 9/10/99 10:54a Jimdose +// +// 1 9/08/99 3:16p Aldie +// +// 28 8/29/99 4:48p Markd +// Added back detail entity +// +// 27 8/28/99 3:26p Markd +// got rid of sv_maxbloodsplats +// +// 26 8/28/99 11:45a Steven +// Removed global from sound function calls. +// +// 25 8/18/99 3:28p Jimdose +// added cylindrical collision detection +// +// 24 7/08/99 4:56p Markd +// removed areaportal.h includes +// +// 23 7/08/99 4:28p Markd +// Removed obsolete QUAKED functions +// +// 22 6/11/99 2:20p Phook +// Renamed a few entities +// +// 21 6/11/99 1:23p Phook +// +// 20 6/11/99 12:58p Phook +// Changed from SINED comments to QUAKED +// +// 19 6/11/99 12:46p Phook +// EClass color changes +// +// DESCRIPTION: +// Basically the big stew pot of the DLLs, or maybe a garbage bin, whichever +// metaphore you prefer. This really should be cleaned up. Anyway, this +// should contain utility functions that could be used by any entity. +// Right now it contains everything from entities that could be in their +// own file to my mother's pot roast recipes. +// + +#include "g_local.h" +#include "entity.h" +#include "trigger.h" +#include "explosion.h" +#include "misc.h" +#include "navigate.h" +#include "specialfx.h" +#include "player.h" +#include "g_utils.h" +#include "weaputils.h" + +/*****************************************************************************/ +/*QUAKED detail (0.5 0 1.0) ? + +Used to fake detail brushes, convenient for grouping + +******************************************************************************/ + +/*****************************************************************************/ +/*QUAKED func_group (0.5 0.5 0.5) ? + +Used to group brushes together just for editor convenience. + +******************************************************************************/ + +/*****************************************************************************/ +/*QUAKED func_remove (0.75 0.75 0.75) ? + +Used for lighting and such + +******************************************************************************/ + +CLASS_DECLARATION( Entity, FuncRemove, "func_remove" ) + { + { NULL, NULL } + }; + +FuncRemove::FuncRemove() + { + PostEvent( EV_Remove, EV_REMOVE ); + } + +/*****************************************************************************/ +/*QUAKED misc_model (1 0.5 1) (0 0 0) (0 0 0) +"model" arbitrary .tik file to display +******************************************************************************/ + +CLASS_DECLARATION( Entity, MiscModel, "misc_model" ) + { + { NULL, NULL } + }; + +MiscModel::MiscModel() + { + PostEvent( EV_Remove, EV_REMOVE ); + } + + +/*****************************************************************************/ +/*QUAKED info_null (0 0.5 0) (-4 -4 -4) (4 4 4) + +Used as a positional target for spotlights, etc. + +******************************************************************************/ + +CLASS_DECLARATION( Entity, InfoNull, "info_null" ) + { + { NULL, NULL } + }; + +InfoNull::InfoNull() + { + PostEvent( EV_Remove, EV_REMOVE ); + } + +/*****************************************************************************/ +/*QUAKED info_notnull (0 0.5 0) (-4 -4 -4) (4 4 4) + +Used as a positional target for lightning. + +******************************************************************************/ + +CLASS_DECLARATION( Entity, InfoNotNull, "info_notnull" ) + { + { NULL, NULL } + }; + + + +/*****************************************************************************/ +/*QUAKED func_explodingwall (0 0.25 0.5) ? RANDOMANGLES LANDSHATTER NOT_PLAYERS MONSTERS PROJECTILES INVISIBLE ACCUMALATIVE TWOSTAGE + +Blows up on activation or when attacked + +"explosions" number of explosions to spawn ( default 1 ) +"land_angles" The angles you want this piece to\ + orient to when it lands on the ground +"land_radius" The distance of the ground the piece\ + should be when on the ground ( default 16 ) +"anglespeed" Speed at which pieces rotate ( default 100 ) \ + if RANDOMANGLES ( default is 600 ) +"key" The item needed to activate this. (default nothing) +"base_velocity" The speed that the debris will have when triggered. (default 0 0 280) +"random_velocity" The variation of the velocity. x & y will be from -n < X,Y < n and z is 0 <= Z < n. (default 140 140 140) + + +IF RANDOMANGLES is set, object randomly spins while in the air. +IF LANDSHATTER is set, object shatters when it hits the ground. +IF TWOSTAGE is set, object can be shattered once it lands on the ground. +IF ACCUMALATIVE is set, damage is accumlative not threshold +IF INVISIBLE is set, these are invisible and not solid until triggered +If NOT_PLAYERS is set, the trigger does not respond to players +If MONSTERS is set, the trigger will respond to monsters +If PROJECTILES is set, the trigger will respond to projectiles (rockets, grenades, etc.) + +******************************************************************************/ +#define RANDOMANGLES ( 1 << 0 ) +#define LANDSHATTER ( 1 << 1 ) +#define INVISIBLE ( 1 << 5 ) +#define ACCUMULATIVE ( 1 << 6 ) +#define TWOSTAGE ( 1 << 7 ) + +Event EV_ExplodingWall_StopRotating + ( + "stoprotating", + EV_DEFAULT, + NULL, + NULL, + "Stop rotating the wall." + ); +Event EV_ExplodingWall_OnGround + ( + "checkonground", + EV_DEFAULT, + NULL, + NULL, + "Check if exploding wall is on ground." + ); +Event EV_ExplodingWall_AngleSpeed + ( + "anglespeed", + EV_DEFAULT, + "f", + "speed", + "Set the angle speed." + ); +Event EV_ExplodingWall_LandRadius + ( + "land_radius", + EV_DEFAULT, + "f", + "radius", + "Set the land radius." + ); +Event EV_ExplodingWall_LandAngles + ( + "land_angles", + EV_DEFAULT, + "v", + "angles", + "Set the land angles." + ); +Event EV_ExplodingWall_BaseVelocity + ( + "base_velocity", + EV_DEFAULT, + "v", + "velocity", + "Set the base velocity." + ); +Event EV_ExplodingWall_RandomVelocity + ( + "random_velocity", + EV_DEFAULT, + "v", + "velocity", + "Set the amount of random variation of the base velocity." + ); +Event EV_ExplodingWall_SetDmg + ( + "dmg", + EV_DEFAULT, + "i", + "dmg", + "Set the damage from the exploding wall." + ); +Event EV_ExplodingWall_SetExplosions + ( + "explosions", + EV_DEFAULT, + "i", + "explosions", + "Set the number of explosions." + ); +Event EV_ExplodingWall_Setup + ( + "setup", + EV_HIDE, + NULL, + NULL, + "Initializes the exploding wall." + ); + +CLASS_DECLARATION( Trigger, ExplodingWall, "func_explodingwall" ) + { + { &EV_ExplodingWall_Setup, Setup }, + { &EV_Trigger_Effect, Explode }, + { &EV_Damage, DamageEvent }, + { &EV_Touch, TouchFunc }, + { &EV_ExplodingWall_StopRotating, StopRotating }, + { &EV_ExplodingWall_OnGround, CheckOnGround }, + { &EV_ExplodingWall_AngleSpeed, AngleSpeed }, + { &EV_ExplodingWall_LandRadius, LandRadius }, + { &EV_ExplodingWall_LandAngles, LandAngles }, + { &EV_ExplodingWall_BaseVelocity, BaseVelocity }, + { &EV_ExplodingWall_RandomVelocity, RandomVelocity }, + { &EV_ExplodingWall_SetDmg, SetDmg }, + { &EV_ExplodingWall_SetExplosions, SetExplosions }, + { NULL, NULL } + }; + +void ExplodingWall::AngleSpeed + ( + Event *ev + ) + + { + angle_speed = ev->GetFloat( 1 ); + } + +void ExplodingWall::LandRadius + ( + Event *ev + ) + + { + land_radius = ev->GetFloat( 1 ); + } + +void ExplodingWall::LandAngles + ( + Event *ev + ) + + { + land_angles = ev->GetVector( 1 ); + } + +void ExplodingWall::BaseVelocity + ( + Event *ev + ) + + { + base_velocity = ev->GetVector( 1 ); + } + +void ExplodingWall::RandomVelocity + ( + Event *ev + ) + + { + random_velocity = ev->GetVector( 1 ); + } + +void ExplodingWall::SetDmg + ( + Event *ev + ) + + { + dmg = ev->GetInteger( 1 ); + } + +void ExplodingWall::SetExplosions + ( + Event *ev + ) + + { + explosions = ev->GetInteger( 1 ); + } + +void ExplodingWall::Explode + ( + Event *ev + ) + + { + Entity *other; + Vector pos; + Vector mins, maxs; + int i; + + if ( spawnflags & INVISIBLE ) + { + showModel(); + setSolidType( SOLID_BSP ); + takedamage = DAMAGE_YES; + } + + if ( takedamage == DAMAGE_NO ) + { + return; + } + + other = ev->GetEntity( 1 ); + + health = 0; + takedamage = DAMAGE_NO; + + // Create explosions + for( i = 0; i < explosions; i++ ) + { + pos[ 0 ] = absmin[ 0 ] + G_Random( size[ 0 ] ); + pos[ 1 ] = absmin[ 1 ] + G_Random( size[ 1 ] ); + pos[ 2 ] = absmin[ 2 ] + G_Random( size[ 2 ] ); + + CreateExplosion( pos, dmg, this, other, this ); + } + + // throw itself + state = 1; + on_ground = false; + PostEvent( EV_ExplodingWall_OnGround, FRAMETIME ); + + velocity.x = base_velocity.x + G_CRandom( random_velocity.x ); + velocity.y = base_velocity.y + G_CRandom( random_velocity.y ); + velocity.z = base_velocity.z + G_Random( random_velocity.z ); + + setMoveType( MOVETYPE_BOUNCE ); + setSolidType( SOLID_BBOX ); + if ( spawnflags & RANDOMANGLES ) + { + avelocity[ 0 ] = G_Random( angle_speed ); + avelocity[ 1 ] = G_Random( angle_speed ); + avelocity[ 2 ] = G_Random( angle_speed ); + } + else + { + Vector delta; + float most; + float time; + int t; + + delta = land_angles - angles; + if ( delta[ 0 ] > 180 ) + delta[ 0 ] -= 360; + if ( delta[ 0 ] < -180 ) + delta[ 0 ] += 360; + if ( delta[ 1 ] > 180 ) + delta[ 1 ] -= 360; + if ( delta[ 1 ] < -180 ) + delta[ 1 ] += 360; + if ( delta[ 2 ] > 180 ) + delta[ 2 ] -= 360; + if ( delta[ 2 ] < -180 ) + delta[ 2 ] += 360; + most = MaxValue( delta ); + if ( !angle_speed ) + angle_speed = 1; + t = 10 * most / angle_speed; + time = (float)t / 10; + delta = delta * (1.0/time); + avelocity = delta; + PostEvent( EV_ExplodingWall_StopRotating, time ); + state = 2; + } + + ActivateTargets( ev ); + + if ( land_radius > 0 ) + { + mins[0] = mins[1] = mins[2] = -land_radius; + maxs[0] = maxs[1] = maxs[2] = land_radius; + setSize( mins, maxs ); + } + + attack_finished = 0; + } + +void ExplodingWall::DamageEvent + ( + Event *ev + ) + + { + Event *event; + Entity *inflictor; + Entity *attacker; + int damage; + + if ( takedamage == DAMAGE_NO ) + { + return; + } + + if ( on_ground ) + { + GroundDamage( ev ); + return; + } + + damage = ev->GetInteger( 1 ); + inflictor = ev->GetEntity( 2 ); + attacker = ev->GetEntity( 3 ); + + if ( spawnflags & ACCUMULATIVE ) + { + health -= damage; + if ( health > 0 ) + return; + } + else + { + if ( damage < health ) + { + return; + } + } + + event = new Event( EV_Activate ); + event->AddEntity( attacker ); + ProcessEvent( event ); + } + +void ExplodingWall::GroundDamage + ( + Event *ev + ) + + { + Entity *inflictor; + Entity *attacker; + Vector pos; + int damage; + + if ( takedamage == DAMAGE_NO ) + { + return; + } + + damage = ev->GetInteger( 1 ); + inflictor = ev->GetEntity( 2 ); + attacker = ev->GetEntity( 3 ); + + if ( spawnflags & ACCUMULATIVE ) + { + health -= damage; + if ( health > 0 ) + return; + } + else + { + if ( damage < health ) + { + return; + } + } + + if ( explosions ) + { + pos[ 0 ] = absmin[ 0 ] + G_Random( size[ 0 ] ); + pos[ 1 ] = absmin[ 1 ] + G_Random( size[ 1 ] ); + pos[ 2 ] = absmin[ 2 ] + G_Random( size[ 2 ] ); + + CreateExplosion( pos, damage, this, attacker, this ); + } + takedamage = DAMAGE_NO; + hideModel(); + BroadcastSound(); + PostEvent( EV_Remove, 0 ); + } + +void ExplodingWall::SetupSecondStage + ( + void + ) + + { + health = max_health; + takedamage = DAMAGE_YES; + } + +void ExplodingWall::StopRotating + ( + Event *ev + ) + + { + avelocity = vec_zero; + setAngles( land_angles ); + if ( spawnflags & TWOSTAGE ) + SetupSecondStage(); + } + +void ExplodingWall::CheckOnGround + ( + Event *ev + ) + + { + if ( ( velocity == vec_zero ) && groundentity ) + { + Vector delta; + float most; + float time; + int t; + + delta = land_angles - angles; + if ( delta.length() > 1 ) + { + if ( delta[ 0 ] > 180 ) + delta[ 0 ] -= 360; + if ( delta[ 0 ] < -180 ) + delta[ 0 ] += 360; + if ( delta[ 1 ] > 180 ) + delta[ 1 ] -= 360; + if ( delta[ 1 ] < -180 ) + delta[ 1 ] += 360; + if ( delta[ 2 ] > 180 ) + delta[ 2 ] -= 360; + if ( delta[ 2 ] < -180 ) + delta[ 2 ] += 360; + most = MaxValue( delta ); + if ( angle_speed > 3 ) + t = 10.0f * most / ( angle_speed / 3 ); + else + t = 10.0f * most; + time = (float)t / 10; + delta = delta * (1.0/time); + avelocity = delta; + PostEvent( EV_ExplodingWall_StopRotating, time ); + } + state = 2; + setSize( orig_mins, orig_maxs ); + on_ground = true; + } + else + PostEvent( ev, FRAMETIME ); + } + +void ExplodingWall::TouchFunc + ( + Event *ev + ) + + { + Entity *other; + + if ( ( velocity == vec_zero ) || ( level.time < attack_finished ) ) + { + return; + } + + other = ev->GetEntity( 1 ); + + if ( ( spawnflags & LANDSHATTER ) && ( other == world ) ) + { + Vector pos; + + takedamage = DAMAGE_NO; + + if ( explosions ) + { + pos[ 0 ] = absmin[ 0 ] + G_Random( size[ 0 ] ); + pos[ 1 ] = absmin[ 1 ] + G_Random( size[ 1 ] ); + pos[ 2 ] = absmin[ 2 ] + G_Random( size[ 2 ] ); + + CreateExplosion( pos, dmg, this, other, this ); + } + hideModel(); + BroadcastSound(); + PostEvent( EV_Remove, 0 ); + return; + } + + if ( other->takedamage ) + { + other->Damage( this, activator, dmg, origin, vec_zero, vec_zero, 20, 0, MOD_EXPLODEWALL ); + Sound( "debris_generic", CHAN_WEAPON ); + attack_finished = level.time + FRAMETIME; + } + } + +void ExplodingWall::Setup + ( + Event *ev + ) + + { + if ( spawnflags & INVISIBLE ) + { + if ( Targeted() ) + takedamage = DAMAGE_YES; + else + takedamage = DAMAGE_NO; + hideModel(); + setSolidType( SOLID_NOT ); + } + else + { + showModel(); + setSolidType( SOLID_BSP ); + takedamage = DAMAGE_YES; + } + + setMoveType( MOVETYPE_PUSH ); + setOrigin(); + } + +ExplodingWall::ExplodingWall() + { + if ( LoadingSavegame ) + { + return; + } + + health = 60; + max_health = health; + on_ground = false; + + state = 0; + angle_speed = ( spawnflags & RANDOMANGLES ) ? 600 : 100; + land_radius = 16; + dmg = 10; + explosions = 1; + + base_velocity = Vector( 0, 0, 280 ); + random_velocity = Vector( 140, 140, 140 ); + + orig_mins = mins; + orig_maxs = maxs; + + respondto = spawnflags ^ TRIGGER_PLAYERS; + + PostEvent( EV_ExplodingWall_Setup, EV_POSTSPAWN ); + } + +/*****************************************************************************/ +/*QUAKED trigger_teleport (0.5 0.5 0.5) ? VISIBLE x NOT_PLAYERS NOT_MONSTERS NOT_PROJECTILES NO_EFFECTS + +Touching this entity will teleport players to the targeted object. + +"key" The item needed to activate this. (default nothing) + +"teleportthread" The thread that is run when the player is teleported + +If NOT_PLAYERS is set, the teleporter does not teleport players +If NOT_MONSTERS is set, the teleporter does not teleport monsters +If NOT_PROJECTILES is set, the teleporter does not teleport projectiles (rockets, grenades, etc.) +If NO_EFFECTS is set, the special effect will not happen and the teleport will be instant + +******************************************************************************/ + +#define NO_EFFECTS ( 1 << 5 ) + +Event EV_Teleporter_Teleport + ( + "teleport", + EV_HIDE, + "e", + "entity", + "Teleports the entity to destination." + ); + +Event EV_Teleporter_StopTeleport + ( + "stopteleport", + EV_HIDE, + "e", + "entity", + "Releases the entity at the end of the teleport." + ); + +Event EV_Teleporter_SetThread + ( + "teleportthread", + EV_HIDE, + "s", + "thread_name", + "Sets the thread to run when the player is teleported." + ); + +CLASS_DECLARATION( Trigger, Teleporter, "trigger_teleport" ) + { + { &EV_Trigger_Effect, StartTeleport }, + { &EV_Teleporter_Teleport, Teleport }, + { &EV_Teleporter_StopTeleport, StopTeleport }, + { &EV_Teleporter_SetThread, SetThread }, + { NULL, NULL } + }; + +void Teleporter::SetThread + ( + Event *ev + ) + { + teleport_thread = ev->GetString( 1 ); + } + +void Teleporter::StartTeleport + ( + Event *ev + ) + { + Animate *fx; + Entity *other; + Event *event; + qboolean is_sentient; + Vector new_position; + + + if ( in_use ) + return; + + in_use = true; + + other = ev->GetEntity( 1 ); + + if ( !other ) + return; + + if ( spawnflags & NO_EFFECTS ) + { + event = new Event( EV_Teleporter_Teleport ); + event->AddEntity( other ); + ProcessEvent( event ); + return; + } + + if ( other->isSubclassOf( Sentient ) ) + is_sentient = true; + else + is_sentient = false; + + if ( is_sentient ) + { + new_position = origin; + new_position.z += mins.z; + other->setOrigin( new_position ); + other->NoLerpThisFrame(); + } + + // Create the teleport special effect + + fx = new Animate; + fx->setOrigin( other->origin ); + + if ( is_sentient ) + { + fx->setModel( "fx_bigteleport.tik" ); + //fx->Sound( "sound/environment/electric/singles/dimming.wav" ); + } + else + { + fx->setModel( "fx_teleport2.tik" ); + } + + fx->RandomAnimate( "idle", EV_Remove ); + + if ( is_sentient ) + { + // Freeze the entity that went into the teleporter + + other->flags |= FL_IMMOBILE; + other->takedamage = DAMAGE_NO; + } + + // Make the entity teleport + + event = new Event( EV_Teleporter_Teleport ); + event->AddEntity( other ); + + if ( is_sentient ) + PostEvent( event, 4 ); + else + PostEvent( event, 0 ); + + if ( is_sentient ) + { + other->PostEvent( EV_Hide, 2 ); + + /* if ( !( spawnflags & NO_EFFECTS ) ) + { + event = new Event( EV_Sound ); + event->AddString( "snd_teleport" ); + other->PostEvent( event, 2 ); + } */ + } + } + +void Teleporter::Teleport + ( + Event *ev + ) + + { + Entity *dest; + int i; + Entity *other; + Vector mid; + Animate *fx; + Event *event; + + other = ev->GetEntity( 1 ); + + if ( !other || ( other == world ) ) + return; + + dest = G_FindTarget( NULL, Target() ); + if ( !dest ) + { + warning( "Teleport", "Couldn't find destination\n" ); + return; + } + + assert( dest ); + + // unlink to make sure it can't possibly interfere with KillBox + other->unlink(); + + if ( other->isSubclassOf( Sentient ) ) + { + PathManager.Teleport( other, other->origin, dest->origin ); + other->origin = dest->origin + Vector( 0, 0, 1 ); + other->velocity = vec_zero; + } + else + { + mid = ( absmax - absmin ) * 0.5; + other->origin = dest->origin + Vector( 0, 0, 1 ); + other->origin += mid; + } + + // set angles + other->setAngles( dest->angles ); + + if ( other->client ) + { + client = other->client; + + // clear the velocity and hold them in place briefly + client->ps.pm_time = 100; + client->ps.pm_flags |= PMF_TIME_TELEPORT; + + // cut the camera on the client + ( ( Player * )other )->CameraCut(); + + for( i = 0; i < 3; i++ ) + { + client->ps.delta_angles[ i ] = ANGLE2SHORT( dest->angles[ i ] - client->cmd_angles[ i ] ); + } + + VectorCopy( angles, client->ps.viewangles ); + } + + if ( dest->isSubclassOf( TeleporterDestination ) ) + { + float len; + + len = other->velocity.length(); + // + // give them a bit of a push + // + if ( len < 400 ) + len = 400; + other->velocity = ( ( TeleporterDestination * )dest )->movedir * len; + } + + // kill anything at the destination + KillBox( other ); + + other->setOrigin( other->origin ); + other->origin.copyTo( other->edict->s.origin2 ); + + // Run the teleport thread if set + + if ( teleport_thread.length() && other->isSubclassOf( Player ) ) + { + if ( !ExecuteThread( teleport_thread.c_str() ) ) + warning( "RunThread", "could not process thread" ); + } + + // Skip effects if no_effects set + + if ( spawnflags & NO_EFFECTS ) + { + Event *event = new Event( EV_Teleporter_StopTeleport ); + event->AddEntity( other ); + ProcessEvent( event ); + return; + } + + // Spawn in effect + + fx = new Animate; + + fx->setOrigin( other->origin ); + + if ( other->isSubclassOf( Sentient ) ) + { + fx->setModel( "fx_bigteleport.tik" ); + //fx->Sound( "sound/environment/electric/singles/dimming.wav" ); + } + else + { + fx->setModel( "fx_teleport2.tik" ); + } + + fx->RandomAnimate( "idle", EV_Remove ); + + event = new Event( EV_Teleporter_StopTeleport ); + event->AddEntity( other ); + + if ( other->isSubclassOf( Sentient ) ) + PostEvent( event, 1.75 ); + else + PostEvent( event, FRAMETIME ); + } + +void Teleporter::StopTeleport + ( + Event *ev + ) + + { + Entity *other; + + other = ev->GetEntity( 1 ); + + if ( other->isSubclassOf( Sentient ) ) + { + other->flags &= ~FL_IMMOBILE; + other->takedamage = DAMAGE_AIM; + other->showModel(); + } + + //if ( !( spawnflags & NO_EFFECTS ) ) + // other->Sound( "snd_teleport" ); + + in_use = false; + } + +Teleporter::Teleporter() + { + if ( LoadingSavegame ) + { + return; + } + + if ( spawnflags & 1 ) + { + PostEvent( EV_Show, EV_POSTSPAWN ); + } + + //respondto = spawnflags ^ ( TRIGGER_PLAYERS | TRIGGER_MONSTERS | TRIGGER_PROJECTILES ); + respondto = spawnflags ^ ( TRIGGER_PLAYERS ); + + in_use = false; + + // Cache all needed stuff + + if ( !( spawnflags & NO_EFFECTS ) ) + { + CacheResource( "models/fx_bigteleport.tik", this ); + //CacheResource( "sound/environment/electric/singles/dimming.wav", this ); + CacheResource( "fx_teleport2.tik", this ); + //CacheResource( "snd_teleport", this ); + } + } + +/*****************************************************************************/ +/*QUAKED func_teleportdest (0 0.25 0.5) (-32 -32 0) (32 32 8) + +Point trigger_teleport at these. + +******************************************************************************/ + +CLASS_DECLARATION( Entity, TeleporterDestination, "func_teleportdest" ) + { + { &EV_SetAngle, SetMoveDir }, + { NULL, NULL } + }; + +TeleporterDestination::TeleporterDestination() + { + movedir = G_GetMovedir( 0 ); + } + +void TeleporterDestination::SetMoveDir + ( + Event *ev + ) + { + float angle; + + angle = ev->GetFloat( 1 ); + movedir = G_GetMovedir( angle ); + setAngles( movedir.toAngles() ); + } + +/*****************************************************************************/ +/*QUAKED func_useanim (0 0.5 0) ? VISIBLE TOUCHABLE CONTINUOUS + +This object allows you to place the player into a specific animation for the +purposes of using an object within the world. + +This object should point at a func_useanimdest which contains specific +information about how the player is supposed to be posed. + +"count" - how many times this should trigger (default -1, infinite) +"thread" - thread to fire when used +"triggertarget" - what to trigger when used. +"delay" - how long it takes to be re-triggered ( default 3 seconds ) +"key" - item needed to activate this + +VISIBLE - if this is checked the trigger itself will be visible +TOUCHABLE - if this is set we can activate the trigger by standing in it. +CONTINUOUS - if this is checked the thing will re-trigger continously, otherwise +it waits until the player has left the trigger field. + +******************************************************************************/ + +Event EV_UseAnim_Reset + ( + "_reset", + EV_HIDE, + NULL, + NULL, + "Reset's the Use Anim after it has no longer been touched." + ); + +Event EV_UseAnim_Thread + ( + "thread", + EV_DEFAULT, + "s", + "label", + "Sets which thread to use when this UseAnim is triggered." + ); + +Event EV_UseAnim_Count + ( + "count", + EV_DEFAULT, + "i", + "newCount", + "Sets how many times the UseAnim can be triggered." + ); + +Event EV_UseAnim_TriggerTarget + ( + "triggertarget", + EV_DEFAULT, + "s", + "targetname", + "Sets what should be triggered, when this UseAnim is triggered." + ); + +Event EV_UseAnim_SetAnim + ( + "anim", + EV_DEFAULT, + "s", + "animName", + "set the animation to use for player." + ); + +Event EV_UseAnim_SetKey + ( + "key", + EV_DEFAULT, + "s", + "keyName", + "set the key needed to make this UseAnim function." + ); + + +Event EV_UseAnim_SetState + ( + "state", + EV_CHEAT, + "s", + "stateName", + "set the state to use for the player." + ); + +Event EV_UseAnim_SetCamera + ( + "camera", + EV_DEFAULT, + "s", + "cameraPosition", + "set the camera to use when in this animation.\n" + "topdown, behind, front, side, behind_fixed, side_left, side_right" + ); + +Event EV_UseAnim_SetNumLoops + ( + "num_loops", + EV_DEFAULT, + "i", + "loopCount", + "set the number of times to loop an animation per use." + ); + +Event EV_UseAnim_SetDelay + ( + "delay", + EV_DEFAULT, + "f", + "delayTime", + "how long it takes for the UseAnim to be retriggered once you leave it." + ); + + +CLASS_DECLARATION( Entity, UseAnim, "func_useanim" ) + { + { &EV_Use, NULL }, + { &EV_Touch, Touched }, + { &EV_UseAnim_Reset, Reset }, + { &EV_UseAnim_Thread, SetThread }, + { &EV_UseAnim_TriggerTarget, SetTriggerTarget }, + { &EV_UseAnim_Count, SetCount }, + { &EV_UseAnim_SetAnim, SetAnim }, + { &EV_UseAnim_SetState, SetState }, + { &EV_UseAnim_SetKey, SetKey }, + { &EV_UseAnim_SetNumLoops, SetNumLoops }, + { &EV_UseAnim_SetCamera, SetCamera }, + { NULL, NULL } + }; + +UseAnim::UseAnim() + { + if ( LoadingSavegame ) + { + return; + } + + setMoveType( MOVETYPE_NONE ); + + anim = "stand_use"; + num_loops = 1; + hideModel(); + + // + // make it not solid unless we want it touchable + // + if ( !( spawnflags & 2 ) ) + { + setSolidType( SOLID_BBOX ); + setContents( CONTENTS_BODY ); + } + else + { + setSolidType( SOLID_TRIGGER ); + edict->svflags |= SVF_NOCLIENT; + } + + // by default this can activated infinitely + count = -1; + // clear out the triggertarget + triggertarget = ""; + // clear out the thread + thread = ""; + // set the default delay + delay = 3; + // initialize the last time the door was triggered + last_active_time = -delay; + // initially its not active + active = 0; + // set the default camera to be side view + camera = "behind"; + // + // only make it visible if so desired + // + if ( spawnflags & 1 ) + { + PostEvent( EV_Show, EV_POSTSPAWN ); + } + } + +void UseAnim::Touched + ( + Event *ev + ) + + { + Entity *other; + + if ( active && ( !( spawnflags & 4 ) ) ) + { + CancelEventsOfType( EV_UseAnim_Reset ); + PostEvent( EV_UseAnim_Reset, 0.25f ); + return; + } + + // don't retrigger to soon + if ( level.time < last_active_time ) + return; + + other = ev->GetEntity( 1 ); + if ( other->isSubclassOf( Player ) ) + { + ( ( Player * ) other )->TouchedUseAnim( this ); + } + } + +bool UseAnim::canBeUsed + ( + Entity * activator + ) + + { + Entity *dest; + + // if this is no longer usable, return false + if ( !count ) + { + return false; + } + + // don't retrigger to soon + if ( level.time < last_active_time ) + { + return false; + } + + if ( key.length() ) + { + if ( !activator->isSubclassOf( Sentient ) ) + { + return false; + } + if ( !( ( (Sentient *)activator )->HasItem( key.c_str() ) ) ) + { + qboolean setModel; + Item *item; + ClassDef *cls; + str dialog; + + cls = FindClass( key.c_str(), &setModel ); + if ( !cls || !checkInheritance( "Item", cls->classname ) ) + { + gi.DPrintf( "No item named '%s'\n", key.c_str() ); + return true; + } + item = ( Item * )cls->newInstance(); + if ( setModel ) + { + item->setModel( key.c_str() ); + } + item->CancelEventsOfType( EV_Item_DropToFloor ); + item->CancelEventsOfType( EV_Remove ); + item->ProcessPendingEvents(); + dialog = item->GetDialogNeeded(); + if ( dialog.length() > 0 ) + { + activator->Sound( dialog ); + } + else + { + gi.centerprintf ( activator->edict, "You need the %s", item->getName() ); + } + delete item; + + // don't retrigger for 5 seconds + last_active_time = level.time + 5; + return false; + } + else + { + return qtrue; + } + } + + if ( isSubclassOf( TouchAnim ) ) + { + return true; + } + + dest = G_FindTarget( NULL, Target() ); + if ( !dest || !dest->isSubclassOf( UseAnimDestination ) ) + { + warning( "UseAnim", "Couldn't find destination\n" ); + return false; + } + + return true; + } + +bool UseAnim::GetInformation + ( + Entity *activator, + Vector *org, + Vector *angles, + str *animation, + int *loopcount, + str *state, + str *camera + ) + + { + Entity *dest; + UseAnimDestination *uadest; + + // if this is no longer usable, return false + if ( !count ) + { + return false; + } + + dest = G_FindTarget( NULL, Target() ); + + if ( !dest || !dest->isSubclassOf( UseAnimDestination ) ) + { + // grab the information from this entity instead + // set the destination origin + *org = origin; + // set the destination angles + *angles = this->angles; + // set the desination animation + *animation = anim; + // set the number of loops + *loopcount = num_loops; + // get the state if necessary + *state = this->state; + // set the camera + *camera = this->camera; + } + else + { + uadest = ( UseAnimDestination * )dest; + + // set the destination origin + *org = uadest->origin; + // set the destination angles + *angles = uadest->angles; + // set the desination animation + *animation = uadest->GetAnim(); + // set the number of loops + *loopcount = uadest->GetNumLoops(); + // get the state if necessary + *state = uadest->GetState(); + // set the camera + *camera = this->camera; + } + + + // make this guy active + active = qtrue; + + // if this is a TouchAnim see if it is linked to another TouchAnim + if ( isSubclassOf( TouchAnim ) ) + { + dest = NULL; + do { + dest = G_FindTarget( dest, Target() ); + if ( dest ) + { + if ( dest->isSubclassOf( UseAnim ) ) + { + // make our linked UseAnim's active as well + ( ( UseAnim * )dest )->active = qtrue; + } + } + else + { + break; + } + } + while( 1 ); + } + // + // decrement the use + // + if ( count > 0 ) + { + count--; + } + + return true; + } + +void UseAnim::TriggerTargets + ( + Entity *activator + ) + + { + // + // fire off our trigger target if appropriate + // + if ( triggertarget.length() ) + { + Event *event; + Entity *ent; + + ent = NULL; + do + { + ent = G_FindTarget( ent, triggertarget.c_str() ); + if ( !ent ) + { + break; + } + event = new Event( EV_Activate ); + event->AddEntity( activator ); + ent->PostEvent( event, 0 ); + } + while ( 1 ); + } + + // + // fire off a thread if necessary + // + if ( thread.length() ) + { + if ( !ExecuteThread( thread ) ) + { + warning( "TriggerTargets", "Null game script" ); + } + } + } + +void UseAnim::Reset + ( + Event *ev + ) + + { + // + // find out if our triggertarget is of type door and only reset if the door is closed + // + if ( triggertarget.length() ) + { + Entity *ent; + + ent = NULL; + do + { + ent = G_FindTarget( ent, triggertarget.c_str() ); + if ( !ent ) + { + break; + } + if ( ent->isSubclassOf( Door ) ) + { + if ( !( ( Door * )ent )->isCompletelyClosed() ) + { + CancelEventsOfType( EV_UseAnim_Reset ); + PostEvent( EV_UseAnim_Reset, 0.25f ); + // + // wait for a little bit + // + return; + } + } + } + while ( 1 ); + } + + active = qfalse; + last_active_time = level.time + delay; + + // if this is a TouchAnim see if it is linked to another TouchAnim + if ( isSubclassOf( TouchAnim ) ) + { + Entity *dest; + + dest = NULL; + do { + dest = G_FindTarget( dest, Target() ); + if ( dest ) + { + if ( dest->isSubclassOf( UseAnim ) ) + { + // make our linked UseAnim's reset as well + ( ( UseAnim * )dest )->active = qfalse; + ( ( UseAnim * )dest )->last_active_time = level.time + delay; + } + } + else + { + break; + } + } + while( 1 ); + } + } + +void UseAnim::SetThread + ( + Event *ev + ) + + { + thread = ev->GetString( 1 ); + } + +void UseAnim::SetDelay + ( + Event *ev + ) + + { + delay = ev->GetFloat( 1 ); + } + +void UseAnim::SetTriggerTarget + ( + Event *ev + ) + + { + triggertarget = ev->GetString( 1 ); + } + +void UseAnim::SetCount + ( + Event *ev + ) + + { + count = ev->GetInteger( 1 ); + } + +void UseAnim::SetAnim + ( + Event *ev + ) + { + anim = ev->GetString( 1 ); + } + +void UseAnim::SetState + ( + Event *ev + ) + { + state = ev->GetString( 1 ); + } + +void UseAnim::SetKey + ( + Event *ev + ) + { + key = ev->GetString( 1 ); + } + +void UseAnim::SetCamera + ( + Event *ev + ) + { + camera = ev->GetString( 1 ); + } + +void UseAnim::SetNumLoops + ( + Event *ev + ) + { + num_loops = ev->GetInteger( 1 ); + } + + +CLASS_DECLARATION( UseAnim, TouchAnim, "func_touchanim" ) + { + { NULL, NULL } + }; + +TouchAnim::TouchAnim() + { + if ( LoadingSavegame ) + { + return; + } + + spawnflags |= 2; + + if ( spawnflags & 8 ) + { + setSize( "-32 -32 0", "32 32 96" ); + } + else + { + setSize( "-16 -16 0", "16 16 96" ); + } + + setSolidType( SOLID_TRIGGER ); + edict->svflags |= SVF_NOCLIENT; + } + +/*****************************************************************************/ +/* func_useanimdest (0 0.25 0.5) (0 0 0) (0 0 0) + +Point func_useanim's at these. + +The player will be lerped to this position and this orientation +and placed into the specified animation + +"anim" specifies the animation that the player should be in. +"state" instead of an animation, sets a state the player should go into +"camera" camera position to use when player is in animation +"num_loops" number of animation loops to play. + + +******************************************************************************/ + +CLASS_DECLARATION( Entity, UseAnimDestination, "func_useanimdest" ) + { + { &EV_UseAnim_SetAnim, SetAnim }, + { &EV_UseAnim_SetState, SetState }, + { &EV_UseAnim_SetNumLoops, SetNumLoops }, + { NULL, NULL } + }; + +UseAnimDestination::UseAnimDestination() + { + if ( LoadingSavegame ) + { + // Archive function will setup all necessary data + return; + } + // + // default animation to use + // + anim = "stand_use"; + num_loops = 1; + setSolidType( SOLID_NOT ); + hideModel(); + } + +void UseAnimDestination::SetAnim + ( + Event *ev + ) + { + anim = ev->GetString( 1 ); + } + +void UseAnimDestination::SetState + ( + Event *ev + ) + { + state = ev->GetString( 1 ); + } + +str UseAnimDestination::GetAnim + ( + void + ) + { + return anim; + } + +str UseAnimDestination::GetState + ( + void + ) + { + return state; + } + +void UseAnimDestination::SetNumLoops + ( + Event *ev + ) + { + num_loops = ev->GetInteger( 1 ); + } + +int UseAnimDestination::GetNumLoops + ( + void + ) + { + return num_loops; + } + +Event EV_UseObject_MoveThread + ( + "move_thread", + EV_DEFAULT, + "s", + "label", + "Sets which move thread to use when this UseObject has finshed looping." + ); + +Event EV_UseObject_StopThread + ( + "stop_thread", + EV_DEFAULT, + "s", + "label", + "Sets which stop thread to use when this UseObject is finished." + ); + +Event EV_UseObject_ResetThread + ( + "reset_thread", + EV_DEFAULT, + "s", + "label", + "Sets which thread to call when resetting." + ); + +Event EV_UseObject_Count + ( + "count", + EV_DEFAULT, + "i", + "newCount", + "Sets how many times the UseObject can be triggered." + ); + +Event EV_UseObject_Cone + ( + "cone", + EV_DEFAULT, + "f", + "newCone", + "Sets the cone in angles of where the Useobject can be used." + ); + +Event EV_UseObject_Offset + ( + "offset", + EV_DEFAULT, + "v", + "newOffset", + "Sets the offset to use for this UseObject." + ); + +Event EV_UseObject_YawOffset + ( + "yaw_offset", + EV_DEFAULT, + "f", + "newYawOffset", + "Sets the yaw offset to use for this UseObject." + ); + +Event EV_UseObject_State + ( + "state", + EV_DEFAULT, + "s", + "newState", + "Sets the state to use for this UseObject." + ); + +Event EV_UseObject_StateBackwards + ( + "state_backwards", + EV_DEFAULT, + "s", + "newState", + "Sets the backward state to use for this UseObject." + ); + +Event EV_UseObject_TriggerTarget + ( + "triggertarget", + EV_DEFAULT, + "s", + "targetname", + "Sets what should be triggered, when this UseObject is triggered." + ); + +Event EV_UseObject_ResetTime + ( + "reset_time", + EV_DEFAULT, + "f", + "newResetTime", + "Sets the time it takes for the UseObject to reset itself." + ); + +Event EV_UseObject_DamageType + ( + "damage_type", + EV_DEFAULT, + "s", + "newDamageType", + "Sets what kind of damage is needed to activate the trigger." + ); + +Event EV_UseObject_Reset + ( + "_useobject_reset", + EV_DEFAULT, + NULL, + NULL, + "Resets the useobject to the start state after a certain amount of time." + ); + +Event EV_UseObject_Resetting + ( + "_useobject_resetting", + EV_DEFAULT, + NULL, + NULL, + "Intermediate function for useobject reset." + ); + +Event EV_UseObject_DamageTriggered + ( + "_useobject_damagetriggered", + EV_DEFAULT, + "e", + "activator", + "Intermediate function for when the useobject was triggered by damage." + ); + +Event EV_UseObject_Activate + ( + "activate", + EV_DEFAULT, + NULL, + NULL, + "Allow the useobject to be used." + ); + +Event EV_UseObject_Deactivate + ( + "deactivate", + EV_DEFAULT, + NULL, + NULL, + "Do not allow the useobject to be used." + ); + +Event EV_UseObject_UseMaterial + ( + "usematerial", + EV_DEFAULT, + "s", + "nameOfUseMaterial", + "the name of the material that glows when active." + ); + +Event EV_UseObject_SetActiveState + ( + "_setactivestate", + EV_DEFAULT, + NULL, + NULL, + "event that sets up the proper skin for the useobject." + ); + + + +#define MULTI_STATE ( 1 << 0 ) + +/*****************************************************************************/ +/*QUAKED func_useobject (0 0.5 0) ? MULTI-STATE + +Allows you to setup a special object that places the player into a specific state +sequence. Primarily used for levers and cranks. + +Object starts out in the "start" animation, when used the following occurs: + +It is determined whether or not the player is in the right position to activate +the object, if it is, the player is moved to the exact offset and angle specified +by "offset" and "yaw_offset". The right position is determined by a dot product +with "offset" and "yaw_offset". The "cone" parameter controls the cone in which the +object can be triggered. Once the player is in the right position, the player is placed +into "state" and the "move" animation is played. Once the player animation ends, the +"move_thread" will be called. If the use button is continued to be held down and count +is not finite, the animation will be continued to be played until the use key is held +down. Once the use key is let go, the "stop" animation will be played on the lever and +the "stop_thread" will be called. + +"activate" - turns the useobject on +"deactivate" - turns the useobject off +"offset" - vector offset of where the player should stand +"state" - state to go into when used +"state_backwards" - what state to use when reversing the object +"yaw_offset" - what direction the player should be facing when using the object +"cone" - the cone in which the object can be used +"count" - how many times this should trigger (default -1, infinite) +"move_thread" - thread that is fired when the object has cycled one animation +"stop_thread" - thread that is fired when the object has finished animating +"reset_thread" - thread that is fired when the object is resetting itself +"reset_time" - the time it takes for the object to reset, (default 0, it doesn't) +"triggertarget" - target to trigger when finished animating, if reset_time is set, target +will be fired again when resetting +"damage_type" - if set, can be triggered by using a weapon to activate it. If set to "all", +any damage will activate it. + +MULTI-STATE - the object has two different states and must be used each time to set the state +when multi state is active, the reset_thread is called instead of stop_thread. All UseObjects +have two states on and off. When reset_time is set, the object will automatically return to the +off state after a preset amount of time. When multi-state is set this must be done manually. + +******************************************************************************/ + +CLASS_DECLARATION( Animate, UseObject, "func_useobject" ) + { + { &EV_Use, NULL }, + { &EV_UseObject_MoveThread, SetMoveThread }, + { &EV_UseObject_StopThread, SetStopThread }, + { &EV_UseObject_ResetThread, SetResetThread }, + { &EV_UseObject_TriggerTarget, SetTriggerTarget }, + { &EV_UseObject_Offset, SetOffset }, + { &EV_UseObject_YawOffset, SetYawOffset }, + { &EV_UseObject_Count, SetCount }, + { &EV_UseObject_Cone, SetCone }, + { &EV_UseObject_State, SetState }, + { &EV_UseObject_StateBackwards, SetBackwardsState }, + { &EV_UseObject_ResetTime, SetResetTime }, + { &EV_UseObject_Reset, Reset }, + { &EV_UseObject_DamageType, DamageType }, + { &EV_UseObject_Resetting, Resetting }, + { &EV_UseObject_DamageTriggered, DamageTriggered }, + { &EV_Damage, DamageFunc }, + { &EV_UseObject_Activate, ActivateEvent }, + { &EV_UseObject_Deactivate, DeactivateEvent }, + { &EV_UseObject_UseMaterial, UseMaterialEvent }, + { &EV_UseObject_SetActiveState, SetActiveState }, + { NULL, NULL } + }; + +UseObject::UseObject() + { + Event * e; + + if ( LoadingSavegame ) + { + // Archive function will setup all necessary data + return; + } + + setMoveType( MOVETYPE_NONE ); + setSolidType( SOLID_BBOX ); + setContents( CONTENTS_BODY ); + + // make sure the bounds get rotated with the object + flags |= FL_ROTATEDBOUNDS; + // by default this can activated infinitely + count = -1; + // clear out the triggertarget + triggertarget = ""; + // clear out the move thread + move_thread = ""; + // clear out the stop thread + stop_thread = ""; + // clear out the reset thread + reset_thread = ""; + // clear out the damage type, by default useobjects do not respond to damage + damage_type = MOD_NONE; + // turn on damage taking ability + takedamage = DAMAGE_YES; + // give it some health + health = 100; + // set the default yaw offset + yaw_offset = 0; + // set the cone + cone = cos( DEG2RAD( 90 ) ); + // set the state + state = ""; + // set the backwards state + state_backwards = ""; + // clear out the reset_time + reset_time = 0; + // clear out the object state + objectState = 0; + // the useobject is active by default + active = qtrue; + + // start off in the start animation + e = new Event( EV_Anim ); + e->AddString( "start" ); + PostEvent( e, 0 ); + PostEvent( EV_Show, 0 ); + // setup our skins once we are spawned + PostEvent( EV_UseObject_SetActiveState, 0 ); + + look_at_me = true; + } + +void UseObject::SetActiveState + ( + Event *ev + ) + { + if ( !useMaterial.length() ) + { + return; + } + + if ( active && count ) + { + SurfaceCommand( useMaterial.c_str(), "+skin1" ); + } + else + { + SurfaceCommand( useMaterial.c_str(), "-skin1" ); + } + if ( objectState ) + { + SurfaceCommand( useMaterial.c_str(), "+skin2" ); + } + else + { + SurfaceCommand( useMaterial.c_str(), "-skin2" ); + } + } + +void UseObject::SetMoveThread + ( + Event *ev + ) + + { + move_thread = ev->GetString( 1 ); + } + +void UseObject::SetStopThread + ( + Event *ev + ) + + { + stop_thread = ev->GetString( 1 ); + } + +void UseObject::SetResetThread + ( + Event *ev + ) + + { + reset_thread = ev->GetString( 1 ); + } + +void UseObject::ActivateEvent + ( + Event *ev + ) + + { + active = qtrue; + PostEvent( EV_UseObject_SetActiveState, 0 ); + } + +void UseObject::DeactivateEvent + ( + Event *ev + ) + + { + active = qfalse; + PostEvent( EV_UseObject_SetActiveState, 0 ); + } + +void UseObject::SetTriggerTarget + ( + Event *ev + ) + + { + triggertarget = ev->GetString( 1 ); + } + +void UseObject::SetOffset + ( + Event *ev + ) + + { + offset = ev->GetVector( 1 ); + } + +void UseObject::SetYawOffset + ( + Event *ev + ) + + { + yaw_offset = ev->GetFloat( 1 ); + } + +void UseObject::SetCount + ( + Event *ev + ) + + { + count = ev->GetInteger( 1 ); + } + +void UseObject::SetCone + ( + Event *ev + ) + + { + cone = cos( DEG2RAD( ev->GetFloat( 1 ) ) ); + } + +void UseObject::SetState + ( + Event *ev + ) + + { + state = ev->GetString( 1 ); + } + +void UseObject::SetBackwardsState + ( + Event *ev + ) + + { + state_backwards = ev->GetString( 1 ); + } + +void UseObject::UseMaterialEvent + ( + Event *ev + ) + + { + useMaterial = ev->GetString( 1 ); + } + +void UseObject::SetResetTime + ( + Event *ev + ) + + { + reset_time = ev->GetFloat( 1 ); + } + +void UseObject::Reset + ( + Event *ev + ) + + { + RandomAnimate( "move_backward", EV_UseObject_Resetting ); + } + +void UseObject::Resetting + ( + Event *ev + ) + + { + SetActiveState( NULL ); + RandomAnimate( "start" ); + + // reset the count + count = 1; + + // + // fire off our trigger target if appropriate + // + if ( triggertarget.length() ) + { + Event *event; + Entity *ent; + + ent = NULL; + do + { + ent = G_FindTarget( ent, triggertarget.c_str() ); + if ( !ent ) + { + break; + } + event = new Event( EV_Activate ); + event->AddEntity( this ); + ent->PostEvent( event, 0 ); + } + while ( 1 ); + } + + // + // fire off a thread if necessary + // + if ( reset_thread.length() ) + { + if ( !ExecuteThread( reset_thread ) ) + { + warning( "Resetting", "Null game script" ); + } + } + } + +bool UseObject::canBeUsed + ( + Vector org, + Vector dir + ) + + { + float dot; + Vector forward; + Vector diff; + Vector ang; + + // see if it is active + if ( !active ) + { + return false; + } + + // if this is no longer usable, return false + if ( !count ) + { + return false; + } + + // convert our yawoffset to a vector + ang = vec_zero; + ang[ YAW ] = angles[ YAW ] + yaw_offset; + ang.AngleVectors( &forward ); + dot = forward * dir; + if ( dot < cone ) + { + return false; + } + +/* + // convert our offset to a vector in worldspace + forward = getLocalVector( offset ); + forward.normalize(); + diff = org - origin; +// diff = origin - org; + diff.normalize(); + dot = forward * dir; + if ( dot < cone ) + { + return false; + } +*/ + + return true; + } + +void UseObject::DamageFunc + ( + Event *ev + ) + + { + Event *e; + Entity *attacker; + int mod; + + // if this is no longer usable, return false + if ( !count ) + { + return; + } + + // what kind of damage hit us + mod = ev->GetInteger( 9 ); + + // if we don't respond to any kind of damage, and our damage types do not match, return + if ( !MOD_matches( mod, damage_type ) ) + { + return; + } + + // get the attacker + attacker = ev->GetEntity( 3 ); + + // + // decrement the use + // + if ( count > 0 ) + { + count--; + } + // setup our damage triggered event + e = new Event( EV_UseObject_DamageTriggered ); + // add our attacker + e->AddEntity( attacker ); + // start up the object with our special event + Start( e ); + } + +void UseObject::DamageTriggered + ( + Event * ev + ) + + { + // grab the attacker from our event + Stop( ev->GetEntity( 1 ) ); + } + +void UseObject::Setup + ( + Entity *activator, + Vector *org, + Vector *ang, + str *newstate + ) + + { + if ( ( spawnflags & MULTI_STATE ) && objectState ) + { + *newstate = state_backwards; + } + else + { + *newstate = state; + } + + // convert our offset to a vector in worldspace + MatrixTransformVector( offset, orientation, *org ); + *org += origin; + + *ang = angles; + ang->y += yaw_offset; + + // + // decrement the use + // + if ( count > 0 ) + { + count--; + } + } + +void UseObject::Start + ( + Event * ev + ) + + { + // + // fire off the move_thread + // + if ( move_thread.length() ) + { + if ( !ExecuteThread( move_thread ) ) + { + warning( "Start", "Null game script" ); + } + } + + if ( ( spawnflags & MULTI_STATE ) && objectState ) + { + RandomAnimate( "move_backward", ev ); + } + else + { + RandomAnimate( "move", ev ); + } + SetActiveState( NULL ); + } + +bool UseObject::Loop + ( + void + ) + + { + if ( !count ) + return qfalse; + + return qtrue; + } + +void UseObject::Stop + ( + Entity *activator + ) + + { + if ( ( spawnflags & MULTI_STATE ) && objectState ) + { + RandomAnimate( "start" ); + } + else + { + RandomAnimate( "stop" ); + } + + // + // fire off our trigger target if appropriate + // + if ( triggertarget.length() ) + { + Event *event; + Entity *ent; + + ent = NULL; + do + { + ent = G_FindTarget( ent, triggertarget.c_str() ); + if ( !ent ) + { + break; + } + event = new Event( EV_Activate ); + event->AddEntity( activator ); + ent->PostEvent( event, 0 ); + } + while ( 1 ); + } + + // + // fire off a thread if necessary + // + if ( ( spawnflags & MULTI_STATE ) && objectState ) + { + if ( reset_thread.length() ) + { + if ( !ExecuteThread( reset_thread ) ) + { + warning( "Stop", "Null game script" ); + } + } + } + else + { + if ( stop_thread.length() ) + { + if ( !ExecuteThread( stop_thread ) ) + { + warning( "Stop", "Null game script" ); + } + } + } + + // toggle the state + objectState ^= 1; + + if ( reset_time ) + { + count = 0; + PostEvent( EV_UseObject_Reset, reset_time ); + } + + SetActiveState( NULL ); + } + +/*****************************************************************************/ +/*QUAKED info_waypoint (0 0.5 0) (-8 -8 -8) (8 8 8) + +Used as a positioning device for objects + +******************************************************************************/ + +CLASS_DECLARATION( Mover, Waypoint, "info_waypoint" ) + { + { NULL, NULL } + }; + + +/*****************************************************************************/ +/*QUAKED func_monkeybars (0.75 0.75 0.75) ? + +Monkey bars + +******************************************************************************/ + +CLASS_DECLARATION( Entity, MonkeyBars, "func_monkeybars" ) + { + { &EV_SetAngle, SetAngleEvent }, + { NULL, NULL } + }; + +MonkeyBars::MonkeyBars() + { + if ( LoadingSavegame ) + { + // Archive function will setup all necessary data + return; + } + setMoveType( MOVETYPE_NONE ); + setContents( CONTENTS_SHOOTABLE_ONLY | MASK_SOLID ); + PostEvent( EV_BecomeSolid, 0 ); + dir = 0; + } + +void MonkeyBars::SetAngleEvent + ( + Event *ev + ) + + { + dir = ev->GetFloat( 1 ); + } + +/*****************************************************************************/ +/*QUAKED func_horizontalpipe (0.75 0.75 0.75) ? + +Horizontal pipe that play can crawl upside down on. + +******************************************************************************/ + +CLASS_DECLARATION( Entity, HorizontalPipe, "func_horizontalpipe" ) + { + { &EV_SetAngle, SetAngleEvent }, + { NULL, NULL } + }; + +HorizontalPipe::HorizontalPipe() + { + if ( LoadingSavegame ) + { + // Archive function will setup all necessary data + return; + } + setMoveType( MOVETYPE_NONE ); + setContents( CONTENTS_SHOOTABLE_ONLY | MASK_SOLID ); + PostEvent( EV_BecomeSolid, 0 ); + dir = 0; + } + +void HorizontalPipe::SetAngleEvent + ( + Event *ev + ) + + { + dir = ev->GetFloat( 1 ); + } + +/*****************************************************************************/ +// TossObject +/*****************************************************************************/ + +Event EV_TossObject_SetBounceSound + ( + "bouncesound", + EV_DEFAULT, + "s", + "sound", + "When bouncing, what sound to play on impact" + ); + +Event EV_TossObject_SetBounceSoundChance + ( + "bouncesoundchance", + EV_DEFAULT, + "f[0,1]", + "chance", + "When bouncing, the chance that the bounce sound will be played" + ); + +CLASS_DECLARATION( Animate, TossObject, "TossObject" ) + { + { &EV_Touch, Touch }, + { &EV_Stop, Stop }, + { &EV_TossObject_SetBounceSound, SetBounceSound }, + { &EV_TossObject_SetBounceSoundChance, SetBounceSoundChance }, + { NULL, NULL } + }; + +TossObject::TossObject() + { + if ( LoadingSavegame ) + { + // Archive function will setup all necessary data + return; + } + setMoveType( MOVETYPE_GIB ); + setSolidType( SOLID_NOT ); + bouncesound = ""; + bouncesoundchance = 1.0f; + } + +TossObject::TossObject( str model ) + { + setMoveType( MOVETYPE_GIB ); + setSolidType( SOLID_NOT ); + bouncesound = ""; + bouncesoundchance = 1.0f; + setModel( model ); + } + +void TossObject::SetBounceSound + ( + str bounce + ) + + { + bouncesound = bounce; + } + +void TossObject::SetBounceSound + ( + Event *ev + ) + + { + bouncesound = ev->GetString( 1 ); + } + +void TossObject::SetBounceSoundChance + ( + float chance + ) + + { + bouncesoundchance = chance; + } + +void TossObject::SetBounceSoundChance + ( + Event *ev + ) + + { + bouncesoundchance = ev->GetFloat( 1 ); + } + +void TossObject::Stop + ( + Event *ev + ) + + { + setMoveType( MOVETYPE_NONE ); + setSolidType( SOLID_NOT ); + // cancel the previous fade out command + CancelEventsOfType( EV_FadeOut ); + PostEvent( EV_FadeOut, 7 + G_Random( 5 ) ); + setAngles( "0 0 0" ); + RandomAnimate( "landed" ); + } + +void TossObject::Touch + ( + Event *ev + ) + + { + Entity * ent; + + ent = ev->GetEntity( 1 ); + + // only touch the world + if ( !ent || ( ent != world ) ) + { + return; + } + // + // every time we bounce try to go back to our nominal angles + // + setAngles( angles * 0.5f ); + + if ( bouncesound.length() ) + { + if ( G_Random( 1 ) < bouncesoundchance ) + { + Sound( bouncesound ); + } + } + } + +void TossObject::SetVelocity + ( + float severity + ) + + { + setSolidType( SOLID_BBOX ); + velocity[0] = 100.0 * crandom(); + velocity[1] = 100.0 * crandom(); + velocity[2] = 200.0 + 100.0 * random(); + + avelocity = Vector( G_Random( 600 ), G_Random( 600 ), G_Random( 600 ) ); + + velocity *= severity; + + if (velocity[0] < -400) + velocity[0] = -400; + else if (velocity[0] > 400) + velocity[0] = 400; + if (velocity[1] < -400) + velocity[1] = -400; + else if (velocity[1] > 400) + velocity[1] = 400; + if (velocity[2] < 200) + velocity[2] = 200; // always some upwards + else if (velocity[2] > 600) + velocity[2] = 600; + RandomAnimate( "idle" ); + // we give it 8 seconds to fall, if not it will get faded out + PostEvent( EV_FadeOut, 8 ); + } + +/*****************************************************************************/ +/*QUAKED func_pushobject (0.75 0.75 0.75) ? + +Pushable object + +"dmg" how much damage to cause when blocked. (default 2) +"pushsound" Sound to play when object is pushed (default is none) + +******************************************************************************/ + +Event EV_PushObject_Start + ( + "start", + EV_DEFAULT, + NULL, + NULL, + "Sets up the pushobject." + ); + +Event EV_PushObject_SetDamage + ( + "dmg", + EV_DEFAULT, + "i", + "damage", + "Set the damage." + ); + +Event EV_PushObject_SetPushSound + ( + "pushsound", + EV_DEFAULT, + "s", + "sound", + "Set the pushing sound" + ); + +CLASS_DECLARATION( Entity, PushObject, "func_pushobject" ) + { + { &EV_PushObject_Start, Start }, + { &EV_Blocked, BlockFunc }, + { &EV_PushObject_SetDamage, SetDamage }, + { &EV_PushObject_SetPushSound, SetPushSound }, + { NULL, NULL } + }; + +PushObject::PushObject() + { + if ( LoadingSavegame ) + { + // Archive function will setup all necessary data + return; + } + dmg = 2; + attack_finished = 0; + + pushsound = "object_slide"; + + PostEvent( EV_PushObject_Start, EV_POSTSPAWN ); + } + +void PushObject::SetPushSound + ( + Event *ev + ) + + { + pushsound = ev->GetString( 1 ); + } + +void PushObject::Start + ( + Event *ev + ) + + { + // make sure that this touches triggers + flags |= FL_TOUCH_TRIGGERS; + edict->clipmask = MASK_SOLID; + setSolidType( SOLID_BSP ); + setMoveType( MOVETYPE_PUSH ); + + // fix the bounding box so that the object isn't stuck in the ground + setSize( mins + Vector( 1, 1, 2 ), maxs - Vector( 1, 1, 1 ) ); + } + +qboolean PushObject::canPush + ( + Vector dir + ) + + { + trace_t trace; + + Vector end( origin.x + dir.x, origin.y + dir.y, origin.z ); + + trace = G_Trace( origin, mins, maxs, end, this, MASK_DEADSOLID, false, "PushObject::Push" ); + return ( !trace.startsolid && ( trace.fraction == 1.0f ) ); + } + +qboolean PushObject::Push + ( + Entity *pusher, + Vector move + ) + + { + trace_t trace; + + if ( pushsound.length() ) + { + if ( !edict->s.loopSound ) + { + LoopSound( pushsound ); + PostEvent( EV_StopLoopSound, level.frametime * 5 ); + } + } + + Vector end( origin.x + move.x, origin.y + move.y, origin.z ); + + trace = G_Trace( origin, mins, maxs, end, this, MASK_DEADSOLID, false, "PushObject::Push" ); + if ( !trace.startsolid && ( trace.fraction > 0 ) ) + { + owner = pusher; + + G_PushMove( this, trace.endpos - origin, vec_zero ); + + if ( edict->s.loopSound ) + PostponeEvent( EV_StopLoopSound, level.frametime ); + + return qtrue; + } + + return qfalse; + } + +Entity *PushObject::getOwner + ( + void + ) + + { + return ( Entity * )owner; + } + +void PushObject::BlockFunc + ( + Event *ev + ) + + { + Entity *other; + + if ( ( dmg != 0 ) && ( level.time >= attack_finished ) ) + { + attack_finished = level.time + 0.5f; + other = ev->GetEntity( 1 ); + if ( other != owner ) + { + other->Damage( this, this, dmg, origin, vec_zero, vec_zero, 0, 0, MOD_CRUSH ); + } + } + } + +void PushObject::SetDamage + ( + Event *ev + ) + + { + dmg = ev->GetInteger( 1 ); + } + +#define SPAWN_AUTO_RESET ( 1 << 0 ) +#define NO_RANDOMNESS ( 1 << 1 ) +#define REMOVE_ON_GROUND ( 1 << 2 ) +/*****************************************************************************/ +/*QUAKED func_fallingrock (0.75 0.75 0.75) ? AUTO_RESET NO_RANDOMNESS REMOVE_ON_GROUND + +Creates a rock that, when triggered, begins falling and bounces along a path +specified by targetname. Use info_waypoint for the path. + +"targetname" the path to follow. +"dmg" how much damage to cause creatures it hits (default 20). +"speed" how fast to move (default 200). +"wait" how long to wait before falling when triggered (default 0). +"noise" sound to play when rock touches the world + +AUTO_RESET - when done falling, automatically return to the start +NO_RANDOMNESS - don't use any randomness when making the rocks fall +REMOVE_ON_GROUND - remove the rocks when done + +******************************************************************************/ + +Event EV_FallingRock_Bounce + ( + "bounce", + EV_DEFAULT, + NULL, + NULL, + "sent to entity when touched." + ); + +Event EV_FallingRock_Rotate + ( + "rotate", + EV_DEFAULT, + NULL, + NULL, + "rotates the falling rock." + ); + +Event EV_FallingRock_SetWait + ( + "wait", + EV_DEFAULT, + "f", + "wait", + "How long to wait before rock starts falling." + ); + +Event EV_FallingRock_Start + ( + "start", + EV_DEFAULT, + NULL, + NULL, + "Starts rock falling." + ); + +Event EV_FallingRock_SetDmg + ( + "dmg", + EV_DEFAULT, + "i", + "dmg", + "Set the damage from the rock." + ); + +Event EV_FallingRock_SetSpeed + ( + "speed", + EV_DEFAULT, + "f", + "speed", + "Set the speed that the rock moves at." + ); + +Event EV_FallingRock_SetBounceSound + ( + "noise", + EV_DEFAULT, + "s", + "sound", + "Set the sound to play when the rock bounces" + ); + +CLASS_DECLARATION( Entity, FallingRock, "func_fallingrock" ) + { + { &EV_Activate, Activate }, + { &EV_Touch, Touch }, + { &EV_FallingRock_Bounce, Bounce }, + { &EV_FallingRock_Rotate, Rotate }, + { &EV_FallingRock_Start, StartFalling }, + { &EV_FallingRock_SetWait, SetWait }, + { &EV_FallingRock_SetSpeed, SetSpeed }, + { &EV_FallingRock_SetDmg, SetDmg }, + { &EV_FallingRock_SetBounceSound, SetBounceSound }, + { NULL, NULL } + }; + +FallingRock::FallingRock() + { + if ( LoadingSavegame ) + { + // Archive function will setup all necessary data + return; + } + active = 0; + current = NULL; + setMoveType( MOVETYPE_NONE ); + wait = 0; + dmg = 20; + speed = 200; + activator = NULL; + attack_finished = 0; + + SetBounceSound( "impact_rock" ); + } + +Entity *FallingRock::SetNextBounceDir + ( + void + ) + + { + Entity *ent; + + if ( !current->target.length() ) + { + return NULL; + } + + ent = G_FindTarget( NULL, current->target.c_str() ); + if ( !ent ) + { + gi.Error( ERR_DROP, "FallingRock :: Entity with targetname of '%s' not found", current->target.c_str() ); + } + + bounce_dir = ent->origin - current->origin; + bounce_dir.normalize(); + + return ent; + } + + +void FallingRock::NextBounce + ( + void + ) + + { + float time; + float distance; + Vector delta, xydelta; + float xy_speed; + float vertical_speed; + + delta = current->origin - origin; + xydelta = delta; + xydelta.z = 0; + xy_speed = speed; + + distance = xydelta.normalize(); + + time = distance / xy_speed; + + if ( !( spawnflags & NO_RANDOMNESS ) ) + { + if ( time > 1.0f ) + { + time = 0.75f + G_Random( 1 ); + } + + if ( time < 0.4f ) + { + time = 0.4f; + } + } + + vertical_speed = ( delta.z / time ) + ( 0.5f * gravity * sv_gravity->value * time ); + if ( vertical_speed < 0 ) + { + vertical_speed = 0; + } + + velocity = xydelta * xy_speed; + velocity.z = vertical_speed; + + Vector ang( 0, vectoyaw( delta ), 0 ); + ang.AngleVectors( NULL, &rotateaxis ); + + // make sure it leaves the ground + groundentity = NULL; + } + +void FallingRock::Rotate + ( + Event *ev + ) + + { + float mat[ 3 ][ 3 ]; + float ang; + + ang = 360.0f * FRAMETIME; + RotatePointAroundVector( mat[ 0 ], rotateaxis, orientation[ 0 ], ang ); + RotatePointAroundVector( mat[ 1 ], rotateaxis, orientation[ 1 ], ang ); + RotatePointAroundVector( mat[ 2 ], rotateaxis, orientation[ 2 ], ang ); + MatrixToEulerAngles( mat, angles ); + setAngles( angles ); + + if ( velocity != vec_zero ) + { + PostEvent( EV_FallingRock_Rotate, FRAMETIME ); + } + } + +void FallingRock::SetWait + ( + Event *ev + ) + + { + wait = ev->GetFloat( 1 ); + } + +void FallingRock::SetSpeed + ( + Event *ev + ) + + { + speed = ev->GetFloat( 1 ); + } + +void FallingRock::SetDmg + ( + Event *ev + ) + + { + dmg = ev->GetInteger( 1 ); + } + +void FallingRock::SetBounceSound + ( + str sound + ) + + { + bouncesound = sound; + // cache the sound in + CacheResource( bouncesound.c_str(), this ); + } + +void FallingRock::SetBounceSound + ( + Event *ev + ) + + { + SetBounceSound( ev->GetString( 1 ) ); + } + +void FallingRock::Activate + ( + Event *ev + ) + + { + if ( active == 1 ) + return; + + if ( ( active == 2 ) && ( spawnflags & SPAWN_AUTO_RESET ) ) + { + current = NULL; + activator = NULL; + setMoveType( MOVETYPE_NONE ); + NoLerpThisFrame(); + setOrigin( start_origin ); + } + + activator = ev->GetEntity( 1 ); + + if ( wait ) + { + PostEvent( EV_FallingRock_Start, wait ); + } + else + { + ProcessEvent( EV_FallingRock_Start ); + } + } + +void FallingRock::StartFalling + ( + Event *ev + ) + + { + if ( current ) + { + return; + } + + if ( !active ) + { + start_origin = origin; + } + + active = 1; + setMoveType( MOVETYPE_BOUNCE ); + setSolidType( SOLID_BBOX ); + PostEvent( EV_FallingRock_Rotate, FRAMETIME ); + edict->clipmask = MASK_SOLID|CONTENTS_BODY; + + last_bounce_origin = origin; + current = this; + current = SetNextBounceDir(); + if ( current ) + { + NextBounce(); + } + } + +void FallingRock::Touch + ( + Event *ev + ) + + { + Entity *other; + + other = ev->GetEntity( 1 ); + + if ( other != world ) + { + if ( ( velocity != vec_zero ) && ( other->takedamage ) && ( level.time >= attack_finished ) ) + { + other->Damage( this, activator, dmg, origin, vec_zero, vec_zero, 20, 0, MOD_THROWNOBJECT ); + attack_finished = level.time + FRAMETIME; + } + } + + if ( !current || ( other != world ) ) + { + return; + } + if ( bouncesound.length() ) + { + Vector delta( origin - last_bounce_origin ); + + if ( delta.length() > 8 ) + { + last_bounce_origin = origin; + Sound( bouncesound.c_str(), CHAN_VOICE ); + } + } + + // we have to wait to set the velocity since the physics code + // will modify it when we return. + PostEvent( EV_FallingRock_Bounce, 0 ); + } + +void FallingRock::Bounce + ( + Event *ev + ) + + { + Vector delta; + + if ( !current ) + { + return; + } + + do + { + // check if we've passed the waypoint + delta = origin - current->origin; + if ( ( delta * bounce_dir ) >= ( -2 * edict->radius ) ) + { + // call any threads on the current waypoint + if ( current->isSubclassOf( Trigger ) ) + { + current->ProcessEvent( EV_Trigger_StartThread ); + } + current = SetNextBounceDir(); + if ( !current ) + { + velocity = vec_zero; + if ( spawnflags & SPAWN_AUTO_RESET ) + { + active = 2; + } + else if ( spawnflags & REMOVE_ON_GROUND ) + { + PostEvent( EV_Remove, 0 ); + } + break; + } + } + else + { + NextBounce(); + break; + } + } + while( 1 ); + } + + + +/*****************************************************************************/ +/*QUAKED func_supplywater (0.75 0.75 0.75) ? x x NOT_PLAYERS MONSTERS PROJECTILES + +Creates a trigger than when touched gives the player water over a continuous time + +"wait" - how long to wait before re-triggering ( default 0.1 seconds ) +"amount" - how much water to give player on each trigger ( default 1 unit ) +"maxwater" - what the maximum amount of water this supply should charge the player to ( default 50 ) + +If NOT_PLAYERS is set, the trigger does not respond to players +If MONSTERS is set, the trigger will respond to monsters +If PROJECTILES is set, the trigger will respond to projectiles (rockets, grenades, etc.) + +******************************************************************************/ + +Event EV_SupplyWater_MaxWater + ( + "maxwater", + EV_DEFAULT, + "f", + "wait", + "How long to wait before rock starts falling." + ); + +Event EV_SupplyWater_ChargeOff + ( + "_chargeoff", + EV_DEFAULT, + NULL, + NULL, + "Turn charging sound off and ambient sound back on." + ); + +CLASS_DECLARATION( Trigger, SupplyWater, "func_supplywater" ) + { + { &EV_Trigger_Effect, Activate }, + { &EV_SupplyWater_MaxWater, MaxWater }, + { &EV_SupplyWater_ChargeOff, ChargeOff }, + { NULL, NULL } + }; + +SupplyWater::SupplyWater + ( + ) + + { + str realname; + + if ( LoadingSavegame ) + { + // Archive function will setup all necessary data + return; + } + wait = 0.1f; + amount = 1; + maxwater = 50; + + // + // turn our sound on once we spawn + // + PostEvent( EV_SupplyWater_ChargeOff, FRAMETIME ); + + // + // this is here so that it gets sent over for the ambients + // + PostEvent( EV_Show, EV_POSTSPAWN ); + } + +void SupplyWater::MaxWater + ( + Event *ev + ) + + { + maxwater = ev->GetInteger( 1 ); + } + +void SupplyWater::ChargeOff + ( + Event *ev + ) + + { + LoopSound( "snd_edenwater_ambient" ); + } + +void SupplyWater::Activate + ( + Event *ev + ) + + { + Entity *ent; + + ent = ev->GetEntity( 1 ); + + if ( ent->isSubclassOf( Player ) ) + { + Player *player = ( Player * )ent; + + if ( player->GetWaterPower() < maxwater ) + { + player->SetWaterPower( player->GetWaterPower() + this->amount ); + if ( EventPending( EV_SupplyWater_ChargeOff ) ) + { + CancelEventsOfType( EV_SupplyWater_ChargeOff ); + } + else + { + LoopSound( "snd_edenwater_charge" ); + } + PostEvent( EV_SupplyWater_ChargeOff, wait * 2 ); + } + } + } + + diff --git a/source/source/fgame/misc.h b/source/source/fgame/misc.h new file mode 100644 index 0000000..8674b7b --- /dev/null +++ b/source/source/fgame/misc.h @@ -0,0 +1,710 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/misc.h $ +// $Revision:: 50 $ +// $Author:: Markd $ +// $Date:: 7/27/00 6:31p $ +// +// Copyright (C) 1997 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source is may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/misc.h $ +// +// 50 7/27/00 6:31p Markd +// made useAnim's work with doors, added key ability +// +// 49 7/17/00 4:58p Markd +// fixed useobjects and skins +// +// 48 7/14/00 11:45p Markd +// Added ambient sounds to func_supllywater +// +// 47 7/11/00 9:28p Markd +// Added MaxWater event to func_watersupply +// +// 46 7/10/00 11:54p Markd +// added exit level code +// +// 45 7/07/00 4:32p Steven +// Teleporter stuff : no_effects flag, warp sentient to middle of teleporter +// and fixed some teleporting multiple times problems. +// +// 44 7/06/00 6:25p Steven +// Added new teleport stuff. +// +// 43 6/28/00 4:17p Markd +// fixed small UseAnim bug +// +// 42 6/23/00 8:41p Markd +// made a lot of changes to different constructors for saved game support +// +// 41 6/09/00 7:36p Markd +// Added activate and deactive to useobjects +// +// 40 6/07/00 5:36p Markd +// fixed falling rock code +// +// 39 6/04/00 6:52p Markd +// Added camera support to TouchAnim's cleaned up player camera interface +// +// 38 6/04/00 6:16p Markd +// Added TouchAnim support +// +// 37 5/26/00 7:44p Markd +// 2nd phase save games +// +// 36 5/24/00 3:14p Markd +// first phase of save/load games +// +// 35 4/21/00 6:16p Markd +// Fixed bounce sound stuff +// +// 34 4/19/00 9:25a Markd +// added bouncesound to falling rock code +// +// 33 4/06/00 5:45p Aldie +// Added func_supplywater +// +// 32 4/05/00 12:20p Markd +// added damage type +// +// 31 4/04/00 5:30p Markd +// Removed sounds from UseObject +// +// 30 3/31/00 6:07p Markd +// improved the functionality of UseObjects +// +// 29 3/31/00 3:19p Markd +// Added UseObject functionality +// +// 28 3/27/00 4:16p Markd +// added state to the UseAnim headers +// +// 27 3/21/00 5:05p Markd +// Added state variable to func_useanim_destination +// +// 26 3/20/00 3:01p Markd +// added more functionality to falling rock +// +// 25 3/18/00 2:43p Aldie +// Changed some func_spawn functionality +// +// 24 3/16/00 10:20a Markd +// fixed useanim firing its targets before the animation was completed +// +// 23 3/15/00 5:52p Aldie +// Added pushsound to func_pushobject and removed a printf. +// +// 22 3/13/00 7:46p Jimdose +// added fallingrock +// +// 21 3/01/00 11:25a Jimdose +// UseAnim now sends the entity that used it as the activator instead of itself +// when triggering targets +// +// 20 2/25/00 7:27p Markd +// Added useanim_numloop support and fixed useanim_orientation +// +// 19 2/24/00 3:17p Jimdose +// added canBeUsed to UseAnim +// added canPush to PushObject +// +// 18 2/22/00 6:57p Jimdose +// pushobjects now do damage when blocked +// push objects are now solid_bsp +// +// 17 2/22/00 1:57p Jimdose +// added PushObject +// +// 16 2/02/00 7:14p Markd +// Added func_explodeobject and TossObject +// +// 15 1/31/00 4:25p Jimdose +// added dir variable to monkeybar and horizontalpipe +// +// 14 1/22/00 12:42p Jimdose +// added HorizontalPipe +// +// 13 1/20/00 6:54p Aldie +// Removed bloodsplats until we do them the right way +// +// 12 1/19/00 7:46p Aldie +// Fixed func_spawns of various types and removed some unused misc classes +// +// 11 1/19/00 5:16p Markd +// Added thread and triggertarget to UseAnim +// +// 10 1/18/00 2:38p Markd +// Made UseAnim not multi-trigger by default +// +// 9 1/15/00 3:57p Markd +// Eliminated multiple "angle" events and replaced them with EV_SetAngle +// +// 8 1/15/00 1:36p Markd +// Added UseAnim and TouchUseAnim functionality to Player and game +// +// 7 1/12/00 6:13p Jimdose +// added base_velocity and random_velocity +// +// 6 1/06/00 11:08p Jimdose +// cleaning up unused code +// +// 5 12/14/18 2:44p Jimdose +// added func_monkeybar +// +// 4 11/04/99 10:03a Markd +// complete overhaul of the camera system +// +// 3 10/14/99 5:08p Markd +// removed a lot of G_GetMoveDir calls from the initialization code +// +// 2 9/23/99 7:30p Markd +// Added misc_model support and fixed shadows +// +// 1 9/10/99 10:54a Jimdose +// +// 1 9/08/99 3:16p Aldie +// +// 7 7/08/99 4:28p Markd +// Removed obsolete QUAKED functions +// +// DESCRIPTION: +// Basically the big stew pot of the DLLs, or maybe a garbage bin, whichever +// metaphore you prefer. This really should be cleaned up. Anyway, this +// should contain utility functions that could be used by any entity. +// Right now it contains everything from entities that could be in their +// own file to my mother pot roast recipes. +// + +#ifndef __MISC_H__ +#define __MISC_H__ + +#include "g_local.h" +#include "entity.h" +#include "mover.h" +#include "animate.h" + +class InfoNull : public Entity + { + public: + CLASS_PROTOTYPE( InfoNull ); + + InfoNull(); + }; + +class FuncRemove : public Entity + { + public: + CLASS_PROTOTYPE( FuncRemove ); + + FuncRemove(); + }; + +class MiscModel : public Entity + { + public: + CLASS_PROTOTYPE( MiscModel ); + + MiscModel(); + }; + +class InfoNotNull : public Entity + { + public: + CLASS_PROTOTYPE( InfoNotNull ); + }; + +class ExplodingWall : public Trigger + { + protected: + int dmg; + int explosions; + float attack_finished; + Vector land_angles; + float land_radius; + float angle_speed; + int state; + Vector base_velocity; + Vector random_velocity; + Vector orig_mins, orig_maxs; + qboolean on_ground; + + public: + CLASS_PROTOTYPE( ExplodingWall ); + + ExplodingWall(); + void Setup( Event *ev ); + void AngleSpeed( Event *ev ); + void LandRadius( Event *ev ); + void LandAngles( Event *ev ); + void BaseVelocity( Event *ev ); + void RandomVelocity( Event *ev ); + void SetDmg( Event *ev ); + void SetExplosions( Event *ev ); + void SetupSecondStage( void ); + void Explode( Event *ev ); + void DamageEvent( Event *ev ); + void GroundDamage( Event *ev ); + void TouchFunc( Event *ev ); + void StopRotating( Event *ev ); + void CheckOnGround( Event *ev ); + void Archive( Archiver &arc ); + }; + +inline void ExplodingWall::Archive + ( + Archiver &arc + ) + { + Trigger::Archive( arc ); + + arc.ArchiveInteger( &dmg ); + arc.ArchiveInteger( &explosions ); + arc.ArchiveFloat( &attack_finished ); + arc.ArchiveVector( &land_angles ); + arc.ArchiveFloat( &land_radius ); + arc.ArchiveFloat( &angle_speed ); + arc.ArchiveInteger( &state ); + arc.ArchiveVector( &base_velocity ); + arc.ArchiveVector( &random_velocity ); + arc.ArchiveVector( &orig_mins ); + arc.ArchiveVector( &orig_maxs ); + arc.ArchiveBoolean( &on_ground ); + } + + +class Teleporter : public Trigger + { + public: + str teleport_thread; + qboolean in_use; + + CLASS_PROTOTYPE( Teleporter ); + + Teleporter(); + virtual void StartTeleport( Event *ev ); + virtual void Teleport( Event *ev ); + virtual void StopTeleport( Event *ev ); + void SetThread( Event *ev ); + virtual void Archive( Archiver &arc ); + }; + +inline void Teleporter::Archive + ( + Archiver &arc + ) + { + Trigger::Archive( arc ); + + arc.ArchiveString( &teleport_thread ); + arc.ArchiveBoolean( &in_use ); + } + +class TeleporterDestination : public Entity + { + public: + Vector movedir; + + CLASS_PROTOTYPE( TeleporterDestination ); + + TeleporterDestination(); + void SetMoveDir( Event *ev ); + virtual void Archive( Archiver &arc ); + }; + +inline void TeleporterDestination::Archive + ( + Archiver &arc + ) + { + Entity::Archive( arc ); + + arc.ArchiveVector( &movedir ); + } + +class UseAnim : public Entity + { + public: + int count; + qboolean active; + str thread; + str triggertarget; + int num_loops; + str state; + str camera; + str anim; + str key; + float delay; + float last_active_time; + + CLASS_PROTOTYPE( UseAnim ); + + UseAnim(); + virtual void Touched( Event *ev ); + void Reset( Event *ev ); + void SetThread( Event * ev ); + void SetTriggerTarget( Event * ev ); + void SetCount( Event * ev ); + void SetAnim( Event *ev ); + void SetState( Event *ev ); + void SetKey( Event *ev ); + void SetCamera( Event *ev ); + void SetNumLoops( Event *ev ); + void SetDelay( Event *ev ); + bool canBeUsed( Entity *activator ); + bool GetInformation( Entity *activator, Vector * org, Vector * angles, str * animatoin, int * loopcount, str * state, str * camera ); + void TriggerTargets( Entity *activator ); + virtual void Archive( Archiver &arc ); + }; + +inline void UseAnim::Archive + ( + Archiver &arc + ) + { + Entity::Archive( arc ); + + arc.ArchiveInteger( &count ); + arc.ArchiveBoolean( &active ); + arc.ArchiveString( &thread ); + arc.ArchiveString( &triggertarget ); + arc.ArchiveInteger( &num_loops ); + arc.ArchiveString( &state ); + arc.ArchiveString( &camera ); + arc.ArchiveString( &anim ); + arc.ArchiveString( &key ); + arc.ArchiveFloat( &delay ); + arc.ArchiveFloat( &last_active_time ); + } + +class TouchAnim : public UseAnim + { + public: + + CLASS_PROTOTYPE( TouchAnim ); + + TouchAnim(); + }; + + +class UseAnimDestination : public Entity + { + public: + int num_loops; + str state; + str anim; + + CLASS_PROTOTYPE( UseAnimDestination ); + + UseAnimDestination(); + void SetAnim( Event *ev ); + void SetState( Event *ev ); + void SetNumLoops( Event *ev ); + int GetNumLoops( void ); + str GetAnim( void ); + str GetState( void ); + virtual void Archive( Archiver &arc ); + }; + +inline void UseAnimDestination::Archive + ( + Archiver &arc + ) + { + Entity::Archive( arc ); + + arc.ArchiveInteger( &num_loops ); + arc.ArchiveString( &state ); + arc.ArchiveString( &anim ); + } + +class UseObject : public Animate + { + public: + str move_thread; + str stop_thread; + str reset_thread; + str triggertarget; + Vector offset; + float yaw_offset; + int count; + float cone; + str state; + str state_backwards; + str useMaterial; + int objectState; + float reset_time; + qboolean active; + + CLASS_PROTOTYPE( UseObject ); + + UseObject(); + void SetMoveThread( Event * ev ); + void SetStopThread( Event * ev ); + void SetResetThread( Event * ev ); + void SetTriggerTarget( Event * ev ); + void SetOffset( Event * ev ); + void SetYawOffset( Event * ev ); + void SetCount( Event * ev ); + void SetCone( Event * ev ); + void SetState( Event * ev ); + void SetBackwardsState( Event * ev ); + void SetResetTime( Event * ev ); + void Reset( Event * ev ); + void Resetting( Event * ev ); + void DamageTriggered( Event * ev ); + void DamageFunc( Event * ev ); + bool canBeUsed( Vector org, Vector dir ); + void Setup( Entity *activator, Vector *org, Vector *ang, str *newstate ); + void Start( Event * ev = NULL ); + bool Loop( void ); + void SetActiveState( Event *ev ); + void Stop( Entity *activator ); + void ActivateEvent( Event *ev ); + void DeactivateEvent( Event *ev ); + void UseMaterialEvent( Event *ev ); + virtual void Archive( Archiver &arc ); + }; + +inline void UseObject::Archive + ( + Archiver &arc + ) + { + Animate::Archive( arc ); + + arc.ArchiveString( &move_thread ); + arc.ArchiveString( &stop_thread ); + arc.ArchiveString( &reset_thread ); + arc.ArchiveString( &triggertarget ); + arc.ArchiveVector( &offset ); + arc.ArchiveFloat( &yaw_offset ); + arc.ArchiveInteger( &count ); + arc.ArchiveFloat( &cone ); + arc.ArchiveString( &state ); + arc.ArchiveString( &state_backwards ); + arc.ArchiveString( &useMaterial ); + arc.ArchiveInteger( &objectState ); + arc.ArchiveFloat( &reset_time ); + arc.ArchiveBoolean( &active ); + } + + +class Waypoint : public Mover + { + public: + CLASS_PROTOTYPE( Waypoint ); + }; + +class MonkeyBars : public Entity + { + public: + float dir; + + CLASS_PROTOTYPE( MonkeyBars ); + + MonkeyBars(); + void SetAngleEvent( Event *ev ); + + virtual void Archive( Archiver &arc ); + }; + +inline void MonkeyBars::Archive + ( + Archiver &arc + ) + + { + Entity::Archive( arc ); + + arc.ArchiveFloat( &dir ); + } + +class HorizontalPipe : public Entity + { + public: + float dir; + + CLASS_PROTOTYPE( HorizontalPipe ); + + HorizontalPipe(); + void SetAngleEvent( Event *ev ); + + virtual void Archive( Archiver &arc ); + }; + +inline void HorizontalPipe::Archive + ( + Archiver &arc + ) + + { + Entity::Archive( arc ); + + arc.ArchiveFloat( &dir ); + } + +class TossObject : public Animate + { + private: + str bouncesound; + float bouncesoundchance; + void Stop( Event *ev ); + void Touch( Event *ev ); + void SetBounceSound( Event *ev ); + void SetBounceSoundChance( Event *ev ); + public: + CLASS_PROTOTYPE( TossObject ); + + TossObject(); + TossObject( str modelname ); + void SetBounceSound( str bounce ); + void SetBounceSoundChance( float chance ); + void SetVelocity( float severity ); + virtual void Archive( Archiver &arc ); + }; + +inline void TossObject::Archive + ( + Archiver &arc + ) + + { + Animate::Archive( arc ); + + arc.ArchiveString( &bouncesound ); + arc.ArchiveFloat( &bouncesoundchance ); + } + + +class PushObject : public Entity + { + private: + EntityPtr owner; + float attack_finished; + int dmg; + str pushsound; + + public: + CLASS_PROTOTYPE( PushObject ); + + PushObject(); + void Start( Event *ev ); + void SetDamage( Event *ev ); + void BlockFunc( Event *ev ); + void SetPushSound( Event *ev ); + qboolean Push( Entity *pusher, Vector move ); + qboolean canPush( Vector dir ); + + Entity *getOwner( void ); + + virtual void Archive( Archiver &arc ); + }; + +inline void PushObject::Archive + ( + Archiver &arc + ) + { + Entity::Archive( arc ); + + arc.ArchiveSafePointer( &owner ); + arc.ArchiveFloat( &attack_finished ); + arc.ArchiveInteger( &dmg ); + arc.ArchiveString( &pushsound ); + } + +class FallingRock : public Entity + { + private: + int active; + Vector start_origin; + Vector last_bounce_origin; + Entity *current; + Entity *activator; + Vector bounce_dir; + Vector rotateaxis; + float attack_finished; + float wait; + float speed; + int dmg; + str bouncesound; + + void Touch( Event *ev ); + void Bounce( Event *ev ); + void Rotate( Event *ev ); + void Activate( Event *ev ); + void NextBounce( void ); + void StartFalling( Event *ev ); + void SetWait( Event *ev ); + void SetSpeed( Event *ev ); + void SetDmg( Event *ev ); + Entity *SetNextBounceDir( void ); + void SetBounceSound( str sound ); + void SetBounceSound( Event *ev ); + virtual void Archive( Archiver &arc ); + + public: + CLASS_PROTOTYPE( FallingRock ); + + FallingRock(); + }; + +inline void FallingRock::Archive + ( + Archiver &arc + ) + + { + Entity::Archive( arc ); + + arc.ArchiveInteger( &active ); + arc.ArchiveVector( &start_origin ); + arc.ArchiveVector( &last_bounce_origin ); + arc.ArchiveObjectPointer( ( Class ** )¤t ); + arc.ArchiveObjectPointer( ( Class ** )&activator ); + arc.ArchiveVector( &bounce_dir ); + arc.ArchiveVector( &rotateaxis ); + arc.ArchiveFloat( &attack_finished ); + arc.ArchiveFloat( &wait ); + arc.ArchiveFloat( &speed ); + arc.ArchiveInteger( &dmg ); + arc.ArchiveString( &bouncesound ); + if ( arc.Loading() ) + { + SetBounceSound( bouncesound ); + } + } + + +class SupplyWater : public Trigger + { + private: + int maxwater; + int amount; + public: + CLASS_PROTOTYPE( SupplyWater ); + + SupplyWater(); + void Activate( Event *ev ); + void MaxWater( Event *ev ); + void ChargeOff( Event *ev ); + virtual void Archive( Archiver &arc ); + }; + +inline void SupplyWater::Archive + ( + Archiver &arc + ) + + { + Trigger::Archive( arc ); + + arc.ArchiveInteger( &amount ); + arc.ArchiveInteger( &maxwater ); + } + +#endif /* misc.h */ diff --git a/source/source/fgame/mover.cpp b/source/source/fgame/mover.cpp new file mode 100644 index 0000000..4e78a2d --- /dev/null +++ b/source/source/fgame/mover.cpp @@ -0,0 +1,309 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/mover.cpp $ +// $Revision:: 7 $ +// $Author:: Markd $ +// $Date:: 5/31/00 10:38a $ +// +// Copyright (C) 1997 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source is may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/mover.cpp $ +// +// 7 5/31/00 10:38a Markd +// fixed initialization bug +// +// 6 5/30/00 7:06p Markd +// saved games 4th pass +// +// 5 10/01/99 2:42p Markd +// moved all the binding code back into Entity from Mover +// +// 4 9/20/99 11:43a Markd +// added currentOrigin and currentAngles support to setOrigin and setAngles +// +// 3 9/17/99 5:32p Jimdose +// added TR_LERP +// +// 2 9/13/99 3:27p Aldie +// code merge +// +// 1 9/10/99 10:54a Jimdose +// +// 1 9/08/99 3:16p Aldie +// +// 14 6/07/99 12:25p Jimdose +// setAngles now properly updates viewangles when bound +// +// DESCRIPTION: +// Base class for any object that needs to move to specific locations over a +// period of time. This class is kept separate from most entities to keep +// class size down for objects that don't need such behavior. +// + +#include "g_local.h" +#include "entity.h" +#include "trigger.h" +#include "mover.h" + +#define MOVE_ANGLES 1 +#define MOVE_ORIGIN 2 + +CLASS_DECLARATION( Trigger, Mover, "mover" ) + { + { &EV_MoveDone, MoveDone }, + { NULL, NULL } + }; + + +Mover::Mover() + { + edict->s.pos.trType = TR_LERP; + endevent = NULL; + } + +Mover::~Mover() + { + } + +void Mover::MoveDone + ( + Event *ev + ) + + { + Event * event; + Vector move; + Vector amove; + + // zero out the movement + if ( moveflags & MOVE_ANGLES ) + { + avelocity = vec_zero; + amove = angledest - localangles; + } + else + { + amove = vec_zero; + } + + if ( moveflags & MOVE_ORIGIN ) + { + velocity = vec_zero; + move = finaldest - localorigin; + } + else + { + move = vec_zero; + } + + if ( !G_PushMove( this, move, amove ) ) + { + // Delay finish till we can move into the final position + PostEvent( EV_MoveDone, FRAMETIME ); + return; + } + + // + // After moving, set origin to exact final destination + // + if ( moveflags & MOVE_ORIGIN ) + { + setOrigin( finaldest ); + } + + if ( moveflags & MOVE_ANGLES ) + { + localangles = angledest; + + if ( ( localangles.x >= 360 ) || ( localangles.x < 0 ) ) + { + localangles.x -= ( (int)localangles.x / 360 ) * 360; + } + if ( ( localangles.y >= 360 ) || ( localangles.y < 0 ) ) + { + localangles.y -= ( (int)localangles.y / 360 ) * 360; + } + if ( ( localangles.z >= 360 ) || ( localangles.z < 0 ) ) + { + localangles.z -= ( (int)localangles.z / 360 ) * 360; + } + } + + event = endevent; + endevent = NULL; + ProcessEvent( event ); + } + +/* +============= +MoveTo + +calculate self.velocity and self.nextthink to reach dest from +self.origin traveling at speed +=============== +*/ +void Mover::MoveTo + ( + Vector tdest, + Vector angdest, + float tspeed, + Event &event + ) + + { + Vector vdestdelta; + Vector angdestdelta; + float len; + float traveltime; + + assert( tspeed >= 0 ); + + if ( !tspeed ) + { + error( "MoveTo", "No speed is defined!" ); + } + + if ( tspeed < 0 ) + { + error( "MoveTo", "Speed is negative!" ); + } + + // Cancel previous moves + CancelEventsOfType( EV_MoveDone ); + + moveflags = 0; + + if ( endevent ) + { + delete endevent; + } + endevent = new Event( event ); + + finaldest = tdest; + angledest = angdest; + + if ( finaldest != localorigin ) + { + moveflags |= MOVE_ORIGIN; + } + if ( angledest != localangles ) + { + moveflags |= MOVE_ANGLES; + } + + if ( !moveflags ) + { + // stop the object from moving + velocity = vec_zero; + avelocity = vec_zero; + + // post the event so we don't wait forever + PostEvent( EV_MoveDone, FRAMETIME ); + return; + } + + // set destdelta to the vector needed to move + vdestdelta = tdest - localorigin; + angdestdelta = angdest - localangles; + + if ( tdest == localorigin ) + { + // calculate length of vector based on angles + len = angdestdelta.length(); + } + else + { + // calculate length of vector based on distance + len = vdestdelta.length(); + } + + // divide by speed to get time to reach dest + traveltime = len / tspeed; + + // Quantize to FRAMETIME +// E3 HACK +// traveltime *= ( 1 / FRAMETIME ); +// traveltime = ( float )( (int)traveltime ) * FRAMETIME; + if ( traveltime < FRAMETIME ) + { + traveltime = FRAMETIME; + vdestdelta = vec_zero; + angdestdelta = vec_zero; + } + + // scale the destdelta vector by the time spent traveling to get velocity + if ( moveflags & MOVE_ORIGIN ) + { + velocity = vdestdelta * ( 1 / traveltime ); + } + + if ( moveflags & MOVE_ANGLES ) + { + avelocity = angdestdelta * ( 1 / traveltime ); + } + + PostEvent( EV_MoveDone, traveltime ); + } + +/* +============= +LinearInterpolate +=============== +*/ +void Mover::LinearInterpolate + ( + Vector tdest, + Vector angdest, + float time, + Event &event + ) + + { + Vector vdestdelta; + Vector angdestdelta; + float t; + + if ( endevent ) + { + delete endevent; + } + endevent = new Event( event ); + finaldest = tdest; + angledest = angdest; + + // Cancel previous moves + CancelEventsOfType( EV_MoveDone ); + + // Quantize to FRAMETIME +//E3 HACK +// time *= ( 1 / FRAMETIME ); +// time = ( float )( (int)time ) * FRAMETIME; + if ( time < FRAMETIME ) + { + time = FRAMETIME; + } + + moveflags = 0; + t = 1 / time; + // scale the destdelta vector by the time spent traveling to get velocity + if ( finaldest != localorigin ) + { + vdestdelta = tdest - localorigin; + velocity = vdestdelta * t; + moveflags |= MOVE_ORIGIN; + } + + if ( angledest != localangles ) + { + angdestdelta = angdest - localangles; + avelocity = angdestdelta * t; + moveflags |= MOVE_ANGLES; + } + + PostEvent( EV_MoveDone, time ); + } + diff --git a/source/source/fgame/mover.h b/source/source/fgame/mover.h new file mode 100644 index 0000000..83324f7 --- /dev/null +++ b/source/source/fgame/mover.h @@ -0,0 +1,80 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/mover.h $ +// $Revision:: 6 $ +// $Author:: Markd $ +// $Date:: 6/14/00 2:17p $ +// +// Copyright (C) 1997 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source is may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/mover.h $ +// +// 6 6/14/00 2:17p Markd +// fixed compiler warnings for Intel Compiler +// +// 5 5/30/00 7:06p Markd +// saved games 4th pass +// +// 4 5/27/00 2:56p Markd +// Save games 2nd pass +// +// 3 5/24/00 3:14p Markd +// first phase of save/load games +// +// 2 10/01/99 2:42p Markd +// moved all the binding code back into Entity from Mover +// +// 1 9/10/99 10:54a Jimdose +// +// 1 9/08/99 3:16p Aldie +// +// DESCRIPTION: +// Base class for any object that needs to move to specific locations over a +// period of time. This class is kept separate from most entities to keep +// class size down for objects that don't need such behavior. +// + +#ifndef __MOVER_H__ +#define __MOVER_H__ + +#include "g_local.h" +#include "entity.h" +#include "trigger.h" + +class Mover : public Trigger + { + private: + Vector finaldest; + Vector angledest; + Event *endevent; + int moveflags; + + public: + CLASS_PROTOTYPE( Mover ); + + Mover(); + virtual ~Mover(); + void MoveDone( Event *ev ); + void MoveTo( Vector tdest, Vector angdest, float tspeed, Event &event ); + void LinearInterpolate( Vector tdest, Vector angdest, float time, Event &event ); + virtual void Archive( Archiver &arc ); + }; + +inline void Mover::Archive + ( + Archiver &arc + ) + { + Trigger::Archive( arc ); + + arc.ArchiveVector( &finaldest ); + arc.ArchiveVector( &angledest ); + arc.ArchiveEventPointer( &endevent ); + arc.ArchiveInteger( &moveflags ); + } + +#endif diff --git a/source/source/fgame/nature.cpp b/source/source/fgame/nature.cpp new file mode 100644 index 0000000..ff1cbd9 --- /dev/null +++ b/source/source/fgame/nature.cpp @@ -0,0 +1,153 @@ +#include "nature.h" + +/*****************************************************************************/ +/*QUAKED func_emitter (0 0.25 0.5) ? + +"emitter" - Name of emitter to use. +******************************************************************************/ +Event EV_Emitter_EmitterName + ( + "emitter", + EV_DEFAULT, + "s", + "name", + "Emitter to use" + ); + +CLASS_DECLARATION( Entity, Emitter, "func_emitter" ) + { + { &EV_Emitter_EmitterName, EmitterName }, + }; + +Emitter::Emitter + ( + ) + + { + edict->s.eType = ET_EMITTER; + } + +void Emitter::setEmitter + ( + str name + ) + + { + emitterName = name; + edict->s.tag_num = gi.imageindex( emitterName ); + } + +void Emitter::EmitterName + ( + Event *ev + ) + + { + setEmitter( ev->GetString( 1 ) ); + } + +/*****************************************************************************/ +/*QUAKED func_rain (0 0.25 0.5) ? + +This creates a raining effect in the brush + +"emitter" - Name of emitter to use for the rain. +******************************************************************************/ + +CLASS_DECLARATION( Entity, Rain, "func_rain" ) + { + { NULL, NULL } + }; + + +Rain::Rain + ( + ) + + { + if ( LoadingSavegame ) + { + // Archive function will setup all necessary data + return; + } + setSolidType( SOLID_NOT ); + edict->s.eType = ET_RAIN; + setRainName( "defaultrain" ); + } + +void Rain::setRainName + ( + str name + ) + + { + rainName = name; + edict->s.tag_num = gi.imageindex( rainName ); + } + + +/*****************************************************************************/ +/* Plant Puffdaddy */ +/*****************************************************************************/ + +Event EV_PuffDaddy_Idle + ( + "idle", + EV_DEFAULT, + NULL, + NULL, + "Animates the puff daddy." + ); + +CLASS_DECLARATION( Animate, PuffDaddy, "plant_puffdaddy" ) + { + { &EV_Touch, Touch }, + { &EV_PuffDaddy_Idle, Idle }, + { NULL, NULL } + }; + +void PuffDaddy::Idle + ( + Event *ev + ) + + { + RandomAnimate( "idle" ); + } + +void PuffDaddy::Touch + ( + Event *ev + ) + + { + Entity *other; + + other = ev->GetEntity( 1 ); + + if ( !other->inheritsFrom( "Sentient" ) ) + return; + + RandomAnimate( "touch", EV_PuffDaddy_Idle ); + //SetFrame( 0 ); + + SurfaceCommand( "puffdaddy", "+nodraw" ); + setSolidType( SOLID_NOT ); + } + +PuffDaddy::PuffDaddy + ( + ) + + { + if ( LoadingSavegame ) + { + // Archive function will setup all necessary data + return; + } + setSolidType( SOLID_TRIGGER ); + edict->s.eType = ET_MODELANIM; + setModel( "plant_puffdaddy.tik" ); + PostEvent( EV_Show, 0 ); + //showModel(); + } diff --git a/source/source/fgame/nature.h b/source/source/fgame/nature.h new file mode 100644 index 0000000..80774d5 --- /dev/null +++ b/source/source/fgame/nature.h @@ -0,0 +1,67 @@ +#include "g_local.h" +#include "trigger.h" + +class Emitter : public Entity + { + private: + str emitterName; + void setEmitter( str name ); + void EmitterName( Event *ev ); + public: + CLASS_PROTOTYPE( Emitter ); + Emitter(); + virtual void Archive( Archiver &arc ); + }; + +inline void Emitter::Archive + ( + Archiver &arc + ) + { + Entity::Archive( arc ); + + arc.ArchiveString( &emitterName ); + if ( arc.Loading() ) + { + setEmitter( emitterName ); + } + } + + +class Rain : public Emitter + { + private: + str rainName; + void setRainName( str name ); + public: + CLASS_PROTOTYPE( Rain ); + Rain(); + virtual void Archive( Archiver &arc ); + }; + +inline void Rain::Archive + ( + Archiver &arc + ) + { + Entity::Archive( arc ); + + arc.ArchiveString( &rainName ); + if ( arc.Loading() ) + { + setRainName( rainName ); + } + } + + +class PuffDaddy : public Animate + { + private: + void Touch( Event *ev ); + void Idle( Event *ev ); + + public: + CLASS_PROTOTYPE( PuffDaddy ); + PuffDaddy(); + }; + diff --git a/source/source/fgame/navigate.cpp b/source/source/fgame/navigate.cpp new file mode 100644 index 0000000..19a27bd --- /dev/null +++ b/source/source/fgame/navigate.cpp @@ -0,0 +1,2673 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/navigate.cpp $ +// $Revision:: 28 $ +// $Author:: Steven $ +// $Date:: 7/05/00 2:30p $ +// +// Copyright (C) 1998 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/navigate.cpp $ +// +// 28 7/05/00 2:30p Steven +// Took out pvs check to draw ai routes because can't see routes in water +// (distance cull is good enough) and added a warning if you target a node to +// itself. +// +// 27 6/27/00 5:47p Steven +// Took out some water restrictions on path connecting. +// +// 26 6/26/00 4:51p Steven +// Fixed some save/load game issues. +// +// 25 6/23/00 9:12p Markd +// fixed some loading of events at spawn time +// +// 24 6/14/00 3:50p Markd +// Cleaned up more Intel Compiler warnings +// +// 23 5/27/00 8:07p Markd +// Saved games 3rd pass +// +// 22 5/25/00 4:27p Markd +// rewrote archive functions +// +// 21 5/24/00 3:14p Markd +// first phase of save/load games +// +// 20 3/17/00 11:52a Steven +// Added jumping stuff. +// +// 19 3/06/00 8:12p Markd +// removed unused cvar +// +// 18 3/03/00 12:06p Steven +// Removed an annoying assert. +// +// 17 2/25/00 11:07a Steven +// Made ai_showroutes cull out nodes that are farther than the new cvar +// ai_showroutes_distance. +// +// 16 2/04/00 6:38p Markd +// Only print out the "." when loading in an archive +// +// 15 2/04/00 1:29p Markd +// Added checksum to ai path nodes. It auto saves on exit now and will +// automatically re-build nodes as needed +// +// 14 2/04/00 11:18a Markd +// Fixed memory leak with AI_PathNodes +// +// 13 1/26/00 7:18p Markd +// put in creating path indicator +// +// 12 1/25/00 6:32p Steven +// Fixed some path node stuff. +// +// 11 1/22/00 12:42p Jimdose +// got rid of calls to vec3() +// +// 10 1/15/00 3:57p Markd +// Eliminated multiple "angle" events and replaced them with EV_SetAngle +// +// 9 12/09/99 3:33p Aldie +// Removed a line where the player's origin was being multiplied by 0.125 +// +// 8 10/02/99 6:51p Markd +// Put in backend work for event documentation and fixed a lot of event +// documentation bugs +// +// 7 10/01/99 6:31p Markd +// added commands hidden inside fgame so that they would show up for command +// completion +// +// 6 10/01/99 4:52p Markd +// Made Warning level 4 work on all projects +// +// 5 9/29/99 5:18p Steven +// Event formatting. +// +// 4 9/27/99 5:45p Markd +// began documentation and cleanup phase after merge +// +// 3 9/16/99 11:18a Markd +// Continuing merge of code, not functional yet but closer +// +// 2 9/15/99 6:57p Aldie +// Update to get game working +// +// 1 9/10/99 10:54a Jimdose +// +// 1 9/08/99 3:16p Aldie +// +// 14 8/18/99 3:28p Jimdose +// added cylindrical collision detection +// +// 13 8/17/99 5:08p Markd +// Changed all FS_ReadFile's to FS_ReadFileEx's in game code +// +// 12 6/11/99 1:23p Phook +// +// 11 6/11/99 12:58p Phook +// Changed from SINED comments to QUAKED +// +// DESCRIPTION: +// C++ implementation of the A* search algorithm. +// + +#include "g_local.h" +#include "navigate.h" +#include "path.h" +#include "misc.h" +#include "doors.h" + +#define PATHFILE_VERSION 6 + +Event EV_AI_SavePaths + ( + "ai_savepaths", + EV_CHEAT, + NULL, + NULL, + "Saves the path nodes under the default name." + ); +Event EV_AI_SaveNodes + ( + "ai_save", + EV_CHEAT, + "s", + "filename", + "Save path nodes." + ); +Event EV_AI_LoadNodes + ( + "ai_load", + EV_CHEAT, + "s", + "filename", + "Loads path nodes." + ); +Event EV_AI_ClearNodes + ( + "ai_clearnodes", + EV_CHEAT, + NULL, + NULL, + "Clears all of the path nodes." + ); +Event EV_AI_RecalcPaths + ( + "ai_recalcpaths", + EV_CHEAT, + "i", + "nodenum", + "Update the specified node." + ); +Event EV_AI_CalcPath + ( + "ai_calcpath", + EV_CHEAT, + "ii", + "nodenum1 nodenum2", + "Calculate path from node1 to node2." + ); +Event EV_AI_DisconnectPath + ( + "ai_disconnectpath", + EV_CHEAT, + "ii", + "nodenum1 nodenum2", + "Disconnect path between node1 and node2." + ); +Event EV_AI_SetNodeFlags + ( + "ai_setflags", + EV_CHEAT, + "iSSSSSS", + "nodenum token1 token2 token3 token4 token5 token6", + "Set the flags for the specified node." + ); + +cvar_t *ai_createnodes = NULL; +cvar_t *ai_debugpath; +cvar_t *ai_debuginfo; +cvar_t *ai_showroutes; +cvar_t *ai_showroutes_distance; +cvar_t *ai_shownodenums; +cvar_t *ai_timepaths; + +static Entity *IgnoreObjects[ MAX_GENTITIES ]; +static int NumIgnoreObjects; + +static PathNode *pathnodes[ MAX_PATHNODES ]; +static qboolean pathnodesinitialized = false; +static qboolean loadingarchive = false; +static qboolean pathnodescalculated = false; +int ai_maxnode; + +#define MASK_PATHSOLID (CONTENTS_SOLID|CONTENTS_MONSTERCLIP) + +PathSearch PathManager; + +int path_checksthisframe; + +PathNode *AI_FindNode + ( + const char *name + ) + + { + int i; + + if ( !name ) + { + return NULL; + } + + if ( name[ 0 ] == '!' ) + { + name++; + return AI_GetNode( atof( name ) ); + } + + if ( name[ 0 ] == '$' ) + { + name++; + } + + for( i = 0; i <= ai_maxnode; i++ ) + { + if ( pathnodes[ i ] && ( pathnodes[ i ]->TargetName() == name ) ) + { + return pathnodes[ i ]; + } + } + + return NULL; + } + +PathNode *AI_GetNode + ( + int num + ) + + { + if ( ( num < 0 ) || ( num > MAX_PATHNODES ) ) + { + assert( false ); + return NULL; + } + + return pathnodes[ num ]; + } + +void AI_AddNode + ( + PathNode *node + ) + + { + int i; + + assert( node ); + + for( i = 0; i < MAX_PATHNODES; i++ ) + { + if ( pathnodes[ i ] == NULL ) + { + break; + } + } + + if ( i < MAX_PATHNODES ) + { + if ( i > ai_maxnode ) + { + ai_maxnode = i; + } + pathnodes[ i ] = node; + node->nodenum = i; + return; + } + + gi.Error( ERR_DROP, "Exceeded MAX_PATHNODES!\n" ); + } + +void AI_RemoveNode + ( + PathNode *node + ) + + { + assert( node ); + if ( ( node->nodenum < 0 ) || ( node->nodenum > ai_maxnode ) ) + { + assert( false ); + gi.Error( ERR_DROP, "Corrupt pathnode!\n" ); + } + + // If the nodenum is 0, the node was probably removed during initialization + // otherwise, it's a bug. + assert( ( pathnodes[ node->nodenum ] == node ) || ( node->nodenum == 0 ) ); + if ( pathnodes[ node->nodenum ] == node ) + { + pathnodes[ node->nodenum ] = NULL; + } + } + +void AI_ResetNodes + ( + void + ) + + { + int i; + + if ( !pathnodesinitialized ) + { + memset( pathnodes, 0, sizeof( pathnodes ) ); + pathnodesinitialized = true; + } + else + { + for( i = 0; i < MAX_PATHNODES; i++ ) + { + if ( pathnodes[ i ] ) + { + delete pathnodes[ i ]; + } + } + } + + ai_maxnode = 0; + } + +/*****************************************************************************/ +/*QUAKED info_pathnode (1 0 0) (-24 -24 0) (24 24 32) FLEE DUCK COVER DOOR JUMP LADDER + +FLEE marks the node as a safe place to flee to. Actor will be removed when it reaches a flee node and is not visible to a player. + +DUCK marks the node as a good place to duck behind during weapon fire. + +COVER marks the node as a good place to hide behind during weapon fire. + +DOOR marks the node as a door node. If an adjacent node has DOOR marked as well, the actor will only use the path if the door in between them is unlocked. + +JUMP marks the node as one to jump from when going to the node specified by target. +"target" the pathnode to jump to. + +******************************************************************************/ + +Event EV_Path_FindChildren + ( + "findchildren", + EV_DEFAULT, + NULL, + NULL, + "Adds this node to the path manager." + ); +Event EV_Path_FindEntities + ( + "findentities", + EV_DEFAULT, + NULL, + NULL, + "Finds doors." + ); +Event EV_Path_SetNodeFlags + ( + "spawnflags", + EV_DEFAULT, + "i", + "node_flags", + "Sets the path nodes flags." + ); +Event EV_Path_SetOriginEvent + ( + "origin", + EV_DEFAULT, + "v", + "origin", + "Sets the path node's origin." + ); +Event EV_Path_SetAngles + ( + "angles", + EV_DEFAULT, + "v", + "angles", + "Sets the path node's angles." + ); +Event EV_Path_SetAnim + ( + "anim", + EV_DEFAULT, + "s", + "animname", + "Sets the animname used for this path node." + ); +Event EV_Path_SetTargetname + ( + "targetname", + EV_DEFAULT, + "s", + "targetname", + "Sets the target name for this path node." + ); +Event EV_Path_SetTarget + ( + "target", + EV_DEFAULT, + "s", + "target", + "Sets the target for this path node." + ); + +CLASS_DECLARATION( Listener, PathNode, "info_pathnode" ) + { + { &EV_Path_FindChildren, FindChildren }, + { &EV_Path_FindEntities, FindEntities }, + { &EV_Path_SetNodeFlags, SetNodeFlags }, + { &EV_Path_SetOriginEvent, SetOriginEvent }, + { &EV_SetAngle, SetAngle }, + { &EV_Path_SetAngles, SetAngles }, + { &EV_Path_SetAnim, SetAnim }, + { &EV_Path_SetTargetname, SetTargetname }, + { &EV_Path_SetTarget, SetTarget }, + { NULL, NULL } + }; + +static Vector pathNodesChecksum; +static int numLoadNodes = 0; +static int numNodes = 0; +static PathNode *NodeList = NULL; + +PathNode::PathNode() + { + numLoadNodes++; + nodenum = 0; + if ( !loadingarchive ) + { + // our archive function will take care of this stuff + AI_AddNode( this ); + PostEvent( EV_Path_FindChildren, 0 ); + } + + occupiedTime = 0; + + nodeflags = 0; + setangles = false; + drawtime = 0; + contents = 0; + + occupiedTime = 0; + entnum = 0; + + // crouch hieght + setSize( "-24 -24 0", "24 24 40" ); + + f = 0; + h = 0; + g = 0; + + gridX = 0; + gridY = 0; + inlist = NOT_IN_LIST; + + // reject is used to indicate that a node is unfit for ending on during a search + reject = false; + + numChildren = 0; + + Parent = NULL; + NextNode = NULL; + } + +PathNode::~PathNode() + { + PathManager.RemoveNode( this ); + + AI_RemoveNode( this ); + } + +void PathNode::SetNodeFlags + ( + Event *ev + ) + + { + nodeflags = ev->GetInteger( 1 ); + } + +void PathNode::SetOriginEvent + ( + Event *ev + ) + + { + setOrigin( ev->GetVector( 1 ) ); + pathNodesChecksum += origin; + } + +void PathNode::SetAngle + ( + Event *ev + ) + + { + Vector movedir; + setangles = true; + + movedir = G_GetMovedir( ev->GetFloat( 1 ) ); + setAngles( movedir.toAngles() ); + } + +void PathNode::SetAngles + ( + Event *ev + ) + + { + setangles = true; + setAngles( ev->GetVector( 1 ) ); + } + +void PathNode::SetAnim + ( + Event *ev + ) + + { + animname = ev->GetString( 1 ); + } + +void PathNode::SetTargetname + ( + Event *ev + ) + + { + targetname = ev->GetString( 1 ); + } + +void PathNode::SetTarget + ( + Event *ev + ) + + { + target = ev->GetString( 1 ); + } + +str &PathNode::TargetName + ( + void + ) + + { + return targetname; + } + +void PathNode::setAngles + ( + Vector ang + ) + + { + angles = ang; + } + +void PathNode::setOrigin + ( + Vector org + ) + + { + origin = org; + contents = gi.pointcontents( origin, 0 ); + } + +void PathNode::setSize + ( + Vector min, + Vector max + ) + + { + mins = min; + maxs = max; + } + +void PathNode::Setup + ( + Vector pos + ) + + { + CancelEventsOfType( EV_Path_FindChildren ); + + setOrigin( pos ); + + ProcessEvent( EV_Path_FindChildren ); + } + +void PathNode::Archive + ( + Archiver &arc + ) + + { + int i; + + Listener::Archive( arc ); + + arc.ArchiveInteger( &nodenum ); + if ( arc.Loading() ) + { + assert( nodenum <= MAX_PATHNODES ); + if ( nodenum > MAX_PATHNODES ) + { + arc.FileError( "Node exceeds max path nodes" ); + } + } + arc.ArchiveInteger( &nodeflags ); + arc.ArchiveVector( &origin ); + arc.ArchiveVector( &angles ); + if ( arc.Loading() ) + { + setOrigin( origin ); + setAngles( angles ); + } + + arc.ArchiveBoolean( &setangles ); + arc.ArchiveString( &target ); + arc.ArchiveString( &targetname ); + arc.ArchiveString( &animname ); + + arc.ArchiveFloat( &occupiedTime ); + arc.ArchiveInteger( &entnum ); + + if ( arc.Loading() && !LoadingSavegame ) + { + occupiedTime = 0; + entnum = 0; + } + + arc.ArchiveInteger( &numChildren ); + if ( arc.Loading() ) + { + assert( numChildren <= NUM_PATHSPERNODE ); + if ( numChildren > NUM_PATHSPERNODE ) + { + arc.FileError( "Exceeded num paths per node" ); + } + } + for( i = 0; i < numChildren; i++ ) + { + arc.ArchiveShort( &Child[ i ].node ); + arc.ArchiveShort( &Child[ i ].moveCost ); + arc.ArchiveRaw( Child[ i ].maxheight, sizeof( Child[ i ].maxheight ) ); + arc.ArchiveInteger( &Child[ i ].door ); + } + + if ( arc.Loading() ) + { + if ( !LoadingSavegame ) + { + // Fixup the doors + PostEvent( EV_Path_FindEntities, 0 ); + } + pathnodes[ nodenum ] = this; + if ( ai_maxnode < nodenum ) + { + ai_maxnode = nodenum; + } + PathManager.AddNode( this ); + } + } + +void PathNode::FindEntities + ( + Event *ev + ) + + { + int i; + Door *door; + PathNode *node; + + for( i = 0; i < numChildren; i++ ) + { + if ( Child[ i ].door ) + { + node = AI_GetNode( Child[ i ].node ); + + assert( node ); + + door = CheckDoor( node->origin ); + if ( door ) + { + Child[ i ].door = door->entnum; + } + else + { + Child[ i ].door = 0; + } + } + } + } + +void RestoreEnts + ( + void + ) + + { + int i; + + for( i = 0; i < NumIgnoreObjects; i++ ) + { + IgnoreObjects[ i ]->link(); + } + } + +qboolean PathNode::TestMove + ( + Entity *ent, + Vector start, + Vector end, + Vector &min, + Vector &max, + qboolean allowdoors, + qboolean fulltest + ) + + { + // NOTE: TestMove may allow wide paths to succeed when they shouldn't since it + // may place the lower node above obstacles that actors can't step over. + // Since any path that's wide enough for large boxes must also allow + // thinner boxes to go through, you must ignore the results of TestMove + // when thinner checks have already failed. + trace_t trace; + Vector end_trace; + Vector pos; + Vector dir; + float t; + float dist; + + // By requiring that paths have STEPSIZE headroom above the path, we simplify the test + // to see if an actor can move to a node down to a simple trace. By stepping up the start + // and end points, we account for the actor's ability to step up any geometry lower than + // STEPSIZE in height. + start.z += STEPSIZE; + end.z += STEPSIZE; + + // Check the move + trace = G_Trace( start, min, max, end, ent, MASK_PATHSOLID, false, "PathNode::TestMove 1" ); + if ( trace.startsolid || ( trace.fraction != 1 ) ) + { + // No direct path available. The actor will most likely not be able to move through here. + return false; + } + + if ( !fulltest ) + { + // Since we're not doing a full test (full tests are only done when we're connecting nodes to save time), + // we test to see if the midpoint of the move would only cause a change in height of STEPSIZE + // from the predicted height. This prevents most cases where a dropoff lies between a actor and a node. + Vector pos; + + // Since we start and end are already STEPSIZE above the ground, we have to check twice STEPSIZE below + // the midpoint to see if the midpoint is on the ground. + dir = end - start; + pos = start + dir * 0.5; + end_trace = pos; + end_trace.z -= STEPSIZE * 2; + + // Check that the midpos is onground. This may fail on ok moves, but a true test would be too slow + // to do in real time. Also, we may miss cases where a dropoff exists before or after the midpoint. + // Once the actor is close enough to the drop off, it will discover the fall and hopefully try + // another route. + trace = G_Trace( pos, min, max, end_trace, ent, MASK_PATHSOLID, false, "PathNode::TestMove 2" ); + if ( trace.startsolid || ( trace.fraction == 1 ) ) + { + // We're not on the ground, so there's a good posibility that we can't make this move without falling. + return false; + } + } + else //if ( !( contents & MASK_WATER ) ) + { + // When we're creating the paths during load time, we do a much more exhaustive test to see if the + // path is valid. This test takes a bounding box and moves it 8 units at a time closer to the goal, + // testing the ground after each move. The test involves checking whether we will fall more than + // STEPSIZE to the ground (since we've raised the start and end points STEPSIZE above the ground, + // we must actually test 2 * STEPSIZE down to see if we're on the ground). After each test, we set + // the new height of the box to be STEPSIZE above the ground. Each move closer to the goal is only + // done horizontally to simulate how the actors normally move. This method ensures that any actor + // wider than 8 units in X and Y will be able to move from start to end. + // + // NOTE: This may allow wide paths to succeed when they shouldn't since it + // may place the lower node above obstacles that actors can't step over. + // Since any path that's wide enough for large boxes must also allow + // thinner boxes to go through, you must ignore the results of TestMove + // when thinner checks have already failed. + + dir = end - start; + dir.z = 0; + dist = dir.length(); + dir *= 1 / dist; + + // check the entire move + pos = start; + for( t = 0; t < dist; t += 8 ) + { + // Move the box to our position along the path and make our downward trace vector + end_trace.x = pos.x = start.x + t * dir.x; + end_trace.y = pos.y = start.y + t * dir.y; + end_trace.z = pos.z - STEPSIZE * 2; + + // check the ground + trace = G_Trace( pos, min, max, end_trace, ent, MASK_PATHSOLID, false, "PathNode::TestMove 3" ); + if ( trace.startsolid || ( trace.fraction == 1 ) ) + { + // Either we're stuck in something solid, or we would fall farther than STEPSIZE to the ground, + // so the path is not acceptable. + return false; + } + + // move the box to STEPSIZE above the ground. + pos.z = trace.endpos[ 2 ] + STEPSIZE; + } + } + + return true; + } + +qboolean PathNode::CheckMove + ( + Entity *ent, + Vector pos, + Vector &min, + Vector &max, + qboolean allowdoors, + qboolean fulltest + ) + + { + // Since we need to support actors of variable widths, we need to do some special checks when a potential + // path goes up or down stairs. Placed pathnodes are only 16x16 in width, so when they are dropped to the + // ground, they may end in a position where a larger box would not fit. Making the pathnodes larger + // would make it hard to place paths where smaller actors could go, and making paths of various sizes would + // be overkill (more work for the level designer, or a lot of redundant data). The solution is to treat + // paths with verticle movement differently than paths that are purely horizontal. For horizontal moves, + // a simple trace STEPSIZE above the ground will be sufficient to prove that we can travel from one node + // to another, in either direction. For moves that have some change in height, we can check that we have + // a clear path by tracing horizontally from the higher node to a point where larger bounding box actors + // could then move at a slope downward to the lower node. This fixes the problem where path points that + // are larger than the depth of a step would have to intersect with the step in order to get the center + // of the box on solid ground. If you're still confused, well, tough. :) Think about the problem of + // larger bounding boxes going up stairs for a bit and you should see the problem. You can also read + // section 8.4, "Translating a Convex Polygon", from Computational Geometry in C (O'Rourke) (a f'ing + // great book, BTW) for information on similar problems (which is also a good explanation of how + // Quake's collision detection works). + trace_t trace; + int height; + + height = ( int )fabs( pos.z - origin.z ); + // Check if the path is strictly horizontal + if ( !height ) + { + // We do two traces for the strictly horizontal test. One normal, and one STEPSIZE + // above. The normal trace is needed because most doors in the game aren't tall enough + // to allow actors to trace STEPSIZE above the ground. This means that failed horizontal + // tests require two traces. Annoying. + trace = G_Trace( origin, min, max, pos, ent, MASK_PATHSOLID, false, "PathNode::CheckMove 1" ); + if ( !trace.startsolid && ( trace.fraction == 1 ) ) + { + return true; + } + + // Do the step test + return TestMove( ent, pos, origin, min, max, allowdoors, fulltest ); + } + + Vector size; + float width; + + size = max - min; + width = max( size.x, size.y ); + + // if our bounding box is smaller than that of the pathnode, we can do the standard trace. + if ( width <= 32 ) + { + return TestMove( ent, pos, origin, min, max, allowdoors, fulltest ); + } + + Vector start; + Vector end; + Vector delta; + float radius; + float len; + + // We calculate the radius of the smallest cylinder that would contain the bounding box. + // In some cases, this would make the first horizontal move longer than it needs to be, but + // that shouldn't be a problem. + + // multiply the width by 1/2 the square root of 2 to get radius + radius = width * 1.415 * 0.5; + + // Make sure that our starting position is the higher node since it doesn't matter which + // direction the move is in. + if ( pos.z < origin.z ) + { + start = origin; + end = pos; + } + else + { + start = pos; + end = origin; + } + + // If the distance between the two points is less than the radius of the bounding box, + // then we only have to do the horizontal test since larger bounding boxes would not fall. + delta = end - start; + len = delta.length(); + if ( len <= radius ) + { + end.z = start.z; + return TestMove( ent, start, end, min, max, allowdoors, fulltest ); + } + + Vector mid; + + // normalize delta and multiply by radius (saving a few multiplies by combining into one). + delta *= radius / len; + + mid = start; + mid.x += delta.x; + mid.y += delta.y; + + // Check the horizontal move + if ( !TestMove( ent, start, mid, min, max, allowdoors, fulltest ) ) + { + return false; + } + + // Calculate our new endpoint + end.z -= delta.z; + + // Check our new sloping move + return TestMove( ent, mid, end, min, max, allowdoors, fulltest ); + } + +Door *PathNode::CheckDoor + ( + Vector pos + ) + + { + trace_t trace; + Entity *ent; + + trace = G_Trace( origin, vec_zero, vec_zero, pos, NULL, MASK_PATHSOLID, false, "PathNode::CheckDoor" ); + + if ( trace.ent ) + { + ent = trace.ent->entity; + } + else + { + ent = NULL; + } + if ( ent && ent->isSubclassOf( Door ) ) + { + return ( Door * )ent; + } + + return NULL; + } + +qboolean PathNode::CheckMove + ( + Vector pos, + Vector min, + Vector max + ) + + { + return true; + } + +qboolean PathNode::CheckPath + ( + PathNode *node, + Vector min, + Vector max, + qboolean fulltest + ) + + { + Vector delta; + qboolean allowdoors; + qboolean result; + + delta = node->origin - origin; + delta[ 2 ] = 0; + if ( delta.length() >= PATHMAP_CELLSIZE ) + { + return false; + } + + allowdoors = ( nodeflags & AI_DOOR ) && ( node->nodeflags & AI_DOOR ); + + result = CheckMove( NULL, node->origin, min, max, allowdoors, fulltest ); + RestoreEnts(); + + return result; + } + +qboolean PathNode::ClearPathTo + ( + PathNode *node, + byte maxheight[ NUM_WIDTH_VALUES ], + qboolean fulltest + ) + + { + int i; + int width; + int height; + int bottom; + int top; + Vector min; + Vector max; + Vector bmin; + Vector bmax; + qboolean path; + int touch[ MAX_GENTITIES ]; + Entity *ent; + int num; + + path = false; + for( i = 0; i < NUM_WIDTH_VALUES; i++ ) + { + maxheight[ i ] = 0; + } + + width = NUM_WIDTH_VALUES * WIDTH_STEP * 0.5; + min = Vector( -width, -width, 0 ); + max = Vector( width, width, MAX_HEIGHT ); + G_CalcBoundsOfMove( origin, node->origin, min, max, &bmin, &bmax ); + + num = gi.AreaEntities( bmin, bmax, touch, MAX_GENTITIES ); + //num = gi.BoxEdicts( bmin, bmax, touch, MAX_GENTITIES, AREA_SOLID ); + for( i = 0; i < num; i++ ) + { + ent = g_entities[ touch[ i ] ].entity; + if ( ent && ent->isSubclassOf( Door ) ) + { + ent->unlink(); + } + } + + for( i = 0; i < NUM_WIDTH_VALUES; i++ ) + { + width = ( i + 1 ) * WIDTH_STEP * 0.5; + + min.x = min.y = -width; + max.x = max.y = width; + + // Perform a binary search to find the height of the path. Neat, eh? :) + bottom = 0; + top = MAX_HEIGHT; + while( top >= bottom ) + { + height = ( ( bottom + top + 3 ) >> 1 ) & ~0x3; + if ( !height ) + { + break; + } + + max.z = ( float )height; + if ( !CheckPath( node, min, max, fulltest ) ) + { + top = height - 4; + } + else + { + bottom = height + 4; + maxheight[ i ] = height; + } + } + + if ( !maxheight[ i ] ) + { + // If no paths were available at this width, don't allow any wider paths. + // CheckPath uses TestMove which may allow wide paths to succeed when they + // shouldn't since it may place the lower node above obstacles that actors + // can't step over. Since any path that's wide enough for large boxes must + // also allow thinner boxes to go through, this check avoids the hole in + // TestMove's functioning. + break; + } + + path = true; + } + + // Restore the doors + for( i = 0; i < num; i++ ) + { + ent = g_entities[ touch[ i ] ].entity; + if ( ent && ent->isSubclassOf( Door ) ) + { + ent->link(); + } + } + + return path; + } + +qboolean PathNode::LadderTo + ( + PathNode *node, + byte maxheight[ NUM_WIDTH_VALUES ] + ) + + { + int i; + int j; + int m; + int width; + Vector min; + Vector max; + qboolean path; + + trace_t trace; + + if ( !( nodeflags & AI_LADDER ) || !( node->nodeflags & AI_LADDER ) ) + { + return false; + } + + if ( ( origin.x != node->origin.x ) || ( origin.y != node->origin.y ) ) + { + return false; + } + + path = false; + + for( i = 0; i < NUM_WIDTH_VALUES; i++ ) + { + width = ( i + 1 ) * WIDTH_STEP * 0.5; + min = Vector( -width, -width, 12 ); + max = Vector( width, width, 40 ); + + trace = G_Trace( origin, min, max, node->origin, NULL, MASK_PATHSOLID, false, "PathNode::LadderTo 1" ); + if ( ( trace.fraction != 1 ) || trace.startsolid ) + { + maxheight[ i ] = 0; + continue; + } + + path = true; + + m = 40; + for( j = 48; j < MAX_HEIGHT; j+= 8 ) + { + max.z = j; + trace = G_Trace( origin, min, max, node->origin, NULL, MASK_PATHSOLID, false, "PathNode::LadderTo 2" ); + if ( ( trace.fraction != 1 ) || trace.startsolid ) + { + break; + } + + m = j; + } + + maxheight[ i ] = m; + } + + return path; + } + +qboolean PathNode::ConnectedTo + ( + PathNode *node + ) + + { + int i; + + for( i = 0; i < numChildren; i++ ) + { + if ( Child[ i ].node == node->nodenum ) + { + return true; + } + } + + return false; + } + +void PathNode::ConnectTo + ( + PathNode *node, + byte maxheight[ NUM_WIDTH_VALUES ], + float cost, + Door *door + ) + + { + int i; + + if ( ( numChildren < NUM_PATHSPERNODE ) && ( node != this ) ) + { + Child[ numChildren ].node = node->nodenum; + for( i = 0; i < NUM_WIDTH_VALUES; i++ ) + { + Child[ numChildren ].maxheight[ i ] = maxheight[ i ]; + } + Child[ numChildren ].moveCost = ( int )cost; + Child[ numChildren ].door = door ? door->entnum : 0; + numChildren++; + } + else + { + warning( "ConnectTo", "Child overflow" ); + } + } + +void PathNode::ConnectTo + ( + PathNode *node, + byte maxheight[ NUM_WIDTH_VALUES ] + ) + + { + Vector delta; + Door *door; + + door = CheckDoor( node->origin ); + delta = node->origin - origin; + ConnectTo( node, maxheight, delta.length(), door ); + } + +void PathNode::Disconnect + ( + PathNode *node + ) + + { + int i; + + for( i = 0; i < numChildren; i++ ) + { + if ( Child[ i ].node == node->nodenum ) + { + break; + } + } + + // Should never happen, but let it slide after release + assert( i != numChildren ); + if ( i == numChildren ) + { + return; + } + + numChildren--; + + // Since we're not worried about the order of the nodes, just + // move the last node into the slot occupied by the removed node. + Child[ i ] = Child[ numChildren ]; + Child[ numChildren ].node = 0; + Child[ numChildren ].moveCost = 0; + } + +void PathNode::FindChildren + ( + Event *ev + ) + + { + trace_t trace; + Vector end; + Vector start; + + pathnodescalculated = true; + + origin.x = ( ( int )( origin.x * 0.125 ) ) * 8; + origin.y = ( ( int )( origin.y * 0.125 ) ) * 8; + setOrigin( origin ); + + //if ( !( contents & MASK_WATER ) ) + { + start = origin + "0 0 1"; + end = origin; + end[ 2 ] -= 256; + + trace = G_Trace( start, mins, maxs, end, NULL, MASK_PATHSOLID, false, "PathNode::FindChildren" ); + if ( trace.fraction != 1 && !trace.allsolid ) + { + setOrigin( trace.endpos ); + } + } + + PathManager.AddNode( this ); + } + +void PathNode::DrawConnections + ( + void + ) + + { + int i; + pathway_t *path; + PathNode *node; + + for( i = 0; i < numChildren; i++ ) + { + path = &Child[ i ]; + node = AI_GetNode( path->node ); + + G_DebugLine( origin + "0 0 24", node->origin + "0 0 24", 0.7, 0.7, 0, 1 ); + } + } + +void DrawAllConnections + ( + void + ) + + { + int i; + pathway_t *path; + PathNode *node; + PathNode *n; + Vector down; + Vector up; + Vector dir; + Vector p1; + Vector p2; + Vector p3; + Vector playerorigin; + qboolean showroutes; + qboolean shownums; + qboolean draw; + int maxheight; + int pathnum; + + showroutes = ( ai_showroutes->integer != 0 ); + shownums = ( ai_shownodenums->integer != 0 ); + + if ( ai_showroutes->integer == 1 || ai_showroutes->integer == 0 ) + { + pathnum = ( 32 / WIDTH_STEP ) - 1; + } + else + { + pathnum = ( ( ( int )ai_showroutes->integer ) / WIDTH_STEP ) - 1; + } + + if ( ( pathnum < 0 ) || ( pathnum >= MAX_WIDTH ) ) + { + gi.Printf( "ai_showroutes: Value out of range\n" ); + gi.cvar_set( "ai_showroutes", "0" ); + return; + } + + // Figure out where the camera is + + if ( !g_entities[ 0 ].client ) + return; + + playerorigin.x = g_entities[ 0 ].client->ps.origin[ 0 ]; + playerorigin.y = g_entities[ 0 ].client->ps.origin[ 1 ]; + playerorigin.z = g_entities[ 0 ].client->ps.origin[ 2 ]; + + playerorigin[ 2 ] += g_entities[ 0 ].client->ps.viewheight; + + for( node = NodeList; node != NULL; node = node->chain ) + { + /* if ( !gi.inPVS( playerorigin, node->origin ) ) + { + continue; + } */ + + if ( Vector( node->origin - playerorigin ).length() > ai_showroutes_distance->integer ) + { + continue; + } + + if ( shownums ) + { + G_DrawDebugNumber( node->origin + Vector( 0, 0, 14 ), node->nodenum, 1.5, 1, 1, 0 ); + } + + draw = false; + for( i = 0; i < node->numChildren; i++ ) + { + path = &node->Child[ i ]; + n = AI_GetNode( path->node ); + + maxheight = path->maxheight[ pathnum ]; + if ( maxheight == 0 ) + { + continue; + } + + draw = true; + + if ( !showroutes ) + { + continue; + } + + // don't draw the path if it's already been drawn by the destination node + if ( n->drawtime < level.time || !n->ConnectedTo( node ) ) + { + down.z = 2; + up.z = maxheight; + + if ( n->nodeflags & AI_JUMP && node->nodeflags & AI_JUMP ) + { + // These are jump nodes draw, them in blue instead of green + G_DebugLine( node->origin + down, n->origin + down, 0, 0, 1, 1 ); + G_DebugLine( n->origin + down, n->origin + up, 0, 0, 1, 1 ); + G_DebugLine( node->origin + up, n->origin + up, 0, 0, 1, 1 ); + G_DebugLine( node->origin + up, node->origin + down, 0, 0, 1, 1 ); + } + else + { + G_DebugLine( node->origin + down, n->origin + down, 0, 1, 0, 1 ); + G_DebugLine( n->origin + down, n->origin + up, 0, 1, 0, 1 ); + G_DebugLine( node->origin + up, n->origin + up, 0, 1, 0, 1 ); + G_DebugLine( node->origin + up, node->origin + down, 0, 1, 0, 1 ); + } + } + + // draw an arrow for the direction + dir.x = n->origin.x - node->origin.x; + dir.y = n->origin.y - node->origin.y; + dir.normalize(); + + p1 = node->origin; + p1.z += maxheight * 0.5; + p2 = dir * 8; + p3 = p1 + p2 * 2; + + G_DebugLine( p1, p3, 0, 1, 0, 1 ); + + p2.z += 8; + G_DebugLine( p3, p3 - p2, 0, 1, 0, 1 ); + + p2.z -= 16; + G_DebugLine( p3, p3 - p2, 0, 1, 0, 1 ); + } + + if ( !draw ) + { + // Put a little X where the node is to show that it had no connections + p1 = node->origin; + p1.z += 2; + + p2 = Vector( 12, 12, 0 ); + G_DebugLine( p1 - p2, p1 + p2, 1, 0, 0, 1 ); + + p2.x = -12; + G_DebugLine( p1 - p2, p1 + p2, 1, 0, 0, 1 ); + } + + node->drawtime = level.time; + } + } + +MapCell::MapCell() + { + Init(); + } + +MapCell::~MapCell() + { + Init(); + } + +void MapCell::Init + ( + void + ) + + { + numnodes = 0; + memset( nodes, 0, sizeof( nodes ) ); + } + +qboolean MapCell::AddNode + ( + PathNode *node + ) + + { + if ( numnodes >= PATHMAP_NODES ) + { + return false; + } + + nodes[ numnodes ] = ( short )node->nodenum; + numnodes++; + + return true; + } + +qboolean MapCell::RemoveNode + ( + PathNode *node + ) + + { + int i; + int num; + + num = node->nodenum; + for( i = 0; i < numnodes; i++ ) + { + if ( num == ( int )nodes[ i ] ) + { + break; + } + } + + if ( i >= numnodes ) + { + return false; + } + + numnodes--; + + // Since we're not worried about the order of the nodes, just + // move the last node into the slot occupied by the removed node. + nodes[ i ] = nodes[ numnodes ]; + nodes[ numnodes ] = 0; + + return true; + } + +PathNode *MapCell::GetNode + ( + int index + ) + + { + assert( index >= 0 ); + assert( index < numnodes ); + if ( index >= numnodes ) + { + return NULL; + } + + return AI_GetNode( nodes[ index ] ); + } + +int MapCell::NumNodes + ( + void + ) + + { + return numnodes; + } + +/* All + work and no play + makes Jim a dull boy. All + work and no play makes Jim a + dull boy. All work and no play + makes Jim a dull boy. All work and no + play makes Jim a dull boy. All work and + no play makes Jim a dull boy. All work and + no play makes Jim a dull boy. All work and no + play makes Jim a dull boy. All work and no play + makes Jim a dull boy. All work and no play makes + Jim a dull boy. All work and no play makes Jim a + dull boy. All work and no play makes Jim a dull boy. + All work and no play makes Jim a dull boy. All work + and no play makes Jim a dull boy. All work and no play + makes Jim a dull boy. All work and no play makes Jim a + dull boy. All work and no play makes Jim a dull boy. All + work and no play makes Jim a dull boy. All work and no + play makes Jim a dull boy. All work and no play makes Jim + a dull boy. All work and no play makes Jim a dull boy. + All work and no play makes Jim a dull boy. All work and + no play makes Jim a dull boy. All work and no play makes + Jim a dull boy. All work and no play makes Jim a dull + boy. All work and no play makes Jim a dull boy. All work + and no play makes Jim a dull boy. All work and no play + makes Jim a dull boy. All work and no play makes Jim a + dull boy. All work and no play makes Jim a dull boy. All + work and no play makes Jim a dull boy. All work and no + play makes Jim a dull boy. All work and no play makes + Jim a dull boy. All work and no play makes Jim a dull + boy. All work and no play makes Jim a dull boy. All + work and no play makes Jim a dull boy. All work and + no play makes Jim a dull boy. All work and no + play makes Jim a dull boy. All work and no play + makes Jim a dull boy. All work and no play + makes Jim a dull boy. All work and no play + makes Jim a dull boy. All work and no + play makes Jim a dull boy. All work + and no play makes Jim a dull boy. + All work and no play makes + Jim a dull boy. All work + and no play makes + Jim a +*/ + +CLASS_DECLARATION( Class, PathSearch, NULL ) + { + { &EV_AI_SavePaths, SavePathsEvent }, + { &EV_AI_LoadNodes, LoadNodes }, + { &EV_AI_SaveNodes, SaveNodes }, + { &EV_AI_ClearNodes, ClearNodes }, + { &EV_AI_SetNodeFlags, SetNodeFlagsEvent }, + { &EV_AI_RecalcPaths, RecalcPathsEvent }, + { &EV_AI_CalcPath, CalcPathEvent }, + { &EV_AI_DisconnectPath, DisconnectPathEvent }, + + { NULL, NULL } + }; + + +PathSearch::PathSearch() + { + AI_ResetNodes(); + } + +PathSearch::~PathSearch() + { + AI_ResetNodes(); + } + +void PathSearch::AddToGrid + ( + PathNode *node, + int x, + int y + ) + + { + PathNode *node2; + MapCell *cell; + int numnodes; + int i; + int j; + byte maxheight[ NUM_WIDTH_VALUES ]; + + cell = GetNodesInCell( x, y ); + if ( !cell ) + { + return; + } + + if ( !cell->AddNode( node ) ) + { + warning( "AddToGrid", "Node overflow at ( %d, %d )\n", x, y ); + return; + } + + if ( !loadingarchive ) + { + // + // explicitly link up the targets and their destinations + // + if ( node->nodeflags & AI_JUMP ) + { + if ( node->target.length() > 1 ) + { + node2 = AI_FindNode( node->target.c_str() ); + if ( node2 && !node->ConnectedTo( node2 ) ) + { + for( j = 0; j < NUM_WIDTH_VALUES; j++ ) + { + maxheight[ j ] = MAX_HEIGHT; + } + + if ( node != node2 ) + node->ConnectTo( node2, maxheight ); + else + gi.DPrintf( "Can't connect pathnode to itself (%s)", node->target.c_str() ); + } + } + } + + // Connect the node to its neighbors + numnodes = cell->NumNodes(); + for( i = 0; i < numnodes; i++ ) + { + node2 = ( PathNode * )cell->GetNode( i ); + if ( node2 == node ) + { + continue; + } + + if ( ( node->numChildren < NUM_PATHSPERNODE ) && !node->ConnectedTo( node2 ) ) + { + if ( node->ClearPathTo( node2, maxheight ) || node->LadderTo( node2, maxheight ) ) + { + node->ConnectTo( node2, maxheight ); + } + } + + if ( ( node2->numChildren < NUM_PATHSPERNODE ) && !node2->ConnectedTo( node ) ) + { + if ( node2->ClearPathTo( node, maxheight ) || node2->LadderTo( node, maxheight ) ) + { + node2->ConnectTo( node, maxheight ); + } + } + } + } + } + +qboolean PathSearch::RemoveFromGrid + ( + PathNode *node, + int x, + int y + ) + + { + MapCell *cell; + PathNode *node2; + int numnodes; + int i; + + cell = GetNodesInCell( x, y ); + if ( !cell || !cell->RemoveNode( node ) ) + { + return false; + } + + // Disconnect the node from all nodes in the cell + numnodes = cell->NumNodes(); + for( i = 0; i < numnodes; i++ ) + { + node2 = ( PathNode * )cell->GetNode( i ); + if ( node2->ConnectedTo( node ) ) + { + node2->Disconnect( node ); + } + } + + return true; + } + +int PathSearch::NodeCoordinate + ( + float coord + ) + + { + return ( ( int )coord + MAX_MAP_BOUNDS - ( PATHMAP_CELLSIZE / 2 ) ) / PATHMAP_CELLSIZE; + } + +int PathSearch::GridCoordinate + ( + float coord + ) + + { + return ( ( int )coord + MAX_MAP_BOUNDS ) / PATHMAP_CELLSIZE; + } + +void PathSearch::AddNode + ( + PathNode *node + ) + + { + int x; + int y; + + assert( node ); + + if ( !loadingarchive ) + { + gi.DPrintf( "." ); + } + + numNodes++; + + if ( NodeList == NULL ) + { + NodeList = node; + node->chain = NULL; + } + else + { + node->chain = NodeList; + NodeList = node; + } + + x = NodeCoordinate( node->origin[ 0 ] ); + y = NodeCoordinate( node->origin[ 1 ] ); + + AddToGrid( node, x, y ); + AddToGrid( node, x + 1, y ); + AddToGrid( node, x, y + 1 ); + AddToGrid( node, x + 1, y + 1 ); + + node->gridX = x; + node->gridY = y; + } + +void PathSearch::RemoveNode + ( + PathNode *node + ) + + { + int x; + int y; + PathNode *n; + PathNode *p; + + assert( node ); + + x = node->gridX; + y = node->gridY; + + RemoveFromGrid( node, x, y ); + RemoveFromGrid( node, x + 1, y ); + RemoveFromGrid( node, x, y + 1 ); + RemoveFromGrid( node, x + 1, y + 1 ); + + p = NULL; + for( n = NodeList; n != node; p = n, n = n->chain ) + { + if ( !n ) + { + // Not in list. + return; + } + } + + if ( p ) + { + p->chain = n->chain; + } + else + { + NodeList = n->chain; + } + + n->chain = NULL; + numNodes--; + } + +void PathSearch::UpdateNode + ( + PathNode *node + ) + + { + int x; + int y; + int mx; + int my; + + assert( node ); + + x = NodeCoordinate( node->origin[ 0 ] ); + y = NodeCoordinate( node->origin[ 1 ] ); + + mx = node->gridX; + my = node->gridY; + + RemoveFromGrid( node, mx, my ); + RemoveFromGrid( node, mx + 1, my ); + RemoveFromGrid( node, mx, my + 1 ); + RemoveFromGrid( node, mx + 1, my + 1 ); + + node->numChildren = 0; + + AddToGrid( node, x, y ); + AddToGrid( node, x + 1, y ); + AddToGrid( node, x, y + 1 ); + AddToGrid( node, x + 1, y + 1 ); + + node->gridX = x; + node->gridY = y; + } + +MapCell *PathSearch::GetNodesInCell + ( + int x, + int y + ) + + { + if ( ( x < 0 ) || ( x >= PATHMAP_GRIDSIZE ) || ( y < 0 ) || ( y >= PATHMAP_GRIDSIZE ) ) + { + return NULL; + } + + return &PathMap[ x ][ y ]; + } + +MapCell *PathSearch::GetNodesInCell + ( + Vector pos + ) + + { + int x; + int y; + + x = GridCoordinate( pos[ 0 ] ); + y = GridCoordinate( pos[ 1 ] ); + + return GetNodesInCell( x, y ); + } + +PathNode *PathSearch::NearestNode + ( + Vector pos, + Entity *ent, + qboolean usebbox + ) + + { + Vector delta; + PathNode *node; + PathNode *bestnode; + float bestdist; + float dist; + int n; + int i; + MapCell *cell; + Vector min; + Vector max; + + cell = GetNodesInCell( pos ); + if ( !cell ) + { + return NULL; + } + + if ( ent && usebbox ) + { + min = ent->mins; + max = ent->maxs; + } + else + { + min = Vector( -16, -16, 12 ); + max = Vector( 16, 16, 40 ); + } + + n = cell->NumNodes(); + + if ( ai_debugpath->integer ) + { + gi.DPrintf( "NearestNode: Checking %d nodes\n", n ); + } + + bestnode = NULL; + bestdist = 999999999; // greater than ( 8192 * sqr(2) ) ^ 2 -- maximum squared distance + for( i = 0; i < n; i++ ) + { + node = ( PathNode * )cell->GetNode( i ); + if ( !node ) + { + continue; + } + + delta = node->origin - pos; + + // get the distance squared (faster than getting real distance) + dist = delta * delta; + if ( ( dist < bestdist ) && node->CheckMove( ent, pos, min, max, false, false ) ) + { + bestnode = node; + bestdist = dist; + + // if we're close enough, early exit + if ( dist < 16 ) + { + break; + } + } + } + + return bestnode; + } + +void PathSearch::Teleport + ( + Entity *teleportee, + Vector from, + Vector to + ) + + { + PathNode *node1; + PathNode *node2; + byte maxheight[ NUM_WIDTH_VALUES ]; + int j; + + if ( ai_createnodes->integer ) + { + node1 = new PathNode; + node1->Setup( from ); + + node2 = new PathNode; + node2->Setup( to ); + + // FIXME + // shouldn't hard-code width and height + for( j = 0; j < NUM_WIDTH_VALUES; j++ ) + { + maxheight[ j ] = 72; + } + + // connect with 0 cost + node1->ConnectTo( node2, maxheight, 0 ); + } + } + +void PathSearch::ShowNodes + ( + void + ) + + { + if ( ai_showroutes->integer || ai_shownodenums->integer ) + { + DrawAllConnections(); + } + } + +int PathSearch::NumNodes + ( + void + ) + + { + return numNodes; + } + +int PathSearch::NumLoadNodes + ( + void + ) + + { + return numLoadNodes; + } + +void PathSearch::Checksum + ( + Vector &checksum + ) + + { + checksum = pathNodesChecksum; + } + +void PathSearch::Archive + ( + Archiver &arc + ) + + { + int i; + int num; + + if ( arc.Saving() ) + { + PathNode *node; + + num = 0; + for( i = 0; i < MAX_PATHNODES; i++ ) + { + node = AI_GetNode( i ); + if ( node ) + { + num++; + } + } + arc.ArchiveInteger( &num ); + for( i = 0; i < MAX_PATHNODES; i++ ) + { + node = AI_GetNode( i ); + if ( node ) + { + arc.ArchiveObject( node ); + } + } + + if ( ai_debuginfo->integer ) + { + gi.DPrintf( "Wrote %d path nodes\n", num ); + } + } + else + { + int x; + int y; + + numNodes = 0; + NodeList = NULL; + loadingarchive = true; + + // Get rid of the nodes that were spawned by the map + AI_ResetNodes(); + + // Init the grid + for( x = 0; x < PATHMAP_GRIDSIZE; x++ ) + { + for( y = 0; y < PATHMAP_GRIDSIZE; y++ ) + { + PathMap[ x ][ y ].Init(); + } + } + + arc.ArchiveInteger( &num ); + + assert( num <= MAX_PATHNODES ); + if ( num > MAX_PATHNODES ) + { + arc.FileError( "Exceeded max path nodes" ); + } + + for( i = 0; i < num; i++ ) + { + arc.ReadObject(); + } + + if ( ai_debuginfo && ai_debuginfo->integer ) + { + gi.DPrintf( "Path nodes loaded: %d\n", NumNodes() ); + } + + loadingarchive = false; + } + } + +void PathSearch::ClearNodes + ( + Event *ev + ) + + { + PathNode *node; + int i; + int num; + + num = 0; + for( i = 0; i < MAX_PATHNODES; i++ ) + { + node = AI_GetNode( i ); + if ( node ) + { + node->PostEvent( EV_Remove, 0 ); + num++; + } + } + + if ( ai_debuginfo->integer ) + { + gi.DPrintf( "Deleted %d path nodes\n", num ); + } + } + +void PathSearch::SetNodeFlagsEvent + ( + Event *ev + ) + + { + const char * token; + int i, argnum; + int mask; + int action; + int nodenum; + PathNode *node; + + nodenum = ev->GetInteger( 1 ); + node = AI_GetNode( nodenum ); + + if ( !node ) + { + ev->Error( "Node not found." ); + return; + } + + argnum = 2; + for ( i = argnum; i <= ev->NumArgs() ; i++ ) + { + token = ev->GetString( i ); + action = 0; + switch( token[0] ) + { + case '+': + action = FLAG_ADD; + token++; + break; + case '-': + action = FLAG_CLEAR; + token++; + break; + default: + ev->Error( "PathSearch::SetNodeFlagsEvent", "First character is not '+' or '-', assuming '+'\n" ); + action = FLAG_ADD; + break; + break; + } + + if (!strcmpi( token, "flee")) + { + mask = AI_FLEE; + } + else if (!strcmpi (token, "duck")) + { + mask = AI_DUCK; + } + else if (!strcmpi (token, "cover")) + { + mask = AI_COVER; + } + else if (!strcmpi (token, "door")) + { + mask = AI_DOOR; + } + else if (!strcmpi (token, "jump")) + { + mask = AI_JUMP; + } + else if (!strcmpi (token, "ladder")) + { + mask = AI_LADDER; + } + else if (!strcmpi (token, "action")) + { + mask = AI_ACTION; + } + else + { + mask = 0; + action = FLAG_IGNORE; + ev->Error( "Unknown token %s.", token ); + } + + switch (action) + { + case FLAG_ADD: + node->nodeflags |= mask; + break; + + case FLAG_CLEAR: + node->nodeflags &= ~mask; + break; + + case FLAG_IGNORE: + break; + } + } + } + +void PathSearch::CalcPathEvent + ( + Event *ev + ) + + { + int nodenum; + PathNode *node; + PathNode *node2; + int j; + byte maxheight[ NUM_WIDTH_VALUES ]; + + nodenum = ev->GetInteger( 1 ); + node = AI_GetNode( nodenum ); + + nodenum = ev->GetInteger( 2 ); + node2 = AI_GetNode( nodenum ); + + if ( !node || !node2 ) + { + ev->Error( "Node not found." ); + return; + } + + if ( ( node->numChildren < NUM_PATHSPERNODE ) && !node->ConnectedTo( node2 ) ) + { + if ( node->ClearPathTo( node2, maxheight, false ) || node->LadderTo( node2, maxheight ) ) + { + node->ConnectTo( node2, maxheight ); + } + else if ( ( node->nodeflags & AI_JUMP ) && ( node->target == node2->targetname ) ) + { + //FIXME + // don't hardcode size + for( j = 0; j < NUM_WIDTH_VALUES; j++ ) + { + maxheight[ j ] = MAX_HEIGHT; + } + node->ConnectTo( node2, maxheight ); + } + } + + if ( ( node2->numChildren < NUM_PATHSPERNODE ) && !node2->ConnectedTo( node ) ) + { + if ( node2->ClearPathTo( node, maxheight, false ) || node2->LadderTo( node, maxheight ) ) + { + node2->ConnectTo( node, maxheight ); + } + else if ( ( node2->nodeflags & AI_JUMP ) && ( node2->target == node->targetname ) ) + { + //FIXME + // don't hardcode size + for( j = 0; j < NUM_WIDTH_VALUES; j++ ) + { + maxheight[ j ] = MAX_HEIGHT; + } + node2->ConnectTo( node, maxheight ); + } + } + } + +void PathSearch::DisconnectPathEvent + ( + Event *ev + ) + + { + int nodenum; + PathNode *node; + PathNode *node2; + + nodenum = ev->GetInteger( 1 ); + node = AI_GetNode( nodenum ); + + nodenum = ev->GetInteger( 2 ); + node2 = AI_GetNode( nodenum ); + + if ( !node || !node2 ) + { + ev->Error( "Node not found." ); + return; + } + + if ( node->ConnectedTo( node2 ) ) + { + node->Disconnect( node2 ); + } + + if ( node2->ConnectedTo( node ) ) + { + node2->Disconnect( node ); + } + } + +void PathSearch::RecalcPathsEvent + ( + Event *ev + ) + + { + int nodenum; + PathNode *node; + + nodenum = ev->GetInteger( 1 ); + node = AI_GetNode( nodenum ); + if ( node ) + { + UpdateNode( node ); + } + else + { + ev->Error( "Node not found." ); + } + } + +qboolean PathSearch::ArchiveNodes + ( + str name, + qboolean save + ) + + { + Archiver arc; + qboolean success; + + if ( save ) + { + Vector checksum; + int tempInt; + + arc.Create( name ); + tempInt = PATHFILE_VERSION; + arc.ArchiveInteger( &tempInt ); + tempInt = NumNodes(); + arc.ArchiveInteger( &tempInt ); + Checksum( checksum ); + arc.ArchiveVector( &checksum ); + arc.ArchiveObject( this ); + success = qtrue; + } + else + { + int version; + + success = qfalse; + arc.Read( name, qfalse ); + arc.ArchiveInteger( &version ); + if ( version == PATHFILE_VERSION ) + { + int numnodes, file_numnodes; + Vector checksum, file_checksum; + + // get current values + numnodes = NumLoadNodes(); + Checksum( checksum ); + + // get file values + arc.ArchiveInteger( &file_numnodes ); + arc.ArchiveVector( &file_checksum ); + if ( + ( numnodes == file_numnodes ) && + ( checksum == file_checksum ) + ) + { + arc.ArchiveObject( this ); + if ( arc.NoErrors() ) + { + success = qtrue; + } + } + else + { + gi.Printf( "Pathnodes have changed, rebuilding.\n" ); + } + } + else + { + gi.Printf( "Expecting version %d path file. Path file is version %d.", PATHFILE_VERSION, version ); + } + + } + arc.Close(); + return success; + } + +void PathSearch::SaveNodes + ( + Event *ev + ) + + { + str name; + + if ( ev->NumArgs() != 1 ) + { + gi.Printf( "Usage: ai_save [filename]\n" ); + return; + } + + name = ev->GetString( 1 ); + + gi.Printf( "Archiving\n" ); + + ArchiveNodes( name, qtrue ); + + gi.Printf( "done.\n" ); + pathnodescalculated = false; + } + +void PathSearch::LoadNodes + ( + Event *ev + ) + + { + Archiver arc; + str name; + bool rebuild; + + if ( ev->NumArgs() != 1 ) + { + gi.Printf( "Usage: ai_load [filename]\n" ); + return; + } + + gi.Printf( "Loading nodes...\n" ); + + name = ev->GetString( 1 ); + + rebuild = !ArchiveNodes( name, qfalse ); + + if ( rebuild ) + { + // Only replace the file if this event was called from our init function (as opposed to the user + // calling us from the console) + if ( ( ev->GetSource() == EV_FROM_CODE ) ) + { + gi.Printf( "Replacing file.\n\n" ); + + // At this point, the nodes are still scheduled to find their neighbors, because we posted this event + // before we the nodes were spawned. Post the event with 0 delay so that it gets processed after all + // the nodes find their neighbors. + PostEvent( EV_AI_SavePaths, 0 ); + } + else + { + // otherwise, just let them know that the path file needs to be replaced. + gi.Printf( "Type 'ai_savepaths' at the console to replace the current path file.\n" ); + } + + // Print out something fairly obvious + gi.DPrintf( "***********************************\n" + "***********************************\n" + "\n" + "Creating paths...\n" + "\n" + "***********************************\n" + "***********************************\n" ); + } + } + +void PathSearch::SavePaths + ( + void + ) + + { + str filename; + Event *ev; + + if ( loadingarchive ) + { + // force it to zero since we probably had an error + gi.cvar_set( "ai_createnodes", "0" ); + } + + if ( + !loadingarchive && + ( + ( ai_createnodes && ai_createnodes->integer ) || + ( pathnodescalculated ) + ) + ) + { + filename = "maps/"; + filename += level.mapname; + filename += ".pth"; + + gi.DPrintf( "\nSaving path nodes to '%s'\n", filename.c_str() ); + + ev = new Event( EV_AI_SaveNodes ); + ev->AddString( filename ); + ProcessEvent( ev ); + } + } + +void PathSearch::SavePathsEvent + ( + Event *ev + ) + + { + str temp; + + temp = ai_createnodes->string; + gi.cvar_set( "ai_createnodes", "1" ); + + SavePaths(); + + gi.cvar_set( "ai_createnodes", temp.c_str() ); + } + +void PathSearch::Init + ( + const char *mapname + ) + + { + int x; + int y; + str filename; + Event *ev; + + pathNodesChecksum = vec_zero; + pathnodescalculated = false; + + gi.AddCommand( "ai_savepaths" ); + gi.AddCommand( "ai_save" ); + gi.AddCommand( "ai_load" ); + gi.AddCommand( "ai_clearnodes" ); + gi.AddCommand( "ai_recalcpaths" ); + ai_createnodes = gi.cvar ("ai_createnodes", "0", 0); + ai_debugpath = gi.cvar ("ai_debugpath", "0", 0); + ai_debuginfo = gi.cvar ("ai_debuginfo", "0", 0); + ai_showroutes = gi.cvar ("ai_showroutes", "0", 0); + ai_showroutes_distance = gi.cvar ("ai_showroutes_distance", "1000", 0); + ai_shownodenums = gi.cvar ("ai_shownodenums", "0", 0); + ai_timepaths = gi.cvar ("ai_timepaths", "0", 0); + + numLoadNodes = 0; + numNodes = 0; + NodeList = NULL; + loadingarchive = false; + + // Get rid of the nodes that were spawned by the map + AI_ResetNodes(); + + // Init the grid + for( x = 0; x < PATHMAP_GRIDSIZE; x++ ) + { + for( y = 0; y < PATHMAP_GRIDSIZE; y++ ) + { + PathMap[ x ][ y ].Init(); + } + } + + if ( LoadingSavegame ) + { + // no need to go further here + return; + } + + if ( mapname ) + { + filename = "maps/"; + filename += mapname; + filename += ".pth"; + if ( gi.FS_ReadFile( filename.c_str(), NULL, qtrue ) != -1 ) + { + ev = new Event( EV_AI_LoadNodes ); + ev->AddString( filename ); + + // This can't happen until the world is spawned + PostEvent( ev, 0 ); + } + else + { + // Print out something fairly obvious + gi.DPrintf( "***********************************\n" + "***********************************\n" + "\n" + "No paths found. Creating paths...\n" + "\n" + "***********************************\n" + "***********************************\n" ); + } + } + } + diff --git a/source/source/fgame/navigate.h b/source/source/fgame/navigate.h new file mode 100644 index 0000000..72f1d7b --- /dev/null +++ b/source/source/fgame/navigate.h @@ -0,0 +1,841 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/navigate.h $ +// $Revision:: 14 $ +// $Author:: Aldie $ +// $Date:: 7/25/00 11:32p $ +// +// Copyright (C) 1998 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/navigate.h $ +// +// 14 7/25/00 11:32p Aldie +// Made some changes to the memory system and fixed a memory allocation bug in +// Z_TagMalloc. Also changed a lot of classes to subclass from Class. +// +// 13 6/14/00 2:17p Markd +// fixed compiler warnings for Intel Compiler +// +// 12 5/25/00 4:27p Markd +// rewrote archive functions +// +// 11 5/24/00 3:14p Markd +// first phase of save/load games +// +// 10 3/17/00 11:53a Steven +// Added jumping stuff. +// +// 9 3/06/00 8:12p Markd +// removed unused cvar +// +// 8 2/04/00 1:29p Markd +// Added checksum to ai path nodes. It auto saves on exit now and will +// automatically re-build nodes as needed +// +// 7 2/04/00 11:18a Markd +// Fixed memory leak with AI_PathNodes +// +// 6 1/25/00 6:33p Steven +// Fixed some path node stuff. +// +// 5 1/06/00 11:08p Jimdose +// cleaning up unused code +// +// 4 10/01/99 6:31p Markd +// added commands hidden inside fgame so that they would show up for command +// completion +// +// 3 10/01/99 4:52p Markd +// Made Warning level 4 work on all projects +// +// 2 9/28/99 5:15p Markd +// Fixed more merge bugs with sharing class, vector and listener between three +// modules +// +// 1 9/10/99 10:54a Jimdose +// +// 1 9/08/99 3:16p Aldie +// +// 9 7/07/99 11:26a Steven +// Added some stuff on the sector pathfinding approach. +// +// DESCRIPTION: +// Potentially could be an C++ implementation of the A* search algorithm, but +// is currently unfinished. +// + +#ifndef __NAVIGATE_H__ +#define __NAVIGATE_H__ + +#include "g_local.h" +#include "class.h" +#include "entity.h" +#include "stack.h" +#include "container.h" +#include "doors.h" +#include "../qcommon/qfiles.h" + + +extern Event EV_AI_SavePaths; +extern Event EV_AI_SaveNodes; +extern Event EV_AI_LoadNodes; +extern Event EV_AI_ClearNodes; +extern Event EV_AI_RecalcPaths; +extern Event EV_AI_CalcPath; +extern Event EV_AI_DisconnectPath; + +extern cvar_t *ai_createnodes; +extern cvar_t *ai_shownodes; +extern cvar_t *ai_debugpath; +extern cvar_t *ai_debuginfo; +extern cvar_t *ai_showroutes; +extern cvar_t *ai_timepaths; + +extern int ai_maxnode; + +#define MAX_PATHCHECKSPERFRAME 4 + +extern int path_checksthisframe; + +#define MAX_PATH_LENGTH 128 // should be more than plenty +#define NUM_PATHSPERNODE 16 + +class Path; +class PathNode; + +#define NUM_WIDTH_VALUES 16 +#define WIDTH_STEP 8 +#define MAX_WIDTH ( WIDTH_STEP * NUM_WIDTH_VALUES ) +#define MAX_HEIGHT 128 + +#define CHECK_PATH( path, width, height ) \ + ( ( ( ( width ) >= MAX_WIDTH ) || ( ( width ) < 0 ) ) ? false : \ + ( ( int )( path )->maxheight[ ( ( width ) / WIDTH_STEP ) - 1 ] < ( int )( height ) ) ) + +typedef struct + { + short node; + short moveCost; + byte maxheight[ NUM_WIDTH_VALUES ]; + int door; + } pathway_t; + +typedef enum { NOT_IN_LIST, IN_OPEN, IN_CLOSED } pathlist_t; + +#define AI_FLEE 1 +#define AI_DUCK 2 +#define AI_COVER 4 +#define AI_DOOR 8 +#define AI_JUMP 16 +#define AI_LADDER 32 +#define AI_ACTION 64 + +void DrawAllConnections( void ); + +class PathNode : public Listener + { + public: + PathNode *chain; + pathway_t Child[ NUM_PATHSPERNODE ]; // these are the real connections between nodex + int numChildren; + + // These variables are all used during the search + int f; + int h; + int g; + + int gridX; + int gridY; + + float drawtime; + float occupiedTime; + int entnum; + + pathlist_t inlist; + + // reject is used to indicate that a node is unfit for ending on during a search + qboolean reject; + + PathNode *Parent; + + // For the open and closed lists + PathNode *NextNode; + + int nodeflags; + + friend class PathSearch; + friend void DrawAllConnections( void ); + + private : + qboolean TestMove( Entity *ent, Vector start, Vector end, Vector &min, Vector &max, qboolean allowdoors = false, qboolean fulltest = false ); + + qboolean ConnectedTo( PathNode *node ); + void ConnectTo( PathNode *node, byte maxheight[ NUM_WIDTH_VALUES ], float cost, Door *door = NULL ); + void ConnectTo( PathNode *node, byte maxheight[ NUM_WIDTH_VALUES ] ); + void Disconnect( PathNode *node ); + + void FindChildren( Event *ev ); + void FindEntities( Event *ev ); + void SetNodeFlags( Event *ev ); + void SetOriginEvent( Event *ev ); + void SetAngle( Event *ev ); + void SetAngles( Event *ev ); + void SetAnim( Event *ev ); + void SetTargetname( Event *ev ); + void SetTarget( Event *ev ); + + public: + CLASS_PROTOTYPE( PathNode ); + + int contents; + Vector origin; + Vector angles; + Vector mins; + Vector maxs; + str targetname; + str target; + + int nodenum; + + qboolean setangles; + str animname; + + PathNode(); + ~PathNode(); + + void Setup( Vector pos ); + void setAngles( Vector ang ); + void setOrigin( Vector org ); + void setSize( Vector min, Vector max ); + str &TargetName( void ); + virtual void Archive( Archiver &arc ); + + qboolean CheckPath( PathNode *node, Vector min, Vector max, qboolean fulltest = true ); + Door *CheckDoor( Vector pos ); + + qboolean CheckMove( Entity *ent, Vector pos, Vector &min, Vector &max, qboolean allowdoors = false, qboolean fulltest = false ); + qboolean CheckMove( Vector pos, Vector min, Vector max ); + qboolean ClearPathTo( PathNode *node, byte maxheight[ NUM_WIDTH_VALUES ], qboolean fulltest = true ); + qboolean LadderTo( PathNode *node, byte maxheight[ NUM_WIDTH_VALUES ] ); + void DrawConnections( void ); + }; + +typedef SafePtr PathNodePtr; + +#define PATHMAP_CELLSIZE 256 +#define PATHMAP_GRIDSIZE ( MAX_MAP_BOUNDS * 2 / PATHMAP_CELLSIZE ) + +#define PATHMAP_NODES 126 // 128 - sizeof( int ) / sizeof( short ) + +class MapCell : public Class + { + private : + int numnodes; + short nodes[ PATHMAP_NODES ]; + + public : + MapCell(); + ~MapCell(); + void Init( void ); + qboolean AddNode( PathNode *node ); + qboolean RemoveNode( PathNode *node ); + PathNode *GetNode( int index ); + int NumNodes( void ); + }; + +class PathSearch : public Listener + { + private: + MapCell PathMap[ PATHMAP_GRIDSIZE ][ PATHMAP_GRIDSIZE ]; + + void AddToGrid( PathNode *node, int x, int y ); + qboolean RemoveFromGrid( PathNode *node, int x, int y ); + int NodeCoordinate( float coord ); + int GridCoordinate( float coord ); + void ClearNodes( Event *ev ); + void LoadNodes( Event *ev ); + void SaveNodes( Event *ev ); + qboolean ArchiveNodes( str name, qboolean save ); + void SavePathsEvent( Event *ev ); + void SetNodeFlagsEvent( Event *ev ); + void RecalcPathsEvent( Event *ev ); + void CalcPathEvent( Event *ev ); + void DisconnectPathEvent( Event *ev ); + + public: + CLASS_PROTOTYPE( PathSearch ); + + PathSearch(); + ~PathSearch(); + void Archive( Archiver &arc ); + void AddNode( PathNode *node ); + void RemoveNode( PathNode *node ); + void UpdateNode( PathNode *node ); + MapCell *GetNodesInCell( int x, int y ); + MapCell *GetNodesInCell( Vector pos ); + PathNode *NearestNode( Vector pos, Entity *ent = NULL, qboolean usebbox = true ); + void Teleport( Entity *teleportee, Vector from, Vector to ); + void ShowNodes( void ); + int NumNodes( void ); + int NumLoadNodes( void ); + void Checksum( Vector &checksum ); + void SavePaths( void ); + void Init( const char *mapname ); + }; + +extern PathSearch PathManager; + +#define MAX_PATHNODES 2048 + +PathNode *AI_FindNode( const char *name ); +PathNode *AI_GetNode( int num ); +void AI_AddNode( PathNode *node ); +void AI_RemoveNode( PathNode *node ); +void AI_ResetNodes( void ); + +#include "path.h" + +template +class PathFinder : public Class + { + private: + Stack stack; + PathNode *OPEN; + PathNode *CLOSED; + PathNode *endnode; + + void ClearPath( void ); + void ClearOPEN( void ); + void ClearCLOSED( void ); + PathNode *ReturnBestNode( void ); + void GenerateSuccessors( PathNode *BestNode ); + void Insert( PathNode *Successor ); + void PropagateDown( PathNode *Old ); + Path *CreatePath( PathNode *startnode ); + + public: + Heuristic heuristic; + + PathFinder(); + ~PathFinder(); + Path *FindPath( PathNode *from, PathNode *to ); + Path *FindPath( Vector start, Vector end ); + }; + +template +PathFinder::PathFinder() + { + OPEN = NULL; + CLOSED = NULL; + } + +template +PathFinder::~PathFinder() + { + ClearPath(); + } + +template +void PathFinder::ClearOPEN + ( + void + ) + + { + PathNode *node; + + while( OPEN ) + { + node = OPEN; + OPEN = node->NextNode; + + node->inlist = NOT_IN_LIST; + node->NextNode = NULL; + node->Parent = NULL; + + // reject is used to indicate that a node is unfit for ending on during a search + node->reject = false; + } + } + +template +void PathFinder::ClearCLOSED + ( + void + ) + + { + PathNode *node; + + while( CLOSED ) + { + node = CLOSED; + CLOSED = node->NextNode; + + node->inlist = NOT_IN_LIST; + node->NextNode = NULL; + node->Parent = NULL; + + // reject is used to indicate that a node is unfit for ending on during a search + node->reject = false; + } + } + +template +void PathFinder::ClearPath + ( + void + ) + + { + stack.Clear(); + ClearOPEN(); + ClearCLOSED(); + } + +template +Path *PathFinder::FindPath + ( + PathNode *from, + PathNode *to + ) + + { + Path *path; + PathNode *node; + int start = 0; + int end; + qboolean checktime; + + checktime = false; + if ( ai_timepaths->integer ) + { + start = gi.Milliseconds(); + checktime = true; + } + + OPEN = NULL; + CLOSED = NULL; + + endnode = to; + + // Should always be NULL at this point + assert( !from->NextNode ); + + // make Open List point to first node + OPEN = from; + from->g = 0; + from->h = heuristic.dist( from, endnode ); + from->NextNode = NULL; + + node = ReturnBestNode(); + while( node && !heuristic.done( node, endnode ) ) + { + GenerateSuccessors( node ); + node = ReturnBestNode(); + } + + if ( !node ) + { + path = NULL; + if ( ai_debugpath->integer ) + { + gi.DPrintf( "Search failed--no path found.\n" ); + } + } + else + { + path = CreatePath( node ); + } + + ClearPath(); + + if ( checktime ) + { + end = gi.Milliseconds(); + if ( ai_timepaths->integer <= ( end - start ) ) + { + gi.DebugPrintf( "%d: ent #%d : %d\n", level.framenum, heuristic.entnum, end - start ); + } + } + + return path; + } + +template +Path *PathFinder::FindPath + ( + Vector start, + Vector end + ) + + { + PathNode *from; + PathNode *to; + Entity *ent; + + ent = G_GetEntity( heuristic.entnum ); + from = PathManager.NearestNode( start, ent ); + to = PathManager.NearestNode( end, ent ); + + if ( !from ) + { + if ( ai_debugpath->integer ) + { + gi.DPrintf( "Search failed--couldn't find closest source.\n" ); + } + return NULL; + } + + if ( !from || !to ) + { + if ( ai_debugpath->integer ) + { + gi.DPrintf( "Search failed--couldn't find closest destination.\n" ); + } + return NULL; + } + + return FindPath( from, to ); + } + +template +Path *PathFinder::CreatePath + ( + PathNode *startnode + ) + + { + PathNode *node; + Path *p; + int i; + int n; + PathNode *reverse[ MAX_PATH_LENGTH ]; + + // unfortunately, the list goes goes from end to start, so we have to reverse it + for( node = startnode, n = 0; ( node != NULL ) && ( n < MAX_PATH_LENGTH ); node = node->Parent, n++ ) + { + assert( n < MAX_PATH_LENGTH ); + reverse[ n ] = node; + } + + p = new Path( n ); + for( i = n - 1; i >= 0; i-- ) + { + p->AddNode( reverse[ i ] ); + } + + if ( ai_debugpath->integer ) + { + gi.DPrintf( "%d nodes in path\n", n ); + gi.DPrintf( "%d nodes allocated\n", PathManager.NumNodes() ); + } + + return p; + } + +template +PathNode *PathFinder::ReturnBestNode + ( + void + ) + + { + PathNode *bestnode; + + if ( !OPEN ) + { + // No more nodes on OPEN + return NULL; + } + + // Pick node with lowest f, in this case it's the first node in list + // because we sort the OPEN list wrt lowest f. Call it BESTNODE. + + bestnode = OPEN; // point to first node on OPEN + OPEN = bestnode->NextNode; // Make OPEN point to nextnode or NULL. + + // Next take BESTNODE (or temp in this case) and put it on CLOSED + bestnode->NextNode = CLOSED; + CLOSED = bestnode; + + bestnode->inlist = IN_CLOSED; + + return( bestnode ); + } + +template +void PathFinder::GenerateSuccessors + ( + PathNode *BestNode + ) + + { + int i; + int g; // total path cost - as stored in the linked lists. + PathNode *node; + pathway_t *path; + + for( i = 0; i < BestNode->numChildren; i++ ) + { + path = &BestNode->Child[ i ]; + node = AI_GetNode( path->node ); + + // g(Successor)=g(BestNode)+cost of getting from BestNode to Successor + g = BestNode->g + heuristic.cost( BestNode, i ); + + switch( node->inlist ) + { + case NOT_IN_LIST : + // Only allow this if it's valid + if ( heuristic.validpath( BestNode, i ) ) + { + node->Parent = BestNode; + node->g = g; + node->h = heuristic.dist( node, endnode ); + node->f = g + node->h; + + // Insert Successor on OPEN list wrt f + Insert( node ); + } + break; + + case IN_OPEN : + // if our new g value is < node's then reset node's parent to point to BestNode + if ( g < node->g ) + { + node->Parent = BestNode; + node->g = g; + node->f = g + node->h; + } + break; + + case IN_CLOSED : + // if our new g value is < Old's then reset Old's parent to point to BestNode + if ( g < node->g ) + { + node->Parent = BestNode; + node->g = g; + node->f = g + node->h; + + // Since we changed the g value of Old, we need + // to propagate this new value downwards, i.e. + // do a Depth-First traversal of the tree! + PropagateDown( node ); + } + break; + + default : + // shouldn't happen, but try to catch it during debugging phase + assert( NULL ); + gi.Error( ERR_DROP, "Corrupted path node" ); + break; + } + } + } + +template +void PathFinder::Insert + ( + PathNode *node + ) + + { + PathNode *prev; + PathNode *next; + int f; + + node->inlist = IN_OPEN; + f = node->f; + + // special case for if the list is empty, or it should go at head of list (lowest f) + if ( ( OPEN == NULL ) || ( f < OPEN->f ) ) + { + node->NextNode = OPEN; + OPEN = node; + return; + } + + // do sorted insertion into OPEN list in order of ascending f + prev = OPEN; + next = OPEN->NextNode; + while( ( next != NULL ) && ( next->f < f ) ) + { + prev = next; + next = next->NextNode; + } + + // insert it between the two nodes + node->NextNode = next; + prev->NextNode = node; + } + +template +void PathFinder::PropagateDown + ( + PathNode *node + ) + + { + int c; + unsigned g; + unsigned movecost; + PathNode *child; + PathNode *parent; + pathway_t *path; + int n; + + g = node->g; + n = node->numChildren; + for( c = 0; c < n; c++ ) + { + path = &node->Child[ c ]; + child = AI_GetNode( path->node ); + + movecost = g + heuristic.cost( node, c ); + if ( movecost < child->g ) + { + child->g = movecost; + child->f = child->g + child->h; + child->Parent = node; + + // reset parent to new path. + // Now the Child's branch need to be + // checked out. Remember the new cost must be propagated down. + stack.Push( child ); + } + } + + while( !stack.Empty() ) + { + parent = stack.Pop(); + n = parent->numChildren; + for( c = 0; c < n; c++ ) + { + path = &parent->Child[ c ]; + child = AI_GetNode( path->node ); + + // we stop the propagation when the g value of the child is equal or better than + // the cost we're propagating + movecost = parent->g + path->moveCost; + if ( movecost < child->g ) + { + child->g = movecost; + child->f = child->g + child->h; + child->Parent = parent; + stack.Push( child ); + } + } + } + } + +class StandardMovement : public Class + { + public: + int minwidth; + int minheight; + int entnum; + qboolean can_jump; + + inline void setSize + ( + Vector size + ) + + { + minwidth = max( size.x, size.y ); + minheight = size.z; + } + + inline int dist + ( + PathNode *node, + PathNode *end + ) + + { + Vector delta; + int d1; + int d2; + int d3; + int h; + + delta = node->origin - end->origin; + d1 = abs( ( int )delta[ 0 ] ); + d2 = abs( ( int )delta[ 1 ] ); + d3 = abs( ( int )delta[ 2 ] ); + h = max( d1, d2 ); + h = max( d3, h ); + + return h; + } + + inline qboolean validpath + ( + PathNode *node, + int i + ) + + { + pathway_t *path; + PathNode *n; + + path = &node->Child[ i ]; + + if ( CHECK_PATH( path, minwidth, minheight ) ) + { + return false; + } + + if ( path->door ) + { + Door *door; + + door = ( Door * )G_GetEntity( path->door ); + if ( !door->CanBeOpenedBy( G_GetEntity( entnum ) ) ) + { + return false; + } + } + + n = AI_GetNode( path->node ); + + if ( node->nodeflags & AI_JUMP && n->nodeflags & AI_JUMP && !can_jump ) + return false; + + if ( n && ( n->occupiedTime > level.time ) && ( n->entnum != entnum ) ) + { + return false; + } + + return true; + } + + inline int cost + ( + PathNode *node, + int i + ) + + { + return node->Child[ i ].moveCost; + } + + inline qboolean done + ( + PathNode *node, + PathNode *end + ) + + { + return node == end; + } + }; + +typedef PathFinder StandardMovePath; + +#endif /* navigate.h */ diff --git a/source/source/fgame/object.cpp b/source/source/fgame/object.cpp new file mode 100644 index 0000000..841f3e3 --- /dev/null +++ b/source/source/fgame/object.cpp @@ -0,0 +1,493 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/object.cpp $ +// $Revision:: 15 $ +// $Author:: Markd $ +// $Date:: 7/03/00 7:56p $ +// +// Copyright (C) 1998 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source is may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/object.cpp $ +// +// 15 7/03/00 7:56p Markd +// fixed setup and anim events +// +// 14 6/23/00 8:41p Markd +// made a lot of changes to different constructors for saved game support +// +// 13 6/14/00 3:50p Markd +// Cleaned up more Intel Compiler warnings +// +// 12 5/10/00 10:32a Steven +// Added com_blood stuff. +// +// 11 1/27/00 11:35a Markd +// Fixed solid/notsolid client side entities +// +// 10 1/15/00 3:57p Markd +// Eliminated multiple "angle" events and replaced them with EV_SetAngle +// +// 9 1/14/00 5:07p Markd +// Removed surface num, tri_num and damage_multiplier from multiple functions +// and events +// +// 8 1/12/00 6:12p Jimdose +// rewrote CreateExplosion +// +// 7 1/05/00 7:25p Jimdose +// made angle functions all use the same coordinate system +// AngleVectors now returns left instead of right +// no longer need to invert pitch +// +// 6 10/21/99 5:24p Aldie +// Changed Object::Setup to use Anim_Random +// +// 5 9/29/99 5:18p Steven +// Event formatting. +// +// 4 9/22/99 4:48p Markd +// fixed more G_GetEntity, G_FindClass and G_GetNextEntity bugs +// +// 3 9/21/99 7:51p Markd +// Fixed a lot of entitynum_none issues +// +// 2 9/13/99 4:22p Jimdose +// merge +// +// 1 9/10/99 10:54a Jimdose +// +// 1 9/08/99 3:16p Aldie +// +// 15 8/26/99 5:57p Markd +// Re-added fx_sprite support +// +// 14 6/11/99 1:23p Phook +// +// 13 6/11/99 12:58p Phook +// Changed from SINED comments to QUAKED +// +// 12 6/11/99 12:46p Phook +// EClass color changes +// +// DESCRIPTION: +// + + +#include "g_local.h" +#include "object.h" +#include "sentient.h" +#include "misc.h" +#include "explosion.h" +#include "gibs.h" +#include "specialfx.h" + +Event EV_Object_Setup + ( + "_setup", + EV_DEFAULT, + NULL, + NULL, + "Sets up an object." + ); +Event EV_Object_SetAnim + ( + "anim", + EV_DEFAULT, + "s", + "animname", + "Sets up the object with the specified animname." + ); + +Event EV_Object_Shootable + ( + "shootable", + EV_DEFAULT, + NULL, + NULL, + "Make the object shootable but not necessarily solid to the player." + ); + +CLASS_DECLARATION( Animate, Object, "object" ) + { + { &EV_Killed, Killed }, + { &EV_Object_Setup, Setup }, + { &EV_Object_SetAnim, SetAnim }, + { &EV_Object_Shootable, MakeShootable }, + { NULL, NULL } + }; + +Object::Object() + { + if ( LoadingSavegame ) + { + // Archive function will setup all necessary data + return; + } + // + // all objects default to not solid + // + setSolidType( SOLID_NOT ); + + health = 0; + + takedamage = ( spawnflags & 2 ) ? DAMAGE_NO : DAMAGE_YES; + + // + // we want the bounds of this model auto-rotated + // + flags |= FL_ROTATEDBOUNDS; + + if ( !com_blood->integer ) + { + flags &= ~FL_BLOOD; + flags &= ~FL_DIE_GIBS; + } + + PostEvent( EV_Object_Setup, EV_POSTSPAWN ); + } + +void Object::SetAnim + ( + Event *ev + ) + + { + int animnum; + + if ( ( ev->NumArgs() >= 1 ) && gi.IsModel( edict->s.modelindex ) ) + { + animnum = gi.Anim_Random( edict->s.modelindex, ev->GetString( 1 ) ); + if ( animnum >= 0 ) + { + NewAnim( animnum ); + } + } + } + + +void Object::Setup + ( + Event *ev + ) + + { + if ( !health ) + { + health = ( maxs - mins ).length(); + max_health = health; + } + } + +void Object::MakeShootable + ( + Event *ev + ) + + { + setContents( CONTENTS_SHOOTABLE_ONLY ); + link(); + } + +void Object::Killed(Event *ev) + { + Entity * ent; + Entity * attacker; + Vector dir; + Event * event; + const char * name; + + takedamage = DAMAGE_NO; + setSolidType( SOLID_NOT ); + hideModel(); + + attacker = ev->GetEntity( 1 ); + + if (flags & FL_DIE_EXPLODE) + { + CreateExplosion( origin, 50, this, this, this ); + } + + if (flags & FL_DIE_GIBS) + { + setSolidType( SOLID_NOT ); + hideModel(); + + CreateGibs( this, -150, edict->s.scale, 3 ); + } + +// +// kill the killtargets +// + name = KillTarget(); + if ( name && strcmp( name, "" ) ) + { + ent = NULL; + do + { + ent = G_FindTarget( ent, name ); + if ( !ent ) + { + break; + } + ent->PostEvent( EV_Remove, 0 ); + } + while ( 1 ); + } + +// +// fire targets +// + name = Target(); + if ( name && strcmp( name, "" ) ) + { + ent = NULL; + do + { + ent = G_FindTarget( ent, name ); + if ( !ent ) + { + break; + } + event = new Event( EV_Activate ); + event->AddEntity( attacker ); + ent->ProcessEvent( event ); + } + while ( 1 ); + } + + PostEvent( EV_Remove, 0 ); + } + +/*****************************************************************************/ +/*QUAKED func_throwobject (0 0.25 0.5) (-16 -16 0) (16 16 32) + +This is an object you can pickup and throw at people +******************************************************************************/ + +Event EV_ThrowObject_Pickup + ( + "pickup", + EV_DEFAULT, + "es", + "entity tag_name", + "Picks up this throw object and attaches it to the entity." + ); +Event EV_ThrowObject_Throw + ( + "throw", + EV_DEFAULT, + "efeF", + "owner speed targetent grav", + "Throw this throw object." + ); +Event EV_ThrowObject_PickupOffset + ( + "pickupoffset", + EV_DEFAULT, + "v", + "pickup_offset", + "Sets the pickup_offset." + ); +Event EV_ThrowObject_ThrowSound + ( + "throwsound", + EV_DEFAULT, + "s", + "throw_sound", + "Sets the sound to play when object is thrown." + ); + +CLASS_DECLARATION( Object, ThrowObject, "func_throwobject" ) + { + { &EV_Touch, Touch }, + { &EV_ThrowObject_Pickup, Pickup }, + { &EV_ThrowObject_Throw, Throw }, + { &EV_ThrowObject_PickupOffset, PickupOffset }, + { &EV_ThrowObject_ThrowSound, ThrowSound }, + { NULL, NULL } + }; + +ThrowObject::ThrowObject() + { + if ( LoadingSavegame ) + { + // Archive function will setup all necessary data + return; + } + pickup_offset = vec_zero; + } + +void ThrowObject::PickupOffset + ( + Event *ev + ) + { + pickup_offset = edict->s.scale * ev->GetVector( 1 ); + } + +void ThrowObject::ThrowSound + ( + Event *ev + ) + { + throw_sound = ev->GetString( 1 ); + } + +void ThrowObject::Touch + ( + Event *ev + ) + + { + Entity *other; + + if ( movetype != MOVETYPE_BOUNCE ) + { + return; + } + + other = ev->GetEntity( 1 ); + assert( other ); + + if ( other->isSubclassOf( Teleporter ) ) + { + return; + } + + if ( other->entnum == owner ) + { + return; + } + + if ( throw_sound.length() ) + { + StopLoopSound(); + } + + if ( other->takedamage ) + { + other->Damage( this, G_GetEntity( owner ), size.length() * velocity.length() / 400, origin, velocity, + level.impact_trace.plane.normal, 32, 0, MOD_THROWNOBJECT ); + } + + Damage( this, this, max_health, origin, velocity, level.impact_trace.plane.normal, 32, 0, MOD_THROWNOBJECT ); + } + +void ThrowObject::Throw + ( + Event *ev + ) + + { + Entity *owner; + Sentient *targetent; + float speed; + float traveltime; + float vertical_speed; + Vector target; + Vector dir; + float grav; + Vector xydir; + Event *e; + + owner = ev->GetEntity( 1 ); + assert( owner ); + + if ( !owner ) + { + return; + } + + speed = ev->GetFloat( 2 ); + if ( !speed ) + { + speed = 1; + } + + targetent = ( Sentient * )ev->GetEntity( 3 ); + assert( targetent ); + if (!targetent) + { + return; + } + + if ( ev->NumArgs() == 4 ) + { + grav = ev->GetFloat( 4 ); + } + else + { + grav = 1; + } + + e = new Event( EV_Detach ); + ProcessEvent( e ); + + this->owner = owner->entnum; + edict->ownerNum = owner->entnum; + + gravity = grav; + + target = targetent->origin; + target.z += targetent->viewheight; + + setMoveType( MOVETYPE_BOUNCE ); + setSolidType( SOLID_BBOX ); + edict->clipmask = MASK_PROJECTILE; + + dir = target - origin; + xydir = dir; + xydir.z = 0; + traveltime = xydir.length() / speed; + vertical_speed = ( dir.z / traveltime ) + ( 0.5f * gravity * sv_gravity->value * traveltime ); + xydir.normalize(); + + // setup ambient flying sound + if ( throw_sound.length() ) + { + LoopSound( throw_sound.c_str() ); + } + + velocity = speed * xydir; + velocity.z = vertical_speed; + + angles = velocity.toAngles(); + setAngles( angles ); + + avelocity.x = crandom() * 200; + avelocity.y = crandom() * 200; + takedamage = DAMAGE_YES; + } + +void ThrowObject::Pickup + ( + Event *ev + ) + + { + Entity * ent; + Event * e; + str bone; + + ent = ev->GetEntity( 1 ); + + assert( ent ); + if ( !ent ) + { + return; + } + bone = ev->GetString( 2 ); + + setOrigin( pickup_offset ); + + e = new Event( EV_Attach ); + e->AddEntity( ent ); + e->AddString( bone ); + ProcessEvent( e ); + + edict->s.renderfx &= ~RF_FRAMELERP; + } diff --git a/source/source/fgame/object.h b/source/source/fgame/object.h new file mode 100644 index 0000000..462789e --- /dev/null +++ b/source/source/fgame/object.h @@ -0,0 +1,91 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/object.h $ +// $Revision:: 5 $ +// $Author:: Markd $ +// $Date:: 6/14/00 3:50p $ +// +// Copyright (C) 1997 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source is may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/object.h $ +// +// 5 6/14/00 3:50p Markd +// Cleaned up more Intel Compiler warnings +// +// 4 5/27/00 2:56p Markd +// Save games 2nd pass +// +// 3 5/24/00 3:14p Markd +// first phase of save/load games +// +// 2 1/27/00 11:35a Markd +// Fixed solid/notsolid client side entities +// +// 1 9/10/99 10:54a Jimdose +// +// 1 9/08/99 3:16p Aldie +// +// 5 8/26/99 5:57p Markd +// Re-added fx_sprite support +// +// DESCRIPTION: +// Object class +// + +#ifndef __OBJECT_H__ +#define __OBJECT_H__ + +#include "g_local.h" +#include "animate.h" +#include "specialfx.h" + +class Object : public Animate + { + public: + CLASS_PROTOTYPE( Object ); + + Object(); + void Killed( Event *ev ); + void SetAngle( Event *ev ); + void Setup( Event *ev ); + void SetAnim( Event *ev ); + void MakeShootable( Event *ev ); + }; + +extern Event EV_ThrowObject_Pickup; +extern Event EV_ThrowObject_Throw; + +class ThrowObject : public Object + { + private: + int owner; + Vector pickup_offset; + str throw_sound; + public: + CLASS_PROTOTYPE( ThrowObject ); + ThrowObject(); + void Touch(Event *ev); + void Throw( Event * ev ); + void Pickup( Event * ev ); + void PickupOffset( Event * ev ); + void ThrowSound( Event * ev ); + virtual void Archive( Archiver &arc ); + }; + +inline void ThrowObject::Archive + ( + Archiver &arc + ) + { + Object::Archive( arc ); + + arc.ArchiveInteger( &owner ); + arc.ArchiveVector( &pickup_offset ); + arc.ArchiveString( &throw_sound ); + } + +#endif /* object.h */ diff --git a/source/source/fgame/path.cpp b/source/source/fgame/path.cpp new file mode 100644 index 0000000..70bd5c3 --- /dev/null +++ b/source/source/fgame/path.cpp @@ -0,0 +1,469 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/path.cpp $ +// $Revision:: 2 $ +// $Author:: Markd $ +// $Date:: 6/14/00 3:50p $ +// +// Copyright (C) 1997 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source is may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/path.cpp $ +// +// 2 6/14/00 3:50p Markd +// Cleaned up more Intel Compiler warnings +// +// 1 9/10/99 10:54a Jimdose +// +// 1 9/08/99 3:16p Aldie +// +// DESCRIPTION: +// + +#include "g_local.h" +#include "entity.h" +#include "path.h" +#include "container.h" +#include "navigate.h" +#include "misc.h" + +CLASS_DECLARATION( Class, Path, NULL ) + { + { NULL, NULL } + }; + +Path::Path() + { + pathlength = 0; + from = NULL; + to = NULL; + nextnode = 1; + } + +Path::Path + ( + int numnodes + ) + + { + pathlength = 0; + from = NULL; + to = NULL; + nextnode = 1; + pathlist.Resize( numnodes ); + dirToNextNode.Resize( numnodes ); + distanceToNextNode.Resize( numnodes ); + } + +void Path::Clear + ( + void + ) + + { + nextnode = 1; + pathlength = 0; + from = NULL; + to = NULL; + pathlist.FreeObjectList(); + dirToNextNode.FreeObjectList(); + distanceToNextNode.FreeObjectList(); + } + +void Path::Reset + ( + void + ) + + { + nextnode = 1; + } + +PathNode *Path::Start + ( + void + ) + + { + return from; + } + +PathNode *Path::End + ( + void + ) + + { + return to; + } + +void Path::AddNode + ( + PathNode *node + ) + + { + Vector dir; + float len; + int num; + + if ( !from ) + { + from = node; + } + + to = node; + pathlist.AddObject( PathNodePtr( node ) ); + + len = 0; + distanceToNextNode.AddObject( len ); + dirToNextNode.AddObject( vec_zero ); + + num = NumNodes(); + if ( num > 1 ) + { + dir = node->origin - GetNode( num - 1 )->origin; + len = dir.length(); + dir *= 1 / len; + + distanceToNextNode.SetObjectAt( num - 1, len ); + dirToNextNode.SetObjectAt( num - 1, dir ); + + pathlength += len; + } + } + +PathNode *Path::GetNode + ( + int num + ) + + { + PathNode *node; + + node = pathlist.ObjectAt( num ); + assert( node != NULL ); + if ( node == NULL ) + { + error( "GetNode", "Null pointer in node list\n" ); + } + + return node; + } + +PathNode *Path::NextNode + ( + void + ) + + { + if ( nextnode <= NumNodes() ) + { + return pathlist.ObjectAt( nextnode++ ); + } + return NULL; + } + +PathNode *Path::NextNode + ( + PathNode *node + ) + + { + int i; + int num; + PathNode *n; + + num = NumNodes(); + + // NOTE: We specifically DON'T check the last object (hence the i < num instead + // of the usual i <= num, so don't go doing something stupid like trying to fix + // this without keeping this in mind!! :) + for( i = 1; i < num; i++ ) + { + n = pathlist.ObjectAt( i ); + if ( n == node ) + { + // Since we only check up to num - 1, it's ok to do this. + // We do this since the last node in the list has no next node (duh!). + return pathlist.ObjectAt( i + 1 ); + } + } + + return NULL; + } + +Vector Path::ClosestPointOnPath + ( + Vector pos + ) + + { + PathNode *s; + PathNode *e; + int num; + int i; + float bestdist; + Vector bestpoint; + float dist; + float segmentlength; + Vector delta; + Vector p1; + Vector p2; + Vector p3; + float t; + + num = NumNodes(); + s = GetNode( 1 ); + + bestpoint = s->origin; + delta = bestpoint - pos; + bestdist = delta * delta; + + for( i = 2; i <= num; i++ ) + { + e = GetNode( i ); + + // check if we're closest to the endpoint + delta = e->origin - pos; + dist = delta * delta; + + if ( dist < bestdist ) + { + bestdist = dist; + bestpoint = e->origin; + } + + // check if we're closest to the segment + segmentlength = distanceToNextNode.ObjectAt( i - 1 ); + p1 = dirToNextNode.ObjectAt( i - 1 ); + p2 = pos - s->origin; + + t = p1 * p2; + if ( ( t > 0 ) && ( t < segmentlength ) ) + { + p3 = ( p1 * t ) + s->origin; + + delta = p3 - pos; + dist = delta * delta; + if ( dist < bestdist ) + { + bestdist = dist; + bestpoint = p3; + } + } + + s = e; + } + + return bestpoint; + } + +float Path::DistanceAlongPath + ( + Vector pos + ) + + { + PathNode *s; + PathNode *e; + int num; + int i; + float bestdist; + float dist; + float segmentlength; + Vector delta; + Vector p1; + Vector p2; + Vector p3; + float t; + float pathdist; + float bestdistalongpath; + + pathdist = 0; + + num = NumNodes(); + s = GetNode( 1 ); + delta = s->origin - pos; + bestdist = delta * delta; + bestdistalongpath = 0; + + for( i = 2; i <= num; i++ ) + { + e = GetNode( i ); + + segmentlength = distanceToNextNode.ObjectAt( i - 1 ); + + // check if we're closest to the endpoint + delta = e->origin - pos; + dist = delta * delta; + + if ( dist < bestdist ) + { + bestdist = dist; + bestdistalongpath = pathdist + segmentlength; + } + + // check if we're closest to the segment + p1 = dirToNextNode.ObjectAt( i - 1 ); + p2 = pos - s->origin; + + t = p1 * p2; + if ( ( t > 0 ) && ( t < segmentlength ) ) + { + p3 = ( p1 * t ) + s->origin; + + delta = p3 - pos; + dist = delta * delta; + if ( dist < bestdist ) + { + bestdist = dist; + bestdistalongpath = pathdist + t; + } + } + + s = e; + + pathdist += segmentlength; + } + + return bestdistalongpath; + } + +Vector Path::PointAtDistance + ( + float dist + ) + + { + PathNode *s; + PathNode *e; + int num; + int i; + float t; + float pathdist; + float segmentlength; + + num = NumNodes(); + s = GetNode( 1 ); + pathdist = 0; + + for( i = 2; i <= num; i++ ) + { + e = GetNode( i ); + + segmentlength = distanceToNextNode.ObjectAt( i - 1 ); + if ( ( pathdist + segmentlength ) > dist ) + { + t = dist - pathdist; + return s->origin + dirToNextNode.ObjectAt( i - 1 ) * t; + } + + s = e; + pathdist += segmentlength; + } + + // cap it off at start or end of path + return s->origin; + } + +PathNode *Path::NextNode + ( + float dist + ) + + { + PathNode *s; + PathNode *e; + int num; + int i; + float pathdist; + float segmentlength; + + num = NumNodes(); + s = GetNode( 1 ); + pathdist = 0; + + for( i = 2; i <= num; i++ ) + { + e = GetNode( i ); + + segmentlength = distanceToNextNode.ObjectAt( i - 1 ); + if ( ( pathdist + segmentlength ) > dist ) + { + return e; + } + + s = e; + pathdist += segmentlength; + } + + // cap it off at start or end of path + return s; + } + +void Path::DrawPath + ( + float r, + float g, + float b, + float time + ) + + { + Vector s; + Vector e; + Vector offset; + PathNode *node; + int num; + int i; + + num = NumNodes(); + + if ( ai_debugpath->integer ) + { + gi.DPrintf( "numnodes %d, len %d, nodes %d :", PathManager.NumNodes(), ( int )Length(), num ); + for( i = 1; i <= num; i++ ) + { + node = GetNode( i ); + gi.DPrintf( " %d", node->nodenum ); + } + + gi.DPrintf( "\n" ); + } + + node = GetNode( 1 ); + s = node->origin; + + offset = Vector( r, g, b ) * 4 + Vector( 0, 0, 20 ); + for( i = 2; i <= num; i++ ) + { + node = GetNode( i ); + e = node->origin; + + G_DebugLine( s + offset, e + offset, r, g, b, 1 ); + s = e; + } + } + +int Path::NumNodes + ( + void + ) + + { + return pathlist.NumObjects(); + } + +float Path::Length + ( + void + ) + + { + return pathlength; + } + diff --git a/source/source/fgame/path.h b/source/source/fgame/path.h new file mode 100644 index 0000000..547f35a --- /dev/null +++ b/source/source/fgame/path.h @@ -0,0 +1,119 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/path.h $ +// $Revision:: 5 $ +// $Author:: Steven $ +// $Date:: 6/26/00 4:53p $ +// +// Copyright (C) 1997 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source is may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/path.h $ +// +// 5 6/26/00 4:53p Steven +// Fixed some save/load game issues. +// +// 4 6/14/00 2:17p Markd +// fixed compiler warnings for Intel Compiler +// +// 3 5/27/00 2:56p Markd +// Save games 2nd pass +// +// 2 5/24/00 3:14p Markd +// first phase of save/load games +// +// 1 9/10/99 10:54a Jimdose +// +// 1 9/08/99 3:16p Aldie +// +// DESCRIPTION: +// + +#ifndef __PATH_H__ +#define __PATH_H__ + +#include "g_local.h" +#include "class.h" +#include "container.h" +#include "navigate.h" + +class Path : public Class + { + private: + Container pathlist; + Container distanceToNextNode; + Container dirToNextNode; + float pathlength; + PathNodePtr from; + PathNodePtr to; + int nextnode; + + public: + CLASS_PROTOTYPE( Path ); + + Path(); + Path( int numnodes ); + void Clear( void ); + void Reset( void ); + void AddNode( PathNode *node ); + PathNode *GetNode( int num ); + PathNode *NextNode( void ); + PathNode *NextNode( PathNode *node ); + Vector ClosestPointOnPath( Vector pos ); + float DistanceAlongPath( Vector pos ); + Vector PointAtDistance( float dist ); + PathNode *NextNode( float dist ); + void DrawPath( float r, float g, float b, float time ); + int NumNodes( void ); + float Length( void ); + PathNode *Start( void ); + PathNode *End( void ); + virtual void Archive( Archiver &arc ); + }; + +inline void Path::Archive + ( + Archiver &arc + ) + { + PathNodePtr node; + int i, num; + + Class::Archive( arc ); + + if ( arc.Saving() ) + { + num = pathlist.NumObjects(); + } + arc.ArchiveInteger( &num ); + if ( arc.Loading() ) + { + pathlist.FreeObjectList(); + if ( num ) + pathlist.Resize( num ); + distanceToNextNode.FreeObjectList(); + dirToNextNode.FreeObjectList(); + } + for ( i = 1; i <= num; i++ ) + { + if ( arc.Loading() ) + pathlist.AddObject( node ); + + arc.ArchiveSafePointer( pathlist.AddressOfObjectAt( i ) ); + } + + distanceToNextNode.Archive( arc ); + dirToNextNode.Archive( arc ); + + arc.ArchiveFloat( &pathlength ); + arc.ArchiveSafePointer( &from ); + arc.ArchiveSafePointer( &to ); + arc.ArchiveInteger( &nextnode ); + } + +typedef SafePtr PathPtr; + +#endif /* path.h */ diff --git a/source/source/fgame/player.cpp b/source/source/fgame/player.cpp new file mode 100644 index 0000000..2bbf234 --- /dev/null +++ b/source/source/fgame/player.cpp @@ -0,0 +1,11381 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/player.cpp $ +// $Revision:: 392 $ +// $Author:: Markd $ +// $Date:: 8/11/00 7:47p $ +// +// Copyright (C) 1997 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source is may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/player.cpp $ +// +// 392 8/11/00 7:47p Markd +// changed a forcemenu from main to demomain for demo +// +// 391 8/04/00 6:06p Markd +// added BeginCinematic and EndCinematic to coolitem code +// +// 389 7/30/00 2:55p Markd +// initialized outfit_level on cleanup +// +// 388 7/30/00 2:48a Aldie +// Added a fudge factor to wall hang +// +// 387 7/29/00 9:05p Aldie +// Fixed armor order +// +// 386 7/29/00 3:59p Aldie +// Fix some fade stuff +// +// 385 7/29/00 2:28p Aldie +// Added a nosound weapon check +// +// 384 7/29/00 12:57p Aldie +// Fixed some ammo check stuff +// +// 383 7/29/00 12:54a Aldie +// Put a couple more checks in checkcanhang +// +// 382 7/28/00 11:59p Aldie +// Added forcemenu +// +// 381 7/28/00 6:58p Steven +// Made crosshairs get hidden when in cinematics. +// +// 380 7/28/00 1:14p Aldie +// Made crosshair collide with the water +// +// 379 7/28/00 1:10a Markd +// fixed outfit bug +// +// 378 7/27/00 11:23p Aldie +// Added a loadstatetable to the archiveperstdata +// +// 377 7/27/00 9:43p Aldie +// Changed dialog for invalid save games +// +// 376 7/27/00 5:16p Markd +// fixed legsstate and torsostate bugs, made canbeUsed pass int the activator +// +// 375 7/27/00 3:52p Aldie +// Changed over letterboxing and fades to the game code. They are sent over in +// player stats and fields now. +// +// 374 7/27/00 1:54a Markd +// changed g_playermodel to be more responsive +// +// 373 7/26/00 6:06p Steven +// Added some reseting of weapon game vars. +// +// 372 7/25/00 11:32p Aldie +// Made some changes to the memory system and fixed a memory allocation bug in +// Z_TagMalloc. Also changed a lot of classes to subclass from Class. +// +// 371 7/25/00 2:41p Markd +// made terminal velocity lethal +// +// 370 7/25/00 12:47p Markd +// Added new player sounds +// +// 369 7/24/00 6:54p Steven +// Changed sv_cinematic from a cvar to a player stat and added actor_camera to +// this also. +// +// 368 7/24/00 6:16p Aldie +// Pushmenu loadsave on death +// +// 367 7/24/00 12:46p Markd +// fixed rope movment +// +// 366 7/23/00 7:58p Steven +// Fixed some boss health stuff. +// +// 365 7/23/00 6:03p Markd +// added fadeout and fadesound to dieing and level change +// +// 364 7/23/00 5:02p Markd +// added boss health +// +// 363 7/22/00 8:37p Steven +// Fixed a prediction thing and added a sound effect to the electric spawn +// effect. +// +// 362 7/22/00 12:52a Markd +// Added can_hang check +// +// 361 7/21/00 10:49p Aldie +// Fixed an animstate problem when dying. +// +// 360 7/21/00 8:36p Steven +// Got gravpaths working fairly well. +// +// 359 7/21/00 3:45p Steven +// Made player have its own showmodel (event & proc) so we could do extra +// commands when the player is shown, fixed throwing evil shglieks, and fixed a +// knockdown bug. +// +// 358 7/21/00 1:14a Markd +// fixed fakeplayer....again +// +// 357 7/19/00 8:46p Markd +// added checkgroundentity +// +// 356 7/19/00 8:19p Steven +// Made it so you wouldn't go to actor camera if already in another camera. +// +// 355 7/19/00 7:26p Markd +// fixed weapons holstered code +// +// 354 7/19/00 5:09p Steven +// Don't do pain event if no damage taken, added electric water means of death, +// and added a loaded proc called after load is done. +// +// 353 7/19/00 3:12p Markd +// Fixed monkey bar problem +// +// 352 7/19/00 11:07a Markd +// changed weapons_active to WeaponsOut +// +// 351 7/18/00 5:19p Markd +// added weapons_active boolean +// +// 350 7/18/00 5:01p Markd +// fixed monkeybar climbing +// +// 349 7/18/00 4:25p Markd +// rewrote holstering code +// +// 348 7/18/00 1:24p Markd +// changed FakePlayer so that it now works like it used to +// +// 347 7/18/00 12:19p Aldie +// Fixed a bug with checkblocked timer +// +// 346 7/17/00 9:51p Aldie +// Added skipcinematic command which is access by pressing the ESC key +// +// 345 7/17/00 7:45p Markd +// made fakeplayer work better +// +// 344 7/17/00 5:26p Aldie +// Fix for fakeplayer to droptofloor +// +// 343 7/17/00 4:42p Aldie +// Removed a print +// +// 342 7/17/00 4:19p Aldie +// Changed to using v_angle instead of torsoangles for some aiming stuff. +// +// 341 7/17/00 3:26p Aldie +// Fix for flashbangs, changed detail variable, and added forcetorsostate +// +// 340 7/17/00 2:56p Steven +// Made it so the player doesn't turn her head as far when looking at things. +// +// 339 7/17/00 11:57a Aldie +// Changed some methods for checking weapons for attack +// +// 338 7/16/00 3:08p Aldie +// Added some holster functions for firing and getting the weapons out. +// +// 337 7/16/00 2:09p Aldie +// Changed some of the player logging +// +// 336 7/16/00 10:46a Steven +// Improved head target stuff. +// +// 335 7/15/00 3:52p Steven +// Only release the shgliek in a throw if he is not in a solid. +// +// 334 7/15/00 2:26p Steven +// Made noclip movement much slower if walking. +// +// 333 7/15/00 1:34p Aldie +// Added takepain command. Allows control for taking pain or not. +// +// 332 7/15/00 1:06p Aldie +// Added specialmove stuff for weapons so we can do special movement with some +// dualhanded weapons +// +// 331 7/15/00 1:36a Markd +// fixed cool item issues +// +// 330 7/14/00 11:45p Markd +// Added ambient sounds to func_supllywater +// +// 329 7/14/00 10:04p Aldie +// Added g_logstats cvar +// +// 328 7/14/00 9:46p Aldie +// Changed the way logstats start up +// +// 327 7/14/00 8:21p Aldie +// Added logstats +// +// 326 7/14/00 5:36p Markd +// took out hand offsets and fixed rolling coming out of cinematics +// +// 325 7/13/00 11:10p Markd +// fixed bug in waitforstate, added waitforstate to legs as well as torso +// +// 324 7/13/00 10:30p Markd +// fixed potential crash bug +// +// 323 7/13/00 9:18p Markd +// added behind_nopitch camera type +// +// 322 7/13/00 8:44p Markd +// fixed prediction on moving platforms +// +// 321 7/13/00 6:24p Markd +// fixed hanging off slanted edges +// +// 320 7/13/00 4:54p Steven +// Made sure the pitch and roll of a thrown shgliek is 0. +// +// 319 7/13/00 4:13p Steven +// Fixed problem with give all cheat and made it so the fakeplayer can't die. +// +// 318 7/13/00 3:19p Markd +// Turned off prediction when standing on non-world brushes +// +// 317 7/12/00 6:34p Aldie +// Added in crosshair scaling for long distances +// +// 316 7/12/00 5:36p Markd +// fixed ammo reporting to support bullets in clip +// +// 315 7/12/00 3:46p Aldie +// Put in a fix for movecontrol_anim where the origin will not get set after a +// pmove +// +// 314 7/12/00 2:54p Markd +// SetWaterPower on initialization +// +// 313 7/12/00 2:10p Markd +// fixed water level hud problem +// +// 312 7/12/00 11:27a Steven +// Changed water to a float. +// +// 311 7/12/00 12:35a Markd +// made player invulnerable during cool item cinematic +// +// 310 7/11/00 9:32p Markd +// Took out water flashing effect +// +// 309 7/11/00 9:28p Markd +// added level.playeritem_edenwater +// +// 308 7/11/00 7:09p Steven +// Made getting knocked onto the ground hurt the player if blow was blocked. +// +// 307 7/11/00 3:11p Aldie +// Testing a fix for ::Killed by not stopping the animation and not cancelling +// the pending events. +// +// 306 7/10/00 11:58p Markd +// fixed level exit issues +// +// 305 7/10/00 11:54p Markd +// added exit level code +// +// 304 7/10/00 9:27p Markd +// added ammo variables for how much ammo the player has. Added levelvars and +// gamevars commands +// +// 303 7/10/00 8:09p Markd +// fixed cool item pickup problems +// +// 302 7/10/00 6:50p Markd +// fixed some issues with water running +// +// 301 7/10/00 5:12p Markd +// made it so that waitForState supports partial names for waitforstate +// Changed archiving of persistant data +// +// 300 7/10/00 10:41a Markd +// added waitforstate +// +// 299 7/07/00 6:34p Steven +// Fixed checkblocked when immobile. +// +// 298 7/07/00 7:32a Steven +// Made it so the player won't not thing she is blocked if immobilized. +// +// 297 7/06/00 7:17p Aldie +// Added in HAS_ARMORPIECE state command +// +// 296 7/06/00 4:51p Markd +// clamped server time on commands so no future packets will be processed +// +// 295 7/06/00 3:37p Markd +// made it so when hurt, the camera is not turned off +// +// 294 7/05/00 9:19p Markd +// tweaked armor stuff +// +// 293 7/05/00 7:36p Steven +// Added more outfit stuff and added it to the saved PersistantData. +// +// 292 7/05/00 6:14p Steven +// Change minimum water needed for turbo speed to 90 and added a damage +// multiplier for combos. +// +// 291 7/05/00 4:17p Markd +// fixed cool item stuff +// +// 290 7/04/00 6:45p Markd +// enhanced cool item features +// +// 289 7/04/00 2:47p Markd +// added ai off to the cool item cinematics +// +// 288 7/04/00 2:25p Markd +// added cool cinematic for new objects +// +// 287 7/03/00 7:00p Steven +// Made throwing of the Shgliek based on the player's torso angles instead of +// her regular angles. +// +// 286 7/03/00 10:23a Steven +// Added some knockback/knockdown stuff. +// +// 285 7/02/00 6:46p Markd +// added spawn thread to PlayerStart +// +// 284 7/01/00 6:55p Markd +// made fakeplayer think +// +// 283 6/30/00 3:11p Markd +// fixed player rise issues +// +// 282 6/29/00 9:32a Markd +// added camera_side_left and side_right support +// +// 281 6/28/00 7:56p Aldie +// Added some pain stuff for use with death. +// +// 280 6/27/00 2:48p Aldie +// Changed some weapon aiming stuff again. Aimed shots are automatically +// determined now. +// +// 279 6/26/00 8:21p Markd +// fixed player hanging off the side of horizontal pipes +// +// 278 6/26/00 7:16p Markd +// tweaked player walking off ledges +// +// 277 6/26/00 5:50p Markd +// re-did some renderfx commands, fixed anti-sb juice stuff +// +// 276 6/26/00 9:42a Steven +// Made it so the player won't target things after being killed. +// +// 275 6/25/00 2:51p Markd +// made use objects easier to use +// +// 274 6/25/00 12:37p Markd +// fixed player getting stuck +// +// 273 6/25/00 11:21a Markd +// fixed slime code for player +// +// 272 6/23/00 8:34p Markd +// fixed player music issues +// +// 271 6/22/00 8:04p Markd +// bullet proofed crosshair usage +// +// 270 6/22/00 12:23p Markd +// must be able to push objects 8 units when pushing them +// +// 269 6/17/00 11:09a Markd +// made it so that julie will not try to grab ledges that are moving +// +// 268 6/16/00 11:28a Aldie +// Added a ground check to 'rise' to see if we are really rising above the +// ground +// +// 267 6/15/00 5:50p Aldie +// Added rise checks +// +// 266 6/15/00 3:54p Aldie +// Took out the legturn command. We don't really need it. +// +// 265 6/15/00 2:54p Aldie +// Fix for the leg turning issue +// +// 264 6/14/00 5:40p Aldie +// Added state ammo check for weapon in hand/mode +// +// 263 6/14/00 3:50p Markd +// Cleaned up more Intel Compiler warnings +// +// 262 6/13/00 6:41p Markd +// Fixed pushing and pulling of objects +// +// 261 6/10/00 1:50p Steven +// Added statemap caching. +// +// 260 6/08/00 9:55a Markd +// added camera_type behind_fixed +// +// 259 6/06/00 7:33p Aldie +// Fix for putting away weapons when crouching and fix for dualhanded weapon +// being out when 2 weapons are being wielded at once. +// +// 258 6/06/00 5:20p Markd +// placed some assertions into infite state stuff +// +// 257 6/06/00 5:02p Markd +// fixed player movement stuff +// +// 256 6/06/00 3:23p Steven +// Now force a shgliek into AI mode if picked up. +// +// 255 6/06/00 3:24p Aldie +// Fix for dead check +// +// 254 6/06/00 12:19p Markd +// working on player movement +// +// 253 6/05/00 6:31p Aldie +// Sped up water power effect and removed cleartorsoanim from the noclip +// resetting +// +// 252 6/05/00 5:03p Aldie +// clear oldstats +// +// 251 6/05/00 3:41p Steven +// Made player not solid when killed. +// +// 250 6/05/00 3:33p Markd +// Fixed sound bug +// +// 249 6/05/00 3:29p Aldie +// Added flickering to waterstats +// +// 248 6/04/00 6:52p Markd +// Added camera support to TouchAnim's cleaned up player camera interface +// +// 247 6/04/00 3:49p Markd +// Added precise shadows to certain characters +// +// 246 6/03/00 6:58p Markd +// don't swing legs when purely strafing +// +// 245 6/03/00 3:14p Aldie +// Added damage effects to player and sentient +// +// 244 6/02/00 6:51p Markd +// added better camera look features +// +// 243 6/02/00 2:01p Markd +// Fixed client persistant data issues +// +// 242 6/01/00 7:02p Markd +// removed activeWeapon variable +// +// 241 6/01/00 3:18p Markd +// rewrote giveItem and item management in sentient +// +// 240 6/01/00 2:47p Aldie +// Change crosshair distance and checkdeath +// +// 239 5/31/00 5:05p Aldie +// New aiming method +// +// 238 5/31/00 10:24a Markd +// Changed LoadingServer to LoadingSavegame +// +// 237 5/30/00 6:54p Aldie +// Added a muzzle clear check +// +// 236 5/30/00 5:06p Aldie +// Added large shield to prevent knockdowns +// +// 235 5/30/00 4:42p Aldie +// Added direction support and knockdown support to player +// +// 234 5/29/00 1:16p Markd +// 3rd round of saved games +// +// 233 5/27/00 5:27p Markd +// zeroed out skipthread once executed +// +// 232 5/27/00 5:14p Steven +// Added player head watch stuff. +// +// 231 5/27/00 9:49a Steven +// Added RemoveTarget stuff. +// +// 230 5/26/00 7:47p Aldie +// Added directonal damage to pain +// +// 229 5/26/00 6:31p Aldie +// Added alternate fire to soulsucker and bug fix to AmmoAvailable() +// +// 228 5/26/00 4:12p Aldie +// Fix another holster bug (crash) +// +// 227 5/26/00 3:41p Aldie +// Fix for holstering in cinematic +// +// 226 5/26/00 2:24p Aldie +// Added waitforplayer commands so we can use it for cinematics when waiting +// for player to finish holstering +// +// 225 5/25/00 4:15p Aldie +// Added weapon holstering while crouching +// +// 224 5/25/00 9:59a Steven +// Fixed picking up of the Shgliek. +// +// 223 5/24/00 6:51p Aldie +// Made some code a little clearer for debugging +// +// 222 5/24/00 3:46p Steven +// Made the player's splash a variable size based on the player's velocity. +// +// 221 5/20/00 6:03p Aldie +// Fixed stat bug +// +// 220 5/20/00 2:12p Steven +// Made it so if the player stands on an actor it will try to push the actor +// downwards. +// +// 219 5/18/00 3:20p Markd +// added damage feedback +// +// 218 5/17/00 7:38p Markd +// moved player into position when starting to push objects +// +// 217 5/16/00 6:25p Markd +// Don't do monkeybar and pipe traces unless the player is on the ground +// +// 216 5/15/00 2:19p Aldie +// Added new tempmodel system and added player accumulated pain +// +// 215 5/11/00 11:12a Steven +// Added pushing actors out of the way and added a splash effect when the +// player lands in water. +// +// 214 5/10/00 10:32a Steven +// Added com_blood stuff. +// +// 213 5/08/00 10:55p Markd +// fixed water_power jumping +// +// 212 5/08/00 6:15p Markd +// put in camera cut choice for state based camera types +// +// 211 5/08/00 6:00p Aldie +// Comment out some debug stuff +// +// 210 5/08/00 3:19p Aldie +// Added initial crosshair work +// +// 209 5/06/00 5:25p Markd +// fixed camera and pipe hang issues +// +// 208 5/06/00 3:15p Markd +// Fixed pipehanging +// +// 207 5/06/00 2:10p Aldie +// Removed a comment +// +// 206 5/06/00 1:28p Aldie +// Changed weapon fire check +// +// 205 5/06/00 11:52a Markd +// fixed player orientation problems +// +// 204 5/05/00 7:38p Aldie +// Fix dual weapon stats +// +// 203 5/04/00 10:25p Markd +// fixed player orienation issues again +// +// 202 5/04/00 5:01p Markd +// fixed player orientation problems +// +// 201 5/02/00 6:42p Steven +// Made the fakeplayer a step size shorter to fix some collision issues. +// +// 200 5/02/00 6:27p Markd +// Fixed checkstate so that it would do a string comparison only up to the +// number of letters in statename and not an exact comparison +// +// 199 5/02/00 3:14p Steven +// Added player watching actors that talk to her. +// +// 198 5/01/00 2:45p Steven +// Added some action level stuff. +// +// 197 5/01/00 11:31a Markd +// Added SetWaterPower to Player +// +// 196 4/30/00 4:42p Markd +// Fixed player turning +// +// 195 4/29/00 11:28a Markd +// removed old rope code, cleaned up rope interface +// +// 194 4/28/00 3:07p Steven +// Got rid of dropping items on death for now. +// +// 193 4/26/00 5:25p Aldie +// Changes to weapons to avoid having to specify the classname +// +// 192 4/26/00 5:19p Aldie +// Changed from entname to item_name for weapon checking code +// +// 191 4/24/00 7:22p Markd +// fixed some uninitialized variables +// +// 190 4/24/00 7:07p Aldie +// Removed old code to try and fix inconsistency between legs and torso for +// firing when moving and standing. It's all done in the state machine now. +// +// 189 4/19/00 12:54p Markd +// put in auto_starttime and auto_stoptime support into auto cameras +// +// 188 4/15/00 5:40p Markd +// fixed falling damage and getting into and out of water +// +// 187 4/15/00 4:24p Markd +// Fixed player turning +// +// 186 4/15/00 1:48p Steven +// Made it so the player doesn't cast a shadow when we are using the +// fakeplayer. +// +// 185 4/15/00 1:30p Markd +// added check_was_running code so that player does not always stop short +// +// 184 4/15/00 9:53a Markd +// fixed player climbing ladder code +// +// 183 4/14/00 6:04p Aldie +// Added checksolidforward to state system +// +// 182 4/13/00 5:31p Steven +// Added a checkshgliekdead check and set have_shgliek to false always when +// throwing not just when the shgliek is found and thrown. +// +// 181 4/11/00 2:46p Markd +// Implemented Automatic camera support +// +// 180 4/10/00 1:43p Markd +// changed rope user interface +// +// 179 4/10/00 11:17a Markd +// Added new rope code +// +// 178 4/07/00 6:00p Aldie +// Added flashing and fixed radius damage for explosions +// +// 177 4/07/00 3:00p Markd +// Added legs dangling code for pipehanging +// +// 176 4/07/00 2:05p Markd +// added MOVETYPE_PIPEHANG +// +// 175 4/07/00 1:24p Markd +// fixed wall climbing issues +// +// 174 4/07/00 10:17a Markd +// fixed shgliek pickup and weapon holstering +// +// 173 4/06/00 6:02p Markd +// changed UseAnim animation from torso to legs +// +// 172 4/06/00 2:52p Markd +// commented out setting orientation based off of v_angle +// +// 171 4/06/00 10:59a Markd +// fixed player speed when player has full water +// +// 170 4/05/00 8:50p Markd +// got rid of damage skin support +// +// 169 4/05/00 8:41p Markd +// Added water_level conditional +// +// 168 4/05/00 7:13p Aldie +// Lots of inventory functionality changes. +// +// 167 4/04/00 3:28p Aldie +// Fix use code for inventory items +// +// 166 4/04/00 11:02a Markd +// put in checkcanclimb and feet checks +// +// 165 4/03/00 3:45p Markd +// fixed timescale bug with movement +// +// 164 3/31/00 6:21p Markd +// took out absolute origin set in StartUseObject +// +// 163 3/31/00 3:19p Markd +// Added UseObject functionality +// +// 162 3/28/00 1:47p Markd +// fixed standing jump +// +// 161 3/27/00 3:45p Markd +// Hooked up UseAnim state info into the game +// +// 160 3/24/00 2:12p Steven +// Fixed an issue with grabbing of ledges. +// +// 159 3/22/00 2:04p Aldie +// Added holster command +// +// 158 3/21/00 6:08p Markd +// Added invehicle check +// +// 157 3/21/00 5:05p Markd +// +// 156 3/21/00 2:31p Aldie +// Changed checkattackleft and right +// +// 155 3/20/00 6:09p Steven +// Added SetMouthAngle. +// +// 154 3/18/00 3:55p Markd +// working on player turning +// +// 153 3/18/00 2:42p Markd +// added facing up and down slopes +// +// 152 3/17/00 6:37p Markd +// Added chance conditional +// +// 151 3/16/00 3:35p Aldie +// Added checkpain state back instead of forcing it +// +// 150 3/16/00 10:20a Markd +// fixed useanim firing its targets before the animation was completed +// +// 149 3/15/00 4:09p Aldie +// Fixed a bug with using weapons, and added some ability to force a state in +// the player +// +// 148 3/13/00 5:18p Aldie +// Made some changes for usable inventory item stuff +// +// 147 3/07/00 6:38p Steven +// Fixed up some angle stuff when throwing the shgliek. +// +// 146 3/06/00 8:17p Markd +// converted certain events from EV_CONSOLE to EV_CHEAT +// +// 145 3/04/00 1:54p Aldie +// Changed UpdateStats +// +// 144 3/04/00 12:29p Jimdose +// separated feet checks into their own functions +// +// 143 3/02/00 11:12a Markd +// Added additional SetReverb function +// +// 142 3/02/00 10:47a Steven +// Changed reverb interface and set players health to 0 after dying to prevent +// negative health being shown. +// +// 141 3/01/00 8:44p Jimdose +// added turning for monkey bars +// made move checks provide pass/fail results +// added checks for feet and falling when both feet aren't on the ground +// +// 140 3/01/00 10:59a Jimdose +// UseAnim now sends the entity that used it as the activator instead of itself +// when triggering targets +// +// 139 2/28/00 6:51p Jimdose +// added checks for running into walls +// +// 138 2/28/00 6:33p Aldie +// Added more advanced pain state checks +// +// 137 2/26/00 7:09p Jimdose +// added better movement checks for pipecrawl, monkey bars +// added checks to prevent player from going into walk or run animation while +// move is blocked +// fixed setting step height when stepping up +// +// 136 2/26/00 2:26p Steven +// Fixed a spot where something was comparing an entnum to 0 instead of +// ENTITYNUM_NONE. +// +// 135 2/26/00 12:59p Jimdose +// made player respawning work +// +// 134 2/26/00 11:50a Jimdose +// added slope checks +// +// 133 2/26/00 11:22a Steven +// Added partial immobile flag. +// +// 132 2/25/00 7:27p Markd +// Added useanim_numloop support and fixed useanim_orientation +// +// 131 2/25/00 5:02p Aldie +// Changed some reloading and put in a fix for the animation problem with the +// firing of the weapons +// +// 130 2/24/00 7:26p Aldie +// Added dual wielding +// +// 129 2/24/00 4:20p Jimdose +// added ladder movement +// merged some redundant variables +// made UseAnim have a movetype +// changed bounding box when crouched +// +// 128 2/23/00 5:25p Aldie +// clarified checkuseweapon state check +// +// 127 2/23/00 3:19p Aldie +// Added more inventory functionality with the player +// +// 126 2/22/00 6:56p Jimdose +// fixed double jumping +// fixed climbing on monsters +// no longer forward and back move on ropes +// +// 125 2/22/00 1:57p Jimdose +// added pushobjects +// +// 124 2/17/00 6:26p Aldie +// Fixed naming conventions for weapon hand and also added various attachtotag +// functionality for weapons that attach to different tags depending on which +// hand they are wielded in. +// +// 123 2/17/00 4:18p Jimdose +// made statemap_Legs and statemap_Torso part of player instead of global +// removed redundant physics variables +// made CheckGround use the one from bg_pmove +// onground now checks if player can walk, instead of if player has a +// groundentity +// +// 122 2/17/00 12:00p Aldie +// Added command processing to state system with the addition of entrycommands +// and exitcommands. +// +// 121 2/16/00 4:01p Aldie +// Added shield functionality +// +// 120 2/15/00 9:14p Jimdose +// fixed wall avoidance +// +// 119 2/15/00 8:57p Jimdose +// added move feedback checks for state system +// added wall avoidance code +// +// 118 2/14/00 7:34p Aldie +// Fixed some auto targeting issues +// +// 117 2/14/00 6:36p Markd +// added code to player to setup bootlights and faster/longer running based on +// water level +// +// 116 2/14/00 5:47p Jimdose +// state system now uses leg state only for MOVECONTROL_LEGS +// torso state is now the controlling state +// +// 115 2/10/00 11:25a Markd +// Added bootlights glowing code +// +// 114 2/09/00 8:02p Aldie +// Added loopfire weapons +// +// 113 2/09/00 12:40p Steven +// Made checkhasweapon take into account dual handed weapons also. +// +// 112 2/08/00 9:53p Jimdose +// player now gets set to proper anim at startup +// +// 111 2/08/00 6:35p Aldie +// Added more blocking code to player and sentient +// +// 110 2/08/00 11:33a Steven +// Added picking up of Shgliek. +// +// 109 2/08/00 12:17a Jimdose +// made rope grabbing controlled by state system +// +// 108 2/07/00 7:38p Aldie +// Fixed swiping, also various weapons fixes for sword and for sling +// +// 107 2/04/00 7:28p Aldie +// Combat code - blocking and combos +// +// 106 2/04/00 3:11p Aldie +// Changed sword attack method for water usage +// +// 105 2/03/00 2:56p Aldie +// Sword and water coding +// +// 104 2/02/00 7:08p Aldie +// Added new sword code and water damage +// +// 103 2/02/00 4:28p Aldie +// Added some new state checks for combo help +// +// 102 2/02/00 8:54a Markd +// Set targetname player +// +// 101 2/01/00 8:13p Aldie +// More autoaim work +// +// 100 2/01/00 6:20p Markd +// put in checks for immobile flag or playerfrozen when checking if we can fire +// +// 99 2/01/00 5:28p Aldie +// More updates for auto aiming +// +// 98 1/31/00 7:56p Aldie +// Added some new states and improved arm tracking +// +// 97 1/31/00 4:25p Jimdose +// added dir variable to monkeybar and horizontalpipe +// +// 96 1/31/00 3:56p Aldie +// working on the auto aim / tracking code +// +// 95 1/29/00 6:17p Aldie +// Fixed some problems when state doesn't exist. +// +// 94 1/29/00 11:27a Jimdose +// made ropes work with state system +// +// 93 1/26/00 5:06p Aldie +// Changed .txt to .scr for giveall script +// +// 92 1/26/00 3:33p Aldie +// Change Amount to getAmount. Added some 'listinventory' command. Added give +// all cheat to execute the script in global/giveall.txt +// +// 91 1/26/00 9:53a Markd +// Changed FOV command to an fov command +// +// 90 1/25/00 8:06p Jimdose +// added hardimpact checks +// improved wall hug checks +// fixed side jump angle +// +// 89 1/25/00 3:39p Markd +// added noclip check in evaluate state +// +// 88 1/24/00 6:55p Steven +// Added reverb stuff. +// +// 87 1/24/00 2:56p Markd +// Moved CheckMoveFlags into non-noclip clause +// +// 86 1/24/00 2:50p Jimdose +// added rope checks +// +// 85 1/22/00 4:04p Jimdose +// added pipe crawl and stepping up +// got rid of vec3() calls +// +// 84 1/20/00 7:10p Jimdose +// added checkcanwallhug +// fixed grabbing onto ledges +// added movecontrol +// only call start movement code when movecontrol changes +// fixed UseAnim null pointer bug +// +// 83 1/20/00 10:45a Markd +// removed bootlights from being turned on and off +// +// 82 1/19/00 10:02p Jimdose +// added airspeed +// +// 81 1/19/00 7:59p Markd +// Rewrote Surface Model Event and also added changeoutfit command to player +// +// 80 1/19/00 10:44a Markd +// Cleaned up MOD messages and fixed music starting because of falling damage +// +// 79 1/18/00 6:49p Aldie +// Removed readtofire calls out of the state checking +// +// 78 1/18/00 6:37p Jimdose +// adjusted hang position +// +// 77 1/18/00 2:59p Markd +// Removed unused code +// +// 76 1/17/00 10:20p Jimdose +// Rewrote state system initialization. Made conditionals defined with array. +// Made Evaluate functions early exit +// +// 75 1/16/00 5:43p Aldie +// Made weapon tag vars +// +// 74 1/15/00 4:13p Markd +// Changed MOVETYPE_ABSOLUTE to have collision and not have user control of the +// angles +// +// 73 1/15/00 3:57p Markd +// Eliminated multiple "angle" events and replaced them with EV_SetAngle +// +// 72 1/15/00 1:36p Markd +// Added UseAnim and TouchUseAnim functionality to Player and game +// +// 71 1/15/00 9:29a Markd +// rename tag_weapon to tag_weapon_right +// +// 70 1/14/00 5:07p Markd +// Removed surface num, tri_num and damage_multiplier from multiple functions +// and events +// +// 69 1/13/00 5:19p Jimdose +// removed lightvolume stuff +// +// 68 1/13/00 4:55p Aldie +// Changed crossbow weap +// +// 67 1/12/00 8:04p Markd +// changed the way camera_flags were cleared out on the client +// +// 66 1/12/00 3:17p Aldie +// Added some water functionality +// +// 65 1/10/00 6:17p Jimdose +// more code cleanup +// +// 64 1/10/00 10:30a Jimdose +// removed unused code +// +// 63 1/06/00 11:08p Jimdose +// cleaning up unused code +// +// 62 1/06/00 4:58p Markd +// changed the camera angle for topdown +// +// 61 1/06/00 4:39p Markd +// fixed tiki file name +// +// 60 1/06/00 11:54a Jimdose +// Converted AngleVectors from forward,right,up to forward,left,up and also +// fixed functionality of vectoangles function. Made all cooridinate systems +// identical. +// +// 59 1/03/00 5:08p Markd +// put in camera offsets for player and state machine +// +// 58 12/20/99 6:51p Steven +// Moved jumpxy to sentient. +// +// 57 12/20/99 6:37p Markd +// Made camera cutting work properly +// +// 56 12/17/99 8:27p Jimdose +// got rid of unused vars and functions +// +// 55 12/17/99 6:35p Jimdose +// changed spawnarg code +// added Level class for spawning and map control +// got rid of unused or superflous variables +// changed setjmp/longjmp calls to try/throw/catch exception handling +// +// 54 12/14/18 2:44p Jimdose +// added monkey bar movement +// +// 53 12/13/99 10:17a Markd +// Fixed merge bug +// +// 52 12/13/99 10:14a Aldie +// Temp update for bug fixing due to merge +// +// 51 12/10/99 6:13p Jimdose +// added movement check functions +// unified redundant yaw based orientation calculations +// added wall hug movetype +// +// 50 12/10/99 11:52a Aldie +// Adjusted player angles a bit +// +// 49 12/10/99 11:17a Jimdose +// got rid of unused movement functions +// fixed pulling up from hang +// +// 48 12/09/99 7:38p Jimdose +// improved grabbing and hanging onto walls +// +// 47 12/09/99 3:41p Jimdose +// fixed direction when jumping +// torso anim no longer gets stuck when coming out of noclip +// +// 46 12/09/99 2:31p Aldie +// Head tracking +// +// 45 12/08/99 7:00p Aldie +// Busting up player a bit and wrote some head tracking code +// +// 44 12/03/99 7:02p Aldie +// More ammo joy +// +// 43 12/03/99 9:46a Markd +// fixed a camera lerping bug +// +// 42 12/02/99 6:53p Aldie +// Changed naming conventions from "both" to "dualhanded" Also put in the +// inventory renderer for the hud file +// +// 41 12/01/99 4:56p Markd +// fixed some reference versus pointer issues with RandomAnimate and NewAnim +// +// 40 12/01/99 3:18p Aldie +// Fix for noclip bug where we should be in idle for noclipping +// +// 39 12/01/99 11:26a Aldie +// Couple of fixes for emitters and more ammo stuff +// +// 38 11/29/99 6:52p Aldie +// Fix 2 handed weapon bug +// +// 37 11/29/99 6:32p Aldie +// Lots of changes for ammo system +// +// 36 11/22/99 6:46p Aldie +// Started working on ammo changes - will finish after Thanksgiving break +// +// 35 11/19/99 6:33p Aldie +// Removed debug print +// +// 34 11/19/99 5:45p Aldie +// Update for primary and alternate fire weapons. Removed PRIMARY and SECONDAY +// mode weapons of Sin, removed SILENCED properties, and changed ammo types to +// use the new system. Still need to fix ammo checking for weapons. +// +// 33 11/15/99 11:55a Aldie +// Added rope archiver +// +// 32 11/11/99 5:29p Jimdose +// removed debugging print +// +// 31 11/11/99 5:25p Jimdose +// added separate torso animation +// +// 30 11/09/99 8:05p Markd +// Added SetViewAngles and also made a SetFOV function +// +// 29 11/09/99 5:12p Aldie +// Added ajustanglesforattack +// +// 28 11/05/99 7:30p Aldie +// Angles Adjustment +// +// 27 11/04/99 10:03a Markd +// complete overhaul of the camera system +// +// 26 11/02/99 2:21p Aldie +// Rope stuff +// +// 25 11/01/99 4:00p Jimdose +// added SetControllerAngles and SetControllerTag +// +// 24 10/29/99 6:48p Jimdose +// added bone controllers +// moved torso and head angle calculation from cg_player.c +// +// 23 10/28/99 6:33p Markd +// Added fakeplayer ability, also added CloneEntity +// +// 22 10/28/99 4:01p Aldie +// Fix rope init +// +// 21 10/28/99 11:54a Aldie +// Some more rope stuff +// +// 20 10/28/99 10:42a Aldie +// Added rope functions +// +// 19 10/27/99 12:19p Markd +// added smooth camera lerping +// +// 18 10/27/99 10:29a Steven +// Added new flag PMF_NO_MOVE. +// +// 17 10/19/99 7:53p Markd +// eliminated 3 part model system +// +// 16 10/18/99 6:10p Jimdose +// got rid of separate state machine for torso and legs +// now use skeletal model for player +// +// 15 10/12/99 2:23p Markd +// Rewrote camera and player movetype system +// +// 14 10/08/99 2:13p Markd +// Made player default to ET_PLAYER type and fixed up some PM_LOCKVIEW issues +// +// 13 10/05/99 4:43p Jimdose +// no longer evaluate state while noclipping +// +// 12 10/05/99 4:32p Jimdose +// fixed out of bounds problem in SetAnim when part is all +// go into stand animation when noclipping +// +// 11 10/01/99 4:52p Markd +// Made Warning level 4 work on all projects +// +// 10 9/30/99 5:24p Steven +// Event formatting. +// +// 9 9/17/99 6:31p Jimdose +// changed checks on groundEntityNum +// +// 8 9/17/99 3:40p Jimdose +// fixed jerkiness in player movement +// +// 7 9/16/99 7:44p Jimdose +// PM_SPECTATOR changed to PM_NOCLIP +// +// 6 9/16/99 4:46p Markd +// more merging +// +// 5 9/16/99 11:18a Markd +// Continuing merge of code, not functional yet but closer +// +// 4 9/15/99 6:57p Aldie +// Update to get game working +// +// 3 9/13/99 4:22p Jimdose +// merge +// +// 2 9/13/99 3:27p Aldie +// code merge +// +// 1 9/10/99 10:54a Jimdose +// +// 1 9/08/99 3:16p Aldie +// +// 104 9/02/99 9:15p Jimdose +// fixed player shimmy left/right on hangs +// +// 103 9/02/99 7:33p Jimdose +// fixed bool to int warning +// +// 102 9/02/99 7:29p Jimdose +// added checks for doors +// +// 101 9/02/99 6:59p Markd +// put in anti_sucknblow support +// +// 100 9/02/99 4:39p Jimdose +// only get hurt when damage > 15 +// +// 99 9/02/99 1:53p Markd +// Added CheckWater to ClientMove +// +// 98 9/01/99 8:09p Markd +// Made slime hurt you +// +// 97 9/01/99 7:54p Jimdose +// fixed canfall checks on player clips +// hardcoded speed when in water +// +// 96 9/01/99 1:44p Jimdose +// made DoUse a script called event +// removed CheckButtons +// disabled obstacle avoidance +// +// 95 9/01/99 12:03p Steven +// Modified sword damage again. +// +// 94 9/01/99 10:29a Aldie +// Added holstering. +// +// 93 8/31/99 8:28p Markd +// fixed noclip +// +// 92 8/31/99 8:23p Steven +// Made it easier to hit with the sword and made the sword do less damage. +// +// 91 8/31/99 7:40p Jimdose +// added check for if she has a weapon +// added movement speed based on animation +// +// 90 8/31/99 10:15a Aldie +// Removed a debug line +// +// 89 8/30/99 10:26p Jimdose +// added check for jump flip +// +// 88 8/30/99 8:58p Aldie +// Fix for sword attack +// +// 87 8/30/99 1:02p Aldie +// Removed a debugline +// +// 86 8/30/99 10:10a Jimdose +// added check in obstacle avoidance to avoid steering away from floor polys +// +// 85 8/27/99 5:05p Markd +// Changed Start( -1 ) to StartImmediately, changed InitInventory. +// +// 84 8/27/99 4:49p Jimdose +// separated state machine into two, one for torso, one for legs +// +// 83 8/23/99 10:16a Jimdose +// added better falling checks +// added 3 part models +// +// 82 8/19/99 3:02p Jimdose +// added steering away from newarly parallel walls +// removed con_clearfade +// +// 81 8/19/99 12:01p Aldie +// Added in firing time checks +// +// 80 8/19/99 11:23a Jimdose +// working on turning away from walls +// +// 79 8/18/99 4:15p Jimdose +// added conditionals for health, death, and pain +// +// 78 8/18/99 3:28p Jimdose +// added cylindrical collision detection +// +// 77 8/17/99 4:52p Jimdose +// added oldorigin +// added various checks for physics +// added JumpXY +// +// 76 8/16/99 10:31a Steven +// Moved ConditionalParameter back into Conditional. +// +// 75 8/12/99 8:04p Jimdose +// working on climbing stuff +// +// 74 8/12/99 12:11p Jimdose +// added g_statefile cvar +// +// 73 8/11/99 10:07p Jimdose +// fixed bug where pmove_t struct wasn't initialized +// +// 72 8/11/99 9:59p Markd +// Added sword to inventory +// +// 71 8/11/99 7:58p Jimdose +// preliminary climbing code in +// +// 70 8/11/99 7:35p Aldie +// Added hand checking to weapons +// +// 69 8/11/99 6:00p Aldie +// Removed a printf +// +// 68 8/11/99 5:43p Aldie +// Fix bug with weapon changing states +// +// 67 8/11/99 11:51a Aldie +// Added giveweapon cheat and fixed weapon changing bug +// +// 66 8/10/99 6:46p Aldie +// Added some better condition logic +// +// 65 8/10/99 11:36a Aldie +// Update of the weapons system +// +// 64 8/10/99 10:52a Jimdose +// started working on climbing +// +// 63 8/06/99 6:52p Jimdose +// changed format of state machine callback functions +// +// 62 8/06/99 6:39p Aldie +// Started moving over to new weapons system +// +// 61 8/04/99 6:02p Jimdose +// now respond to the movetype command from the state machine +// +// 60 8/03/99 3:36p Aldie +// Made the crossbow the default weapon +// +// 59 7/30/99 7:53p Markd +// Added jumping ability to the player +// +// 58 7/29/99 5:33p Markd +// Fixed weird compiler bug +// +// 57 7/23/99 3:27p Aldie +// +// 56 7/19/99 7:55p Markd +// removed unused leftsword, lefttorch, torch loadings +// +// 55 7/07/99 4:06p Jimdose +// changed julie2.st to julie.st +// +// 54 7/07/99 2:53p Jimdose +// added new keys for controlling the player +// added ResetState and LoadState +// +// 53 7/06/99 8:53p Jimdose +// only trace down stepsize from move when on ground +// +// 52 7/06/99 8:33p Jimdose +// removed unused player code +// added state machine for player animation +// +// 51 6/25/99 5:24p Markd +// changed the player animations and movement speed +// +// DESCRIPTION: +// Class definition of the player. +// +#include "g_local.h" +#include "entity.h" +#include "player.h" +#include "worldspawn.h" +#include "weapon.h" +#include "trigger.h" +#include "scriptmaster.h" +#include "path.h" +#include "navigate.h" +#include "misc.h" +#include "earthquake.h" +#include "gravpath.h" +#include "armor.h" +#include "inventoryitem.h" +#include "gibs.h" +#include "actor.h" +#include "object.h" +#include "characterstate.h" +#include "rope.h" +#include "weaputils.h" + +//Forward +//Back +//TurnRight +//TurnLeft +//Moveleft (strafe) +//Moveright (strafe) +//Moveup (Jump) +//Movedown (Duck) +//Action (Use) +//Sneak (Toggle or Momentary) +//Speed/Walk (Toggle or Momentary) +//Fire Left hand +//Fire Right hand + +#define SLOPE_45_MIN 0.7071f +#define SLOPE_45_MAX 0.831f +#define SLOPE_22_MIN SLOPE_45_MAX +#define SLOPE_22_MAX 0.95f + +#define MIN_Z -999999 +#define PUSH_OBJECT_DISTANCE 16.0f + +#define R_ARM_NAME "Bip01 R UpperArm" +#define L_ARM_NAME "Bip01 L UpperArm" + +const Vector power_color( 0.0, 1.0, 0.0 ); +const Vector acolor( 1.0, 1.0, 1.0 ); +const Vector bcolor( 1.0, 0.0, 0.0 ); + +static Vector min_box_8x8( -4, -4, -4 ); +static Vector max_box_8x8( 4, 4, 4 ); +static Vector min4x4( -4, -4, 0 ); +static Vector max4x4x0( 4, 4, 0 ); +static Vector max4x4x8( 4, 4, 8 ); + +qboolean TryPush( int entnum, vec3_t move_origin, vec3_t move_end ); + +Event EV_Player_DumpState + ( + "state", + EV_CHEAT, + NULL, + NULL, + "Dumps the player's state to the console." + ); +Event EV_Player_ForceTorsoState + ( + "forcetorsostate", + EV_DEFAULT, + "s", + "torsostate", + "Force the player's torso to a certain state" + ); +Event EV_Player_GiveAllCheat + ( + "wuss", + EV_CHEAT, + NULL, + NULL, + "Gives player all weapons." + ); +Event EV_Player_EndLevel + ( + "endlevel", + EV_DEFAULT, + NULL, + NULL, + "Called when the player gets to the end of the level." + ); +Event EV_Player_DevGodCheat + ( + "god", + EV_CHEAT, + "I", + "god_mode", + "Sets the god mode cheat or toggles it." + ); +Event EV_Player_DevNoTargetCheat + ( + "notarget", + EV_CHEAT, + NULL, + NULL, + "Toggles the notarget cheat." + ); +Event EV_Player_DevNoClipCheat + ( + "noclip", + EV_CHEAT, + NULL, + NULL, + "Toggles the noclip cheat." + ); +Event EV_Player_PrevItem + ( + "invprev", + EV_CONSOLE, + NULL, + NULL, + "Cycle to player's previous item." + ); +Event EV_Player_NextItem + ( + "invnext", + EV_CONSOLE, + NULL, + NULL, + "Cycle to player's next item." + ); +Event EV_Player_GiveCheat + ( + "give", + EV_CHEAT, + "sI", + "name amount", + "Gives the player the specified thing (weapon, ammo, item, etc.) and optionally the amount." + ); +Event EV_Player_GiveWeaponCheat + ( + "giveweapon", + EV_CHEAT, + "s", + "weapon_name", + "Gives the player the specified weapon." + ); +Event EV_Player_UseItem + ( + "use", + EV_CONSOLE, + "sI", + "name weapon_hand", + "Use the specified weapon in the hand choosen (optional)." + ); +Event EV_Player_GameVersion + ( + "gameversion", + EV_CONSOLE, + NULL, + NULL, + "Prints the game version." + ); +Event EV_Player_Fov + ( + "fov", + EV_CONSOLE, + "F", + "fov", + "Sets the fov." + ); +Event EV_Player_Dead + ( + "dead", + EV_DEFAULT, + NULL, + NULL, + "Called when the player is dead." + ); +Event EV_Player_SpawnEntity + ( + "spawn", + EV_CHEAT, + "sSSSSSSSS", + "entityname keyname1 value1 keyname2 value2 keyname3 value3 keyname4 value4", + "Spawns an entity." + ); +Event EV_Player_SpawnActor + ( + "actor", + EV_CHEAT, + "sSSSSSSSS", + "modelname keyname1 value1 keyname2 value2 keyname3 value3 keyname4 value4", + "Spawns an actor." + ); +Event EV_Player_Respawn + ( + "respawn", + EV_DEFAULT, + NULL, + NULL, + "Respawns the player." + ); +Event EV_Player_TestThread + ( + "testthread", + EV_CHEAT, + "sS", + "scriptfile label", + "Starts the named thread at label if provided." + ); +Event EV_Player_PowerupTimer + ( + "poweruptimer", + EV_DEFAULT, + "ii", + "poweruptimer poweruptype", + "Sets the powerup timer and powerup type." + ); +Event EV_Player_UpdatePowerupTimer + ( + "updatepoweruptime", + EV_DEFAULT, + NULL, + NULL, + "Called once a second to decrement powerup time." + ); +Event EV_Player_ResetState + ( + "resetstate", + EV_CHEAT, + NULL, + NULL, + "Reset the player's state table." + ); +Event EV_Player_WhatIs + ( + "whatis", + EV_CHEAT, + "i", + "entity_number", + "Prints info on the specified entity." + ); +Event EV_Player_ActorInfo + ( + "actorinfo", + EV_CHEAT, + "i", + "actor_number", + "Prints info on the specified actor." + ); +Event EV_Player_KillEnt + ( + "killent", + EV_CHEAT, + "i", + "entity_number", + "Kills the specified entity." + ); +Event EV_Player_KillClass + ( + "killclass", + EV_CHEAT, + "sI", + "classname except_entity_number", + "Kills all of the entities in the specified class." + ); +Event EV_Player_RemoveEnt + ( + "removeent", + EV_CHEAT, + "i", + "entity_number", + "Removes the specified entity." + ); +Event EV_Player_RemoveClass + ( + "removeclass", + EV_CHEAT, + "sI", + "classname except_entity_number", + "Removes all of the entities in the specified class." + ); +Event EV_Player_ActivateNewWeapon + ( + "activatenewweapon", + EV_DEFAULT, + NULL, + NULL, + "Active the new weapon specified by useWeapon." + ); +Event EV_Player_DeactivateWeapon + ( + "deactivateweapon", + EV_DEFAULT, + "s", + "side", + "Deactivate the weapon in the specified hand." + ); +Event EV_Player_Jump + ( + "jump", + EV_DEFAULT, + "f", + "height", + "Makes the player jump." + ); +Event EV_Player_SwordAttack + ( + "swordattack", + EV_DEFAULT, + "s", + "hand", + "Makes the player attack with the sword in the specified sword." + ); +Event EV_Player_SwipeOn + ( + "swipeon", + EV_DEFAULT, + NULL, + NULL, + "Turn on the sword swiping for the weapon in the specified hand" + ); +Event EV_Player_SwipeOff + ( + "swipeoff", + EV_DEFAULT, + NULL, + NULL, + "Turn off the sword swiping for the weapon in the specified hand" + ); +Event EV_Player_AnimLoop_Torso + ( + "animloop_torso", + EV_DEFAULT, + NULL, + NULL, + "Called when the torso animation has finished." + ); +Event EV_Player_AnimLoop_Legs + ( + "animloop_legs", + EV_DEFAULT, + NULL, + NULL, + "Called when the legs animation has finished." + ); +Event EV_Player_DoUse + ( + "usestuff", + EV_DEFAULT, + NULL, + NULL, + "Makes the player try to use whatever is in front of her." + ); +Event EV_Player_SetHeadTarget + ( + "headtarget", + EV_CONSOLE, + NULL, + NULL, + "Sets the Makes the player try to use whatever is in front of her." + ); +Event EV_Player_ChangeOutfit + ( + "changeoutfit", + EV_CONSOLE, + "i", + "outfit_stage", + "Change the outfit to the specified stage." + ); +Event EV_Player_ListInventory + ( + "listinventory", + EV_CONSOLE, + NULL, + NULL, + "List of the player's inventory." + ); +Event EV_Player_PickupShgliek + ( + "pickup", + EV_DEFAULT, + NULL, + NULL, + "Picks up a shgliek." + ); +Event EV_Player_ThrowShgliek + ( + "throw", + EV_DEFAULT, + NULL, + NULL, + "Throws a shgliek." + ); +Event EV_Player_ClearLeftArmTarget + ( + "clearleftarmtarget", + EV_DEFAULT, + NULL, + NULL, + "Clears the left arm target of the player" + ); +Event EV_Player_ClearRightArmTarget + ( + "clearrightarmtarget", + EV_DEFAULT, + NULL, + NULL, + "Clears the right arm target of the player" + ); +Event EV_Player_ActivateShield + ( + "activateshield", + EV_DEFAULT, + NULL, + NULL, + "Activates the player's shield" + ); +Event EV_Player_DeactivateShield + ( + "deactivateshield", + EV_DEFAULT, + NULL, + NULL, + "Deactivates the player's shield" + ); +Event EV_Player_AdjustTorso + ( + "adjust_torso", + EV_DEFAULT, + "b", + "boolean", + "Turn or off the torso adjustment" + ); +Event EV_Player_DualWield + ( + "dualwield", + EV_CONSOLE, + "ss", + "weaponleft weaponright", + "Dual wield the specified weapons" + ); +Event EV_Player_UseDualWield + ( + "usedualwield", + EV_CONSOLE, + NULL, + NULL, + "Use the weapons that are on the dual wield list" + ); +Event EV_Player_EvaluateTorsoAnim + ( + "evaluatetorsoanim", + EV_CONSOLE, + NULL, + NULL, + "Evaluate the torso anim for possible changes" + ); +Event EV_Player_StepUp + ( + "stepup", + EV_DEFAULT, + NULL, + NULL, + "Causes player to step up" + ); +Event EV_Player_Turn + ( + "turn", + EV_DEFAULT, + "f", + "yawangle", + "Causes player to turn the specified amount." + ); +Event EV_Player_TurnUpdate + ( + "turnupdate", + EV_DEFAULT, + "ff", + "yaw timeleft", + "Causes player to turn the specified amount." + ); +Event EV_Player_TurnLegs + ( + "turnlegs", + EV_DEFAULT, + "f", + "yawangle", + "Turns the players legs instantly by the specified amount." + ); +Event EV_Player_NextPainTime + ( + "nextpaintime", + EV_DEFAULT, + "f", + "seconds", + "Set the next time the player experiences pain (Current time + seconds specified)." + ); + +Event EV_Player_FinishUseAnim + ( + "finishuseanim", + EV_DEFAULT, + NULL, + NULL, + "Fires off all targets associated with a particular useanim." + ); +Event EV_Player_Holster + ( + "holster", + EV_CONSOLE, + NULL, + NULL, + "Holsters all wielded weapons, or unholsters previously put away weapons" + ); +Event EV_Player_SafeHolster + ( + "safeholster", + EV_CONSOLE, + "b", + "putaway", + "Holsters all wielded weapons, or unholsters previously put away weapons\n" + "preserves state, so it will not holster or unholster unless necessary" + ); +Event EV_Player_StartUseObject + ( + "startuseobject", + EV_DEFAULT, + NULL, + NULL, + "starts up the useobject's animations." + ); +Event EV_Player_FinishUseObject + ( + "finishuseobject", + EV_DEFAULT, + NULL, + NULL, + "Fires off all targets associated with a particular useobject." + ); +Event EV_Player_SetWaterPower + ( + "waterpower", + EV_DEFAULT, + NULL, + NULL, + "Sets the eden water level of the player." + ); +Event EV_Player_WatchActor + ( + "watchactor", + EV_DEFAULT, + "e", + "actor_to_watch", + "Makes the player's camera watch the specified actor." + ); +Event EV_Player_StopWatchingActor + ( + "stopwatchingactor", + EV_DEFAULT, + "e", + "actor_to_stop_watching", + "Makes the player's camera stop watching the specified actor." + ); +Event EV_Player_PutawayWeapon + ( + "putawayweapon", + EV_DEFAULT, + "s", + "whichHand", + "Put away or deactivate the current weapon, whichHand can be left, right or dual." + ); +Event EV_Player_Weapon + ( + "weaponcommand", + EV_DEFAULT, + "sSSSSSSS", + "hand arg1 arg2 arg3 arg4 arg5 arg6 arg7", + "Pass the args to the active weapon in the specified hand" + ); +Event EV_Player_Done + ( + "playerdone", + EV_DEFAULT, + NULL, + NULL, + "Clears the waitForPlayer script command, allowing threads to run" + ); +Event EV_Player_ActivateDualWeapons + ( + "activatedualweapons", + EV_DEFAULT, + NULL, + NULL, + "Activates 2 weapons at once" + ); + +Event EV_Player_StartCoolItem + ( + "startcoolitem", + EV_DEFAULT, + NULL, + NULL, + "Player is starting to show off the cool item" + ); + +Event EV_Player_StopCoolItem + ( + "stopcoolitem", + EV_DEFAULT, + NULL, + NULL, + "Player is starting to show off the cool item" + ); + +Event EV_Player_ShowCoolItem + ( + "showcoolitem", + EV_DEFAULT, + NULL, + NULL, + "Player is showing the cool item, actually display it" + ); + +Event EV_Player_HideCoolItem + ( + "hidecoolitem", + EV_DEFAULT, + NULL, + NULL, + "Player is finished showing the cool item, now hide it" + ); +Event EV_Player_SetDamageMultiplier + ( + "damage_multiplier", + EV_DEFAULT, + "f", + "damage_multiplier", + "Sets the current damage multiplier" + ); +Event EV_Player_WaitForState + ( + "waitForState", + EV_DEFAULT, + "s", + "stateToWaitFor", + "When set, the player will clear waitforplayer when this state is hit\n" + "in the legs or torso." + ); +Event EV_Player_LogStats + ( + "logstats", + EV_CHEAT, + "b", + "state", + "Turn on/off the debugging playlog" + ); +Event EV_Player_TakePain + ( + "takepain", + EV_DEFAULT, + "b", + "bool", + "Set whether or not to take pain" + ); +Event EV_Player_SkipCinematic + ( + "skipcinematic", + EV_CONSOLE, + NULL, + NULL, + "Skip the current cinematic" + ); +Event EV_Player_ResetHaveItem + ( + "resethaveitem", + EV_CONSOLE, + "s", + "weapon_name", + "Resets the game var that keeps track that we have gotten this weapon" + ); + + +/* +============================================================================== + +PLAYER + +============================================================================== +*/ + +CLASS_DECLARATION( Sentient, Player, "player" ) + { + { &EV_ClientMove, ClientThink }, + { &EV_ClientEndFrame, EndFrame }, + { &EV_Vehicle_Enter, EnterVehicle }, + { &EV_Vehicle_Exit, ExitVehicle }, + { &EV_Player_EndLevel, EndLevel }, + { &EV_Player_UseItem, EventUseItem }, + { &EV_Player_GiveCheat, GiveCheat }, + { &EV_Player_GiveWeaponCheat, GiveWeaponCheat }, + { &EV_Player_GiveAllCheat, GiveAllCheat }, + { &EV_Player_DevGodCheat, GodCheat }, + { &EV_Player_DevNoTargetCheat, NoTargetCheat }, + { &EV_Player_DevNoClipCheat, NoclipCheat }, + { &EV_Player_GameVersion, GameVersion }, + { &EV_Player_DumpState, DumpState }, + { &EV_Player_ForceTorsoState, ForceTorsoState }, + { &EV_Player_Fov, Fov }, + { &EV_Kill, Kill }, + { &EV_Player_Dead, Dead }, + { &EV_Player_SpawnEntity, SpawnEntity }, + { &EV_Player_SpawnActor, SpawnActor }, + { &EV_Player_Respawn, Respawn }, + { &EV_Player_DoUse, DoUse }, + { &EV_Pain, Pain }, + { &EV_Killed, Killed }, + { &EV_Gib, GibEvent }, + { &EV_GotKill, GotKill }, + { &EV_Player_TestThread, TestThread }, + { &EV_Player_PowerupTimer, SetPowerupTimer }, + { &EV_Player_UpdatePowerupTimer, UpdatePowerupTimer }, + { &EV_Player_ResetState, ResetState }, + { &EV_Player_WhatIs, WhatIs }, + { &EV_Player_ActorInfo, ActorInfo }, + { &EV_Player_KillEnt, KillEnt }, + { &EV_Player_RemoveEnt, RemoveEnt }, + { &EV_Player_KillClass, KillClass }, + { &EV_Player_RemoveClass, RemoveClass }, + { &EV_Player_AnimLoop_Legs, EndAnim_Legs }, + { &EV_Player_AnimLoop_Torso, EndAnim_Torso }, + { &EV_Player_Jump, Jump }, + { &EV_Sentient_JumpXY, JumpXY }, + { &EV_Player_ActivateNewWeapon, ActivateNewWeapon }, + { &EV_Player_DeactivateWeapon, DeactivateWeapon }, + { &EV_Player_SwordAttack, SwordAttackEvent }, + { &EV_Player_SwipeOn, SwipeOn }, + { &EV_Player_SwipeOff, SwipeOff }, + { &EV_Player_SetHeadTarget, SetHeadTarget }, + { &EV_Player_ChangeOutfit, ChangeOutfit }, + { &EV_Player_ListInventory, ListInventoryEvent }, + { &EV_Player_PickupShgliek, PickupShgliek }, + { &EV_Player_ThrowShgliek, ThrowShgliek }, + { &EV_Player_ClearLeftArmTarget, ClearLeftArmTarget }, + { &EV_Player_ClearRightArmTarget, ClearRightArmTarget }, + { &EV_Player_ActivateShield, ActivateShield }, + { &EV_Player_DeactivateShield, DeactivateShield }, + { &EV_Player_AdjustTorso, AdjustTorso }, + { &EV_Player_DualWield, DualWield }, + { &EV_Player_UseDualWield, UseDualWield }, + { &EV_Player_EvaluateTorsoAnim, EvaluateTorsoAnim }, + { &EV_Player_NextPainTime, NextPainTime }, + { &EV_Player_StepUp, StepUp }, + { &EV_Player_Turn, Turn }, + { &EV_Player_TurnUpdate, TurnUpdate }, + { &EV_Player_TurnLegs, TurnLegs }, + { &EV_Player_FinishUseAnim, FinishUseAnim }, + { &EV_Sentient_SetMouthAngle, SetMouthAngle }, + { &EV_Player_Holster, HolsterToggle }, + { &EV_Player_SafeHolster, Holster }, + { &EV_Player_StartUseObject, StartUseObject }, + { &EV_Player_FinishUseObject, FinishUseObject }, + { &EV_Player_SetWaterPower, SetWaterPower }, + { &EV_Player_WatchActor, WatchActor }, + { &EV_Player_StopWatchingActor, StopWatchingActor }, + { &EV_Player_PutawayWeapon, PutawayWeapon }, + { &EV_Player_Weapon, WeaponCommand }, + { &EV_Player_Done, PlayerDone }, + { &EV_Player_ActivateDualWeapons, ActivateDualWeapons }, + { &EV_Player_StartCoolItem, StartCoolItem }, + { &EV_Player_StopCoolItem, StopCoolItem }, + { &EV_Player_ShowCoolItem, ShowCoolItem }, + { &EV_Player_HideCoolItem, HideCoolItem }, + { &EV_Player_SetDamageMultiplier, SetDamageMultiplier }, + { &EV_Player_WaitForState, WaitForState }, + { &EV_Player_LogStats, LogStats }, + { &EV_Player_TakePain, SetTakePain }, + { &EV_Player_SkipCinematic, SkipCinematic }, + { &EV_Player_ResetHaveItem, ResetHaveItem }, + { &EV_Show, PlayerShowModel }, + { NULL, NULL } + }; + +qboolean Player::checkturnleft + ( + Conditional &condition + ) + + { + float yaw; + + yaw = SHORT2ANGLE( last_ucmd.angles[ YAW ] + client->ps.delta_angles[ YAW ] ); + + return ( angledist( old_v_angle[ YAW ] - yaw ) < -8.0f ); + } + +qboolean Player::checkturnright + ( + Conditional &condition + ) + + { + float yaw; + + yaw = SHORT2ANGLE( last_ucmd.angles[ YAW ] + client->ps.delta_angles[ YAW ] ); + + return ( angledist( old_v_angle[ YAW ] - yaw ) > 8.0f ); + } + +qboolean Player::checkforward + ( + Conditional &condition + ) + + { + return last_ucmd.forwardmove > 0; + } + +qboolean Player::checkbackward + ( + Conditional &condition + ) + + { + return last_ucmd.forwardmove < 0; + } + +qboolean Player::checkstrafeleft + ( + Conditional &condition + ) + + { + return last_ucmd.rightmove < 0; + } + +qboolean Player::checkstraferight + ( + Conditional &condition + ) + + { + return last_ucmd.rightmove > 0; + } + +qboolean Player::checkrise + ( + Conditional &condition + ) + + { + if ( ( do_rise ) && ( velocity.z > 32 ) ) + { + return true; + } + do_rise = qfalse; + + return false; + } + +qboolean Player::checkjump + ( + Conditional &condition + ) + + { + return last_ucmd.upmove > 0; + } + +qboolean Player::checkcrouch + ( + Conditional &condition + ) + + { + // If the crouch_flag is set, then return true and clear the flag + if ( crouch_flag ) + { + crouch_flag = false; + return true; + } + else if ( last_ucmd.upmove < 0 ) // check for downward movement + { + if ( client->ps.walking ) + { + // Player has a weapon, so we can't crouch yet + // and we must putaway the weapons first. The crouch_flag is + // set so we can allow the state machine to crouch after + // the weapons have been put away + if ( WeaponsOut() ) + { + SafeHolster( qtrue ); + crouch_flag = true; + return false; + } + else // no weapons + { + return true; + } + } + else // No weapons out, or not on the ground, and moving down + { + return true; + } + } + + return false; + } + +qboolean Player::checkjumpflip + ( + Conditional &condition + ) + + { + return velocity.z < ( sv_gravity->value * 0.5f ); + } + +qboolean Player::checkanimdone_legs + ( + Conditional &condition + ) + + { + return animdone_Legs; + } + +qboolean Player::checkanimdone_torso + ( + Conditional &condition + ) + + { + return animdone_Torso; + } + + +qboolean Player::checkattackleft + ( + Conditional &condition + ) + + { + if ( level.playerfrozen || ( flags & FL_IMMOBILE ) ) + { + return false; + } + + if ( last_ucmd.buttons & BUTTON_ATTACKLEFT ) + { + Weapon *weapon; + + last_attack_button = BUTTON_ATTACKLEFT; + + weapon = GetActiveWeapon( WEAPON_LEFT ); + if ( weapon ) + { + return true; + } + + weapon = GetActiveWeapon( WEAPON_RIGHT ); + if ( weapon ) + { + return true; + } + + weapon = GetActiveWeapon( WEAPON_DUAL ); + if ( weapon ) + { + return true; + } + + // No ammo + return false; + } + else + { + return false; + } + } + +qboolean Player::checkattackbuttonleft + ( + Conditional &condition + ) + + { + if ( level.playerfrozen || ( flags & FL_IMMOBILE ) ) + { + return false; + } + + return ( last_ucmd.buttons & BUTTON_ATTACKLEFT ); + } + + +qboolean Player::checkattackright + ( + Conditional &condition + ) + + { + if ( level.playerfrozen || ( flags & FL_IMMOBILE ) ) + { + return false; + } + + if ( last_ucmd.buttons & BUTTON_ATTACKRIGHT ) + { + Weapon *weapon; + + last_attack_button = BUTTON_ATTACKRIGHT; + + weapon = GetActiveWeapon( WEAPON_RIGHT ); + if ( weapon ) + { + return true; + } + + weapon = GetActiveWeapon( WEAPON_LEFT ); + if ( weapon ) + { + return true; + } + + weapon = GetActiveWeapon( WEAPON_DUAL ); + if ( weapon ) + { + return true; + } + + // No ammo + return false; + } + else + { + return false; + } + } + +qboolean Player::checkattackbuttonright + ( + Conditional &condition + ) + + { + if ( level.playerfrozen || ( flags & FL_IMMOBILE ) ) + { + return false; + } + + return ( last_ucmd.buttons & BUTTON_ATTACKRIGHT ); + } + +qboolean Player::checksneak + ( + Conditional &condition + ) + + { + return ( last_ucmd.buttons & BUTTON_SNEAK ) != 0; + } + +qboolean Player::checkrun + ( + Conditional &condition + ) + + { + return ( last_ucmd.buttons & BUTTON_RUN ) != 0; + } + +qboolean Player::checkwasrunning + ( + Conditional &condition + ) + + { + return ( pm_lastruntime > MINIMUM_RUNNING_TIME ); + } + +qboolean Player::checkholsterweapon + ( + Conditional &condition + ) + + { + return ( last_ucmd.buttons & BUTTON_HOLSTERWEAPON ) != 0; + } + +qboolean Player::checkuse + ( + Conditional &condition + ) + + { + return ( last_ucmd.buttons & BUTTON_USE ) != 0; + } + +qboolean Player::checkcanmoveleft + ( + Conditional &condition + ) + + { + if ( condition.numParms() ) + { + return move_left_dist >= atof( condition.getParm( 1 ) ); + } + + return move_left_dist > 1.0f; + } + +qboolean Player::checkcanturn + ( + Conditional &condition + ) + + { + float yaw; + Vector oldang( v_angle ); + qboolean result; + + yaw = atof( condition.getParm( 1 ) ); + + v_angle[ YAW ] = ( int )( anglemod( v_angle[ YAW ] + yaw ) / 22.5f ) * 22.5f; + SetViewAngles( v_angle ); + + result = CheckMove( vec_zero ); + + SetViewAngles( oldang ); + + return result; + } + +qboolean Player::checkcanmoveright + ( + Conditional &condition + ) + + { + if ( condition.numParms() ) + { + return move_right_dist >= atof( condition.getParm( 1 ) ); + } + + return move_right_dist > 1.0f; + } + +qboolean Player::checkcanmovebackward + ( + Conditional &condition + ) + + { + if ( condition.numParms() ) + { + return move_backward_dist >= atof( condition.getParm( 1 ) ); + } + + return move_backward_dist > 1.0f; + } + +qboolean Player::checkcanmoveforward + ( + Conditional &condition + ) + + { + if ( condition.numParms() ) + { + return move_forward_dist >= atof( condition.getParm( 1 ) ); + } + + return move_forward_dist > 1.0f; + } + +qboolean Player::checkcanwallhug + ( + Conditional &condition + ) + + { + trace_t trace; + Vector start( origin.x, origin.y, origin.z + 4 ); + Vector end( start - yaw_forward * 15.0f ); + + while( end.z < absmax.z - 4.0f ) + { + trace = G_Trace( start, min_box_8x8, max_box_8x8, end, this, MASK_DEADSOLID, true, "checkcanwallhug" ); + if ( ( trace.fraction == 1.0f ) || ( trace.ent->entity->getSolidType() != SOLID_BSP ) ) + { + return false; + } + + start.z += 16.0f; + end.z += 16.0f; + } + + return true; + } + +qboolean Player::checkblocked + ( + Conditional &condition + ) + + { + int test_moveresult; + + test_moveresult = moveresult; + + if ( flags & FL_IMMOBILE ) + test_moveresult = MOVERESULT_BLOCKED; + + if ( condition.numParms() ) + { + return test_moveresult >= atoi( condition.getParm( 1 ) ); + } + + return test_moveresult >= MOVERESULT_BLOCKED; + } + +qboolean Player::checkhangatwall + ( + Conditional &condition + ) + + { + trace_t trace; + + Vector end( centroid + yaw_forward * 16.0f ); + + trace = G_Trace( centroid, Vector( mins.x, mins.y, -8 ), Vector( maxs.x, maxs.y, 8 ), + end, this, MASK_DEADSOLID, true, "Player::checkhangatwall" ); + return ( trace.fraction < 0.7f ); + } + +qboolean Player::checkcanhang + ( + Conditional &condition + ) + + { + trace_t trace; + + Vector end( origin + yaw_forward * 16.0f ); + + trace = G_Trace( origin, mins, maxs, end, this, MASK_DEADSOLID, true, "Player::checkcanhang" ); + if ( trace.ent && trace.ent->entity ) + { + if ( + ( trace.ent->entity->velocity.length() ) || + ( trace.ent->entity->avelocity.length() ) + ) + { + return qfalse; + } + } + + if ( ledgeheight_right == MIN_Z ) + return qfalse; + + if ( ledgeheight_left == MIN_Z ) + return qfalse; + + if ( !trace.ent ) + return qfalse; + + return qtrue; + } + + +qboolean Player::checkcanhangleft + ( + Conditional &condition + ) + + { + trace_t trace; + + Vector move( origin.x + 26 * yaw_left.x, origin.y + 26 * yaw_left.y, origin.z ); + + trace = G_Trace( origin, mins, maxs, move, this, MASK_DEADSOLID, true, "Player::checkcanhangleft" ); + if ( trace.fraction < 1.0f ) + { + return false; + } + + Vector lefthand( lefthand_pos + move - origin ); + Vector end( lefthand + yaw_forward * 8.0f ); + + lefthand.z -= 4; + end.z -= 4; + + trace = G_Trace( lefthand, vec_zero, vec_zero, end, this, MASK_DEADSOLID, true, "Player::checkcanhangleft" ); + return ( trace.startsolid ) || ( trace.fraction < 1.0f ); + } + +qboolean Player::checkcanhangright + ( + Conditional &condition + ) + + { + trace_t trace; + + Vector move( origin.x - 26 * yaw_left.x, origin.y - 26 * yaw_left.y, origin.z ); + + trace = G_Trace( origin, mins, maxs, move, this, MASK_DEADSOLID, true, "Player::checkcanhangright" ); + if ( trace.fraction < 1.0f ) + { + return false; + } + + Vector righthand( righthand_pos + move - origin ); + Vector end( righthand + yaw_forward * 8.0f ); + + righthand.z -= 4; + end.z -= 4; + + trace = G_Trace( righthand, vec_zero, vec_zero, end, this, MASK_DEADSOLID, true, "Player::checkcanhangright" ); + return ( trace.startsolid ) || ( trace.fraction < 1.0f ); + } + +qboolean Player::checktouchrope + ( + Conditional &condition + ) + + { + return ( rope_touch != NULL ); + } + +qboolean Player::checkonrope + ( + Conditional &condition + ) + + { + return ( rope_grabbed != NULL ); + } + +qboolean Player::checkcanclimbrope + ( + Conditional &condition + ) + + { + if ( rope_grabbed ) + { + return ( rope_grabbed->CanClimb( atof( condition.getParm( 1 ) ) ) ); + } + return false; + } + +qboolean Player::checkonground + ( + Conditional &condition + ) + + { + return client->ps.walking; + } + +qboolean Player::check22degreeslope + ( + Conditional &condition + ) + + { + if ( client->ps.walking && client->ps.groundPlane && ( client->ps.groundTrace.plane.normal[ 2 ] < SLOPE_22_MAX ) && + ( client->ps.groundTrace.plane.normal[ 2 ] >= SLOPE_22_MIN ) ) + { + return qtrue; + } + + return qfalse; + } + +qboolean Player::check45degreeslope + ( + Conditional &condition + ) + + { + if ( client->ps.walking && client->ps.groundPlane && ( client->ps.groundTrace.plane.normal[ 2 ] < SLOPE_45_MAX ) && + ( client->ps.groundTrace.plane.normal[ 2 ] >= SLOPE_45_MIN ) ) + { + return qtrue; + } + + return qfalse; + } + +qboolean Player::checkrightleghigh + ( + Conditional &condition + ) + + { + float groundyaw; + float yawdelta; + int which; + + groundyaw = ( int )vectoyaw( client->ps.groundTrace.plane.normal ); + yawdelta = anglemod( v_angle.y - groundyaw ); + which = ( ( int )yawdelta + 45 ) / 90; + + return ( which == 3 ); + } + +qboolean Player::checkleftleghigh + ( + Conditional &condition + ) + + { + float groundyaw; + float yawdelta; + int which; + + groundyaw = ( int )vectoyaw( client->ps.groundTrace.plane.normal ); + yawdelta = anglemod( v_angle.y - groundyaw ); + which = ( ( int )yawdelta + 45 ) / 90; + + return ( which == 1 ); + } + +qboolean Player::checkfacingupslope + ( + Conditional &condition + ) + + { + float groundyaw; + float yawdelta; + int which; + + groundyaw = ( int )vectoyaw( client->ps.groundTrace.plane.normal ); + yawdelta = anglemod( v_angle.y - groundyaw ); + which = ( ( int )yawdelta + 45 ) / 90; + + return ( which == 2 ); + } + +qboolean Player::checkfacingdownslope + ( + Conditional &condition + ) + + { + float groundyaw; + float yawdelta; + int which; + + groundyaw = ( int )vectoyaw( client->ps.groundTrace.plane.normal ); + yawdelta = anglemod( v_angle.y - groundyaw ); + which = ( ( int )yawdelta + 45 ) / 90; + + return ( ( which == 0 ) || ( which == 4 ) ); + } + +qboolean Player::checkfalling + ( + Conditional &condition + ) + + { + return falling; + } + +qboolean Player::checkgroundentity + ( + Conditional &condition + ) + + { + return ( groundentity != NULL ); + } + +qboolean Player::checkhardimpact + ( + Conditional &condition + ) + + { + return hardimpact; + } + +qboolean Player::checkcanfall + ( + Conditional &condition + ) + + { + return canfall; + } + +qboolean Player::checkatdoor + ( + Conditional &condition + ) + + { + // Check if the player is at a door + return ( atobject && atobject->isSubclassOf( Door ) ); + } + +qboolean Player::checkatshgliek + ( + Conditional &condition + ) + + { + Vector start; + Vector end; + trace_t trace; + + // See if there are any Shglieks in front of us + + start = origin + Vector( 0, 0, 32 ); + end = start + yaw_forward * 64.0f; + trace = G_Trace( start, mins, maxs, end, this, MASK_PLAYERSOLID, true, "checkatshgliek" ); + + if ( trace.ent && trace.ent->entity && ( trace.ent->entity != world ) && trace.ent->entity->isSubclassOf( Actor ) ) + { + Actor *act = (Actor *)trace.ent->entity; + + if ( act->name == "Shgliek" ) + return true; + } + + return false; + } + +qboolean Player::checkhaveshgliek + ( + Conditional &condition + ) + + { + return have_shgliek; + } + +qboolean Player::checkshgliekdead + ( + Conditional &condition + ) + + { + int i; + Entity *child; + Actor *act; + + + for ( i=0; i < MAX_MODEL_CHILDREN; i++ ) + { + if ( children[i] == ENTITYNUM_NONE ) + { + continue; + } + + child = ( Entity * )G_GetEntity( children[i] ); + + if ( child->isSubclassOf( Actor ) ) + { + act = (Actor *)child; + + if ( ( act->name == "Partially Evil Shgliek" ) || ( act->name == "Evil Shgliek" ) ) + return true; + + if ( act->name == "Shgliek" ) + { + if ( act->deadflag ) + return true; + else + return false; + } + } + } + + return true; + } + +qboolean Player::checkatuseanim + ( + Conditional &condition + ) + + { + // Check if the player is at a useanim + if ( atobject && atobject->isSubclassOf( UseAnim ) ) + { + return ( ( UseAnim * )( Entity * )atobject )->canBeUsed( this ); + } + + return false; + } + +qboolean Player::checktouchuseanim + ( + Conditional &condition + ) + + { + if ( toucheduseanim ) + { + return ( ( UseAnim * )( Entity * )toucheduseanim )->canBeUsed( this ); + } + + return qfalse; + } + +qboolean Player::checkuseanimfinished + ( + Conditional &condition + ) + + { + return ( useanim_numloops <= 0 ); + } + +qboolean Player::checkatuseobject + ( + Conditional &condition + ) + + { + // Check if the player is at a useanim + if ( atobject && atobject->isSubclassOf( UseObject ) ) + { + return ( ( UseObject * )( Entity * )atobject )->canBeUsed( origin, yaw_forward ); + } + + return false; + } + +qboolean Player::checkloopuseobject + ( + Conditional &condition + ) + + { + // Check if the player is at a useanim + if ( useitem_in_use && useitem_in_use->isSubclassOf( UseObject ) ) + { + return ( ( UseObject * )( Entity * )useitem_in_use )->Loop(); + } + + return false; + } + +qboolean Player::checkcangrabledge + ( + Conditional &condition + ) + + { + float old_hang_pullup_distance; + float hang_pullup_distance; + float deltaleft; + float deltaright; + bool hangleft; + bool hangright; + + if ( ( ledgeheight_left <= MIN_Z ) || ( ledgeheight_right <= MIN_Z ) ) + { + return false; + } + + if ( groundentity ) + { + deltaleft = ledgeheight_left - origin.z - 128.0f; + deltaright = ledgeheight_right - origin.z - 128.0f; + + return ( Q_fabs( deltaleft ) < 1.1f ) && ( Q_fabs( deltaright ) < 1.1f ); + } + +#define WALL_FUDGE_FACTOR 5 + hang_pullup_distance = lefthand_pos.z; + old_hang_pullup_distance = hang_pullup_distance - origin.z + oldorigin.z; + if ( hang_pullup_distance > old_hang_pullup_distance ) + { + hangleft = ( hang_pullup_distance >= ledgeheight_left ) && ( ledgeheight_left+WALL_FUDGE_FACTOR >= old_hang_pullup_distance ); + } + else + { + hangleft = ( old_hang_pullup_distance >= ledgeheight_left ) && ( ledgeheight_left+WALL_FUDGE_FACTOR >= hang_pullup_distance ); + } + + hang_pullup_distance = righthand_pos.z; + old_hang_pullup_distance = hang_pullup_distance - origin.z + oldorigin.z; + if ( hang_pullup_distance > old_hang_pullup_distance ) + { + hangright = ( hang_pullup_distance >= ledgeheight_right ) && ( ledgeheight_right+WALL_FUDGE_FACTOR >= old_hang_pullup_distance ); + } + else + { + hangright = ( old_hang_pullup_distance >= ledgeheight_right ) && ( ledgeheight_right+WALL_FUDGE_FACTOR >= hang_pullup_distance ); + } + + return hangleft && hangright; + } + +qboolean Player::checkledgeheight + ( + Conditional &condition + ) + + { + float deltaleft; + float deltaright; + float minclimbheight; + float maxclimbheight; + + if ( ( ledgeheight_left <= MIN_Z ) || ( ledgeheight_right <= MIN_Z ) ) + { + return false; + } + + if ( condition.numParms() != 2 ) + { + error( "checkledgeheight", "CAN_CLIMB requires 2 parameters.\n" ); + } + + minclimbheight = atof( condition.getParm( 1 ) ); + maxclimbheight = atof( condition.getParm( 2 ) ); + + deltaleft = Q_fabs( ledgeheight_left - origin.z ); + deltaright = Q_fabs( ledgeheight_right - origin.z ); + + if ( Q_fabs( deltaright - deltaleft ) < 1.1f ) + { + deltaright = max( deltaleft, deltaright ); + deltaleft = deltaright; + } + + return ( deltaleft > minclimbheight ) && ( deltaleft <= maxclimbheight ) && + ( deltaright > minclimbheight ) && ( deltaright <= maxclimbheight ); + } + +qboolean Player::checkcangrabpipe + ( + Conditional &condition + ) + + { + return horizontalpipe != NULL; + } + +qboolean Player::checkcangrabmonkeybar + ( + Conditional &condition + ) + + { + float old_hang_pullup_distance; + float hang_pullup_distance; + float deltaleft; + float deltaright; + bool hangleft; + bool hangright; + + if ( ( monkeybar_left <= MIN_Z ) || ( monkeybar_right <= MIN_Z ) ) + { + return false; + } + + if ( groundentity ) + { + deltaleft = monkeybar_left - origin.z - 128.0f; + deltaright = monkeybar_right - origin.z - 128.0f; + + return ( Q_fabs( deltaleft ) < 1.0f ) && ( Q_fabs( deltaright ) < 1.0f ); + } + + hang_pullup_distance = lefthand_pos.z; + old_hang_pullup_distance = hang_pullup_distance - origin.z + oldorigin.z; + if ( hang_pullup_distance > old_hang_pullup_distance ) + { + hangleft = ( hang_pullup_distance >= monkeybar_left ) && ( monkeybar_left >= old_hang_pullup_distance ); + } + else + { + hangleft = ( old_hang_pullup_distance >= monkeybar_left ) && ( monkeybar_left >= hang_pullup_distance ); + } + + hang_pullup_distance = righthand_pos.z; + old_hang_pullup_distance = hang_pullup_distance - origin.z + oldorigin.z; + if ( hang_pullup_distance > old_hang_pullup_distance ) + { + hangright = ( hang_pullup_distance >= monkeybar_right ) && ( monkeybar_right >= old_hang_pullup_distance ); + } + else + { + hangright = ( old_hang_pullup_distance >= monkeybar_right ) && ( monkeybar_right >= hang_pullup_distance ); + } + + return hangleft && hangright; + } + +qboolean Player::checkcanpullup + ( + Conditional &condition + ) + + { + trace_t trace; + + Vector start( origin.x, origin.y, max( ledgeheight_left, ledgeheight_right ) ); + Vector end( start + yaw_forward * 16.0f ); + + trace = G_Trace( origin, mins, maxs, start, this, MASK_DEADSOLID, true, "Player::checkcanpullup" ); + if ( trace.fraction < 1.0f ) + { + return false; + } + + trace = G_Trace( start, mins, maxs, end, this, MASK_DEADSOLID, true, "Player::checkcanpullup" ); + return trace.fraction == 1.0f; + } + +qboolean Player::checkdead + ( + Conditional &condition + ) + + { + return ( deadflag ); + } + +qboolean Player::checkhealth + ( + Conditional &condition + ) + + { + return health < atoi( condition.getParm( 1 ) ); + } + +qboolean Player::checkpain + ( + Conditional &condition + ) + + { + return ( pain != 0 || knockdown != 0 ); + } + +qboolean Player::checkknockdown + ( + Conditional &condition + ) + + { + if ( knockdown ) + { + knockdown = false; + return true; + } + else + { + return false; + } + } + +qboolean Player::checkpaintype + ( + Conditional &condition + ) + + { + if ( pain_type == MOD_string_to_int( condition.getParm( 1 ) ) ) + { + return qtrue; + } + else + { + return qfalse; + } + } + +qboolean Player::checkpaindirection + ( + Conditional &condition + ) + + { + if ( pain_dir == Pain_string_to_int( condition.getParm( 1 ) ) ) + { + return qtrue; + } + else + { + return qfalse; + } + } + +qboolean Player::checkaccumulatedpain + ( + Conditional &condition + ) + + { + float threshold = atof( condition.getParm( 1 ) ); + + if ( accumulated_pain >= threshold ) + { + accumulated_pain = 0; // zero out accumulation + return true; + } + else + { + return false; + } + } + +qboolean Player::checkpainthreshold + ( + Conditional &condition + ) + + { + float threshold = atof( condition.getParm( 1 ) ); + + if ( ( pain >= threshold ) && ( level.time > nextpaintime ) ) + { + accumulated_pain = 0; // zero out accumulation since we are going into a pain anim right now + return true; + } + else + { + return false; + } + } + +qboolean Player::checklegsstate + ( + Conditional &condition + ) + + { + if ( currentState_Legs ) + { + str current = currentState_Legs->getName(); + str compare = condition.getParm( 1 ); + + if ( current == compare ) + { + return true; + } + } + + return false; + } + +qboolean Player::checktorsostate + ( + Conditional &condition + ) + + { + if ( currentState_Torso ) + { + str current = currentState_Torso->getName(); + str compare = condition.getParm( 1 ); + + if ( current == compare ) + { + return true; + } + } + + return false; + } + +qboolean Player::checkhasweapon + ( + Conditional &condition + ) + + { + return WeaponsOut(); + } + +qboolean Player::checknewweapon + ( + Conditional &condition + ) + + { + Weapon * weapon; + + weapon = GetNewActiveWeapon(); + + if ( weapon ) + return true; + else + return false; + } + +// Check to see if a weapon has been raised +qboolean Player::checkuseweapon + ( + Conditional &condition + ) + + { + const char *weaponName; + const char *parm; + + weaponhand_t hand; + Weapon *weap; + + weap = GetNewActiveWeapon(); + parm = condition.getParm( 1 ); + + if ( !str::icmp( parm, "ERROR" ) ) + { + if ( weap ) + warning( "Player::checkuseweapon", "%s does not have a valid RAISE_WEAPON state\n", weap->item_name ); + else + warning( "Player::checkuseweapon", "New Active weapon does not exist\n" ); + + ClearNewActiveWeapon(); + return qtrue; + } + + hand = WeaponHandNameToNum( parm ); + + if ( hand == WEAPON_ERROR ) + return false; + + weaponName = condition.getParm( 2 ); + + if ( + ( weap != NULL ) && + ( GetNewActiveWeaponHand() == hand ) && + ( !stricmp( weap->item_name, weaponName ) ) + ) + { + return true; + } + else + { + return false; + } + } + +// Checks to see if any weapon is active in the specified hand +qboolean Player::checkanyweaponactive + ( + Conditional &condition + ) + + { + weaponhand_t hand; + Weapon *weap; + + hand = WeaponHandNameToNum( condition.getParm( 1 ) ); + + if ( hand == WEAPON_ERROR ) + return false; + + weap = GetActiveWeapon( hand ); + return ( weap != NULL ); + } + +// Checks to see if any weapon is active in the specified hand +qboolean Player::checkweaponhasammo + ( + Conditional &condition + ) + + { + weaponhand_t hand; + Weapon *weap; + firemode_t mode = FIRE_PRIMARY; + + hand = WeaponHandNameToNum( condition.getParm( 1 ) ); + + if ( condition.numParms() > 1 ) + mode = WeaponModeNameToNum( condition.getParm( 2 ) ); + + if ( hand == WEAPON_ERROR ) + return false; + + weap = GetActiveWeapon( hand ); + + if ( !weap ) + return false; + else + return ( weap->HasAmmo( mode ) ); + } + +qboolean Player::checkmuzzleclear + ( + Conditional &condition + ) + + { + weaponhand_t hand; + + hand = WeaponHandNameToNum( condition.getParm( 1 ) ); + + if ( hand == WEAPON_ERROR ) + return false; + + Weapon *weapon = GetActiveWeapon( hand ); + return ( weapon && weapon->MuzzleClear() ); + } + +// Checks to see if weapon is active +qboolean Player::checkweaponactive + ( + Conditional &condition + ) + + { + const char *weaponName; + weaponhand_t hand; + + weaponName = condition.getParm( 2 ); + hand = WeaponHandNameToNum( condition.getParm( 1 ) ); + + if ( hand == WEAPON_ERROR ) + return false; + + Weapon *weapon = GetActiveWeapon( hand ); + + return ( weapon && !strcmp( weaponName, weapon->item_name ) ); + } + +qboolean Player::checkdualweaponreadytofire + ( + Conditional &condition + ) + + { + firemode_t mode = FIRE_PRIMARY; + str weaponName="None"; + Weapon *weapon = GetActiveWeapon( WEAPON_DUAL ); + qboolean ready; + + mode = WeaponModeNameToNum( condition.getParm( 1 ) ); + + if ( condition.numParms() > 1 ) + weaponName = condition.getParm( 2 ); + + // Weapon there check + if ( !weapon ) + return qfalse; + + // Name check + if ( condition.numParms() > 1 ) + { + if ( strcmp( weaponName, weapon->item_name ) ) + { + return qfalse; + } + } + + // Ammo check + ready = weapon->ReadyToFire( mode ); + return( ready ); + } + +// Checks to see if weapon is active and ready to fire +qboolean Player::checkweaponreadytofire + ( + Conditional &condition + ) + + { + firemode_t mode = FIRE_PRIMARY; + str weaponName="None"; + weaponhand_t hand; + qboolean ready; + + if ( level.playerfrozen || ( flags & FL_IMMOBILE ) ) + { + return false; + } + + hand = WeaponHandNameToNum( condition.getParm( 1 ) ); + + if ( hand == WEAPON_DUAL ) + { + gi.DPrintf( "This check should only be used for single handed weapons\n" ); + return false; + } + + if ( condition.numParms() > 1 ) + weaponName = condition.getParm( 2 ); + + if ( hand == WEAPON_ERROR ) + return false; + + Weapon *weapon = GetActiveWeapon( hand ); + + // Weapon there check + if ( !weapon ) + return qfalse; + + // Name check + if ( condition.numParms() > 1 ) + { + if ( strcmp( weaponName, weapon->item_name ) ) + { + return qfalse; + } + } + + // Ammo check + ready = weapon->ReadyToFire( mode ); + return( ready ); + } + +qboolean Player::checkweaponreadytofire_nosound + ( + Conditional &condition + ) + + { + firemode_t mode = FIRE_PRIMARY; + str weaponName="None"; + weaponhand_t hand; + qboolean ready; + + if ( level.playerfrozen || ( flags & FL_IMMOBILE ) ) + { + return false; + } + + hand = WeaponHandNameToNum( condition.getParm( 1 ) ); + + if ( hand == WEAPON_DUAL ) + { + gi.DPrintf( "This check should only be used for single handed weapons\n" ); + return false; + } + + if ( condition.numParms() > 1 ) + weaponName = condition.getParm( 2 ); + + if ( hand == WEAPON_ERROR ) + return false; + + Weapon *weapon = GetActiveWeapon( hand ); + + // Weapon there check + if ( !weapon ) + return qfalse; + + // Name check + if ( condition.numParms() > 1 ) + { + if ( strcmp( weaponName, weapon->item_name ) ) + { + return qfalse; + } + } + + // Ammo check + ready = weapon->ReadyToFire( mode, qfalse ); + return( ready ); + } + +// Check to see if any of the active weapons need to be put away +qboolean Player::checkputawayleft + ( + Conditional &condition + ) + + { + Weapon *weapon = GetActiveWeapon( WEAPON_LEFT ); + + return weapon && weapon->GetPutaway(); + } + +qboolean Player::checkputawayright + ( + Conditional &condition + ) + + { + Weapon *weapon = GetActiveWeapon( WEAPON_RIGHT ); + + return weapon && weapon->GetPutaway(); + } + +qboolean Player::checkputawayboth + ( + Conditional &condition + ) + + { + Weapon *weapon = GetActiveWeapon( WEAPON_DUAL ); + + return weapon && weapon->GetPutaway(); + } + +qboolean Player::checktargetacquired + ( + Conditional &condition + ) + + { + str side = condition.getParm( 1 ); + + if ( !side.icmp( "left" ) ) + { + return ( left_arm_target != NULL ); + } + else if ( !side.icmp( "right" ) ) + { + return ( right_arm_target != NULL ); + } + else if ( !side.icmp( "both" ) ) + { + return ( ( left_arm_target != NULL ) && ( right_arm_target != NULL ) ); + } + else if ( !side.icmp( "any" ) ) + { + return ( ( left_arm_target != NULL ) || ( right_arm_target != NULL ) ); + } + else + { + return false; + } + } + +qboolean Player::returntrue + ( + Conditional &condition + ) + + { + return true; + } + +qboolean Player::checkstatename + ( + Conditional &condition + ) + + { + str part = condition.getParm( 1 ); + str statename = condition.getParm( 2 ); + + if ( currentState_Legs && !part.icmp( "legs" ) ) + { + return ( !statename.icmpn( currentState_Legs->getName(), statename.length() ) ); + } + else if ( !part.icmp( "torso" ) ) + { + return ( !statename.icmpn( currentState_Torso->getName(), statename.length() ) ); + } + + return false; + } + +qboolean Player::checkattackblocked + ( + Conditional &condition + ) + + { + if ( attack_blocked ) + { + attack_blocked = qfalse; + return true; + } + else + { + return false; + } + } + +qboolean Player::checkblockdelay + ( + Conditional &condition + ) + + { + float t = atof ( condition.getParm( 1 ) ); + return ( level.time > ( attack_blocked_time + t ) ); + } + +qboolean Player::checkpush + ( + Conditional &condition + ) + + { + // Check if the player is at a pushobject + if ( atobject && atobject->isSubclassOf( PushObject ) && ( atobject_dist < ( PUSH_OBJECT_DISTANCE + 15.0f ) ) ) + { + Vector dir; + + dir = atobject_dir * 8.0f; + return ( ( PushObject * )( Entity * )atobject )->canPush( dir ); + } + + return qfalse; + } + +qboolean Player::checkpull + ( + Conditional &condition + ) + + { + // Check if the player is at a pushobject + if ( atobject && atobject->isSubclassOf( PushObject ) && ( atobject_dist < ( PUSH_OBJECT_DISTANCE + 15.0f ) ) ) + { + Vector dir; + + dir = atobject_dir * -64.0f; + return ( ( PushObject * )( Entity * )atobject )->canPush( dir ); + } + + return qfalse; + } + +#define LADDER_HAND_HEIGHT ( MAXS_X - MINS_X ) + +qboolean Player::checkladder + ( + Conditional &condition + ) + + { + trace_t trace; + float hands_fraction; + Vector newmins; + Vector end( origin + yaw_forward * 20.0f ); + + // the bounding box is made skinnier to account for the hands + newmins = mins; + newmins.z = MAXS_Z - LADDER_HAND_HEIGHT; + + trace = G_Trace( origin, newmins, maxs, end, this, MASK_SOLID, true, "checkladder" ); + if ( ( trace.fraction == 1.0f ) || !( trace.surfaceFlags & SURF_LADDER ) ) + { + return qfalse; + } + hands_fraction = trace.fraction; + + // check for the body + trace = G_Trace( origin, mins, maxs, end, this, MASK_SOLID, true, "checkladder" ); + + // if our body does not go as far as our hands, we aren't at a ladder + if ( trace.fraction < hands_fraction ) + { + return qfalse; + } + + return qtrue; + } + +qboolean Player::checkcanclimbladder + ( + Conditional &condition + ) + + { + trace_t trace; + Vector newmins; + Vector vec; + Vector start( origin ); + int i; + + for ( i = 0; i < 3; i++ ) + { + vec[ i ] = atof ( condition.getParm( i + 1 ) ); + } + start += vec[ 0 ] * yaw_forward; + start += vec[ 1 ] * yaw_left; + start.z += vec[ 2 ]; + + Vector end( start + yaw_forward * 20.0f ); + + // check the normal bounding box first and trace to that position + trace = G_Trace( origin, mins, maxs, start, this, MASK_SOLID, true, "checkcanclimbladder" ); + if ( ( trace.fraction != 1.0f ) || ( trace.startsolid ) || ( trace.allsolid ) ) + { + return qfalse; + } + + // the bounding box is made skinnier to account for the hands + newmins = mins; + newmins.z = MAXS_Z - LADDER_HAND_HEIGHT; + + trace = G_Trace( start, newmins, maxs, end, this, MASK_SOLID, true, "checkcanclimbladder" ); + if ( ( trace.fraction == 1.0f ) || !( trace.surfaceFlags & SURF_LADDER ) ) + { + return qfalse; + } + + return qtrue; + } + + +qboolean Player::checkfeetatladder + ( + Conditional &condition + ) + + { + trace_t trace; + Vector newmins, newmaxs; + Vector end( origin + yaw_forward * 20.0f ); + + // the bounding box is made skinnier to account for the feet + newmaxs.x = MAXS_X / 2; + newmaxs.y = MAXS_Y / 2; + // just underneath the feet + newmaxs.z = 28; + newmins.x = MINS_X / 2; + newmins.y = MINS_Y / 2; + newmins.z = 0; + trace = G_Trace( origin, newmins, newmaxs, end, this, MASK_SOLID, true, "checkfeetatladder" ); + if ( ( trace.fraction == 1.0f ) || !( trace.surfaceFlags & SURF_LADDER ) ) + { + return qfalse; + } + + return qtrue; + } + + +qboolean Player::checkcanstand + ( + Conditional &condition + ) + + { + Vector newmins( mins ); + Vector newmaxs( maxs ); + trace_t trace; + + newmins[ 2 ] = MINS_Z; + newmaxs[ 2 ] = MAXS_Z; + + trace = G_Trace( origin, newmins, newmaxs, origin, this, MASK_PLAYERSOLID, true, "checkcanstand" ); + if ( trace.startsolid ) + { + return qfalse; + } + + return qtrue; + } + +qboolean Player::checkspecialmove + ( + Conditional &condition + ) + + { + weaponhand_t hand; + + hand = WeaponHandNameToNum( condition.getParm( 1 ) ); + + if ( hand == WEAPON_ERROR ) + return false; + + Weapon *weapon = GetActiveWeapon( hand ); + + if ( !weapon ) + return qtrue; + else + return weapon->GetSpecialMove(); + } + +qboolean Player::checkdualwield + ( + Conditional &condition + ) + + { + // Only start the dual wield state if dual wield is set and the hands have no weapons + + return ( dual_wield_active ); + } + +qboolean Player::checkdualweapons + ( + Conditional &condition + ) + + { + int i,j; + + for ( i=1; i<=condition.numParms(); i++ ) + { + str weaponName; + weaponName = condition.getParm( i ); + + for ( j=1; j<=dual_wield_weaponlist.NumObjects(); j++ ) + { + DualWieldWeapon *dw; + dw = dual_wield_weaponlist.ObjectAt( j ); + + if ( dw->name == weaponName ) + { + goto out; + } + } + return false; +out: + ; + } + + return true; + } + +qboolean Player::checkchance + ( + Conditional &condition + ) + + { + float percent_chance; + + percent_chance = atof( condition.getParm( 1 ) ); + + return ( G_Random() < percent_chance ); + } + +qboolean Player::checkturnedleft + ( + Conditional &condition + ) + + { + return yawing_left; + } + + +qboolean Player::checkturnedright + ( + Conditional &condition + ) + + { + return yawing_right; + } + +qboolean Player::checkinvehicle + ( + Conditional &condition + ) + + { + return ( vehicle != NULL ); + } + +qboolean Player::checkwaterlevel + ( + Conditional &condition + ) + + { + return ( water_power >= atof( condition.getParm( 1 ) ) ); + } + +qboolean Player::checkpickupenemy + ( + Conditional &condition + ) + + { + return pickup_enemy; + } + +qboolean Player::checksolidforward + ( + Conditional &condition + ) + + { + // Trace out forward to see if there is a solid ahead + float dist = atof( condition.getParm( 1 ) ); + Vector end( centroid + yaw_forward * dist ); + + trace_t trace = G_Trace( centroid, Vector( mins.x, mins.y, -8 ), Vector( maxs.x, maxs.y, 8 ), + end, this, MASK_SOLID, true, "Player::checksolidforward" ); + + return ( trace.fraction < 0.7f ); + } + +qboolean Player::checkcoolitem + ( + Conditional &condition + ) + + { + return ( cool_item != NULL ); + } + +qboolean Player::checkarmorpiece + ( + Conditional &condition + ) + + { + str piece = condition.getParm( 1 ); + + if ( !stricmp( piece, "Arm" ) ) + { + if ( outfit_level >= 2 ) + return true; + } + else if ( !stricmp( piece, "Knee" ) ) + { + if ( outfit_level >= 3 ) + return true; + } + else if ( !stricmp( piece, "Shoulder" ) ) + { + if ( outfit_level >= 4 ) + return true; + } + + return false; + } + +qboolean Player::checkweaponsholstered + ( + Conditional &condition + ) + + { + + if ( + ( holsteredWeapons[WEAPON_DUAL] ) || + ( holsteredWeapons[WEAPON_LEFT] ) || + ( holsteredWeapons[WEAPON_RIGHT] ) + ) + { + return qtrue; + } + else + { + return qfalse; + } + } + +qboolean Player::checkfakeplayeractive + ( + Conditional &condition + ) + + { + return fakePlayer_active; + } + +Condition Player::Conditions[] = + { + { "default", returntrue }, + { "SNEAK", checksneak }, + { "RUN", checkrun }, + { "WAS_RUNNING", checkwasrunning }, + { "HOLSTERWEAPON", checkholsterweapon }, + { "USE", checkuse }, + { "LEFT", checkturnleft }, + { "RIGHT", checkturnright }, + { "FORWARD", checkforward }, + { "BACKWARD", checkbackward }, + { "STRAFE_LEFT", checkstrafeleft }, + { "STRAFE_RIGHT", checkstraferight }, + { "JUMP", checkjump }, + { "RISE", checkrise }, + { "CROUCH", checkcrouch }, + { "DO_JUMP_FLIP", checkjumpflip }, + { "ANIMDONE_LEGS", checkanimdone_legs }, + { "ANIMDONE_TORSO", checkanimdone_torso }, + { "CAN_TURN", checkcanturn }, + { "CAN_MOVE_LEFT", checkcanmoveleft }, + { "CAN_MOVE_RIGHT", checkcanmoveright }, + { "CAN_MOVE_BACKWARD", checkcanmovebackward }, + { "CAN_MOVE_FORWARD", checkcanmoveforward }, + { "CAN_WALL_HUG", checkcanwallhug }, + { "BLOCKED", checkblocked }, + { "HANG_ATWALL", checkhangatwall }, + { "TOUCHED_ROPE", checktouchrope }, + { "ONROPE", checkonrope }, + { "CAN_CLIMB_ROPE", checkcanclimbrope }, + { "ONGROUND", checkonground }, + { "SLOPE_22", check22degreeslope }, + { "SLOPE_45", check45degreeslope }, + { "RIGHT_LEG_HIGH", checkrightleghigh }, + { "LEFT_LEG_HIGH", checkleftleghigh }, + { "CAN_HANG_LEFT", checkcanhangleft }, + { "CAN_HANG_RIGHT", checkcanhangright }, + { "CAN_HANG", checkcanhang }, + { "CAN_FALL", checkcanfall }, + { "AT_DOOR", checkatdoor }, + { "AT_SHGLIEK", checkatshgliek }, + { "HAVE_SHGLIEK", checkhaveshgliek }, + { "SHGLIEK_DEAD", checkshgliekdead }, + { "FALLING", checkfalling }, + { "HARD_IMPACT", checkhardimpact }, + { "CAN_GRAB_LEDGE", checkcangrabledge }, + { "LEDGE_HEIGHT", checkledgeheight }, + { "CAN_GRAB_PIPE", checkcangrabpipe }, + { "CAN_GRAB_MONKEYBARS", checkcangrabmonkeybar }, + { "CAN_PULLUP", checkcanpullup }, + { "KILLED", checkdead }, + { "HEALTH", checkhealth }, + { "PAIN", checkpain }, + { "PAIN_TYPE", checkpaintype }, + { "PAIN_DIRECTION", checkpaindirection }, + { "PAIN_THRESHOLD", checkpainthreshold }, + { "PAIN_ACCUMULATED", checkaccumulatedpain }, + { "KNOCKDOWN", checkknockdown }, + { "LEGS", checklegsstate }, + { "TORSO", checktorsostate }, + { "AT_USEANIM", checkatuseanim }, + { "TOUCHEDUSEANIM", checktouchuseanim }, + { "FINISHEDUSEANIM", checkuseanimfinished }, + { "AT_USEOBJECT", checkatuseobject }, + { "LOOP_USEOBJECT", checkloopuseobject }, + { "CAN_PUSH", checkpush }, + { "CAN_PULL", checkpull }, + { "AT_LADDER", checkladder }, + { "FEET_AT_LADDER", checkfeetatladder }, + { "CAN_CLIMB_LADDER", checkcanclimbladder }, + { "CAN_STAND", checkcanstand }, + { "CHANCE", checkchance }, + { "FACING_UP_SLOPE", checkfacingupslope }, + { "FACING_DOWN_SLOPE", checkfacingdownslope }, + { "TURNED_LEFT", checkturnedleft }, + { "TURNED_RIGHT", checkturnedright }, + { "IN_VEHICLE", checkinvehicle }, + { "WATER_LEVEL", checkwaterlevel }, + { "PICKUP_ENEMY", checkpickupenemy }, + { "SOLID_FORWARD", checksolidforward }, + { "GOT_COOL_ITEM", checkcoolitem }, + { "GROUNDENTITY", checkgroundentity }, + { "FAKEPLAYERACTIVE", checkfakeplayeractive }, + + // Weapon conditions + { "ATTACKLEFT", checkattackleft }, // Checks to see if there is an active weapon as well as the button being pressed + { "ATTACKRIGHT", checkattackright }, // Checks to see if there is an active weapon as well as the button being pressed + { "ATTACKLEFTBUTTON", checkattackbuttonleft }, // Checks to see if the left attack button is pressed + { "ATTACKRIGHTBUTTON", checkattackbuttonright },// Checks to see if the right attack button is pressed + { "HAS_WEAPON", checkhasweapon }, + { "NEW_WEAPON", checknewweapon }, + { "IS_NEW_WEAPON", checkuseweapon }, + { "IS_WEAPON_ACTIVE", checkweaponactive }, + { "IS_WEAPON_READY_TO_FIRE", checkweaponreadytofire }, + { "IS_WEAPON_READY_TO_FIRE_NOSOUND", checkweaponreadytofire_nosound }, + { "IS_DUALWEAPON_READY_TO_FIRE", checkdualweaponreadytofire }, + { "PUTAWAYLEFT", checkputawayleft }, + { "PUTAWAYRIGHT", checkputawayright }, + { "PUTAWAYBOTH", checkputawayboth }, + { "TARGET_ACQUIRED", checktargetacquired }, + { "ANY_WEAPON_ACTIVE", checkanyweaponactive }, + { "ATTACK_BLOCKED", checkattackblocked }, + { "STATE_ACTIVE", checkstatename }, + { "BLOCK_DELAY", checkblockdelay }, + { "DUALWIELD", checkdualwield }, + { "DUALWIELDWEAPONS", checkdualweapons }, + { "MUZZLE_CLEAR", checkmuzzleclear }, + { "HAS_AMMO", checkweaponhasammo }, + { "HAS_ARMORPIECE", checkarmorpiece }, + { "SPECIALMOVE", checkspecialmove }, + { "WEAPONS_HOLSTERED", checkweaponsholstered }, + { NULL, NULL }, + }; + +movecontrolfunc_t Player::MoveStartFuncs[] = + { + NULL, // MOVECONTROL_USER, // Quake style + NULL, // MOVECONTROL_LEGS, // Quake style, legs state system active + NULL, // MOVECONTROL_ANIM, // move based on animation, with full collision testing + NULL, // MOVECONTROL_ABSOLUTE, // move based on animation, with full collision testing but no turning + StartHang, // MOVECONTROL_HANGING, // move based on animation, with full collision testing, hanging + NULL, // MOVECONTROL_WALLHUG, // move based on animation, with full collision testing, hanging + StartMonkeyBars, // MOVECONTROL_MONKEYBARS, // move based on animation, with full collision testing, monkey bars + StartPipeCrawl, // MOVECONTROL_PIPECRAWL, // move based on animation, with full collision testing, crawling on pipe + StartPipeCrawl, // MOVECONTROL_PIPEHANG, // move based on animation, with full collision testing, hanging from pipe + StartStepUp, // MOVECONTROL_STEPUP, + RopeGrab, // MOVECONTROL_ROPE_GRAB + RopeRelease, // MOVECONTROL_ROPE_RELEASE + NULL, // MOVECONTROL_ROPE_MOVE + StartPickup, // MOVECONTROL_PICKUPENEMY + StartPush, // MOVECONTROL_PUSH + StartClimbWall, // MOVECONTROL_CLIMBWALL + StartUseAnim, // MOVECONTROL_USEANIM + NULL, // MOVECONTROL_CROUCH + StartLoopUseAnim, // MOVECONTROL_LOOPUSEANIM + SetupUseObject, // MOVECONTROL_USEOBJECT + StartCoolItemAnim, // MOVECONTROL_COOLOBJECT + StartFakePlayer, // MOVECONTROL_FAKEPLAYER + }; + +Player::Player() + { + // + // set the entity type + // + edict->s.eType = ET_PLAYER; + respawn_time = -1; + statemap_Legs = NULL; + statemap_Torso = NULL; + camera = NULL; + atobject = NULL; + atobject_dist = 0; + toucheduseanim = NULL; + useitem_in_use = NULL; + horizontalpipe = NULL; + damage_blood = 0; + damage_count = 0; + damage_from = vec_zero; + damage_alpha = 0; + last_attack_button = 0; + attack_blocked = qfalse; + shield_active = qfalse; + crouch_flag = qfalse; + ledgeheight_left = 0; + ledgeheight_right = 0; + monkeybar_left = 0; + monkeybar_right = 0; + monkeybar_dir = 0; + canfall = false; + move_left_dist = 0; + move_right_dist = 0; + move_backward_dist = 0; + move_forward_dist = 0; + moveresult = MOVERESULT_NONE; + animspeed = 0; + airspeed = 200; + vehicle = NULL; + action_level = 0; + have_shgliek = false; + pickup_enemy = false; + adjust_torso = qfalse; + dual_wield_active = qfalse; + cool_item = NULL; + weapons_holstered_by_code = qfalse; + actor_camera = NULL; + cool_camera = NULL; + damage_multiplier = 1; + take_pain = true; + look_at_time = 0; + outfit_level = 0; + fakePlayer_active = qfalse; + + memset( oldstats, 0, sizeof( oldstats ) ); + + // make sure that we are not overflowing the stats for players + assert( STAT_LAST_STAT <= MAX_STATS ); + + fov = atof( Info_ValueForKey( client->pers.userinfo, "fov" ) ); + if ( fov < 1 ) + { + fov = 90; + } + else if ( fov > 160 ) + { + fov = 160; + } + + if ( !LoadingSavegame ) + { + crosshair = new Entity; + crosshair->setModel( "crosshair.spr" ); + crosshair->setSolidType( SOLID_NOT ); + crosshair->setMoveType( MOVETYPE_NONE ); + crosshair->takedamage = DAMAGE_NO; + crosshair->hideModel(); + } + + // + // set targetnameplayer + // + SetTargetName( "player" ); + + Init(); + + SetOutfit( 0 ); + } + +Player::~Player() + { + int i,num; + Conditional *cond; + + edict->s.modelindex = 0; + + num = legs_conditionals.NumObjects(); + for ( i=num; i>0; i-- ) + { + cond = legs_conditionals.ObjectAt( i ); + delete cond; + } + + num = torso_conditionals.NumObjects(); + for ( i=num; i>0; i-- ) + { + cond = torso_conditionals.ObjectAt( i ); + delete cond; + } + + legs_conditionals.FreeObjectList(); + torso_conditionals.FreeObjectList(); + } + +static qboolean logfile_started = qfalse; + +void Player::Init + ( + void + ) + + { + InitClient(); + InitPhysics(); + InitPowerups(); + InitWorldEffects(); + InitSound(); + InitView(); + InitState(); + InitEdict(); + InitModel(); + InitWeapons(); + InitInventory(); + InitHealth(); + InitWaterPower(); + + LoadStateTable(); + + if ( !LoadingSavegame ) + { + ChooseSpawnPoint(); + } + + // make sure we put the player back into the world + link(); + logfile_started = qfalse; + } + +void Player::InitEdict + ( + void + ) + + { + // entity state stuff + setSolidType( SOLID_BBOX ); + setMoveType( MOVETYPE_WALK ); + setSize( Vector( -16, -16, 0 ), Vector( 16, 16, STAND_HEIGHT ) ); + edict->clipmask = MASK_PLAYERSOLID; + edict->svflags &= ~SVF_DEADMONSTER; + edict->svflags &= ~SVF_HIDEOWNER; + edict->ownerNum = ENTITYNUM_NONE; + + // clear entity state values + edict->s.eFlags = 0; + edict->s.frame = 0; + + // players have precise shadows + edict->s.renderfx |= RF_SHADOW_PRECISE; + } + +void Player::InitSound + ( + void + ) + + { + // + // reset the music + // + client->ps.current_music_mood = mood_normal; + client->ps.fallback_music_mood = mood_normal; + ChangeMusic( "normal", "normal", false ); + + client->ps.music_volume = 1.0; + client->ps.music_volume_fade_time = 0.0; + ChangeMusicVolume( 1.0, 0.0 ); + + music_forced = false; + + // Reset the reverb stuff + + client->ps.reverb_type = eax_generic; + client->ps.reverb_level = 0; + SetReverb( client->ps.reverb_type, client->ps.reverb_level ); + } + +void Player::InitClient + ( + void + ) + + { + client_persistant_t saved; + + // deathmatch wipes most client data every spawn + if ( deathmatch->integer ) + { + char userinfo[ MAX_INFO_STRING ]; + + memcpy( userinfo, client->pers.userinfo, sizeof( userinfo ) ); + G_InitClientPersistant( client ); + G_ClientUserinfoChanged( edict, userinfo ); + } + + // clear everything but the persistant data and fov + saved = client->pers; + memset( client, 0, sizeof( *client ) ); + client->pers = saved; + + client->ps.clientNum = client - game.clients; + } + +void Player::InitState + ( + void + ) + + { + gibbed = false; + pain = 0; + accumulated_pain = 0; + nextpaintime = 0; + knockdown = false; + pain_dir = PAIN_NONE; + pain_type = MOD_NONE; + crouch_flag = false; + takedamage = DAMAGE_AIM; + deadflag = DEAD_NO; + flags &= ~FL_NO_KNOCKBACK; + flags |= ( FL_BLOOD | FL_DIE_GIBS ); + + if ( !com_blood->integer ) + { + flags &= ~FL_BLOOD; + flags &= ~FL_DIE_GIBS; + } + } + + +void Player::InitWaterPower + ( + void + ) + + { + water_power = 50; + max_water_power = 100; + SetWaterPower( water_power ); + } + +void Player::InitHealth + ( + void + ) + + { + // Don't do anything if we're loading a server game. + // This is either a loadgame or a restart + if ( LoadingSavegame ) + { + return; + } + + // reset the health values + health = 100; + max_health = 100; + } + +void Player::InitModel + ( + void + ) + + { + orientation_t orient; + int anim; + int tagnum; + + setModel( str( g_playermodel->string ) + ".tik" ); + + SetControllerTag( HEAD_TAG, gi.Tag_NumForName( edict->s.modelindex, "Bip01 Head" ) ); + SetControllerTag( TORSO_TAG, gi.Tag_NumForName( edict->s.modelindex, "Bip01 Spine1" ) ); + SetControllerTag( R_ARM_TAG, gi.Tag_NumForName( edict->s.modelindex, R_ARM_NAME ) ); + SetControllerTag( L_ARM_TAG, gi.Tag_NumForName( edict->s.modelindex, L_ARM_NAME ) ); + SetControllerTag( MOUTH_TAG, gi.Tag_NumForName( edict->s.modelindex, "tag_mouth" ) ); + + anim = gi.Anim_NumForName( edict->s.modelindex, "hang_idle" ); + + tagnum = gi.Tag_NumForName( edict->s.modelindex, "tag_weapon_right" ) & TAG_MASK; + orient = gi.Tag_Orientation( edict->s.modelindex, anim, 0, tagnum, 1.0f, NULL, NULL ); + base_righthand_pos = orient.origin; + + tagnum = gi.Tag_NumForName( edict->s.modelindex, "tag_weapon_left" ) & TAG_MASK; + orient = gi.Tag_Orientation( edict->s.modelindex, anim, 0, tagnum, 1.0f, NULL, NULL ); + base_lefthand_pos = orient.origin; + + anim = gi.Anim_NumForName( edict->s.modelindex, "stand_idle" ); + + tagnum = gi.Tag_NumForName( edict->s.modelindex, "Bip01 R Foot" ) & TAG_MASK; + orient = gi.Tag_Orientation( edict->s.modelindex, anim, 0, tagnum, 1.0f, NULL, NULL ); + base_rightfoot_pos = orient.origin; + base_rightfoot_pos.z = 0; + + tagnum = gi.Tag_NumForName( edict->s.modelindex, "Bip01 L Foot" ) & TAG_MASK; + orient = gi.Tag_Orientation( edict->s.modelindex, anim, 0, tagnum, 1.0f, NULL, NULL ); + base_leftfoot_pos = orient.origin; + base_leftfoot_pos.z = 0; + + showModel(); + + yawing_left = qfalse; + yawing_right = qfalse; + } + +void Player::InitPhysics + ( + void + ) + + { + // Physics stuff + oldvelocity = vec_zero; + velocity = vec_zero; + old_v_angle = v_angle; + gravity = 1.0; + falling = false; + hardimpact = false; + mass = 200; + rope_touch = NULL; + rope_grabbed = NULL; + memset( &last_ucmd, 0, sizeof( last_ucmd ) ); + } + +void Player::InitPowerups + ( + void + ) + + { + // powerups + poweruptimer = 0; + poweruptype = 0; + } + +void Player::InitWorldEffects + ( + void + ) + + { + // world effects + next_drown_time = 0; + next_painsound_time = 0; + air_finished = level.time + 20; + old_waterlevel = 0; + drown_damage = 0; + } + +void Player::InitWeapons + ( + void + ) + + { + // Don't do anything if we're loading a server game. + // This is either a loadgame or a restart + if ( LoadingSavegame ) + { + return; + } + + + } + +void Player::InitInventory + ( + void + ) + + { + } + +void Player::InitView + ( + void + ) + + { + // view stuff + camera = NULL; + v_angle = vec_zero; + SetViewAngles( v_angle ); + viewheight = STAND_EYE_HEIGHT; + + head_target = NULL; + left_arm_target = NULL; + right_arm_target = NULL; + + // blend stuff + damage_blend = vec_zero; + } + +void Player::ChooseSpawnPoint + ( + void + ) + + { + str thread; + + // set up the player's spawn location + SelectSpawnPoint( origin, angles, thread ); + setOrigin( origin + "0 0 1" ); + origin.copyTo( edict->s.origin2 ); + edict->s.renderfx |= RF_FRAMELERP; + + KillBox( this ); + + setAngles( angles ); + SetViewAngles( angles ); + + if ( thread.length() ) + { + ExecuteThread( thread ); + } + } + +void Player::EndLevel + ( + Event *ev + ) + + { + InitPowerups(); + if ( health > max_health ) + { + health = max_health; + } + + if ( health < 1 ) + { + health = 1; + } + } + +void Player::Respawn + ( + Event *ev + ) + + { + if ( deathmatch->integer ) + { + assert ( deadflag == DEAD_DEAD ); + + respawn_time = level.time; + + Init(); + + // hold in place briefly + client->ps.pm_time = 50; + client->ps.pm_flags |= PMF_TIME_TELEPORT; + + return; + } + else + { +#ifdef PRE_RELEASE_DEMO + gi.SendConsoleCommand( "forcemenu demomain; forcemenu loadsave\n" ); +#else + gi.SendConsoleCommand( "forcemenu main; forcemenu loadsave\n" ); +#endif + logfile_started = qfalse; + } + } + +void Player::SetDeltaAngles + ( + void + ) + + { + int i; + + // Use v_angle since we may be in a camera + for( i = 0; i < 3; i++ ) + { + client->ps.delta_angles[ i ] = ANGLE2SHORT( v_angle[ i ] ); + } + } + +void Player::Obituary + ( + Entity *attacker, + Entity *inflictor, + int meansofdeath + ) + + { + if ( !deathmatch->integer ) + { + return; + } + } + +void Player::Dead + ( + Event *ev + ) + + { + deadflag = DEAD_DEAD; + + // stop animating + StopAnimating( legs ); + + // + // drop anything that might be attached to us + // + + // FIXME : re-enable and fix dropping issues for deathmatch? + /* if ( numchildren ) + { + Entity * child; + int i; + // + // detach all our children + // + for ( i=0; i < MAX_MODEL_CHILDREN; i++ ) + { + if ( children[i] != ENTITYNUM_NONE ) + { + child = ( Entity * )G_GetEntity( children[ i ] ); + child->ProcessEvent( EV_Detach ); + } + } + } */ + } + +void Player::Killed + ( + Event *ev + ) + + { + Entity *attacker; + Entity *inflictor; + int meansofdeath; + + attacker = ev->GetEntity( 1 ); + inflictor = ev->GetEntity( 3 ); + meansofdeath = ev->GetInteger( 4 ); + + pain_type = (meansOfDeath_t)meansofdeath; + + if ( attacker && inflictor ) + Obituary( attacker, inflictor, meansofdeath ); + + + deadflag = DEAD_DYING; + + respawn_time = level.time + 1.0; + + edict->clipmask = MASK_DEADSOLID; + edict->svflags |= SVF_DEADMONSTER; + + setContents( CONTENTS_CORPSE ); + + setMoveType( MOVETYPE_NONE ); + + angles.x = 0; + angles.z = 0; + setAngles( angles ); + + // + // change music + // + ChangeMusic( "failure", "normal", true ); + + health = 0; + + // Stop targeting monsters + + if ( left_arm_target ) + { + left_arm_target->edict->s.eFlags &= ~EF_LEFT_TARGETED; + left_arm_target = NULL; + } + + if ( right_arm_target ) + { + right_arm_target->edict->s.eFlags &= ~EF_RIGHT_TARGETED; + right_arm_target = NULL; + } + + // Post a dead event just in case + PostEvent( EV_Player_Dead, 2 ); + } + +void Player::Pain + ( + Event *ev + ) + + { + float damage,yawdiff; + Entity *attacker; + int meansofdeath; + Vector dir,pos,attack_angle; + + damage = ev->GetFloat( 1 ); + attacker = ev->GetEntity( 2 ); + meansofdeath = ev->GetInteger( 3 ); + pos = ev->GetVector( 4 ); + dir = ev->GetVector( 5 ); + + if ( !damage && !knockdown ) + return; + + client->ps.stats[ STAT_LAST_PAIN ] = damage; + + // Determine direction + attack_angle = dir.toAngles(); + yawdiff = torsoAngles[YAW] - attack_angle[YAW] + 180; + yawdiff = AngleNormalize180( yawdiff ); + + if ( yawdiff > -45 && yawdiff < 45 ) + pain_dir = PAIN_FRONT; + else if ( yawdiff < -45 && yawdiff > -135 ) + pain_dir = PAIN_LEFT; + else if ( yawdiff > 45 && yawdiff < 135 ) + pain_dir = PAIN_RIGHT; + else + pain_dir = PAIN_REAR; + + // accumulate pain for animation purposes + if ( take_pain ) + { + accumulated_pain += damage; + } + + // Spawn off any damage effect if we get hit with a certain type of damage + SpawnDamageEffect( (meansOfDeath_t)meansofdeath ); + + pain_type = (meansOfDeath_t)meansofdeath; + + // Only set the regular pain level if enough time since last pain has passed + if ( ( level.time > nextpaintime ) && take_pain ) + { + pain = damage; + } + + if ( meansofdeath > MOD_LAST_SELF_INFLICTED ) + { + // increase action level of game as we're getting hurt + IncreaseActionLevel( damage ); + } + + // 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 + damage_blood += damage; + damage_from += ev->GetVector( 5 ) * damage; + } + +void Player::DoUse + ( + Event *ev + ) + + { + int i; + int num; + int touch[ MAX_GENTITIES ]; + gentity_t *hit; + Event *event; + Vector min; + Vector max; + Vector offset; + trace_t trace; + Vector start; + Vector end; + float t; + + // if we are in a vehicle, we want to use the vehicle always + if ( vehicle ) + { + event = new Event( EV_Use ); + event->AddEntity( this ); + vehicle->ProcessEvent( event ); + return; + } + + start = origin; + start.z += viewheight; + end = start + yaw_forward * 64.0f; + + trace = G_Trace( start, vec_zero, vec_zero, end, this, MASK_USABLE, true, "Player::DoUse" ); + + t = 64 * trace.fraction - maxs[ 0 ]; + if ( t < 0 ) + { + t = 0; + } + + offset = yaw_forward * t; + + min = start + offset + "-16 -16 -16"; + max = start + offset + "16 16 16"; + + num = gi.AreaEntities( min, max, touch, MAX_GENTITIES ); + + // be careful, it is possible to have an entity in this + // list removed before we get to it (killtriggered) + for( i = 0; i < num; i++ ) + { + hit = &g_entities[ touch[ i ] ]; + if ( !hit->inuse ) + { + continue; + } + + assert( hit->entity ); + + event = new Event( EV_Use ); + event->AddEntity( this ); + hit->entity->ProcessEvent( event ); + } + } + +void Player::TouchStuff + ( + pmove_t *pm + ) + + { + gentity_t *other; + Event *event; + int i; + int j; + + // + // clear out any conditionals that are controlled by touching + // + toucheduseanim = NULL; + + if ( getMoveType() != MOVETYPE_NOCLIP ) + { + G_TouchTriggers( this ); + } + + // touch other objects + for( i = 0; i < pm->numtouch; i++ ) + { + other = &g_entities[ pm->touchents[ i ] ]; + + for( j = 0; j < i ; j++ ) + { + gentity_t *ge = &g_entities[ j ]; + + if ( ge == other ) + break; + } + + if ( j != i ) + { + // duplicated + continue; + } + + // Don't bother touching the world + if ( ( !other->entity ) || ( other->entity == world ) ) + { + continue; + } + + event = new Event( EV_Touch ); + event->AddEntity( this ); + other->entity->ProcessEvent( event ); + + event = new Event( EV_Touch ); + event->AddEntity( other->entity ); + ProcessEvent( event ); + } + } + +void Player::GetMoveInfo + ( + pmove_t *pm + ) + + { + moveresult = pm->moveresult; + + if ( !deadflag ) + { + v_angle[ 0 ] = pm->ps->viewangles[ 0 ]; + v_angle[ 1 ] = pm->ps->viewangles[ 1 ]; + v_angle[ 2 ] = pm->ps->viewangles[ 2 ]; + + if ( moveresult == MOVERESULT_TURNED ) + { + angles.y = v_angle[ 1 ]; + setAngles( angles ); + SetViewAngles( angles ); + } + } + + setOrigin( Vector( pm->ps->origin[ 0 ], pm->ps->origin[ 1 ], pm->ps->origin[ 2 ] ) ); + velocity = Vector( pm->ps->velocity[ 0 ], pm->ps->velocity[ 1 ], pm->ps->velocity[ 2 ] ); + + if ( client->ps.pm_flags & PMF_FROZEN || client->ps.pm_flags & PMF_NO_MOVE ) + { + velocity = vec_zero; + } + else + { + setSize( pm->mins, pm->maxs ); + + viewheight = pm->ps->viewheight; + } + + // water type and level is set in the predicted code + waterlevel = pm->waterlevel; + watertype = pm->watertype; + + // Set the ground entity + groundentity = NULL; + if ( pm->ps->groundEntityNum != ENTITYNUM_NONE ) + { + groundentity = &g_entities[ pm->ps->groundEntityNum ]; + airspeed = 200; + } + } + +void Player::SetMoveInfo + ( + pmove_t *pm, + usercmd_t *ucmd + ) + + { + Vector move; + + // set up for pmove + memset( pm, 0, sizeof( pmove_t ) ); + + velocity.copyTo( client->ps.velocity ); + + pm->ps = &client->ps; + + if ( ucmd ) + { + pm->cmd = *ucmd; + } + + pm->tracemask = MASK_PLAYERSOLID; + pm->trace = gi.trace; + pm->pointcontents = gi.pointcontents; + pm->trypush = TryPush; + + pm->ps->origin[ 0 ] = origin.x; + pm->ps->origin[ 1 ] = origin.y; + pm->ps->origin[ 2 ] = origin.z; + + pm->ps->velocity[ 0 ] = velocity.x; + pm->ps->velocity[ 1 ] = velocity.y; + pm->ps->velocity[ 2 ] = velocity.z; + + // save off pm_runtime + if ( pm->ps->pm_runtime ) + pm_lastruntime = pm->ps->pm_runtime; + } + +pmtype_t Player::GetMovePlayerMoveType + ( + void + ) + + { + if ( getMoveType() == MOVETYPE_NOCLIP ) + { + return PM_NOCLIP; + } + else if ( deadflag ) + { + return PM_DEAD; + } + else + { + return PM_NORMAL; + } + } + +void Player::CheckGround + ( + void + ) + + { + pmove_t pm; + + SetMoveInfo( &pm, current_ucmd ); + Pmove_GroundTrace( &pm ); + GetMoveInfo( &pm ); + } + +qboolean Player::MonkeyBarMove + ( + Vector &move, + Vector *endpos + ) + + { + Vector up; + Vector down; + trace_t trace; + + Vector start( origin ); + Vector end( origin + move ); + + trace = G_Trace( start, mins, maxs, end, this, MASK_PLAYERSOLID, true, "MonkeyBarMove" ); + if ( trace.startsolid ) + { + if ( endpos ) + { + *endpos = origin; + } + return qfalse; + } + + Vector pos( trace.endpos ); + + // + // check if the right hand will still be on the monkey bars + // + end = righthand_pos + yaw_left * 4.0f - origin + pos; + start.x = end.x; + start.y = end.y; + start.z = absmax.z; + + trace = G_Trace( start, Vector( -4, -4, 0 ), Vector( 4, 4, 2 ), end, this, MASK_PLAYERSOLID, false, "MonkeyBarMove" ); + if ( trace.startsolid || ( trace.fraction >= 1.0f ) || !trace.ent || !trace.ent->entity->isSubclassOf( MonkeyBars ) ) + { + if ( endpos ) + { + *endpos = origin; + } + return qfalse; + } + + // + // check if the left hand will still be on the monkey bars + // + end = lefthand_pos - yaw_left * 4.0f - origin + pos; + start.x = end.x; + start.y = end.y; + start.z = absmax.z; + + trace = G_Trace( start, Vector( -4, -4, 0 ), Vector( 4, 4, 2 ), end, this, MASK_PLAYERSOLID, false, "MonkeyBarMove" ); + if ( trace.startsolid || ( trace.fraction >= 1.0f ) || !trace.ent || !trace.ent->entity->isSubclassOf( MonkeyBars ) ) + { + if ( endpos ) + { + *endpos = origin; + } + return qfalse; + } + + if ( endpos ) + { + *endpos = pos; + } + + return qtrue; + } + +qboolean Player::PipeMove + ( + Vector &move, + Vector *endpos + ) + + { + Vector up; + Vector down; + trace_t trace; + + Vector start( origin ); + Vector end( origin + move ); + + trace = G_Trace( start, mins, maxs, end, this, MASK_PLAYERSOLID, true, "PipeMove" ); + if ( trace.startsolid ) + { + if ( endpos ) + { + *endpos = origin; + } + return qfalse; + } + + Vector pos( trace.endpos ); + + end.x = pos.x; + end.y = pos.y; + + end.z = righthand_pos.z + 1 - maxs.z; + + trace = G_Trace( pos, mins, maxs, end, this, MASK_DEADSOLID, true, "PipeMove" ); + if ( ( trace.fraction < 1.0f ) && trace.ent && trace.ent->entity->isSubclassOf( HorizontalPipe ) ) + { + if ( endpos ) + { + *endpos = pos; + } + + return qtrue; + } + + if ( endpos ) + { + *endpos = origin; + } + + return qfalse; + } + +qboolean Player::AnimMove + ( + Vector &move, + Vector *endpos + ) + + { + Vector up; + Vector down; + trace_t trace; + int mask; + Vector start( origin ); + Vector end( origin + move ); + + mask = MASK_PLAYERSOLID; + + // test the player position if they were a stepheight higher + trace = G_Trace( start, mins, maxs, end, this, mask, true, "AnimMove" ); + if ( trace.fraction < 1 ) + { + if ( ( movecontrol == MOVECONTROL_HANGING ) || ( movecontrol == MOVECONTROL_CLIMBWALL ) ) + { + up = origin; + up.z += move.z; + trace = G_Trace( origin, mins, maxs, up, this, mask, true, "AnimMove" ); + if ( trace.fraction < 1 ) + { + if ( endpos ) + { + *endpos = origin; + } + return qfalse; + } + + origin = trace.endpos; + end = origin; + end.x += move.x; + end.y += move.y; + + trace = G_Trace( origin, mins, maxs, end, this, mask, true, "AnimMove" ); + if ( endpos ) + { + *endpos = trace.endpos; + } + + return ( trace.fraction > 0 ); + } + else + { + return TestMove( move, endpos ); + } + } + else + { + if ( endpos ) + { + *endpos = trace.endpos; + } + + return qtrue; + } + } + +qboolean Player::TestMove + ( + Vector &move, + Vector *endpos + ) + + { + trace_t trace; + Vector pos( origin + move ); + + trace = G_Trace( origin, mins, maxs, pos, this, MASK_PLAYERSOLID, true, "TestMove" ); + if ( trace.allsolid ) + { + // player is completely trapped in another solid + if ( endpos ) + { + *endpos = origin; + } + return qfalse; + } + + if ( trace.fraction < 1.0f ) + { + Vector up( origin ); + up.z += STEPSIZE; + + trace = G_Trace( origin, mins, maxs, up, this, MASK_PLAYERSOLID, true, "TestMove" ); + if ( trace.fraction == 0.0f ) + { + if ( endpos ) + { + *endpos = origin; + } + return qfalse; + } + + Vector temp( trace.endpos ); + Vector end( temp + move ); + + trace = G_Trace( temp, mins, maxs, end, this, MASK_PLAYERSOLID, true, "TestMove" ); + if ( trace.fraction == 0.0f ) + { + if ( endpos ) + { + *endpos = origin; + } + return qfalse; + } + + temp = trace.endpos; + + Vector down( trace.endpos ); + down.z = origin.z; + + trace = G_Trace( temp, mins, maxs, down, this, MASK_PLAYERSOLID, true, "TestMove" ); + } + + if ( endpos ) + { + *endpos = trace.endpos; + } + + return qtrue; + } + +qboolean Player::RopeMove + ( + Vector &move, + Vector *endpos + ) + + { + if ( rope_grabbed ) + { + if ( rope_grabbed->CanClimb( move.z ) ) + { + rope_grabbed->Climb( move.z ); + *endpos = origin; + return qtrue; + } + } + return qfalse; + } + +float Player::TestMoveDist + ( + Vector &move + ) + + { + Vector endpos; + + TestMove( move, &endpos ); + endpos -= origin; + + return endpos.length(); + } + + +void Player::CheckMoveFlags + ( + void + ) + + { + trace_t trace; + Vector start; + Vector end; + float startz; + float oldsp; + Vector olddir( oldvelocity.x, oldvelocity.y, 0 ); + + MatrixTransformVector( base_righthand_pos, orientation, righthand_pos ); + MatrixTransformVector( base_lefthand_pos, orientation, lefthand_pos ); + MatrixTransformVector( base_rightfoot_pos, orientation, rightfoot_pos ); + MatrixTransformVector( base_leftfoot_pos, orientation, leftfoot_pos ); + righthand_pos += origin; + lefthand_pos += origin; + rightfoot_pos += origin; + leftfoot_pos += origin; + + if ( !client->ps.walking ) + { + // + // if we're not on a pole, check if there's a pole we can grab + // + if ( + ( movecontrol != MOVECONTROL_PIPECRAWL ) && + ( movecontrol != MOVECONTROL_PIPEHANG ) + ) + { + end.x = origin.x; + end.y = origin.y; + end.z = righthand_pos.z + 1 - maxs.z; + trace = G_Trace( origin, mins, maxs, end, this, MASK_DEADSOLID, false, "CheckMoveFlags" ); + if ( ( trace.fraction < 1.0f ) && trace.ent && trace.ent->entity->isSubclassOf( HorizontalPipe ) ) + { + horizontalpipe = trace.ent->entity; + } + else + { + horizontalpipe = NULL; + } + } + + // + // get the right hand monkey bar height + // + end = righthand_pos + yaw_left * 4.0f; + start.x = end.x; + start.y = end.y; + start.z = absmax.z; + + monkeybar_dir = v_angle.y; + + trace = G_Trace( start, min4x4, max4x4x0, end, this, MASK_DEADSOLID, false, "CheckMoveFlags" ); + if ( !trace.startsolid && ( trace.fraction < 1.0f ) && trace.ent && trace.ent->entity->isSubclassOf( MonkeyBars ) ) + { + monkeybar_right = end.z + ( start.z - end.z ) * ( 1.0f - trace.fraction ); + monkeybar_dir = ( ( MonkeyBars * )trace.ent->entity )->dir; + } + else + { + monkeybar_right = MIN_Z; + } + + // + // get the left hand monkey bar height + // + end = lefthand_pos - yaw_left * 4.0f; + start.x = end.x; + start.y = end.y; + start.z = absmax.z; + + trace = G_Trace( start, min4x4, max4x4x0, end, this, MASK_DEADSOLID, false, "CheckMoveFlags" ); + if ( !trace.startsolid && ( trace.fraction < 1.0f ) && trace.ent && trace.ent->entity->isSubclassOf( MonkeyBars ) ) + { + monkeybar_left = end.z + ( start.z - end.z ) * ( 1.0f - trace.fraction ); + } + else + { + monkeybar_left = MIN_Z; + } + } + else + { + horizontalpipe = NULL; + monkeybar_left = MIN_Z; + monkeybar_right = MIN_Z; + } + + // trace up to see if the player's hands are not in a solid + end.x = origin.x; + end.y = origin.y; + end.z = origin.z + 208; + trace = G_Trace( origin, min4x4, max4x4x8, end, this, MASK_DEADSOLID, false, "CheckMoveFlags" ); + startz = trace.endpos[ 2 ]; + + // + // get the right hand ledge height for grabbing ledges + // + end = righthand_pos + yaw_left * 4.0f; // + yaw_forward * 4.0f; + end.z = origin.z; + start.x = end.x; + start.y = end.y; + start.z = startz; + + trace = G_Trace( start, min4x4, max4x4x8, end, this, MASK_DEADSOLID, false, "CheckMoveFlags" ); + ledgeheight_right = end.z + ( start.z - end.z ) * ( 1.0f - trace.fraction ); + + if ( trace.fraction == 1 ) + ledgeheight_right = MIN_Z; + + if ( trace.startsolid ) + { + start.z = ledgeheight_right; + trace = G_Trace( start, min4x4, max4x4x8, start, this, MASK_DEADSOLID, false, "CheckMoveFlags" ); + if ( trace.startsolid ) + { + ledgeheight_right = MIN_Z; + } + } + + if ( + ( ledgeheight_right != MIN_Z ) && + trace.ent && + ( + trace.ent->entity->isSubclassOf( HorizontalPipe ) || + ( trace.ent->entity->velocity.length() > 0 ) || + ( trace.ent->entity->avelocity.length() > 0 ) + ) + ) + { + ledgeheight_right = MIN_Z; + } + if ( + ( ledgeheight_right != MIN_Z ) && + ( trace.plane.normal[ 2 ] < 0.707 ) + ) + { + ledgeheight_right = MIN_Z; + } + + // + // get the left hand ledge height for grabbing ledges + // + end = lefthand_pos - yaw_left * 4.0f; // + yaw_forward * 4.0f; + end.z = origin.z; + start.x = end.x; + start.y = end.y; + start.z = startz; + + trace = G_Trace( start, min4x4, max4x4x8, end, this, MASK_DEADSOLID, false, "CheckMoveFlags" ); + ledgeheight_left = end.z + ( start.z - end.z ) * ( 1.0f - trace.fraction ); + + if ( trace.fraction == 1 ) + ledgeheight_left = MIN_Z; + + if ( trace.startsolid ) + { + start.z = ledgeheight_left; + trace = G_Trace( start, min4x4, max4x4x8, start, this, MASK_DEADSOLID, false, "CheckMoveFlags" ); + if ( trace.startsolid ) + { + ledgeheight_left = MIN_Z; + } + } + + if ( + ( ledgeheight_left != MIN_Z ) && + trace.ent && + ( + trace.ent->entity->isSubclassOf( HorizontalPipe ) || + ( trace.ent->entity->velocity.length() > 0 ) + ) + ) + { + ledgeheight_left = MIN_Z; + } + + if ( + ( ledgeheight_left != MIN_Z ) && + ( trace.plane.normal[ 2 ] < 0.707 ) + ) + { + ledgeheight_left = MIN_Z; + } + + // + // Check if moving forward will cause the player to fall + // + start = origin + yaw_forward * 52.0f; + end = start; + end.z -= STEPSIZE * 2; + + trace = G_Trace( start, mins, maxs, end, this, MASK_PLAYERSOLID, true, "CheckMoveFlags" ); + canfall = !( trace.fraction < 1.0f ); + + if ( !groundentity && ( velocity.z < 0 ) ) + { + falling = true; + hardimpact = false; + } + else + { + hardimpact = ( oldvelocity.z < -400.0f ); + falling = false; + } + + // check for running into walls + oldsp = VectorNormalize( olddir ); + if ( ( oldsp > 250.0f ) && ( velocity * olddir < 5.0f ) ) + { + moveresult = MOVERESULT_HITWALL; + } + + // + // Check if the player is at a door, pushobject, or useanim + // + start = origin; + end = start + yaw_forward * 64.0f; + trace = G_Trace( start, mins, maxs, end, this, MASK_USABLE, true, "CheckMoveFlags" ); + + if ( trace.ent && trace.ent->entity && ( trace.ent->entity != world ) ) + { + atobject = trace.ent->entity; + atobject_dist = trace.fraction * 64.0f; + atobject_dir.setXYZ( -trace.plane.normal[ 0 ], -trace.plane.normal[ 1 ], -trace.plane.normal[ 2 ] ); + } + else + { + atobject = NULL; + } + + // + // get the distances the player can move left, right, forward, and back + // + if ( ( movecontrol == MOVECONTROL_USER ) || ( movecontrol == MOVECONTROL_LEGS ) ) + { + move_left_dist = TestMoveDist( yaw_left * 128.0f ); + move_right_dist = TestMoveDist( yaw_left * -128.0f ); + move_backward_dist = TestMoveDist( yaw_forward * -128.0f ); + move_forward_dist = TestMoveDist( yaw_forward * 128.0f ); + } + else + { + move_left_dist = CheckMoveDist( yaw_left * 2.0f ); + move_right_dist = CheckMoveDist( yaw_left * -2.0f ); + move_backward_dist = CheckMoveDist( yaw_forward * -2.0f ); + move_forward_dist = CheckMoveDist( yaw_forward * 2.0f ); + } + } + +qboolean Player::CheckMove + ( + Vector &move, + Vector *endpos + ) + + { + switch( movecontrol ) + { + case MOVECONTROL_MONKEYBARS : + return MonkeyBarMove( move, endpos ); + break; + + case MOVECONTROL_PIPECRAWL : + case MOVECONTROL_PIPEHANG : + return PipeMove( move, endpos ); + break; + + case MOVECONTROL_ROPE_MOVE : + return RopeMove( move, endpos ); + break; + + default : + return AnimMove( move, endpos ); + break; + } + } + +float Player::CheckMoveDist + ( + Vector &move + ) + + { + Vector endpos; + + CheckMove( move, &endpos ); + endpos -= origin; + + return endpos.length(); + } + +void Player::ClientMove + ( + usercmd_t *ucmd + ) + + { + pmove_t pm; + Vector move; + + oldorigin = origin; + + client->ps.pm_type = GetMovePlayerMoveType(); + + // set move flags + client->ps.pm_flags &= ~( PMF_FROZEN | PMF_NO_PREDICTION | PMF_NO_MOVE | PMF_DUCKED | PMF_LEGS_LIFTED | PMF_NO_GRAVITY ); + + if ( level.playerfrozen ) + { + client->ps.pm_flags |= PMF_FROZEN; + } + + if ( flags & FL_IMMOBILE || flags & FL_PARTIAL_IMMOBILE ) + { + client->ps.pm_flags |= PMF_NO_MOVE; + client->ps.pm_flags |= PMF_NO_PREDICTION; + } + + switch( movecontrol ) + { + case MOVECONTROL_USER : + case MOVECONTROL_LEGS : + // FIXME, should be done properly, but not enough time + // turn off prediction when standing on platforms that are moving + if ( groundentity && ( groundentity->entity ) && + ( ( groundentity->entity->velocity.length() ) || ( groundentity->entity->avelocity.length() ) ) ) + { + // + // we kill the delta, so we don't move twice as fast + // + total_delta = vec_zero; + client->ps.pm_flags |= PMF_NO_PREDICTION; + } + break; + + case MOVECONTROL_ANIM : + case MOVECONTROL_ABSOLUTE : + case MOVECONTROL_HANGING : + case MOVECONTROL_STEPUP : + case MOVECONTROL_MONKEYBARS : + case MOVECONTROL_WALLHUG : + case MOVECONTROL_ROPE_RELEASE : + case MOVECONTROL_PICKUPENEMY : + case MOVECONTROL_PUSH : + case MOVECONTROL_CLIMBWALL : + case MOVECONTROL_PIPEHANG : + client->ps.pm_flags |= PMF_NO_PREDICTION; + break; + + case MOVECONTROL_PIPECRAWL : + client->ps.pm_flags |= PMF_NO_PREDICTION | PMF_LEGS_LIFTED; + break; + + case MOVECONTROL_CROUCH : + client->ps.pm_flags |= PMF_NO_PREDICTION | PMF_DUCKED; + break; + + default: + client->ps.pm_flags |= PMF_NO_PREDICTION; + } + + // No prediction on a rope + if ( rope_grabbed ) + { + client->ps.pm_flags |= PMF_NO_PREDICTION | PMF_NO_GRAVITY; + } + + if ( !groundentity ) + { + client->ps.speed = airspeed; + } + else if ( getMoveType() == MOVETYPE_NOCLIP || ( waterlevel > 1 ) ) + { + client->ps.speed = 200; + } + else + { + client->ps.speed = animspeed; + } + + if ( getMoveType() == MOVETYPE_NOCLIP ) + { + if ( last_ucmd.buttons & BUTTON_RUN ) + client->ps.speed = 200; + else + client->ps.speed = 50; + } + + if ( + client->ps.feetfalling && + ( !rope_grabbed ) && + ( waterlevel < 2 ) && + !( client->ps.pm_time ) + ) + { + ucmd->forwardmove = 0; + ucmd->rightmove = 0; + } + if ( fakePlayer_active ) + { + ucmd->forwardmove = 0; + ucmd->rightmove = 0; + ucmd->upmove = 0; + } + + client->ps.gravity = sv_gravity->value * gravity; + + // FIXME + // do this a better way + if ( ( movecontrol != MOVECONTROL_HANGING ) && ( movecontrol != MOVECONTROL_ABSOLUTE ) && + ( movecontrol != MOVECONTROL_WALLHUG ) && ( movecontrol != MOVECONTROL_MONKEYBARS ) && + ( movecontrol != MOVECONTROL_PIPECRAWL ) && ( movecontrol != MOVECONTROL_STEPUP ) && + ( movecontrol != MOVECONTROL_PIPEHANG ) && + ( movecontrol != MOVECONTROL_PUSH ) && ( movecontrol != MOVECONTROL_CLIMBWALL ) ) + { + Vector oldpos( origin ); + qboolean standing; + + CheckGround(); + + //FIXME + // There's probably a better way to do this + // this assumes we are moving less than 5 units per second or about 3 inches per second + if ( client->ps.walking && ( getMoveType() != MOVETYPE_NOCLIP ) && ( velocity == vec_zero ) && ( animspeed < 5 ) ) + { + // pretend that we can really move + client->ps.speed = 200; + + standing = qtrue; + + Vector oldvel( velocity ); + + SetMoveInfo( &pm, ucmd ); + Pmove( &pm ); + GetMoveInfo( &pm ); + + client->ps.speed = animspeed; + + // save off origin + velocity = oldvel; + VectorCopy( velocity, client->ps.velocity ); + } + else + { + standing = qfalse; + + SetMoveInfo( &pm, ucmd ); + Pmove( &pm ); + GetMoveInfo( &pm ); + } + + ProcessPmoveEvents( pm.pmoveEvent ); + + // if we're not moving, set the blocked flag in case the user is trying to move + if ( ( ucmd->forwardmove || ucmd->rightmove ) && ( ( oldpos - origin ).length() < 0.01f ) ) + { + moveresult = MOVERESULT_BLOCKED; + } + if ( standing && client->ps.walking && !client->ps.feetfalling ) + { + setOrigin( oldpos ); + VectorCopy( origin, client->ps.origin ); + } + } + else + { + //FIXME + // should collect objects to touch against + memset( &pm, 0, sizeof( pmove_t ) ); + + // keep the command time up to date or else the next PMove we run will try to catch up + client->ps.commandTime = ucmd->serverTime; + + velocity = vec_zero; + } + + if ( movecontrol == MOVECONTROL_WALLHUG ) + { + trace_t trace; + + Vector end( origin - yaw_forward * 18.0f ); + + trace = G_Trace( origin, mins, maxs, end, this, MASK_DEADSOLID, true, "ClientMove" ); + if ( !trace.allsolid && ( trace.fraction < 1.0f ) ) + { + v_angle.y = Vector( trace.plane.normal ).toYaw(); + angles.y = v_angle.y; + setAngles( angles ); + setOrigin( ( yaw_forward * 0.1f ) + trace.endpos ); + } + } + + if ( ( getMoveType() == MOVETYPE_NOCLIP ) || !( client->ps.pm_flags & PMF_NO_PREDICTION ) ) + { + total_delta = vec_zero; + } + else + { + if ( ( movecontrol == MOVECONTROL_ABSOLUTE ) || ( movecontrol == MOVECONTROL_HANGING ) || + ( movecontrol == MOVECONTROL_WALLHUG ) || ( movecontrol == MOVECONTROL_STEPUP ) || ( movecontrol == MOVECONTROL_CLIMBWALL ) ) + { + velocity = vec_zero; + } + + if ( total_delta != vec_zero ) + { + MatrixTransformVector( total_delta, orientation, move ); + if ( ( movecontrol == MOVECONTROL_PUSH ) && atobject && atobject->isSubclassOf( PushObject ) ) + { + ( ( PushObject * )( Entity * )atobject )->Push( this, move ); + // move the player right up to the object + StartPush(); + } + else + { + CheckMove( move, &origin ); + setOrigin( origin ); + CheckGround(); + } + } + } + + total_delta = vec_zero; + + TouchStuff( &pm ); + + if ( ( whereami->integer ) && ( origin != oldorigin ) ) + { + gi.DPrintf( "x %8.2f y%8.2f z %8.2f area %2d\n", origin[ 0 ], origin[ 1 ], origin[ 2 ], edict->areanum ); + } + } + +/* +============== +ClientThink + +This will be called once for each client frame, which will +usually be a couple times for each server frame. +============== +*/ +void Player::ClientThink + ( + Event *ev + ) + + { + // sanity check the command time to prevent speedup cheating + if ( current_ucmd->serverTime > level.inttime ) + { + // + // we don't want any future commands, these could be from the previous game + // + return; + } + + if ( current_ucmd->serverTime < level.inttime - 1000 ) + { + current_ucmd->serverTime = level.inttime - 1000; + } + + if ( ( current_ucmd->serverTime - client->ps.commandTime ) < 1 ) + { + return; + } + + last_ucmd = *current_ucmd; + new_buttons = current_ucmd->buttons & ~buttons; + buttons = current_ucmd->buttons; + + if ( level.intermissiontime ) + { + client->ps.pm_flags |= PMF_FROZEN; + + // can exit intermission after five seconds + if ( level.time > level.intermissiontime ) + { + if ( deathmatch->integer ) + { + if ( new_buttons & BUTTON_ANY ) + { + level.exitintermission = true; + } + } + else + { + level.exitintermission = true; + } + } + + // Save cmd angles so that we can get delta angle movements next frame + client->cmd_angles[ 0 ] = SHORT2ANGLE( current_ucmd->angles[ 0 ] ); + client->cmd_angles[ 1 ] = SHORT2ANGLE( current_ucmd->angles[ 1 ] ); + client->cmd_angles[ 2 ] = SHORT2ANGLE( current_ucmd->angles[ 2 ] ); + + return; + } + + moveresult = MOVERESULT_NONE; + + if ( !vehicle || !vehicle->Drive( current_ucmd ) ) + { + ClientMove( current_ucmd ); + } + + // only evaluate the state when not noclipping + if ( getMoveType() == MOVETYPE_NOCLIP ) + { + // force the stand animation if were in noclip + SetAnim( "idle", all ); + } + else + { + // set flags for state machine + CheckMoveFlags(); + EvaluateState(); + + if ( groundentity && groundentity->entity && groundentity->entity->isSubclassOf( Actor ) ) + { + Event *event = new Event( EV_Actor_Push ); + event->AddVector( Vector( 0, 0, -10 ) ); + groundentity->entity->PostEvent( event, 0 ); + } + } + + oldvelocity = velocity; + old_v_angle = v_angle; + + // clear out rope_touch flag after evalutating the state + rope_touch = NULL; + + // If we're dying, check for respawn + if ( ( deadflag == DEAD_DEAD && ( level.time > respawn_time ) ) ) + { + // wait for any button just going down + if ( new_buttons || ( DM_FLAG( DF_FORCE_RESPAWN ) ) ) + { + G_PlayerDied( 1 ); + } + } + + // Save cmd angles so that we can get delta angle movements next frame + client->cmd_angles[ 0 ] = SHORT2ANGLE( current_ucmd->angles[ 0 ] ); + client->cmd_angles[ 1 ] = SHORT2ANGLE( current_ucmd->angles[ 1 ] ); + client->cmd_angles[ 2 ] = SHORT2ANGLE( current_ucmd->angles[ 2 ] ); + + if ( g_logstats->integer ) + { + if ( !logfile_started ) + { + ProcessEvent( EV_Player_LogStats ); + logfile_started = qtrue; + } + } + } + +void Player::LoadStateTable + ( + void + ) + + { + statemap_Legs = NULL; + statemap_Torso = NULL; + + legs_conditionals.FreeObjectList(); + torso_conditionals.FreeObjectList(); + + statemap_Legs = GetStatemap( str( g_statefile->string ) + "_Legs.st", ( Condition * )Conditions, &legs_conditionals, true ); + statemap_Torso = GetStatemap( str( g_statefile->string ) + "_Torso.st", ( Condition * )Conditions, &torso_conditionals, true ); + + animdone_Legs = false; + animdone_Torso = false; + + movecontrol = MOVECONTROL_USER; + + currentState_Legs = statemap_Legs->FindState( "STAND" ); + currentState_Torso = statemap_Torso->FindState( "STAND" ); + + str legsAnim( currentState_Legs->getLegAnim( *this, &legs_conditionals ) ); + if ( legsAnim == "" ) + { + partAnim[ legs ] = ""; + ClearLegsAnim(); + } + else if ( legsAnim != "none" ) + { + SetAnim( legsAnim, legs ); + } + + str torsoAnim( currentState_Torso->getTorsoAnim( *this, &torso_conditionals ) ); + if ( torsoAnim == "" ) + { + partAnim[ torso ] = ""; + ClearTorsoAnim(); + } + else if ( torsoAnim != "none" ) + { + SetAnim( torsoAnim.c_str(), torso ); + } + + movecontrol = currentState_Legs->getMoveType(); + if ( ( movecontrol < ( sizeof( MoveStartFuncs ) / sizeof( MoveStartFuncs[ 0 ] ) ) ) && ( MoveStartFuncs[ movecontrol ] ) ) + { + ( this->*MoveStartFuncs[ movecontrol ] )(); + } + + SetViewAngles( v_angle ); + } + +void Player::ResetState + ( + Event *ev + ) + + { + if ( rope_grabbed ) + { + rope_grabbed->Release( this ); + } + + movecontrol = MOVECONTROL_USER; + LoadStateTable(); + } + +void Player::StartHang + ( + void + ) + + { + Vector hand; + trace_t trace; + float ang; + float ledgeheight; + + if ( ( ledgeheight_right <= MIN_Z ) || ( ledgeheight_left <= MIN_Z ) ) + { + return; + } + + ledgeheight = max( ledgeheight_left, ledgeheight_right ); + + hand = righthand_pos - origin; + if ( ledgeheight > origin.z ) + { + origin.z = ledgeheight - hand.z - 1.0f; + } + + Vector start( origin.x, origin.y, hand.z - 2.0f + origin.z ); + Vector end( start + yaw_forward * 24.0f ); + + start -= yaw_forward * 8.0f; + + trace = G_Trace( start, min_box_8x8, max_box_8x8, end, this, MASK_DEADSOLID, true, "StartHang" ); + if ( trace.fraction == 1.0f ) + { + return; + } + + ang = vectoyaw( trace.plane.normal ) - 180; + + end = origin + yaw_forward * 8.0f; + start = origin - yaw_forward * 1.0f; + trace = G_Trace( start, mins, maxs, end, this, MASK_DEADSOLID, true, "StartHang" ); + if ( trace.fraction == 1.0f ) + { + return; + } + + v_angle.y = ang; + SetViewAngles( v_angle ); + angles.y = ang; + setAngles( angles ); + setOrigin( trace.endpos - yaw_forward * 0.4f ); + } + +void Player::StartPickup + ( + void + ) + + { + Vector start; + Vector end; + trace_t trace; + Actor *act; + Vector dir; + Vector new_angles; + + if ( WeaponsOut() ) + { + if ( !pickup_enemy ) + { + // put away our weapons + SafeHolster( qtrue ); + pickup_enemy = true; + } + return; + } + + pickup_enemy = false; + + start = origin + Vector( 0, 0, 32 ); + end = start + yaw_forward * 64.0f; + trace = G_Trace( start, vec_zero, vec_zero, end, this, MASK_PLAYERSOLID, true, "StartPickup" ); + + if ( trace.ent && trace.ent->entity && ( trace.ent->entity != world ) && trace.ent->entity->isSubclassOf( Actor ) ) + { + act = (Actor *)trace.ent->entity; + + if ( act->name == "Shgliek" ) + { + // Make sure are turned towards Shgliek + dir = act->centroid - centroid; + new_angles = dir.toAngles(); + + angles[YAW] = new_angles[YAW]; + + setAngles( angles ); + SetViewAngles( angles ); + } + } + } + +void Player::StartPush + ( + void + ) + + { + trace_t trace; + Vector end( origin + yaw_forward * 64.0f ); + + trace = G_Trace( origin, mins, maxs, end, this, MASK_SOLID, true, "StartPush" ); + if ( trace.fraction == 1.0f ) + { + return; + } + v_angle.y = vectoyaw( trace.plane.normal ) - 180; + SetViewAngles( v_angle ); + + setOrigin( trace.endpos - yaw_forward * 0.4f ); + } + +void Player::StartClimbWall + ( + void + ) + + { + trace_t trace; + Vector end( origin + yaw_forward * 20.0f ); + + trace = G_Trace( origin, mins, maxs, end, this, MASK_SOLID, true, "StartClimbWall" ); + if ( ( trace.fraction == 1.0f ) || !( trace.surfaceFlags & SURF_LADDER ) ) + { + return; + } + + v_angle.y = vectoyaw( trace.plane.normal ) - 180; + SetViewAngles( v_angle ); + + setOrigin( trace.endpos - yaw_forward * 0.4f ); + } + +void Player::StartUseAnim + ( + void + ) + + { + UseAnim *ua; + Vector neworg; + Vector newangles; + str newanim; + str state; + str camera; + trace_t trace; + + if ( toucheduseanim ) + { + ua = ( UseAnim * )( Entity * )toucheduseanim; + } + else if ( atobject ) + { + ua = ( UseAnim * )( Entity * )atobject; + } + else + { + return; + } + + useitem_in_use = ua; + toucheduseanim = NULL; + atobject = NULL; + + if ( ua->GetInformation( this, &neworg, &newangles, &newanim, &useanim_numloops, &state, &camera ) ) + { + trace = G_Trace( origin, mins, maxs, neworg, this, MASK_PLAYERSOLID, true, "StartUseAnim" ); + if ( trace.startsolid || ( trace.fraction < 1.0f ) ) + { + gi.DPrintf( "Move to UseAnim was blocked.\n" ); + } + + if ( !trace.startsolid ) + { + setOrigin( trace.endpos ); + } + + setAngles( newangles ); + v_angle.y = newangles.y; + SetViewAngles( v_angle ); + + movecontrol = MOVECONTROL_ABSOLUTE; + + if ( state.length() ) + { + State * newState; + + newState = statemap_Torso->FindState( state ); + if ( newState ) + { + EvaluateState( newState ); + } + else + { + gi.DPrintf( "Could not find state %s on UseAnim\n", state.c_str() ); + } + } + else + { + if ( currentState_Torso ) + { + if ( camera.length() ) + { + currentState_Torso->setCameraType( camera ); + } + else + { + currentState_Torso->setCameraType( "behind" ); + } + } + SetAnim( newanim, legs ); + } + } + } + +void Player::StartLoopUseAnim + ( + void + ) + + { + useanim_numloops--; + } + +void Player::FinishUseAnim + ( + Event *ev + ) + + { + UseAnim *ua; + + if ( !useitem_in_use ) + return; + + ua = ( UseAnim * )( Entity * )useitem_in_use; + ua->TriggerTargets( this ); + useitem_in_use = NULL; + } + +void Player::SetupUseObject + ( + void + ) + + { + UseObject *uo; + Vector neworg; + Vector newangles; + str state; + trace_t trace; + + if ( atobject ) + { + uo = ( UseObject * )( Entity * )atobject; + } + else + { + return; + } + + useitem_in_use = uo; + + uo->Setup( this, &neworg, &newangles, &state ); + { + trace = G_Trace( neworg, mins, maxs, neworg, this, MASK_PLAYERSOLID, true, "SetupUseObject - 1" ); + if ( trace.startsolid || trace.allsolid ) + { + trace = G_Trace( origin, mins, maxs, neworg, this, MASK_PLAYERSOLID, true, "SetupUseObject - 2" ); + if ( trace.startsolid || ( trace.fraction < 1.0f ) ) + { + gi.DPrintf( "Move to UseObject was blocked.\n" ); + } + } + + if ( !trace.startsolid ) + { + setOrigin( trace.endpos ); + } + + setAngles( newangles ); + v_angle.y = newangles.y; + SetViewAngles( v_angle ); + + movecontrol = MOVECONTROL_ABSOLUTE; + + if ( state.length() ) + { + State * newState; + + newState = statemap_Torso->FindState( state ); + if ( newState ) + { + EvaluateState( newState ); + } + else + { + gi.DPrintf( "Could not find state %s on UseObject\n", state.c_str() ); + } + } + } + } + +void Player::StartUseObject + ( + Event *ev + ) + + { + UseObject *uo; + + if ( !useitem_in_use ) + return; + + uo = ( UseObject * )( Entity * )useitem_in_use; + uo->Start(); + } + +void Player::FinishUseObject + ( + Event *ev + ) + + { + UseObject *uo; + + if ( !useitem_in_use ) + return; + + uo = ( UseObject * )( Entity * )useitem_in_use; + uo->Stop( this ); + useitem_in_use = NULL; + } + +void Player::PickupShgliek + ( + Event *ev + ) + + { + Vector start; + Vector end; + trace_t trace; + Actor *act; + int tag_num; + + start = origin + Vector( 0, 0, 32 ); + end = start + yaw_forward * 64.0f; + trace = G_Trace( start, mins, maxs, end, this, MASK_PLAYERSOLID, true, "PickupShgliek" ); + + if ( trace.ent && trace.ent->entity && ( trace.ent->entity != world ) && trace.ent->entity->isSubclassOf( Actor ) ) + { + act = (Actor *)trace.ent->entity; + + if ( act->name == "Shgliek" ) + { + // Pickup the Shgliek + + tag_num = gi.Tag_NumForName( edict->s.modelindex, "TAG_WEAPON_RIGHT" ); + act->setAngles( Vector( 0, 0, 0 ) ); + act->attach( entnum, tag_num ); + act->SetAnim( "neckhold" ); + act->StartMode( ACTOR_MODE_AI ); + have_shgliek = true; + } + } + } + +void Player::ThrowShgliek + ( + Event *ev + ) + + { + int i; + int num; + Entity *child; + Actor *act; + int tag_num; + Vector pos; + Vector forward; + Vector shgliek_angles; + Vector torso_angles; + trace_t trace; + + + have_shgliek = false; + + for ( i=0,num = numchildren; i < MAX_MODEL_CHILDREN; i++ ) + { + if ( children[i] == ENTITYNUM_NONE ) + { + continue; + } + + child = ( Entity * )G_GetEntity( children[i] ); + + if ( child->isSubclassOf( Actor ) ) + { + act = (Actor *)child; + + if ( ( act->name == "Shgliek" ) || ( act->name == "Partially Evil Shgliek" ) || ( act->name == "Evil Shgliek" ) ) + { + // Make sure it is not in a solid right now + + trace = G_Trace( act->origin, act->mins, act->maxs, act->origin, this, MASK_MONSTERSOLID, false, "throwshgliek" ); + + if ( !trace.startsolid && !trace.allsolid ) + { + act->detach(); + + // Make it so the shgliek will not get stuck on the player when thrown + + act->setSolidType( SOLID_BBOX ); + + // Make the Shgliek face the same way as the player + + torso_angles = GetTorsoAngles(); + + torso_angles[PITCH] = 0; + torso_angles[ROLL] = 0; + + act->setAngles( torso_angles ); + + // Throw the shgliek a little ways + + act->groundentity = NULL; + + tag_num = gi.Tag_NumForName( edict->s.modelindex, "TAG_WEAPON_RIGHT" ); + GetTag( tag_num, &pos, &forward ); + + shgliek_angles = forward.toAngles(); + + shgliek_angles[YAW] = torso_angles[YAW]; + + shgliek_angles.AngleVectors( &forward ); + + act->velocity = forward * 500; + } + else + { + have_shgliek = true; + } + } + } + + num--; + + if ( !num ) + break; + } + } + +void Player::StartPipeCrawl + ( + void + ) + + { + trace_t trace; + float ang; + float dist; + Vector pos; + float horizang; + + if ( !horizontalpipe ) + { + return; + } + + // + // make sure the correct pm_flags get set for the CheckGround call + // + if ( movecontrol == MOVECONTROL_PIPECRAWL ) + { + client->ps.pm_flags |= PMF_NO_PREDICTION | PMF_LEGS_LIFTED; + } + + // + // this ensures that our boudning boxes are correct + // + CheckGround(); + + Vector end( origin.x, origin.y, righthand_pos.z + 1 - maxs.z ); + + trace = G_Trace( origin, mins, maxs, end, this, MASK_DEADSOLID, true, "StartPipeCrawl" ); + setOrigin( trace.endpos ); + + horizang = ( ( HorizontalPipe * )( Entity * )horizontalpipe )->dir; + ang = AngleSubtract( v_angle.y, horizang ); + if ( Q_fabs( ang ) > 90.0f ) + { + v_angle.y = horizang + 180.0f; + } + else + { + v_angle.y = horizang; + } + + SetViewAngles( v_angle ); + + pos = origin - horizontalpipe->centroid; + dist = pos * yaw_left; + + setOrigin( origin - yaw_left * dist ); + } + +void Player::StartMonkeyBars + ( + void + ) + + { + trace_t trace; + Vector oldang( v_angle ); + + if ( monkeybar_right <= MIN_Z ) + { + return; + } + + Vector end( origin.x, origin.y, monkeybar_right - ( righthand_pos.z - origin.z ) ); + + trace = G_Trace( origin, mins, maxs, end, this, MASK_DEADSOLID, true, "StartMonkeyBars" ); + setOrigin( trace.endpos ); + + //v_angle[ YAW ] = monkeybar_dir; + v_angle[ YAW ] = ( int )( anglemod( v_angle[ YAW ] + 45.0f ) / 90.0f ) * 90.0f; + SetViewAngles( v_angle ); + + if ( !CheckMove( vec_zero ) ) + { + SetViewAngles( oldang ); + } + } + +void Player::StartStepUp + ( + void + ) + + { + Vector delta; + Vector end( origin + yaw_forward * 24.0f ); + trace_t trace; + + gi.Anim_Delta( edict->s.modelindex, edict->s.anim & ANIM_MASK, delta ); + animheight = delta.z + origin.z; + + trace = G_Trace( origin, mins, maxs, end, this, MASK_DEADSOLID, true, "StartStepUp" ); + + v_angle.y = vectoyaw( trace.plane.normal ) - 180; + SetViewAngles( v_angle ); + setOrigin( trace.endpos ); + } + +void Player::StepUp + ( + Event *ev + ) + + { + float ledgeheight; + trace_t trace; + + ledgeheight = max( ledgeheight_left, ledgeheight_right ); + if ( ledgeheight > animheight ) + { + Vector end( origin ); + + end.z += ledgeheight - animheight; + trace = G_Trace( origin, mins, maxs, end, this, MASK_DEADSOLID, true, "StartStepUp" ); + setOrigin( trace.endpos ); + } + } + +void Player::Turn + ( + Event *ev + ) + + { + float yaw; + Vector oldang( v_angle ); + + yaw = ev->GetFloat( 1 ); + + v_angle[ YAW ] = ( int )( anglemod( v_angle[ YAW ] ) / 22.5f ) * 22.5f; + SetViewAngles( v_angle ); + + if ( !CheckMove( vec_zero ) ) + { + SetViewAngles( oldang ); + return; + } + + CancelEventsOfType( EV_Player_TurnUpdate ); + + ev = new Event( EV_Player_TurnUpdate ); + ev->AddFloat( yaw / 5.0f ); + ev->AddFloat( 0.5f ); + ProcessEvent( ev ); + } + +void Player::TurnUpdate + ( + Event *ev + ) + + { + float yaw; + float timeleft; + Vector oldang( v_angle ); + + yaw = ev->GetFloat( 1 ); + timeleft = ev->GetFloat( 2 ); + timeleft -= 0.1f; + + if ( timeleft > 0 ) + { + ev = new Event( EV_Player_TurnUpdate ); + ev->AddFloat( yaw ); + ev->AddFloat( timeleft ); + PostEvent( ev, 0.1f ); + + v_angle[ YAW ] += yaw; + SetViewAngles( v_angle ); + } + else + { + v_angle[ YAW ] = ( int )( anglemod( v_angle[ YAW ] ) / 22.5f ) * 22.5f; + SetViewAngles( v_angle ); + } + + if ( !CheckMove( vec_zero ) ) + { + SetViewAngles( oldang ); + } + } + +void Player::TurnLegs + ( + Event *ev + ) + + { + float yaw; + + yaw = ev->GetFloat( 1 ); + + angles[ YAW ] += yaw; + setAngles( angles ); + } + +void Player::RopeRelease + ( + void + ) + + { + if ( rope_grabbed ) + { + rope_grabbed->Release( this ); + } + + movecontrol = MOVECONTROL_USER; + } + +void Player::RopeGrab + ( + void + ) + + { + if ( rope_touch && !rope_grabbed ) + { + // pass in origin offset + rope_touch->Grab( this, 28 + maxs.z - mins.z ); + } + + rope_touch = NULL; + movecontrol = MOVECONTROL_USER; + } + + +void Player::EvaluateState + ( + State *forceTorso, + State *forceLegs + ) + + { + int count; + State *laststate_Legs; + State *laststate_Torso; + State *startstate_Legs; + State *startstate_Torso; + movecontrol_t move; + + if ( getMoveType() == MOVETYPE_NOCLIP ) + { + return; + } + + // Evaluate the current state. + // When the state changes, we reevaluate the state so that if the + // conditions aren't met in the new state, we don't play one frame of + // the animation for that state before going to the next state. + startstate_Torso = laststate_Torso = currentState_Torso; + count = 0; + do + { + // since we could get into an infinite loop here, do a check + // to make sure we don't. + count++; + if ( count > 10 ) + { + gi.DPrintf( "Possible infinite loop in state '%s'\n", currentState_Torso->getName() ); + assert( 0 ); + if ( count > 20 ) + { + gi.Error( ERR_DROP, "Stopping due to possible infinite state loop\n" ); + break; + } + } + + laststate_Torso = currentState_Torso; + + if ( forceTorso ) + currentState_Torso = forceTorso; + else + currentState_Torso = currentState_Torso->Evaluate( *this, &torso_conditionals ); + + animdone_Torso = false; + if ( movecontrol != MOVECONTROL_LEGS ) + { + animdone_Legs = false; + } + if ( laststate_Torso != currentState_Torso ) + { + // Process exit commands of the last state + laststate_Torso->ProcessExitCommands( this ); + + // Process entry commands of the new state + currentState_Torso->ProcessEntryCommands( this ); + + if ( waitForState.length() && ( !waitForState.icmpn( currentState_Torso->getName(), waitForState.length() ) ) ) + { + waitForState = ""; + PlayerDone( NULL ); + } + + move = currentState_Torso->getMoveType(); + + str legsAnim( currentState_Torso->getLegAnim( *this, &torso_conditionals ) ); + str torsoAnim( currentState_Torso->getTorsoAnim( *this, &torso_conditionals ) ); + + if ( legsAnim != "" ) + { + animdone_Legs = false; + SetAnim( legsAnim, legs ); + } + else if ( move == MOVECONTROL_LEGS ) + { + if ( !currentState_Legs ) + { + animdone_Legs = false; + currentState_Legs = statemap_Legs->FindState( "STAND" ); + + legsAnim = currentState_Legs->getLegAnim( *this, &legs_conditionals ); + if ( legsAnim == "" ) + { + partAnim[ legs ] = ""; + ClearLegsAnim(); + } + else if ( legsAnim != "none" ) + { + SetAnim( legsAnim, legs ); + } + } + } + else + { + partAnim[ legs ] = ""; + ClearLegsAnim(); + } + + if ( torsoAnim == "" ) + { + partAnim[ torso ] = ""; + ClearTorsoAnim(); + } + else if ( torsoAnim != "none" ) + { + SetAnim( torsoAnim.c_str(), torso ); + } + + if ( movecontrol != move ) + { + movecontrol = move; + if ( ( move < ( sizeof( MoveStartFuncs ) / sizeof( MoveStartFuncs[ 0 ] ) ) ) && ( MoveStartFuncs[ move ] ) ) + { + ( this->*MoveStartFuncs[ move ] )(); + } + } + + SetViewAngles( v_angle ); + } + } + while( laststate_Torso != currentState_Torso ); + + // Evaluate the current state. + // When the state changes, we reevaluate the state so that if the + // conditions aren't met in the new state, we don't play one frame of + // the animation for that state before going to the next state. + startstate_Legs = laststate_Legs = currentState_Legs; + if ( movecontrol == MOVECONTROL_LEGS ) + { + count = 0; + do + { + // since we could get into an infinite loop here, do a check + // to make sure we don't. + count++; + if ( count > 10 ) + { + gi.DPrintf( "Possible infinite loop in state '%s'\n", currentState_Legs->getName() ); + assert( 0 ); + if ( count > 20 ) + { + gi.Error( ERR_DROP, "Stopping due to possible infinite state loop\n" ); + break; + } + } + + if ( !currentState_Legs ) + { + currentState_Legs = statemap_Legs->FindState( "STAND" ); + } + + laststate_Legs = currentState_Legs; + + if ( forceLegs ) + currentState_Legs = forceLegs; + else + currentState_Legs = currentState_Legs->Evaluate( *this, &legs_conditionals ); + + animdone_Legs = false; + if ( laststate_Legs != currentState_Legs ) + { + // Process exit commands of the last state + laststate_Legs->ProcessExitCommands( this ); + + // Process entry commands of the new state + currentState_Legs->ProcessEntryCommands( this ); + + if ( waitForState.length() && ( !waitForState.icmpn( currentState_Legs->getName(), waitForState.length() ) ) ) + { + waitForState = ""; + PlayerDone( NULL ); + } + + str legsAnim( currentState_Legs->getLegAnim( *this, &legs_conditionals ) ); + if ( legsAnim == "" ) + { + partAnim[ legs ] = ""; + ClearLegsAnim(); + } + else if ( legsAnim != "none" ) + { + SetAnim( legsAnim, legs ); + } + } + } + while( laststate_Legs != currentState_Legs ); + } + else + { + currentState_Legs = NULL; + } + + if ( g_showplayeranim->integer ) + { + if ( last_leg_anim_name != AnimName( legs ) ) + { + gi.DPrintf( "Legs change from %s to %s\n", last_leg_anim_name.c_str(), AnimName( legs ) ); + last_leg_anim_name = AnimName( legs ); + } + + if ( last_torso_anim_name != AnimName( torso ) ) + { + gi.DPrintf( "Torso change from %s to %s\n", last_torso_anim_name.c_str(), AnimName( torso ) ); + last_torso_anim_name = AnimName( torso ); + } + } + + if ( g_showplayerstate->integer ) + { + if ( startstate_Legs != currentState_Legs ) + { + gi.DPrintf( "Legs change from %s to %s\n", + startstate_Legs ? startstate_Legs->getName() : "NULL", + currentState_Legs ? currentState_Legs->getName() : "NULL" ); + } + + if ( startstate_Torso != currentState_Torso ) + { + gi.DPrintf( "Torso change from %s to %s\n", + startstate_Torso ? startstate_Torso->getName() : "NULL", + currentState_Torso ? currentState_Torso->getName() : "NULL" ); + } + } + + // This is so we don't remember pain when we change to a state that has a PAIN condition + pain = 0; + // Every second drop accumulated pain by 1 + if ( ( float )( int )( level.time ) == level.time ) + { + accumulated_pain -= 1; + if ( accumulated_pain < 0 ) + accumulated_pain = 0; + } + } + +void Player::EventUseItem + ( + Event *ev + ) + + { + const char *name; + weaponhand_t hand = WEAPON_RIGHT; + + if ( deadflag ) + { + return; + } + + name = ev->GetString( 1 ); + + Item *item = ( Item * )FindItem( name ); + + if ( item && item->isSubclassOf( InventoryItem ) ) + { + InventoryItem *ii = ( InventoryItem * )item; + Event *ev1; + + ev1 = new Event( EV_InventoryItem_Use ); + ev1->AddEntity( this ); + ii->ProcessEvent( ev1 ); + } + else if ( ev->NumArgs() > 1 ) + { + hand = WeaponHandNameToNum( ev->GetString( 2 ) ); + useWeapon( name, hand ); + } + } + +void Player::GiveWeaponCheat + ( + Event *ev + ) + + { + giveItem( ev->GetString( 1 ) ); + } + +void Player::GiveCheat + ( + Event *ev + ) + + { + str name; + + if ( deadflag ) + { + return; + } + + name = ev->GetString( 1 ); + + if ( !name.icmp( "all" ) ) + { + GiveAllCheat( ev ); + return; + } + EventGiveItem( ev ); + } + +void Player::GiveAllCheat + ( + Event *ev + ) + + { + char *buffer; + char *buf; + char com_token[MAX_STRING_CHARS]; + + if ( deadflag ) + { + return; + } + + if ( gi.FS_ReadFile( "global/giveall.scr", ( void ** )&buf, qtrue ) != -1 ) + { + buffer = buf; + while ( 1 ) + { + strcpy( com_token, COM_ParseExt( &buffer, qtrue ) ); + + if (!com_token[0]) + break; + + // Create the event + ev = new Event( com_token ); + + // get the rest of the line + while( 1 ) + { + strcpy( com_token, COM_ParseExt( &buffer, qfalse ) ); + if (!com_token[0]) + break; + + ev->AddToken( com_token ); + } + + this->ProcessEvent( ev ); + } + gi.FS_FreeFile( buf ); + } + } + +void Player::GodCheat + ( + Event *ev + ) + + { + const char *msg; + + if ( ev->NumArgs() > 0 ) + { + if ( ev->GetInteger( 1 ) ) + { + flags |= FL_GODMODE; + } + else + { + flags &= ~FL_GODMODE; + } + } + else + { + flags ^= FL_GODMODE; + } + + if ( ev->GetSource() == EV_FROM_CONSOLE ) + { + if ( !( flags & FL_GODMODE ) ) + { + msg = "godmode OFF\n"; + } + else + { + msg = "godmode ON\n"; + } + + gi.SendServerCommand( edict-g_entities, "print \"%s\"", msg ); + } + } + +void Player::Kill + ( + Event *ev + ) + + { + if ( ( level.time - respawn_time ) < 5 ) + { + return; + } + + flags &= ~FL_GODMODE; + health = 1; + Damage( this, this, 10, origin, vec_zero, vec_zero, 0, DAMAGE_NO_PROTECTION, MOD_SUICIDE ); + } + +void Player::NoTargetCheat + ( + Event *ev + ) + + { + const char *msg; + + flags ^= FL_NOTARGET; + if ( !( flags & FL_NOTARGET ) ) + { + msg = "notarget OFF\n"; + } + else + { + msg = "notarget ON\n"; + } + + gi.SendServerCommand( edict-g_entities, "print \"%s\"", msg ); + } + +void Player::NoclipCheat + ( + Event *ev + ) + + { + const char *msg; + + if ( vehicle ) + { + msg = "Must exit vehicle first\n"; + } + else if ( getMoveType() == MOVETYPE_NOCLIP ) + { + setMoveType( MOVETYPE_WALK ); + msg = "noclip OFF\n"; + + // reset the state machine so that her animations are correct + ResetState( NULL ); + } + else + { + if ( rope_grabbed ) + { + rope_grabbed->Release( this ); + } + + client->ps.feetfalling = false; + movecontrol = MOVECONTROL_USER; + + setMoveType( MOVETYPE_NOCLIP ); + msg = "noclip ON\n"; + } + + gi.SendServerCommand( edict-g_entities, "print \"%s\"", msg ); + } + +void Player::GameVersion + ( + Event *ev + ) + + { + gi.SendServerCommand( edict-g_entities, "print \"%s : %s\n\"", GAMEVERSION, __DATE__ ); + } + +void Player::SetFov + ( + float newFov + ) + + { + fov = newFov; + + if ( ( fov < 90 ) && DM_FLAG( DF_FIXED_FOV ) ) + { + fov = 90; + return; + } + + if ( fov < 1 ) + { + fov = 90; + } + else if ( fov > 160 ) + { + fov = 160; + } + } + +void Player::Fov + ( + Event *ev + ) + + { + if ( ev->NumArgs() < 1 ) + { + gi.SendServerCommand( edict-g_entities, "print \"Fov = %d\n\"", fov ); + return; + } + + SetFov( ev->GetFloat( 1 ) ); + } + +/* +=============== +CalcRoll + +=============== +*/ +float Player::CalcRoll + ( + void + ) + + { + float sign; + float side; + float value; + Vector l; + + angles.AngleVectors( NULL, &l, NULL ); + side = velocity * l; + sign = side < 0 ? 4 : -4; + side = fabs( side ); + + value = sv_rollangle->value; + + if ( side < sv_rollspeed->value ) + { + side = side * value / sv_rollspeed->value; + } + else + { + side = value; + } + + return side * sign; + } + +void Player::GravityNodes + ( + void + ) + + { + Vector grav; + Vector gravnorm; + Vector velnorm; + float dot; + qboolean force; + float max_speed; + Vector new_velocity; + + // + // Check for gravity pulling points + // + + // no pull during waterjumps + if ( client->ps.pm_flags & PMF_TIME_WATERJUMP ) + { + return; + } + + grav = gravPathManager.CalculateGravityPull( *this, origin, &force, &max_speed ); + + // Check for unfightable gravity. + if ( force && grav != vec_zero ) + { + velnorm = velocity; + velnorm.normalize(); + + gravnorm = grav; + gravnorm.normalize(); + + dot = gravnorm.x * velnorm.x + gravnorm.y * velnorm.y + gravnorm.z * velnorm.z; + + // This prevents the player from trying to swim upstream + if ( dot < 0 ) + { + float tempdot; + Vector tempvec; + + tempdot = 0.2f - dot; + tempvec = velocity * tempdot; + velocity = velocity - tempvec; + } + } + + if ( grav != vec_zero ) + { + new_velocity = velocity + grav; + + if ( new_velocity.length() < velocity.length() ) + { + // Is slowing down, defintely need to apply grav + velocity = new_velocity; + } + else if ( velocity.length() < max_speed ) + { + // Applay grav + + velocity = new_velocity; + + // Make sure we aren't making the player go too fast + + if ( velocity.length() > max_speed ) + { + velocity.normalize(); + velocity *= max_speed; + } + } + else + { + // Going too fast but still want to pull the player up if any z velocity in grav + + grav.x = 0; + grav.y = 0; + + velocity = velocity + grav; + } + } + } + +// +// PMove Events +// +void Player::ProcessPmoveEvents + ( + int event + ) + + { + float damage; + + switch( event ) + { + case EV_NONE: + break; + case EV_FALL_SHORT: + break; + case EV_FALL_MEDIUM: + case EV_FALL_FAR: + case EV_FALL_FATAL: + if ( event == EV_FALL_FATAL ) + { + damage = 1000; + } + else if ( event == EV_FALL_FAR ) + { + damage = 20; + } + else + { + damage = 5; + } + if ( !DM_FLAG( DF_NO_FALLING ) ) + { + Damage( world, world, ( int )damage, origin, vec_zero, vec_zero, 0, DAMAGE_NO_ARMOR, MOD_FALLING ); + } + break; + case EV_TERMINAL_VELOCITY: + Sound( "snd_fall", CHAN_VOICE ); + break; + + case EV_WATER_TOUCH: // foot touches + if ( watertype & CONTENTS_LAVA ) + { + Sound( "snd_burn", CHAN_LOCAL ); + } + else + { + Animate *water; + trace_t trace; + Vector start; + float scale; + + Sound( "impact_playersplash", CHAN_AUTO ); + + // Find the correct place to put the splash + + start = origin + Vector(0, 0, 90); + trace = G_Trace( start, vec_zero, vec_zero, origin, NULL, MASK_WATER, false, "ProcessPmoveEvents" ); + + // Figure out a good scale for the splash + + scale = 1 + ( velocity[2] + 400 ) / -1500; + + if ( scale < 1 ) + scale = 1; + else if ( scale > 1.5 ) + scale = 1.5; + + // Spawn in a water splash + + water = new Animate; + + water->setOrigin( trace.endpos ); + water->setModel( "fx_splashsmall.tik" ); + water->setScale( scale ); + water->RandomAnimate( "idle" ); + water->PostEvent( EV_Remove, 5 ); + + } + break; + case EV_WATER_LEAVE: // foot leaves + Sound( "impact_playerleavewater", CHAN_AUTO ); + break; + case EV_WATER_UNDER: // head touches + Sound( "impact_playersubmerge", CHAN_AUTO ); + break; + case EV_WATER_CLEAR: // head leaves + Sound( "snd_gasp", CHAN_LOCAL ); + break; + } + } + +/* +============= +WorldEffects +============= +*/ +void Player::WorldEffects + ( + void + ) + + { + if ( deadflag == DEAD_DEAD ) + { + // if we are dead, no world effects + return; + } + + if ( movetype == MOVETYPE_NOCLIP ) + { + // don't need air + air_finished = level.time + 20; + return; + } + + // + // Check for earthquakes + // + if ( groundentity && ( level.earthquake > level.time ) ) + { +// velocity[ 0 ] += G_CRandom( EARTHQUAKE_STRENGTH * level.earthquake_magnitude ); +// velocity[ 1 ] += G_CRandom( EARTHQUAKE_STRENGTH * level.earthquake_magnitude ); +// velocity[ 2 ] += G_Random( EARTHQUAKE_STRENGTH * 1.5f * level.earthquake_magnitude ); + } + // + // check for on fire + // + if ( on_fire ) + { + if ( next_painsound_time < level.time ) + { + next_painsound_time = level.time + 4; + Sound( "snd_onfire", CHAN_LOCAL ); + } + } + + // + // check for lava + // + if ( watertype & CONTENTS_LAVA ) + { + if ( next_drown_time < level.time ) + { + next_drown_time = level.time + 0.2f; + Damage( world, world, 10 * waterlevel, origin, vec_zero, vec_zero, 0, DAMAGE_NO_ARMOR, MOD_LAVA ); + } + if ( next_painsound_time < level.time ) + { + next_painsound_time = level.time + 3; + Sound( "snd_burned", CHAN_LOCAL ); + } + } + + // + // check for slime + // + if ( watertype & CONTENTS_SLIME ) + { + if ( next_drown_time < level.time ) + { + next_drown_time = level.time + 0.4f; + Damage( world, world, 7 * waterlevel, origin, vec_zero, vec_zero, 0, DAMAGE_NO_ARMOR, MOD_SLIME ); + } + if ( next_painsound_time < level.time ) + { + next_painsound_time = level.time + 5; + Sound( "snd_burned", CHAN_LOCAL ); + } + } + + // + // check for drowning + // + if ( waterlevel == 3 ) + { + // if out of air, start drowning + if ( ( air_finished < level.time ) && !( flags & FL_GODMODE ) ) + { + // drown! + if ( next_drown_time < level.time && health > 0 ) + { + next_drown_time = level.time + 1; + + // take more damage the longer underwater + drown_damage += 2; + if ( drown_damage > 15 ) + { + drown_damage = 15; + } + + // play a gurp sound instead of a normal pain sound + if ( health <= drown_damage ) + { + Sound( "snd_drown", CHAN_LOCAL ); + BroadcastSound(); + } + else if ( rand() & 1 ) + { + Sound( "snd_choke", CHAN_LOCAL ); + BroadcastSound(); + } + else + { + Sound( "snd_choke", CHAN_LOCAL ); + BroadcastSound(); + } + + Damage( world, world, drown_damage, origin, vec_zero, vec_zero, 0, DAMAGE_NO_ARMOR, MOD_DROWN ); + } + } + } + else + { + air_finished = level.time + 20; + drown_damage = 2; + } + + // If on a rope, increase gravity on the player +// if ( rope_grabbed ) +// { +// velocity.z += -1250 * level.frametime; +// } + + GravityNodes(); + + old_waterlevel = waterlevel; + } + +/* +============= +AddBlend +============= +*/ +void Player::AddBlend + ( + float r, + float g, + float b, + float a + ) + + { + float a2; + float a3; + + if ( a <= 0 ) + { + return; + } + + // new total alpha + a2 = blend[ 3 ] + ( 1 - blend[ 3 ] ) * a; + + // fraction of color from old + a3 = blend[ 3 ] / a2; + + blend[ 0 ] = blend[ 0 ] * a3 + r * ( 1 - a3 ); + blend[ 1 ] = blend[ 1 ] * a3 + g * ( 1 - a3 ); + blend[ 2 ] = blend[ 2 ] * a3 + b * ( 1 - a3 ); + blend[ 3 ] = a2; + } + +/* +============= +CalcBlend +============= +*/ +void Player::CalcBlend + ( + void + ) + + { + int contents; + Vector vieworg; + + client->ps.stats[STAT_ADDFADE] =0; + blend[ 0 ] = blend[ 1 ] = blend[ 2 ] = blend[ 3 ] = 0; + + // add for contents + vieworg = origin; + vieworg[ 2 ] += viewheight; + + contents = gi.pointcontents( vieworg, 0 ); + + if ( contents & CONTENTS_SOLID ) + { + // Outside of world + //AddBlend( 0.8, 0.5, 0.0, 0.2 ); + } + else if ( contents & CONTENTS_LAVA ) + { + AddBlend( level.lava_color[0], level.lava_color[1], level.lava_color[2], level.lava_alpha ); + } + else if ( contents & CONTENTS_WATER ) + { + AddBlend( level.water_color[0], level.water_color[1], level.water_color[2], level.water_alpha ); + } + + // add for damage + if ( damage_alpha > 0 ) + { + AddBlend( damage_blend[ 0 ], damage_blend[ 1 ], damage_blend[ 2 ], damage_alpha ); + + // drop the damage value + damage_alpha -= 0.06; + if ( damage_alpha < 0 ) + { + damage_alpha = 0; + } + client->ps.blend[0] = blend[0]; + client->ps.blend[1] = blend[1]; + client->ps.blend[2] = blend[2]; + client->ps.blend[3] = blend[3]; + } + + // Do the cinematic fading + float alpha=1; + + level.m_fade_time -= level.frametime; + + // Return if we are completely faded in + if ( ( level.m_fade_time <= 0 ) && ( level.m_fade_type == fadein ) ) + { + client->ps.blend[3] = 0 + damage_alpha; + return; + } + + // If we are faded out, and another fade out is coming in, then don't bother + if ( ( level.m_fade_time_start > 0 ) && ( level.m_fade_type == fadeout ) ) + { + if ( client->ps.blend[3] >= 1 ) + return; + } + + if ( level.m_fade_time_start > 0 ) + alpha = level.m_fade_time / level.m_fade_time_start; + + if ( level.m_fade_type == fadeout ) + alpha = 1.0f - alpha; + + if ( alpha < 0 ) + alpha = 0; + + if ( alpha > 1 ) + alpha = 1; + + if ( level.m_fade_style == additive ) + { + client->ps.blend[0] = level.m_fade_color[0] * level.m_fade_alpha * alpha; + client->ps.blend[1] = level.m_fade_color[1] * level.m_fade_alpha * alpha; + client->ps.blend[2] = level.m_fade_color[2] * level.m_fade_alpha * alpha; + client->ps.blend[3] = level.m_fade_alpha * alpha; + client->ps.stats[STAT_ADDFADE] = 1; + } + else + { + client->ps.blend[0] = level.m_fade_color[0]; + client->ps.blend[1] = level.m_fade_color[1]; + client->ps.blend[2] = level.m_fade_color[2]; + client->ps.blend[3] = level.m_fade_alpha * alpha; + client->ps.stats[STAT_ADDFADE] = 0; + } + } + +/* +=============== +P_DamageFeedback + +Handles color blends and view kicks +=============== +*/ + +void Player::DamageFeedback + ( + void + ) + + { + float realcount; + float count; + + // if we are dead, don't setup any feedback + if ( health <= 0 ) + { + damage_count = 0; + damage_blood = 0; + damage_alpha = 0; + VectorClear( damage_angles ); + return; + } + +#define DAMAGE_MAX_PITCH_SCALE 0.3f +#define DAMAGE_MAX_YAW_SCALE 0.3f + + if ( damage_blood > damage_count ) + { + float pitch_delta; + float yaw_delta; + + damage_angles = damage_from.toAngles(); + pitch_delta = AngleDelta( angles.x, damage_angles.x ) / 90.0f; + yaw_delta = AngleDelta( angles.y, damage_angles.y ) / 90.0f; + + if ( pitch_delta > DAMAGE_MAX_PITCH_SCALE ) + pitch_delta = DAMAGE_MAX_PITCH_SCALE; + else if ( pitch_delta < -DAMAGE_MAX_PITCH_SCALE ) + pitch_delta = -DAMAGE_MAX_PITCH_SCALE; + + if ( yaw_delta > DAMAGE_MAX_YAW_SCALE ) + yaw_delta = DAMAGE_MAX_YAW_SCALE; + else if ( yaw_delta < -DAMAGE_MAX_YAW_SCALE ) + yaw_delta = -DAMAGE_MAX_YAW_SCALE; + + damage_angles[ PITCH ] = pitch_delta; + damage_angles[ ROLL ] = yaw_delta; + damage_count = damage_blood * 2.0f; + } + + if ( damage_count ) + { + // decay damage_count over time + damage_count *= 0.90f; + if ( damage_count < 0.1f ) + damage_count = 0; + + } + + // total points of damage shot at the player this frame + if ( !damage_blood ) + { + // didn't take any damage + return; + } + + count = damage_blood; + realcount = count; + if ( count < 10 ) + { + // always make a visible effect + count = 10; + } + + // the total alpha of the blend is always proportional to count + if ( damage_alpha < 0 ) + { + damage_alpha = 0; + } + + damage_alpha += count * 0.001; + if ( damage_alpha < 0.2 ) + { + damage_alpha = 0.2; + } + if ( damage_alpha > 0.6 ) + { + // don't go too saturated + damage_alpha = 0.6; + } + + // the color of the blend will vary based on how much was absorbed + // by different armors + damage_blend = vec_zero; + if ( damage_blood ) + { + damage_blend += ( damage_blood / realcount ) * bcolor; + } + + // + // clear totals + // + damage_blood = 0; + } + +void Player::GetPlayerView + ( + Vector *pos, + Vector *angle + ) + + { + if ( pos ) + { + *pos = origin; + pos->z += viewheight; + } + + if ( angle ) + { + *angle = Vector( client->ps.viewangles ); + } + } + +void Player::SetPlayerView + ( + Camera *camera, + Vector position, + float cameraoffset, + Vector ang, + Vector vel, + float camerablend[ 4 ], + float camerafov + ) + + { + client->ps.viewangles[ 0 ] = ang[ 0 ]; + client->ps.viewangles[ 1 ] = ang[ 1 ]; + client->ps.viewangles[ 2 ] = ang[ 2 ]; + + client->ps.viewheight = cameraoffset; + + client->ps.origin[ 0 ] = position[ 0 ]; + client->ps.origin[ 1 ] = position[ 1 ]; + client->ps.origin[ 2 ] = position[ 2 ]; + + client->ps.velocity[ 0 ] = vel[ 0 ]; + client->ps.velocity[ 1 ] = vel[ 1 ]; + client->ps.velocity[ 2 ] = vel[ 2 ]; + + /* + client->ps.blend[ 0 ] = camerablend[ 0 ]; + client->ps.blend[ 1 ] = camerablend[ 1 ]; + client->ps.blend[ 2 ] = camerablend[ 2 ]; + client->ps.blend[ 3 ] = camerablend[ 3 ]; + */ + + client->ps.fov = camerafov; + + if ( camera ) + { + client->ps.camera_angles[ 0 ] = camera->angles[ 0 ]; + client->ps.camera_angles[ 1 ] = camera->angles[ 1 ]; + client->ps.camera_angles[ 2 ] = camera->angles[ 2 ]; + + client->ps.camera_origin[ 0 ] = camera->origin[ 0 ]; + client->ps.camera_origin[ 1 ] = camera->origin[ 1 ]; + client->ps.camera_origin[ 2 ] = camera->origin[ 2 ]; + client->ps.pm_flags |= PMF_CAMERA_VIEW; + + // + // clear out the flags, but preserve the CF_CAMERA_CUT_BIT + // + client->ps.camera_flags = client->ps.camera_flags & CF_CAMERA_CUT_BIT; + } + else + { + client->ps.pm_flags &= ~PMF_CAMERA_VIEW; + // + // make sure the third person camera is setup correctly. + // + + if ( getMoveType() != MOVETYPE_NOCLIP ) + { + qboolean do_cut; + int camera_type; + + camera_type = currentState_Torso->getCameraType(); + if ( last_camera_type != camera_type ) + { + // + // clear out the flags, but preserve the CF_CAMERA_CUT_BIT + // + client->ps.camera_flags = client->ps.camera_flags & CF_CAMERA_CUT_BIT; + do_cut = qtrue; + switch( camera_type ) + { + case CAMERA_TOPDOWN: + client->ps.camera_flags |= CF_CAMERA_ANGLES_IGNORE_PITCH; + client->ps.camera_offset[ PITCH ] = -75; + client->ps.camera_flags |= CF_CAMERA_ANGLES_ALLOWOFFSET; + do_cut = qfalse; + break; + case CAMERA_FRONT: + client->ps.camera_flags |= CF_CAMERA_ANGLES_IGNORE_PITCH; + client->ps.camera_flags |= CF_CAMERA_ANGLES_ALLOWOFFSET; + client->ps.camera_offset[ YAW ] = 180; + client->ps.camera_offset[ PITCH ] = 0; + break; + case CAMERA_SIDE: + client->ps.camera_flags |= CF_CAMERA_ANGLES_IGNORE_PITCH; + client->ps.camera_flags |= CF_CAMERA_ANGLES_ALLOWOFFSET; + // randomly invert the YAW + if ( G_Random( 1 ) > 0.5f ) + { + client->ps.camera_offset[ YAW ] = -90; + } + else + { + client->ps.camera_offset[ YAW ] = 90; + } + client->ps.camera_offset[ PITCH ] = 0; + break; + case CAMERA_SIDE_LEFT: + client->ps.camera_flags |= CF_CAMERA_ANGLES_IGNORE_PITCH; + client->ps.camera_flags |= CF_CAMERA_ANGLES_ALLOWOFFSET; + client->ps.camera_offset[ YAW ] = 90; + client->ps.camera_offset[ PITCH ] = 0; + break; + case CAMERA_SIDE_RIGHT: + client->ps.camera_flags |= CF_CAMERA_ANGLES_IGNORE_PITCH; + client->ps.camera_flags |= CF_CAMERA_ANGLES_ALLOWOFFSET; + client->ps.camera_offset[ YAW ] = -90; + client->ps.camera_offset[ PITCH ] = 0; + break; + case CAMERA_BEHIND_FIXED: + do_cut = qfalse; + client->ps.camera_offset[ YAW ] = 0; + client->ps.camera_offset[ PITCH ] = 0; + client->ps.camera_flags |= CF_CAMERA_ANGLES_ALLOWOFFSET; + break; + case CAMERA_BEHIND_NOPITCH: + do_cut = qfalse; + client->ps.camera_flags |= CF_CAMERA_ANGLES_IGNORE_PITCH; + client->ps.camera_offset[ YAW ] = 0; + client->ps.camera_offset[ PITCH ] = 0; + break; + case CAMERA_BEHIND: + do_cut = qfalse; + client->ps.camera_offset[ YAW ] = 0; + client->ps.camera_offset[ PITCH ] = 0; + break; + default: + do_cut = qfalse; + client->ps.camera_offset[ YAW ] = 0; + client->ps.camera_offset[ PITCH ] = 0; + break; + } + last_camera_type = camera_type; + if ( do_cut ) + CameraCut(); + } + } + + // + // these are explicitly not cleared so that when the client lerps it still has the last + // camera position for reference. Additionally this causes no extra hits to the network + // traffic. + // + //VectorClear( client->ps.camera_angles ); + //VectorClear( client->ps.camera_origin ); + } + +#define EARTHQUAKE_SCREENSHAKE_PITCH 2 +#define EARTHQUAKE_SCREENSHAKE_YAW 2 +#define EARTHQUAKE_SCREENSHAKE_ROLL 3 + + if ( level.earthquake > level.time ) + { + client->ps.damage_angles[ PITCH ] = G_CRandom() * level.earthquake_magnitude * EARTHQUAKE_SCREENSHAKE_PITCH; + client->ps.damage_angles[ YAW ] = G_CRandom() * level.earthquake_magnitude * EARTHQUAKE_SCREENSHAKE_YAW; + client->ps.damage_angles[ ROLL ] = G_CRandom() * level.earthquake_magnitude * EARTHQUAKE_SCREENSHAKE_ROLL; + } + else if ( damage_count ) + { + client->ps.damage_angles[ PITCH ] = damage_angles[ PITCH ] * damage_count; + client->ps.damage_angles[ ROLL ] = damage_angles[ ROLL ] * damage_count; + } + else + { + VectorClear( client->ps.damage_angles ); + } + } + +void Player::SetupView + ( + void + ) + + { + // if we currently are not in a camera or the camera we are looking through is automatic, evaluate our camera choices + + if ( actor_to_watch || actor_camera ) + { + Vector dir; + Vector watch_angles; + float dist = 0; + Vector focal_point; + Vector left; + trace_t trace; + qboolean delete_actor_camera = false; + Vector camera_mins; + Vector camera_maxs; + + if ( actor_to_watch ) + { + dir = actor_to_watch->origin - origin; + dist = dir.length(); + } + + // See if we still want to watch this actor + + if ( !actor_to_watch || dist > 150 || actor_to_watch->deadflag ) + { + delete_actor_camera = true; + } + else + { + // Create the camera if we don't have one yet + + if ( !actor_camera ) + { + actor_camera = new Camera(); + + if ( G_Random() < .5 ) + { + actor_camera_right = true; + starting_actor_camera_right = true; + } + else + { + actor_camera_right = false; + starting_actor_camera_right = false; + } + } + + // Setup the new position of the actor camera + + // Go a little above the view height + + actor_camera->origin = origin; + actor_camera->origin[2] += DEFAULT_VIEWHEIGHT + 10; + + // Find the focal point ( either the actor's watch offset or top of the bounding box) + + if ( actor_to_watch->watch_offset != vec_zero ) + { + MatrixTransformVector( actor_to_watch->watch_offset, actor_to_watch->orientation, focal_point ); + focal_point += actor_to_watch->origin; + } + else + { + focal_point = actor_to_watch->origin; + focal_point[2] = actor_to_watch->maxs[2]; + } + + // Shift the camera back just a little + + dir = focal_point - actor_camera->origin; + dir.normalize(); + actor_camera->origin -= dir * 15; + + // Shift the camera a little to the left or right + + watch_angles = dir.toAngles(); + watch_angles.AngleVectors( NULL, &left ); + + if ( actor_camera_right ) + actor_camera->origin -= left * 15; + else + actor_camera->origin += left * 15; + + // Make sure this camera position is ok + + camera_mins = "-5 -5 -5"; + camera_maxs = "5 5 5"; + + trace = G_Trace( actor_camera->origin, camera_mins, camera_maxs, actor_camera->origin, actor_camera, MASK_DEADSOLID, false, "SetupView" ); + + if ( trace.startsolid ) + { + // Try other side + + if ( actor_camera_right == starting_actor_camera_right ) + { + if ( actor_camera_right ) + actor_camera->origin += left * 30; + else + actor_camera->origin -= left * 30; + + actor_camera_right = !actor_camera_right; + + trace = G_Trace( actor_camera->origin, camera_mins, camera_maxs, actor_camera->origin, actor_camera, MASK_DEADSOLID, false, "SetupView2" ); + + if ( trace.startsolid ) + { + // Both spots have failed stop doing actor camera + delete_actor_camera = true; + } + } + else + { + // Both spots have failed stop doing actor camera + delete_actor_camera = true; + } + } + + if ( !delete_actor_camera ) + { + // Set the camera's position + + actor_camera->setOrigin( actor_camera->origin ); + + // Set the camera's angles + + dir = focal_point - actor_camera->origin; + watch_angles = dir.toAngles(); + actor_camera->setAngles( watch_angles ); + + // Set this as our camera + + SetCamera( actor_camera, .5 ); + } + } + + if ( delete_actor_camera ) + { + // Get rid of this camera + + actor_to_watch = NULL; + + if ( actor_camera ) + { + delete actor_camera; + actor_camera = NULL; + SetCamera( NULL, .5 ); + } + } + } + else if ( ( level.automatic_cameras.NumObjects() > 0 ) && ( !camera || camera->IsAutomatic() ) ) + { + int i; + float score, bestScore; + Camera *cam, *bestCamera; + + bestScore = 999; + bestCamera = NULL; + for( i = 1; i <= level.automatic_cameras.NumObjects(); i++ ) + { + cam = level.automatic_cameras.ObjectAt( i ); + score = cam->CalculateScore( this, currentState_Torso->getName() ); + // if this is our current camera, scale down the score a bit to favor it. + if ( cam == camera ) + { + score *= 0.9f; + } + + if ( score < bestScore ) + { + bestScore = score; + bestCamera = cam; + } + } + if ( bestScore <= 1.0f ) + { + // we have a camera to switch to + if ( bestCamera != camera ) + { + float time; + + if ( camera ) + { + camera->AutomaticStop( this ); + } + time = bestCamera->AutomaticStart( this ); + SetCamera( bestCamera, time ); + } + } + else + { + // we don't have a camera to switch to + if ( camera ) + { + float time; + + time = camera->AutomaticStop( this ); + SetCamera( NULL, time ); + } + } + } + // If there is no camera, use the player's view + if ( !camera ) + { + SetPlayerView( NULL, origin, viewheight, v_angle, velocity, blend, fov ); + } + else + { + SetPlayerView( camera, origin, viewheight, v_angle, velocity, blend, camera->Fov() ); + } + } + +/* +================== +SwingAngles +================== +*/ +void Player::SwingAngles + ( + float destination, + float swingTolerance, + float clampTolerance, + float speed, + float *angle, + qboolean *swinging + ) + + { + float swing; + float move; + float scale; + + if ( !*swinging ) + { + // see if a swing should be started + swing = AngleSubtract( *angle, destination ); + if ( swing > swingTolerance || swing < -swingTolerance ) + { + *swinging = qtrue; + // we intentionally return so that we can start the animation before turning + return; + } + } + + if ( !*swinging ) + { + return; + } + + // modify the speed depending on the delta + // so it doesn't seem so linear + swing = AngleSubtract( destination, *angle ); + scale = fabs( swing ); + +#if 0 + if ( scale < swingTolerance * 0.5 ) + { + scale = 0.5; + } + else if ( scale < swingTolerance ) + { + scale = 1.0; + } + else + { + scale = 2.0; + } +#else + scale = 1.0f; +#endif + + // swing towards the destination angle + if ( swing >= 0 ) + { + move = level.frametime * scale * speed; + if ( move >= swing ) + { + move = swing; + *swinging = qfalse; + } + + *angle = AngleMod( *angle + move ); + } + else if ( swing < 0 ) + { + move = level.frametime * scale * -speed; + if ( move <= swing ) + { + move = swing; + *swinging = qfalse; + } + *angle = AngleMod( *angle + move ); + } + + // clamp to no more than tolerance + swing = AngleSubtract( destination, *angle ); + if ( swing > clampTolerance ) + { + *angle = AngleMod( destination - ( clampTolerance - 1 ) ); + } + else if ( swing < -clampTolerance ) + { + *angle = AngleMod( destination + ( clampTolerance - 1 ) ); + } + } + +void Player::SetHeadTarget + ( + Event *ev + ) + + { + str ht = ev->GetString( 1 ); + + head_target = G_FindTarget( 0, ht ); + } + +qboolean Player::GetTagPositionAndOrientation + ( + int tagnum, + orientation_t *new_or + ) + + { + int i; + orientation_t tag_or; + vec3_t axis[3]; + + tag_or = gi.Tag_OrientationEx( edict->s.modelindex, + CurrentAnim( legs ), + CurrentFrame( legs ), + tagnum & TAG_MASK, + edict->s.scale, + edict->s.bone_tag, + edict->s.bone_quat, + 0, + 0, + 1.0f, + ( edict->s.anim & ANIM_BLEND ) != 0, + ( edict->s.torso_anim & ANIM_BLEND ) != 0, + CurrentAnim( torso ), + CurrentFrame( torso ), + 0, + 0, + 1.0f + ); + + AnglesToAxis( angles, axis ); + VectorCopy( origin, new_or->origin ); + + for ( i=0; i<3; i++ ) + VectorMA( new_or->origin, tag_or.origin[i], axis[i], new_or->origin ); + + MatrixMultiply( tag_or.axis, axis, new_or->axis ); + return true; + } + +qboolean Player::GetTagPositionAndOrientation + ( + str tagname, + orientation_t *new_or + ) + + { + int tagnum; + + tagnum = gi.Tag_NumForName( edict->s.modelindex, tagname ); + + if ( tagnum < 0 ) + { + warning( "Player::GetTagPositionAndOrientation", "Could not find tag \"%s\"", tagname.c_str() ); + return false; + } + + return GetTagPositionAndOrientation( tagnum, new_or ); + } + +Vector Player::GetAngleToTarget + ( + Entity *ent, + str tag, + float yawclamp, + float pitchclamp, + Vector baseangles + ) + + { + assert( ent ); + + if ( ent ) + { + Vector delta,angs; + orientation_t tag_or; + + int tagnum = gi.Tag_NumForName( edict->s.modelindex, tag.c_str() ); + + if ( tagnum < 0 ) + return Vector( 0,0,0 ); + + GetTagPositionAndOrientation( tagnum, &tag_or ); + + delta = ent->centroid - tag_or.origin; + delta.normalize(); + + angs = delta.toAngles(); + + AnglesSubtract( angs, baseangles, angs ); + + angs[PITCH] = AngleNormalize180( angs[PITCH] ); + angs[YAW] = AngleNormalize180( angs[YAW] ); + + if ( angs[PITCH] > pitchclamp ) + angs[PITCH] = pitchclamp; + else if ( angs[PITCH] < -pitchclamp ) + angs[PITCH] = -pitchclamp; + + if ( angs[YAW] > yawclamp ) + angs[YAW] = yawclamp; + else if ( angs[YAW] < -yawclamp ) + angs[YAW] = -yawclamp; + + return angs; + } + else + { + return Vector( 0,0,0 ); + } + } + +void Player::DebugWeaponTags + ( + int controller_tag, + Weapon *weapon, + str weapon_tagname + ) + + { + int i; + orientation_t bone_or, tag_weapon_or, barrel_or, final_barrel_or; + + GetTagPositionAndOrientation( edict->s.bone_tag[controller_tag], &bone_or ); + //G_DrawCoordSystem( Vector( bone_or.origin ), Vector( bone_or.axis[0] ), Vector( bone_or.axis[1] ), Vector( bone_or.axis[2] ), 20 ); + + GetTagPositionAndOrientation( gi.Tag_NumForName( edict->s.modelindex, weapon_tagname ), &tag_weapon_or ); + //G_DrawCoordSystem( Vector( tag_weapon_or.origin ), Vector( tag_weapon_or.axis[0] ), Vector( tag_weapon_or.axis[1] ), Vector( tag_weapon_or.axis[2] ), 40 ); + + weapon->GetRawTag( "tag_barrel", &barrel_or ); + VectorCopy( tag_weapon_or.origin, final_barrel_or.origin ); + + for ( i = 0 ; i < 3 ; i++ ) + VectorMA( final_barrel_or.origin, barrel_or.origin[i], tag_weapon_or.axis[i], final_barrel_or.origin ); + + MatrixMultiply( barrel_or.axis, tag_weapon_or.axis, final_barrel_or.axis ); + //G_DrawCoordSystem( Vector( final_barrel_or.origin ), Vector( final_barrel_or.axis[0] ), Vector( final_barrel_or.axis[1] ), Vector( final_barrel_or.axis[2] ), 80 ); + + if ( g_crosshair->integer ) + { + trace_t trace; + Vector start,end,ang,dir,delta; + vec3_t mat[3]; + + AnglesToAxis( v_angle, mat ); + + dir = mat[0]; + start = final_barrel_or.origin; + end = start + ( dir * MAX_MAP_BOUNDS ); + + G_DrawCoordSystem( start, Vector( mat[0] ), Vector( mat[1] ), Vector( mat[2] ), 80 ); + + trace = G_Trace( start, vec_zero, vec_zero, end, this, MASK_PROJECTILE|MASK_WATER, qfalse, "Crosshair" ); + crosshair->setOrigin( trace.endpos ); + + delta = trace.endpos - start; + float length = delta.length(); + float scale = g_crosshair_maxscale->value * length / MAX_MAP_BOUNDS; + + if ( scale < 1 ) + scale = 1; + + crosshair->setScale( scale ); + + if ( trace.ent ) + { + vectoangles( trace.plane.normal, ang ); + } + else + { + vectoangles( dir, ang ); + } + + crosshair->setAngles( ang ); + } + } + +Vector Player::CalcArmTracking + ( + int controller_tag, + str weapon_tagname, + Vector baseAngles, + Entity *target, + Weapon *weapon + ) + + { + Vector forward, delta, angs; + orientation_t bone_or, tag_weapon_or, barrel_or, final_barrel_or; + int i; + + assert( target ); + + if ( !target ) + { + warning( "Player::CalcArmTracking", "NULL target for Arm Tracking." ); + return Vector( 0,0,0 ); + } + + GetTagPositionAndOrientation( edict->s.bone_tag[controller_tag], &bone_or ); + + if ( g_showautoaim->integer ) + G_DebugLine( bone_or.origin, bone_or.origin + Vector( bone_or.axis[0] ) * 200, 1,1,1,1 ); + + GetTagPositionAndOrientation( gi.Tag_NumForName( edict->s.modelindex, weapon_tagname ), &tag_weapon_or ); + + if ( g_showautoaim->integer ) + G_DebugLine( tag_weapon_or.origin, tag_weapon_or.origin + Vector( tag_weapon_or.axis[0] ) * 50, 1,0,0,1 ); + + if ( !weapon->GetRawTag( "tag_barrel", &barrel_or ) ) + { + warning( "Player::CalcArmTracking", "Could not find tag_barrel." ); + return Vector( 0,0,0 ); + } + + VectorCopy( tag_weapon_or.origin, final_barrel_or.origin ); + + for ( i = 0 ; i < 3 ; i++ ) + VectorMA( final_barrel_or.origin, barrel_or.origin[i], tag_weapon_or.axis[i], final_barrel_or.origin ); + + MatrixMultiply( barrel_or.axis, tag_weapon_or.axis, final_barrel_or.axis ); + + delta = target->centroid - final_barrel_or.origin; + delta.normalize(); + + angs = delta.toAngles(); + AnglesSubtract( angs, torsoAngles, angs ); + + if ( g_showautoaim->integer ) + G_DebugLine( final_barrel_or.origin, final_barrel_or.origin + Vector( final_barrel_or.axis[0] ) * 50, 0,0,1,1 ); + if ( g_showautoaim->integer ) + G_DebugLine( final_barrel_or.origin, target->centroid, 0,1,0,1 ); + + return angs; + } + + +void Player::AcquireTarget + ( + void + ) + + { + Weapon *weapon; + Vector offset; + vec3_t mat[3]; + Entity *new_target; + + AnglesToAxis( headAngles, mat ); + + if ( left_arm_target ) + { + left_arm_target->edict->s.eFlags &= ~EF_LEFT_TARGETED; + } + + if ( right_arm_target ) + { + right_arm_target->edict->s.eFlags &= ~EF_RIGHT_TARGETED; + } + + // Find a left hand target if the left hand weapon is an auto aim + weapon = GetActiveWeapon( WEAPON_LEFT ); + + if ( weapon && weapon->autoaim ) + { + offset = Vector( mat[1] ) * 25; + + if ( left_arm_target ) + { + new_target = FindEnemyInFOVFromTagWithOffset( 60, weapon->GetMaxRange(), L_ARM_NAME, offset ); + } + else + { + new_target = FindEnemyInFOVFromTagWithOffset( 40, weapon->GetMaxRange(), L_ARM_NAME, offset ); + } + + if ( new_target ) + { + left_arm_target = new_target; + left_arm_target->edict->s.eFlags |= EF_LEFT_TARGETED; + CancelEventsOfType( EV_Player_ClearLeftArmTarget ); + } + else + PostEvent( EV_Player_ClearLeftArmTarget, 1.0f ); + } + else + { + PostEvent( EV_Player_ClearLeftArmTarget, 1.0f ); + } + + // Find a right hand target ( might be the same one ) + weapon = GetActiveWeapon( WEAPON_RIGHT ); + + if ( weapon && weapon->autoaim ) + { + offset = Vector( mat[1] ) * -25; + + if ( right_arm_target ) + { + new_target = FindEnemyInFOVFromTagWithOffset( 60, weapon->GetMaxRange(), R_ARM_NAME, offset ); + } + else + { + new_target = FindEnemyInFOVFromTagWithOffset( 40, weapon->GetMaxRange(), R_ARM_NAME, offset ); + } + + if ( new_target ) + { + right_arm_target = new_target; + right_arm_target->edict->s.eFlags |= EF_RIGHT_TARGETED; + CancelEventsOfType( EV_Player_ClearRightArmTarget ); + } + else + { + PostEvent( EV_Player_ClearRightArmTarget, 1.0f ); + } + } + else + { + PostEvent( EV_Player_ClearRightArmTarget, 1.0f ); + } + } + +void Player::RemoveTarget + ( + Entity *ent_to_remove + ) + + { + if ( left_arm_target == ent_to_remove ) + { + left_arm_target->edict->s.eFlags &= ~EF_LEFT_TARGETED; + left_arm_target = NULL; + } + + if ( right_arm_target == ent_to_remove) + { + right_arm_target->edict->s.eFlags &= ~EF_RIGHT_TARGETED; + right_arm_target = NULL; + } + } + +void Player::AutoAim + ( + void + ) + + { + Weapon *weapon; + Vector newAimAngles; + + + if ( deadflag ) + return; + + // Check for targets in the FOV + AcquireTarget(); + + // Update Crosshair + weapon = GetActiveWeapon( WEAPON_DUAL ); + if ( crosshair ) + { + if ( g_crosshair->integer ) + { + if ( weapon && weapon->crosshair && !level.cinematic ) + { + // Update the position of the crosshair based on the attachment of the weapon + if ( weapon->dual_attachToTag == "tag_weapon_right" ) + DebugWeaponTags( R_ARM_TAG, weapon, "tag_weapon_right" ); + else + DebugWeaponTags( L_ARM_TAG, weapon, "tag_weapon_left" ); + + crosshair->showModel(); + } + else + { + crosshair->hideModel(); + } + } + else + { + crosshair->hideModel(); + } + } + + // Check for auto targeting on right side + weapon = GetActiveWeapon( WEAPON_RIGHT ); + + if ( weapon ) + { + DebugWeaponTags( R_ARM_TAG, weapon, "tag_weapon_right" ); + weapon->SetAimTarget( NULL ); + } + + if ( weapon && weapon->autoaim && right_arm_target ) + { + weapon->SetAimTarget( right_arm_target ); + + newAimAngles = CalcArmTracking( R_ARM_TAG, "tag_weapon_right", torsoAngles, right_arm_target, weapon ); + + // Clamp newAimAngles + if ( newAimAngles[YAW] > 30 ) + newAimAngles[YAW] = 30; + if ( newAimAngles[YAW] < -30 ) + newAimAngles[YAW] = -30; + if ( newAimAngles[PITCH] > 30 ) + newAimAngles[PITCH] = 30; + if ( newAimAngles[PITCH] < -30 ) + newAimAngles[PITCH] = -30; + + rightArmAimAngles[PITCH] = LerpAngle( rightArmAimAngles[PITCH], newAimAngles[PITCH], 0.5f ); + rightArmAimAngles[YAW] = LerpAngle( rightArmAimAngles[YAW], newAimAngles[YAW], 0.5f ); + } + else + { + rightArmAimAngles[PITCH] = LerpAngle( rightArmAimAngles[PITCH], 0, 0.5f ); + rightArmAimAngles[YAW] = LerpAngle( rightArmAimAngles[YAW], 0, 0.5f ); + } + + SetControllerAngles( R_ARM_TAG, rightArmAimAngles ); + + // Check for auto targeting on left side + weapon = GetActiveWeapon( WEAPON_LEFT ); + + if ( weapon ) + { + DebugWeaponTags( L_ARM_TAG, weapon, "tag_weapon_left" ); + weapon->SetAimTarget( NULL ); + } + + if ( weapon && weapon->autoaim && left_arm_target ) + { + weapon->SetAimTarget( left_arm_target ); + + newAimAngles = CalcArmTracking( L_ARM_TAG, "tag_weapon_left", torsoAngles, left_arm_target, weapon ); + // Clamp newAimAngles + if ( newAimAngles[YAW] > 30 ) + newAimAngles[YAW] = 30; + if ( newAimAngles[YAW] < -30 ) + newAimAngles[YAW] = -30; + if ( newAimAngles[PITCH] > 30 ) + newAimAngles[PITCH] = 30; + if ( newAimAngles[PITCH] < -30 ) + newAimAngles[PITCH] = -30; + + leftArmAimAngles[PITCH] = LerpAngle( leftArmAimAngles[PITCH], newAimAngles[PITCH], 0.5f ); + leftArmAimAngles[YAW] = LerpAngle( leftArmAimAngles[YAW], newAimAngles[YAW], 0.5f ); + } + else + { + leftArmAimAngles[PITCH] = LerpAngle( leftArmAimAngles[PITCH], 0, 0.5f ); + leftArmAimAngles[YAW] = LerpAngle( leftArmAimAngles[YAW], 0, 0.5f ); + } + + SetControllerAngles( L_ARM_TAG, leftArmAimAngles ); + } + +/* +=============== +PlayerAngles +=============== +*/ +void Player::PlayerAngles + ( + void + ) + + { + float deltayaw; + Vector moveangles; + float speed; + float yawAngle; + float speedscale; + vec3_t temp; + Vector dir; + Vector newAimAngles; + + // Adjust the angles of the player for attacking an enemy + // AdjustAnglesForAttack(); + + if ( gi.Anim_Flags( edict->s.modelindex, CurrentAnim( legs ) ) & MDL_ANIM_DEFAULT_ANGLES ) + { + SetControllerAngles( HEAD_TAG, vec_zero ); + SetControllerAngles( TORSO_TAG, vec_zero ); + setAngles( Vector( 0, v_angle.y, 0 ) ); + AutoAim(); + return; + } + + // set the head and torso directly + headAngles.setXYZ( v_angle.x, AngleMod( v_angle.y ), v_angle.z ); + torsoAngles.setXYZ( v_angle.x, AngleMod( v_angle.y ), v_angle.z ); + + dir = Vector( velocity.x, velocity.y, 0 ); + speed = VectorNormalize( dir ); + + // If moving, angle the legs toward the direction we are moving + if ( ( speed > 32 ) && groundentity && last_ucmd.forwardmove ) + { + speedscale = 3; + yawing = qtrue; // always center + deltayaw = AngleSubtract( dir.toYaw(), headAngles[ YAW ] ); + } + else + { + speedscale = 1; + deltayaw = 0; + } + + // --------- yaw ------------- + // Clamp to g_legclampangle + if ( fabs( deltayaw ) > 90 ) + deltayaw = AngleSubtract( deltayaw, 180 ); + + if ( deltayaw > g_legclampangle->value ) + deltayaw = g_legclampangle->value; + else if ( deltayaw < -g_legclampangle->value ) + deltayaw = -g_legclampangle->value; + + yawAngle = headAngles[ YAW ] + deltayaw; + + yawing_left = qfalse; + yawing_right = qfalse; + + if ( client->ps.walking && client->ps.groundPlane && ( movecontrol == MOVECONTROL_LEGS ) && + !last_ucmd.forwardmove && !last_ucmd.rightmove && ( client->ps.groundTrace.plane.normal[ 2 ] < SLOPE_22_MAX ) ) + { + float groundyaw; + float yawdelta; + + groundyaw = ( int )vectoyaw( client->ps.groundTrace.plane.normal ); + yawdelta = anglemod( v_angle.y - groundyaw ); + yawdelta = ( ( ( int )yawdelta + 45 ) / 90 ) * 90.0f; + angles.y = groundyaw + yawdelta; + } + else + { + // if purely strafing, don't swing the legs + if ( client->ps.walking && last_ucmd.rightmove && !last_ucmd.forwardmove ) + { + setAngles( Vector( 0, v_angle.y, 0 ) ); + } + else + { + SwingAngles( yawAngle, g_legtolerance->value, g_legclamptolerance->value, g_legswingspeed->value * speedscale, &angles[ YAW ], &yawing ); + if ( yawing ) + { + float swing; + swing = AngleSubtract( yawAngle, angles[ YAW ] ); + if ( swing > 0 ) + { + yawing_left = qtrue; + } + else + { + yawing_right = qtrue; + } + } + } + } + + // --------- pitch ------------- + + // only show a fraction of the pitch angle in the torso + if ( headAngles[ PITCH ] > 180 ) + { + torsoAngles[PITCH] = ( -360 + headAngles[ PITCH ] ) * 0.75; + } + else + { + torsoAngles[PITCH] = headAngles[ PITCH ] * 0.75; + } + + AcquireHeadTarget(); + + // Adjust head and torso angles for the target if needed + if ( head_target ) + { + //newAimAngles = GetAngleToTarget( head_target, "Bip01 Head", 60, 45, torsoAngles ); + newAimAngles = GetAngleToTarget( head_target, "Bip01 Head", 40, 30, torsoAngles ); + + headAimAngles[PITCH] = LerpAngle( headAimAngles[PITCH], newAimAngles[PITCH], 0.25f ); + headAimAngles[YAW] = LerpAngle( headAimAngles[YAW], newAimAngles[YAW], 0.25f ); + + torsoAimAngles[PITCH] = LerpAngle( torsoAimAngles[PITCH], 0, 0.5f ); + torsoAimAngles[YAW] = LerpAngle( torsoAimAngles[YAW], 0, 0.5f ); + } + else // Otherwise return to them to 0 + { + headAimAngles[PITCH] = LerpAngle( headAimAngles[PITCH], 0, 0.5f ); + headAimAngles[YAW] = LerpAngle( headAimAngles[YAW], 0, 0.1f ); + + torsoAimAngles[PITCH] = LerpAngle( torsoAimAngles[PITCH], 0, 0.5f ); + torsoAimAngles[YAW] = LerpAngle( torsoAimAngles[YAW], 0, 0.5f ); + } + + // pull the head angles back out of the hierarchial chain + AnglesSubtract( headAngles, torsoAngles, temp ); + + // Add in the aim angles for the head + VectorAdd( temp, headAimAngles, temp ); + + // Update the head controller + SetControllerAngles( HEAD_TAG, temp ); + + // pull the torso angles back out of the hierarchial chain + AnglesSubtract( torsoAngles, angles, temp ); + + // Add in the aim angles for the torso + VectorAdd( temp, torsoAimAngles, temp ); + + // Update the torso controller + SetControllerAngles( TORSO_TAG, temp ); + + // Auto aim for the arms + AutoAim(); + + // Set the rest (legs) + setAngles( angles ); + +// warning( "PlayerAngles", "head %.2f torso %.2f legs %.2f\n", headAngles.y, torsoAngles.y, angles.y ); + } + +void Player::FinishMove + ( + void + ) + + { + // + // If the origin or velocity have changed since ClientThink(), + // update the pmove values. This will happen when the client + // is pushed by a bmodel or kicked by an explosion. + // + // If it wasn't updated here, the view position would lag a frame + // behind the body position when pushed -- "sinking into plats" + // + if ( !( client->ps.pm_flags & PMF_FROZEN ) && !( client->ps.pm_flags & PMF_NO_MOVE )) + { + origin.copyTo( client->ps.origin ); + velocity.copyTo( client->ps.velocity ); + } + + if ( !( client->ps.pm_flags & PMF_FROZEN ) ) + { + PlayerAngles(); + } + + // burn from lava, etc + WorldEffects(); + + // determine the view offsets + DamageFeedback(); + CalcBlend(); + } + +void Player::StatCount + ( + int index, + int count + ) + + { + // If stat is going up + if ( oldstats[index] < count ) + { + oldstats[index] += count * level.frametime * 4; + + // Clamp + if ( oldstats[index] > count ) + { + oldstats[index] = count; + } + + client->ps.stats[index] = oldstats[index]; + } + else + { + client->ps.stats[index] = count; + } + } + +void Player::UpdateStats + ( + void + ) + + { + int i,count; + + // + // Health + // + if ( ( health < 1 ) && ( health > 0 ) ) + { + client->ps.stats[ STAT_HEALTH ] = 1; + } + else + { + client->ps.stats[ STAT_HEALTH ] = health; + } + + // + // if we just got full water or lost it, update our boots + // + if ( water_power >= MINIMUM_WATER_FOR_TURBO && client->ps.stats[STAT_WATER_LEVEL] < MINIMUM_WATER_FOR_TURBO ) + { + SurfaceCommand( "bootlights", "+skin1" ); + } + else if ( water_power < MINIMUM_WATER_FOR_TURBO && client->ps.stats[STAT_WATER_LEVEL] >= MINIMUM_WATER_FOR_TURBO ) + { + SurfaceCommand( "bootlights", "-skin1" ); + } + + client->ps.stats[ STAT_WATER_LEVEL ] = water_power; + //StatCount( STAT_WATER_LEVEL, water_power ); + + /* + if ( oldstats[STAT_WATER_LEVEL] != water_power ) + { + client->ps.stats[STAT_WATER_LEVEL] = 0; + oldstats[STAT_WATER_LEVEL] = water_power; + } + else + { + client->ps.stats[STAT_WATER_LEVEL] = water_power; + } + */ + + Weapon *leftweapon = GetActiveWeapon( WEAPON_LEFT ); + Weapon *rightweapon = GetActiveWeapon( WEAPON_RIGHT ); + Weapon *dualweapon = GetActiveWeapon( WEAPON_DUAL ); + + client->ps.stats[STAT_AMMO_LEFT] = 0; + client->ps.stats[STAT_AMMO_RIGHT] = 0; + client->ps.stats[STAT_CLIPAMMO_LEFT] = 0; + client->ps.stats[STAT_CLIPAMMO_RIGHT] = 0; + client->ps.stats[STAT_MAXAMMO_LEFT] = 0; + client->ps.stats[STAT_MAXAMMO_RIGHT] = 0; + client->ps.stats[STAT_MAXCLIPAMMO_LEFT] = 0; + client->ps.stats[STAT_MAXCLIPAMMO_RIGHT] = 0; + + client->ps.stats[ STAT_ACCUMULATED_PAIN] = accumulated_pain; + + client->ps.activeItems[ ITEM_NAME_AMMO_LEFT ] = -1; + client->ps.activeItems[ ITEM_NAME_AMMO_RIGHT ] = -1; + client->ps.activeItems[ ITEM_NAME_WEAPON_LEFT ] = -1; + client->ps.activeItems[ ITEM_NAME_WEAPON_RIGHT ] = -1; + client->ps.activeItems[ ITEM_NAME_WEAPON_DUAL ] = -1; + + + if ( leftweapon ) + { + client->ps.stats[STAT_AMMO_LEFT] = AmmoCount( leftweapon->GetAmmoType( FIRE_PRIMARY ) ); + client->ps.stats[STAT_MAXAMMO_LEFT] = MaxAmmoCount( leftweapon->GetAmmoType( FIRE_PRIMARY ) ); + client->ps.stats[STAT_CLIPAMMO_LEFT] = leftweapon->ClipAmmo( FIRE_PRIMARY ); + client->ps.stats[STAT_MAXCLIPAMMO_LEFT] = leftweapon->GetClipSize( FIRE_PRIMARY ); + client->ps.activeItems[ITEM_NAME_AMMO_LEFT] = AmmoIndex( leftweapon->GetAmmoType( FIRE_PRIMARY ) ); + client->ps.activeItems[ITEM_NAME_WEAPON_LEFT] = leftweapon->getIndex(); + } + if ( rightweapon ) + { + client->ps.stats[STAT_AMMO_RIGHT] = AmmoCount( rightweapon->GetAmmoType( FIRE_PRIMARY ) ); + client->ps.stats[STAT_MAXAMMO_RIGHT] = MaxAmmoCount( rightweapon->GetAmmoType( FIRE_PRIMARY ) ); + client->ps.stats[STAT_CLIPAMMO_RIGHT] = rightweapon->ClipAmmo( FIRE_PRIMARY ); + client->ps.stats[STAT_MAXCLIPAMMO_RIGHT] = rightweapon->GetClipSize( FIRE_PRIMARY ); + client->ps.activeItems[ITEM_NAME_AMMO_RIGHT] = AmmoIndex( rightweapon->GetAmmoType( FIRE_PRIMARY ) ); + client->ps.activeItems[ITEM_NAME_WEAPON_RIGHT] = rightweapon->getIndex(); + } + if ( dualweapon ) + { + // Left is PRIMARY + client->ps.stats[STAT_AMMO_LEFT] = AmmoCount( dualweapon->GetAmmoType( FIRE_PRIMARY ) ); + client->ps.stats[STAT_MAXAMMO_LEFT] = MaxAmmoCount( dualweapon->GetAmmoType( FIRE_PRIMARY ) ); + client->ps.stats[STAT_CLIPAMMO_LEFT] = dualweapon->ClipAmmo( FIRE_PRIMARY ); + client->ps.activeItems[ITEM_NAME_AMMO_LEFT] = AmmoIndex( dualweapon->GetAmmoType( FIRE_PRIMARY ) ); + // Right is AlTERNATE + client->ps.stats[STAT_AMMO_RIGHT] = AmmoCount( dualweapon->GetAmmoType( FIRE_ALTERNATE ) ); + client->ps.stats[STAT_MAXAMMO_RIGHT] = MaxAmmoCount( dualweapon->GetAmmoType( FIRE_ALTERNATE ) ); + client->ps.stats[STAT_CLIPAMMO_RIGHT] = dualweapon->ClipAmmo( FIRE_ALTERNATE ); + client->ps.activeItems[ITEM_NAME_AMMO_RIGHT] = AmmoIndex( dualweapon->GetAmmoType( FIRE_ALTERNATE ) ); + + client->ps.activeItems[ITEM_NAME_WEAPON_DUAL] = dualweapon->getIndex(); + } + + // + // set boss health + // + client->ps.stats[ STAT_BOSSHEALTH ] = bosshealth->value * 100.0f; + + if ( bosshealth->value * 100.0f > 0 && client->ps.stats[ STAT_BOSSHEALTH ] == 0 ) + client->ps.stats[ STAT_BOSSHEALTH ] = 1; + + // Set cinematic stuff + + client->ps.stats[ STAT_CINEMATIC ] = 0; + + if ( level.cinematic ) + client->ps.stats[ STAT_CINEMATIC ] = (1<<0); + + if ( actor_camera ) + client->ps.stats[ STAT_CINEMATIC ] += (1<<1); + + // Go through all the player's weapons and send over the indexes of the names + memset( client->ps.inventory_name_index, 0, sizeof( client->ps.inventory_name_index ) ); + + count = inventory.NumObjects(); + + assert( count < MAX_INVENTORY ); + if ( count > MAX_INVENTORY ) + { + gi.Error( ERR_DROP, "Player::UpdateStats : Exceeded MAX_ITEMS\n" ); + } + + for ( i=1; i<=count; i++ ) + { + int entnum = inventory.ObjectAt( i ); + Item *item = ( Item * )G_GetEntity( entnum ); + + if ( item ) + client->ps.inventory_name_index[i-1] = item->getIndex(); + } + + // Go through all the player's ammo and send over the names/amounts + memset( client->ps.ammo_amount, 0, sizeof( client->ps.ammo_amount ) ); + + count = ammo_inventory.NumObjects(); + + assert( count < MAX_AMMO ); + if ( count > MAX_AMMO ) + { + gi.Error( ERR_DROP, "Player::UpdateStats : Exceeded MAX_AMMO\n" ); + } + + for ( i=1; i<=count; i++ ) + { + Ammo *ammo = ammo_inventory.ObjectAt( i ); + + if ( ammo ) + { + client->ps.ammo_amount[i-1] = ammo->getAmount(); + client->ps.max_ammo_amount[i-1] = ammo->getMaxAmount(); + client->ps.ammo_name_index[i-1] = ammo->getIndex(); + } + } + + // Do letterbox + + // Check for letterbox fully out + if ( ( level.m_letterbox_time <= 0 ) && ( level.m_letterbox_dir == letterbox_in ) ) + { + client->ps.stats[STAT_LETTERBOX] = level.m_letterbox_fraction * MAX_LETTERBOX_SIZE; + return; + } + else if ( ( level.m_letterbox_time <= 0 ) && ( level.m_letterbox_dir == letterbox_out ) ) + { + client->ps.stats[STAT_LETTERBOX] = 0; + return; + } + + float frac; + + level.m_letterbox_time -= level.frametime; + + frac = level.m_letterbox_time / level.m_letterbox_time_start; + + if ( frac > 1 ) + frac = 1; + if ( frac < 0 ) + frac = 0; + + if ( level.m_letterbox_dir == letterbox_in ) + frac = 1.0f - frac; + + client->ps.stats[STAT_LETTERBOX] = ( frac * level.m_letterbox_fraction ) * MAX_LETTERBOX_SIZE; + } + +void Player::UpdateMusic + ( + void + ) + { + if ( music_forced ) + { + client->ps.current_music_mood = music_current_mood; + client->ps.fallback_music_mood = music_fallback_mood; + } + else if ( action_level > 30 ) + { + client->ps.current_music_mood = mood_action; + client->ps.fallback_music_mood = mood_normal; + } + else if ( action_level < 15 ) + { + client->ps.current_music_mood = music_current_mood; + client->ps.fallback_music_mood = music_fallback_mood; + } + + if (action_level > 0) + { + action_level -= level.fixedframetime * 2.0f; + if ( action_level > 80 ) + { + action_level = 80; + } + } + else + { + action_level = 0; + } + + // + // set the music + // naturally decay the action level + // + if ( s_debugmusic->integer ) + { + gi.DPrintf( "%s's action_level = %4.2f\n", client->pers.netname, action_level ); + } + + // Copy music volume and fade time to player state + client->ps.music_volume = music_current_volume; + client->ps.music_volume_fade_time = music_volume_fade_time; + } + +void Player::SetReverb + ( + int type, + float level + ) + + { + reverb_type = type; + reverb_level = level; + } + +void Player::SetReverb + ( + str type, + float level + ) + + { + reverb_type = EAXMode_NameToNum( type ); + reverb_level = level; + } + +void Player::SetReverb + ( + Event *ev + ) + { + if ( ev->NumArgs() < 2 ) + return; + + SetReverb( ev->GetInteger( 1 ), ev->GetFloat( 2 ) ); + } + +void Player::UpdateReverb + ( + void + ) + { + client->ps.reverb_type = reverb_type; + client->ps.reverb_level = reverb_level; + } + +void Player::EndAnim_Legs + ( + Event *ev + ) + + { + animdone_Legs = true; + SetAnimDoneEvent( EV_Player_AnimLoop_Legs, legs ); + EvaluateState(); + } + +void Player::EndAnim_Torso + ( + Event *ev + ) + + { + animdone_Torso = true; + SetAnimDoneEvent( EV_Player_AnimLoop_Torso, torso ); + EvaluateState(); + } + +void Player::SetAnim + ( + const char *anim, + bodypart_t part + ) + + { + assert( anim ); + + if ( ( part != all ) && ( partAnim[ part ] == anim ) ) + { + return; + } + + if ( ( part == all ) && ( partAnim[ legs ] == anim ) && ( partAnim[ torso ] == anim ) ) + { + return; + } + + if ( getMoveType() == MOVETYPE_NOCLIP ) + { + anim = "idle"; + } + + if ( part != all ) + { + partAnim[ part ] = anim; + } + else + { + partAnim[ legs ] = anim; + partAnim[ torso ] = anim; + } + + switch( part ) + { + default : + case all : + RandomAnimate( anim, EV_Player_AnimLoop_Legs, part ); + break; + + case legs : + RandomAnimate( anim, EV_Player_AnimLoop_Legs, part ); + break; + + case torso : + RandomAnimate( anim, EV_Player_AnimLoop_Torso, part ); + break; + } + + if ( ( part == legs ) || ( part == all ) ) + { + Vector animmove; + float time; + float len; + + time = gi.Anim_Time( edict->s.modelindex, CurrentAnim() ); + gi.Anim_Delta( edict->s.modelindex, CurrentAnim(), animmove ); + len = animmove.length(); + if ( len == 0 || time == 0 ) + { + animspeed = 0; + } + else + { + animspeed = len / time; + } + } + } + +void Player::UpdateSword + ( + Sword *sword + ) + + { + if ( GetWaterPower() >= sword->GetWaterRequired() ) + { + sword->SetPowerOn(); + } + else + { + sword->SetPowerOff(); + } + } + +void Player::CheckReloadWeapons + ( + void + ) + + { + Weapon *weap; + + weap = GetActiveWeapon( WEAPON_LEFT ); + if ( weap ) + { + weap->CheckReload( FIRE_PRIMARY ); + } + + weap = GetActiveWeapon( WEAPON_RIGHT ); + if ( weap ) + { + weap->CheckReload( FIRE_PRIMARY ); + } + + weap = GetActiveWeapon( WEAPON_DUAL ); + if ( weap ) + { + weap->CheckReload( FIRE_PRIMARY ); + weap->CheckReload( FIRE_ALTERNATE ); + } + } + +void Player::UpdateWeapons + ( + void + ) + + { + // Check for ammo reload and sword power + Weapon *weap; + Sword *sword; + + weap = GetActiveWeapon( WEAPON_LEFT ); + if ( weap ) + { + if ( weap->isSubclassOf( Sword ) ) + { + sword = ( Sword * )weap; + UpdateSword( sword ); + } + } + + weap = GetActiveWeapon( WEAPON_RIGHT ); + if ( weap ) + { + if ( weap->isSubclassOf( Sword ) ) + { + sword = ( Sword * )weap; + UpdateSword( sword ); + } + } + + weap = GetActiveWeapon( WEAPON_DUAL ); + if ( weap ) + { + if ( weap->isSubclassOf( Sword ) ) + { + sword = ( Sword * )weap; + UpdateSword( sword ); + } + } + } + +void Player::UpdateMisc + ( + void + ) + + { + // + // clear out the level exit flag + // + client->ps.pm_flags &= ~PMF_LEVELEXIT; + + // + // see if our camera is the level exit camera + // + if ( camera && camera->IsLevelExit() ) + { + client->ps.pm_flags |= PMF_LEVELEXIT; + } + else if ( level.near_exit ) + { + client->ps.pm_flags |= PMF_LEVELEXIT; + } + // + // do anything special for level exits + // + if ( client->ps.pm_flags & PMF_LEVELEXIT ) + { + // + // change music + // + if ( music_current_mood != mood_success ) + { + ChangeMusic( "success", "normal", false ); + } + } + } + +/* +================= +EndFrame + +Called for each player at the end of the server frame +and right after spawning +================= +*/ +void Player::EndFrame + ( + Event *ev + ) + + { + FinishMove(); + CheckReloadWeapons(); + UpdateStats(); + UpdateMusic(); + UpdateReverb(); + UpdateMisc(); + SetupView(); + } + +void Player::GibEvent + ( + Event *ev + ) + + { + qboolean hidemodel; + + hidemodel = !ev->GetInteger( 1 ); + + if ( com_blood->integer ) + { + if ( hidemodel ) + { + gibbed = true; + takedamage = DAMAGE_NO; + setSolidType( SOLID_NOT ); + hideModel(); + } + + CreateGibs( this, health, 0.75f, 3 ); + } + } + +void Player::GotKill + ( + Event *ev + ) + + { +/* + Entity *victim; + Entity *inflictor; + float damage; + int meansofdeath; + qboolean gibbed; + + if ( deathmatch->integer ) + { + return; + } + + victim = ev->GetEntity( 1 ); + damage = ev->GetInteger( 2 ); + inflictor = ev->GetEntity( 3 ); + meansofdeath = ev->GetInteger( 4 ); + gibbed = ev->GetInteger( 5 ); +*/ + } + +void Player::SetPowerupTimer + ( + Event *ev + ) + + { + Event *event; + + poweruptimer = ev->GetInteger( 1 ); + poweruptype = ev->GetInteger( 2 ); + event = new Event( EV_Player_UpdatePowerupTimer ); + PostEvent ( event, 1 ); + } + +void Player::UpdatePowerupTimer + ( + Event *ev + ) + + { + poweruptimer -= 1; + if ( poweruptimer > 0 ) + { + PostEvent( ev, 1 ); + } + else + { + poweruptype = 0; + } + } + +void Player::ChangeMusic + ( + const char * current, + const char * fallback, + qboolean force + ) + + { + int current_mood_num; + int fallback_mood_num; + + music_forced = force; + if ( str( current ) == "normal" ) + { + music_forced = false; + } + // + // we no longer let any music be forced + // + music_forced = false; + + // zero out action_level so that we do get a change + // + action_level = 0; + + if ( current ) + { + current_mood_num = MusicMood_NameToNum( current ); + if ( current_mood_num < 0 ) + { + gi.DPrintf( "current music mood %s not found", current ); + } + else + { + music_current_mood = current_mood_num; + } + } + + if ( fallback ) + { + fallback_mood_num = MusicMood_NameToNum( fallback ); + if ( fallback_mood_num < 0 ) + { + gi.DPrintf( "fallback music mood %s not found", fallback ); + fallback = NULL; + } + else + { + music_fallback_mood = fallback_mood_num; + } + } + } + +void Player::ChangeMusicVolume + ( + float volume, + float fade_time + ) + + { + music_volume_fade_time = fade_time; + music_saved_volume = music_current_volume; + music_current_volume = volume; + } + +void Player::RestoreMusicVolume + ( + float fade_time + ) + + { + music_volume_fade_time = fade_time; + music_current_volume = music_saved_volume; + music_saved_volume = -1.0; + } + +void Player::GiveOxygen + ( + float time + ) + + { + air_finished = level.time + time; + } + +void Player::Jump + ( + Event *ev + ) + + { + float maxheight; + + maxheight = ev->GetFloat( 1 ); + + if ( maxheight > 16 ) + { + // v^2 = 2ad + velocity[ 2 ] += sqrt( 2 * sv_gravity->integer * maxheight ); + + // make sure the player leaves the ground + client->ps.walking = qfalse; + } + } + +void Player::JumpXY + ( + Event *ev + ) + + { + float forwardmove; + float sidemove; + float distance; + float time; + float speed; + + forwardmove = ev->GetFloat( 1 ); + sidemove = ev->GetFloat( 2 ); + speed = ev->GetFloat( 3 ); + + if ( water_power >= MINIMUM_WATER_FOR_TURBO ) + { + if ( pm_lastruntime > WATER_TURBO_TIME ) + { + forwardmove *= WATER_TURBO_SPEED; + //speed *= WATER_TURBO_SPEED; + } + } + + velocity = yaw_forward * forwardmove - yaw_left * sidemove; + distance = velocity.length(); + velocity *= speed / distance; + time = distance / speed; + velocity[ 2 ] = sv_gravity->integer * time * 0.5f; + + airspeed = distance; + + // make sure the player leaves the ground + client->ps.walking = qfalse; + } + +void Player::StartFakePlayer + ( + void + ) + { + Actor * fake; + + // + // if we don't have a fakePlayer active, no need to check + // + if ( !fakePlayer_active ) + { + return; + } + + fakePlayer_active = qfalse; + + fakePlayer = new Actor; + + if ( !fakePlayer ) + return; + + fake = fakePlayer; + + CloneEntity( fake, this ); + + fake->SetTargetName( "fakeplayer" ); + fake->ProcessEvent( EV_Actor_AIOff ); + + // make sure it thinks so that it can fall when necessary + fake->flags |= FL_THINK; + + // Make the fake player a stepsize shorter to prevent some collision issues + + fake->maxs[2] -= STEPSIZE; + fake->setSize( mins, maxs ); + + fake->takedamage = DAMAGE_NO; + + // hide the player + this->hideModel(); + this->ProcessEvent( EV_Sentient_TurnOffShadow ); + // + // immobolize the player + // + this->flags |= FL_IMMOBILE; + // make the player not solid + setSolidType( SOLID_NOT ); + + // let the scripts now we are ready + PostEvent( EV_Player_Done, 0 ); + } + +void Player::FakePlayer + ( + qboolean holster + ) + { + // + // make sure we don't have one already + // + if ( fakePlayer ) + { + return; + } + + fakePlayer_active = qtrue; + + // if we are in the holster state, wait until next frame + // if we aren't process immediately + if ( !holster ) + { + StartFakePlayer(); + } + else + { + if ( WeaponsOut() ) + { + SafeHolster( qtrue ); + } + } + } + +void Player::RemoveFakePlayer + ( + void + ) + { + Actor * fake; + + // + // make sure we have one + // + if ( !fakePlayer ) + { + return; + } + fake = fakePlayer; + + // + // warp the real player to the fakeplayer location + // + this->setOrigin( fake->origin ); + this->setAngles( fake->angles ); + this->SetViewAngles( fake->angles ); + // show the player + this->showModel(); + this->ProcessEvent( EV_Sentient_TurnOnShadow ); + // allow the player to move + this->flags &= ~FL_IMMOBILE; + // make the player solid + setSolidType( SOLID_BBOX ); + // remove the fake + fake->PostEvent ( EV_Remove, 0.f ); + // null out the fake player + fakePlayer = NULL; + SafeHolster( qfalse ); + } + +void Player::SetViewAngles + ( + Vector newViewangles + ) + + { + // set the delta angle + client->ps.delta_angles[0] = ANGLE2SHORT( newViewangles.x - client->cmd_angles[0] ); + client->ps.delta_angles[1] = ANGLE2SHORT( newViewangles.y - client->cmd_angles[1] ); + client->ps.delta_angles[2] = ANGLE2SHORT( newViewangles.z - client->cmd_angles[2] ); + + v_angle = newViewangles; + + // get the pitch and roll from our leg angles + newViewangles.x = angles.x; + newViewangles.z = angles.z; + AnglesToMat( newViewangles, orientation ); + yaw_forward = orientation[ 0 ]; + yaw_left = orientation[ 1 ]; + + MatrixTransformVector( base_righthand_pos, orientation, righthand_pos ); + MatrixTransformVector( base_lefthand_pos, orientation, lefthand_pos ); + MatrixTransformVector( base_rightfoot_pos, orientation, rightfoot_pos ); + MatrixTransformVector( base_leftfoot_pos, orientation, leftfoot_pos ); + righthand_pos += origin; + lefthand_pos += origin; + rightfoot_pos += origin; + leftfoot_pos += origin; + } + +void Player::DumpState + ( + Event *ev + ) + + { + gi.DPrintf( "Legs: %s Torso: %s\n", currentState_Legs ? currentState_Legs->getName() : "NULL", currentState_Torso->getName() ); + } + +void Player::ForceTorsoState + ( + Event *ev + ) + + { + State *ts = statemap_Torso->FindState( ev->GetString( 1 ) ); + EvaluateState( ts ); + } + +float Player::GetWaterPower + ( + void + ) + + { + return water_power; + } + +void Player::SetWaterPower + ( + float w + ) + + { + float diff; + + ScriptVariable * var; + + + // Clamp the water + if ( w < 0 ) + w = 0; + + if ( w > max_water_power ) + w = max_water_power; + + diff = w - water_power; + water_power = w; + + // shift the player because they picked up the water + diff *= 16.0f / 100.0f; + if ( diff > 1.0f ) + diff = 1.0f; + else if ( diff < 0 ) + diff = 0; + + if ( diff > 0 ) + { + SetOffsetColor( 0, 0, diff, diff * 2 ); + } + + // + // set our level variables + // + var = levelVars.GetVariable( "playerammo_edenwater" ); + if ( !var ) + { + levelVars.SetVariable( "playerammo_edenwater", water_power ); + } + else + { + var->setIntValue( water_power ); + } + + oldstats[STAT_WATER_LEVEL] = 0; + UpdateWeapons(); + } + +void Player::TouchedUseAnim + ( + Entity * ent + ) + { + toucheduseanim = ent; + } + +void Player::ChangeOutfit + ( + Event *ev + ) + { + int stage = ev->GetInteger( 1 ); + + SetOutfit( stage ); + } + +void Player::SetOutfit + ( + int stage + ) + { + // cancel any pending outfit changes + CancelEventsOfType( EV_Player_ChangeOutfit ); + + outfit_level = stage; + + SurfaceCommand( "armpad*", "+nodraw" ); + SurfaceCommand( "holster*", "+nodraw" ); + SurfaceCommand( "pouch", "+nodraw" ); + SurfaceCommand( "kneepad*", "+nodraw" ); + SurfaceCommand( "shoulderpad*", "+nodraw" ); + SurfaceCommand( "glasses", "+nodraw" ); + switch( stage ) + { + case 5: + SurfaceCommand( "glasses", "-nodraw" ); + case 4: + SurfaceCommand( "shoulderpad*", "-nodraw" ); + case 3: + SurfaceCommand( "kneepad*", "-nodraw" ); + case 2: + SurfaceCommand( "armpad*", "-nodraw" ); + case 1: + SurfaceCommand( "holster*", "-nodraw" ); + SurfaceCommand( "pouch", "-nodraw" ); + case 0: + break; + } + } + +int Player::GetOutfit + ( + void + ) + { + return outfit_level; + } + +void Player::ClearLeftArmTarget + ( + Event *ev + ) + + { + left_arm_target = NULL; + } + +void Player::ClearRightArmTarget + ( + Event *ev + ) + + { + right_arm_target = NULL; + } + +void Player::AdjustTorso + ( + Event *ev + ) + + { + adjust_torso = ev->GetBoolean( 1 ); + } + +void Player::UseDualWield + ( + Event *ev + ) + + { + // This is triggered by the state machine. + // If there is a weapon in the dual wield list, use it, then remove it from the list. + if ( dual_wield_weaponlist.NumObjects() ) + { + DualWieldWeapon *dw; + + dw = dual_wield_weaponlist.ObjectAt( 1 ); + + useWeapon( dw->name, dw->hand ); + dual_wield_weaponlist.RemoveObjectAt( 1 ); + delete dw; + } + else + { + dual_wield_active = qfalse; // We are done wielding all the weapons + } + } + +void Player::DualWield + ( + Event *ev + ) + + { + str leftweap, rightweap; + Weapon *leftactweap, *rightactweap, *dualactweap; + + leftweap = ev->GetString( 1 ); + rightweap = ev->GetString( 2 ); + + // Set the putaway flags on any active weapons + leftactweap = GetActiveWeapon( WEAPON_LEFT ); + rightactweap = GetActiveWeapon( WEAPON_RIGHT ); + dualactweap = GetActiveWeapon( WEAPON_DUAL ); + + // Check for any dual handed weapon being out, and mark it for putaway + if ( dualactweap ) + { + dualactweap->SetPutAway( qtrue ); + } + + // if the left and right weapons are already out, then holster them both + if ( + ( leftactweap && !leftweap.icmp( leftactweap->getName() ) ) && + ( rightactweap && !rightweap.icmp( rightactweap->getName() ) ) + ) + { + leftactweap->SetPutAway( qtrue ); + rightactweap->SetPutAway( qtrue ); + return; + } + + DualWieldWeapon *dualweap; + + // Putaway the old weapons, and add the new ones to the dual_wield list + if ( !leftactweap ) + { + dualweap = new DualWieldWeapon; + dualweap->name = leftweap; + dualweap->hand = WEAPON_LEFT; + dual_wield_weaponlist.AddObject( dualweap ); + } + else if ( leftweap.icmp( leftactweap->getName() ) ) + { + leftactweap->SetPutAway( qtrue ); + + dualweap = new DualWieldWeapon; + dualweap->name = leftweap; + dualweap->hand = WEAPON_LEFT; + dual_wield_weaponlist.AddObject( dualweap ); + } + + if ( !rightactweap ) + { + dualweap = new DualWieldWeapon; + dualweap->name = rightweap; + dualweap->hand = WEAPON_RIGHT; + dual_wield_weaponlist.AddObject( dualweap ); + } + else if ( rightweap.icmp( rightactweap->getName() ) ) + { + rightactweap->SetPutAway( qtrue ); + + dualweap = new DualWieldWeapon; + dualweap->name = rightweap; + dualweap->hand = WEAPON_RIGHT; + dual_wield_weaponlist.AddObject( dualweap ); + } + + dual_wield_active = qtrue; + } + +void Player::EvaluateTorsoAnim + ( + Event *ev + ) + + { + str torsoAnim( currentState_Torso->getTorsoAnim( *this, &torso_conditionals ) ); + + if ( torsoAnim == "" ) + { + partAnim[ torso ] = ""; + ClearTorsoAnim(); + } + else if ( torsoAnim != "none" ) + { + SetAnim( torsoAnim.c_str(), torso ); + } + } + +void Player::NextPainTime + ( + Event *ev + ) + + { + nextpaintime = level.time + ev->GetFloat( 1 ); + pain_type = MOD_NONE; + pain = 0; + } + +void Player::SetMouthAngle + ( + Event *ev + ) + + { + int tag_num; + float angle_percent; + Vector mouth_angles; + + + angle_percent = ev->GetFloat( 1 ); + + if ( angle_percent < 0 ) + angle_percent = 0; + + if ( angle_percent > 1 ) + angle_percent = 1; + + tag_num = gi.Tag_NumForName( edict->s.modelindex, "tag_mouth" ); + + if ( tag_num != -1 ) + { + SetControllerTag( MOUTH_TAG, tag_num ); + + mouth_angles = vec_zero; + mouth_angles[PITCH] = max_mouth_angle * angle_percent; + + SetControllerAngles( MOUTH_TAG, mouth_angles ); + } + } + +void Player::EnterVehicle + ( + Event *ev + ) + + { + Entity *ent; + + ent = ev->GetEntity( 1 ); + if ( ent && ent->isSubclassOf( Vehicle ) ) + { + flags |= FL_PARTIAL_IMMOBILE; + viewheight = STAND_EYE_HEIGHT; + velocity = vec_zero; + vehicle = ( Vehicle * )ent; + if ( vehicle->IsDrivable() ) + setMoveType( MOVETYPE_VEHICLE ); + else + setMoveType( MOVETYPE_NOCLIP ); + } + } + +void Player::ExitVehicle + ( + Event *ev + ) + + { + flags &= ~FL_PARTIAL_IMMOBILE; + setMoveType( MOVETYPE_WALK ); + vehicle = NULL; + } + +qboolean Player::WeaponsOut + ( + void + ) + + { + return ( GetActiveWeapon( WEAPON_LEFT ) || GetActiveWeapon( WEAPON_RIGHT ) || GetActiveWeapon( WEAPON_DUAL ) ); + } + +void Player::Holster + ( + qboolean putaway + ) + + { + Weapon *leftWeap, *rightWeap, *dualWeap; + + leftWeap = GetActiveWeapon( WEAPON_LEFT ); + rightWeap = GetActiveWeapon( WEAPON_RIGHT ); + dualWeap = GetActiveWeapon( WEAPON_DUAL ); + + // Holster + if ( leftWeap || rightWeap || dualWeap ) + { + if ( putaway ) + { + if ( leftWeap ) + { + leftWeap->SetPutAway( qtrue ); + holsteredWeapons[WEAPON_LEFT] = leftWeap; + } + if ( rightWeap ) + { + rightWeap->SetPutAway( qtrue ); + holsteredWeapons[WEAPON_RIGHT] = rightWeap; + } + if ( dualWeap ) + { + dualWeap->SetPutAway( qtrue ); + holsteredWeapons[WEAPON_DUAL] = dualWeap; + } + + // Set a level var so the script can know if the player is going to holster + levelVars.SetVariable( "holster_active", 1 ); + } + } + else + { + if ( !putaway ) + { + // Unholster + if ( holsteredWeapons[WEAPON_DUAL] ) + { + useWeapon( holsteredWeapons[WEAPON_DUAL], WEAPON_DUAL ); + } + else if ( holsteredWeapons[WEAPON_LEFT] && holsteredWeapons[WEAPON_RIGHT] ) + { + Event *ev1; + + ev1 = new Event( EV_Player_DualWield ); + ev1->AddString( holsteredWeapons[WEAPON_LEFT]->getName() ); + ev1->AddString( holsteredWeapons[WEAPON_RIGHT]->getName() ); + ProcessEvent( ev1 ); + } + else if ( holsteredWeapons[WEAPON_RIGHT] ) + { + useWeapon( holsteredWeapons[WEAPON_RIGHT], WEAPON_RIGHT ); + } + else if ( holsteredWeapons[WEAPON_LEFT] ) + { + useWeapon( holsteredWeapons[WEAPON_LEFT], WEAPON_LEFT ); + } + + holsteredWeapons[WEAPON_LEFT] = NULL; + holsteredWeapons[WEAPON_RIGHT] = NULL; + holsteredWeapons[WEAPON_DUAL] = NULL; + // Set a level var to let the script know there is no holstering + levelVars.SetVariable( "holster_active", 0 ); + } + } + } + +void Player::SafeHolster + ( + qboolean putaway + ) + { + if ( WeaponsOut() ) + { + if ( putaway ) + { + weapons_holstered_by_code = qtrue; + Holster( qtrue ); + } + } + else + { + if ( putaway ) + { + if ( !fakePlayer_active ) + { + WeaponsHolstered(); + } + } + else + { + if ( weapons_holstered_by_code ) + { + weapons_holstered_by_code = qfalse; + Holster( qfalse ); + } + } + } + } + +void Player::WeaponsNotHolstered + ( + void + ) + { + } + +void Player::WeaponsHolstered + ( + void + ) + { + } + +void Player::HolsterToggle + ( + Event *ev + ) + + { + if ( WeaponsOut() ) + { + Holster( qtrue ); + } + else + { + Holster( qfalse ); + } + } + +void Player::Holster + ( + Event *ev + ) + + { + SafeHolster( ev->GetBoolean( 1 ) ); + } + +void Player::GrabRope + ( + Entity * ent + ) + { + rope_grabbed = ( Rope * )ent; + } + +void Player::TouchRope + ( + Entity * ent + ) + { + rope_touch = ( Rope * )ent; + } + +qboolean Player::OnRope + ( + void + ) + { + return ( rope_grabbed != NULL ); + } + +void Player::SetWaterPower + ( + Event *ev + ) + + { + SetWaterPower( ev->GetInteger( 1 ) ); + } + +void Player::IncreaseActionLevel + ( + float action_level_increase + ) + { + action_level += action_level_increase; + } + +void Player::WatchActor + ( + Event *ev + ) + + { + if ( camera || currentState_Torso->getCameraType() != CAMERA_BEHIND ) + return; + + actor_to_watch = (Actor *)ev->GetEntity( 1 ); + } + +void Player::StopWatchingActor + ( + Event *ev + ) + + { + Actor *old_actor; + + old_actor = (Actor *)ev->GetEntity( 1 ); + + if ( old_actor == actor_to_watch ) + actor_to_watch = NULL; + } + +void Player::setAngles + ( + Vector ang + ) + + { + // set the angles normally + Entity::setAngles( ang ); + + // set the orientation based off of the current view, also update our yaw_forward and yaw_left + ang[ YAW ] = v_angle[ YAW ]; + AnglesToMat( ang, orientation ); + yaw_forward = orientation[ 0 ]; + yaw_left = orientation[ 1 ]; + } + +void Player::WeaponCommand + ( + Event *ev + ) + + { + weaponhand_t hand; + Weapon *weap; + int i; + + if ( ev->NumArgs() < 2 ) + return; + + hand = WeaponHandNameToNum( ev->GetString( 1 ) ); + weap = GetActiveWeapon( hand ); + + if ( !weap ) + return; + + Event *e; + e = new Event( ev->GetToken( 2 ) ); + + for( i=3; i<=ev->NumArgs(); i++ ) + e->AddToken( ev->GetToken( i ) ); + + weap->ProcessEvent( e ); + } + +qboolean TryPush + ( + int entnum, + vec3_t move_origin, + vec3_t move_end + ) + + { + Actor *act; + Vector dir; + Vector dir2; + Entity *ent; + + if ( entnum == ENTITYNUM_NONE ) + return false; + + ent = G_GetEntity( entnum ); + + if ( ent->isSubclassOf( Actor ) ) + { + act = (Actor *) ent; + + dir = act->origin - move_origin; + dir.z = 0; + dir.normalize(); + + dir2 = move_end; + dir2 -= move_origin; + + if ( act->flags & FL_FLY ) + { + dir *= dir2.length() / 2; + + if ( act->Push( dir ) ) + return true; + } + else + { + dir *= dir2.length(); + + Event *event = new Event( EV_Actor_Push ); + event->AddVector( dir ); + act->PostEvent( event, 0 ); + } + } + + return false; + } + +void Player::PlayerDone + ( + Event *ev + ) + + { + // This is used to let scripts know that the player is done doing something + + // let any threads waiting on us know they can go ahead + Director.PlayerSpawned(); + } + +painDirection_t Player::Pain_string_to_int + ( + str pain + ) + + { + if ( !pain.icmp( pain, "Front" ) ) + return PAIN_FRONT; + else if ( !pain.icmp( pain, "Left" ) ) + return PAIN_LEFT; + else if ( !pain.icmp( pain, "Right" ) ) + return PAIN_RIGHT; + else if ( !pain.icmp( pain, "Rear" ) ) + return PAIN_REAR; + else + return PAIN_NONE; + } + +void Player::ArchivePersistantData + ( + Archiver &arc + ) + + { + int i; + str model_name; + + Sentient::ArchivePersistantData( arc ); + + arc.ArchiveFloat( &water_power ); + arc.ArchiveFloat( &max_water_power ); + + arc.ArchiveInteger( &outfit_level ); + + model_name = g_playermodel->string; + + arc.ArchiveString( &model_name ); + + if ( arc.Loading() ) + { + // set the cvar + gi.cvar_set( "g_playermodel", model_name.c_str() ); + + model_name += ".tik"; + setModel( model_name.c_str() ); + + Event *event = new Event( EV_Player_ChangeOutfit ); + event->AddInteger( outfit_level ); + PostEvent( event, FRAMETIME * 3 ); + } + + for( i = 0; i < MAX_ACTIVE_WEAPONS; i++ ) + { + str name; + if ( arc.Saving() ) + { + if ( holsteredWeapons[ i ] ) + { + name = holsteredWeapons[ i ]->getName(); + } + else + { + name = "none"; + } + } + arc.ArchiveString( &name ); + if ( arc.Loading() ) + { + if ( name != "none" ) + { + holsteredWeapons[ i ] = ( Weapon * )FindItem( name ); + } + } + } + UpdateWeapons(); + // Force a re-evaluation of the player's state + LoadStateTable(); + } + +void Player::SpawnDamageEffect + ( + meansOfDeath_t mod + ) + + { + switch ( mod ) + { + case MOD_ELECTRIC: + case MOD_ELECTRICWATER: + { + SpawnEffect( "fx_elecstrike.tik", origin ); + Sound( "sound/weapons/sword/electric/hitmix2.wav", 0 ); + } + default: + { + } + } + } + +void Player::ActivateDualWeapons + ( + Event *ev + ) + + { + int i; + + for ( i=dual_wield_weaponlist.NumObjects(); i>=1; i-- ) + { + DualWieldWeapon *dw; + Weapon *weapon; + + dw = dual_wield_weaponlist.ObjectAt( i ); + + weapon = ( Weapon * )FindItem( dw->name ); + + // Check to see if player has the weapon + if ( !weapon ) + { + warning( "Player::ActivateDualWeapons", "Player does not have weapon %s", dw->name ); + return; + } + + ChangeWeapon( weapon, dw->hand ); + dual_wield_weaponlist.RemoveObjectAt( i ); + delete dw; + } + + // Check for water and ammo + UpdateWeapons(); + + // Clear out the newActiveWeapon + ClearNewActiveWeapon(); + + // Clear out the holstered weapons + holsteredWeapons[WEAPON_LEFT] = NULL; + holsteredWeapons[WEAPON_RIGHT] = NULL; + holsteredWeapons[WEAPON_DUAL] = NULL; + + // let the player know that our weapons are not holstered + WeaponsNotHolstered(); + } + +void Player::VelocityModified + ( + void + ) + { + if ( velocity.z > 32 ) + { + do_rise = qtrue; + } + } + +int Player::GetKnockback + ( + int original_knockback, + qboolean blocked + ) + { + int new_knockback; + + new_knockback = original_knockback; + + // If blocked, absorb some of the knockback + + if ( blocked ) + { + if ( LargeShieldActive() ) + new_knockback -= 150; + else + new_knockback -= 50; + } + + // See if we still have enough knockback to knock the player down + + if ( new_knockback >= 200 && take_pain ) + { + knockdown = true; + + if ( blocked ) + { + float damage; + + damage = new_knockback / 50; + + if ( damage > 10 ) + damage = 10; + + Damage( world, world, damage, origin, vec_zero, vec_zero, 0, DAMAGE_NO_ARMOR, MOD_CRUSH ); + } + } + + // Make sure knockback is still at least 0 + + if ( new_knockback < 0 ) + new_knockback = 0; + + return new_knockback; + } + +void Player::ResetHaveItem + ( + Event *ev + ) + { + str fullname; + ScriptVariable * var; + + fullname = str( "playeritem_" ) + ev->GetString( 1 ); + + var = gameVars.GetVariable( fullname.c_str() ); + + if ( var ) + var->setIntValue( 0 ); + } + +void Player::ReceivedItem + ( + Item * item + ) + { + qboolean forced; + qboolean first; + str fullname; + str dialog; + str anim; + ScriptVariable * var; + + // + // set our global game variables + // + + fullname = str( "playeritem_" ) + item->getName(); + + first = qtrue; + + var = gameVars.GetVariable( fullname.c_str() ); + if ( !var ) + { + gameVars.SetVariable( fullname.c_str(), 1 ); + } + else + { + int amount; + + amount = var->intValue() + 1; + var->setIntValue( amount ); + // + // if we just received it, let the player know + // + if ( amount > 1 ) + { + first = qfalse; + } + } + + var = levelVars.GetVariable( fullname.c_str() ); + if ( !var ) + { + levelVars.SetVariable( fullname.c_str(), 1 ); + } + else + { + int amount; + + amount = var->intValue() + 1; + var->setIntValue( amount ); + } + + if ( item->IsItemCool( &dialog, &anim, &forced ) ) + { + if ( first || forced ) + { + cool_item = item; + cool_dialog = dialog; + cool_anim = anim; + } + } + } + +void Player::RemovedItem + ( + Item * item + ) + { + str fullname; + ScriptVariable * var; + + // + // set our global game variables if client + // + + fullname = str( "playeritem_" ) + item->getName(); + + var = levelVars.GetVariable( fullname.c_str() ); + if ( var ) + { + int amount; + + amount = var->intValue() - 1; + if ( amount < 0 ) + amount = 0; + var->setIntValue( amount ); + } + + var = gameVars.GetVariable( fullname.c_str() ); + if ( var ) + { + int amount; + + amount = var->intValue() - 1; + if ( amount < 0 ) + amount = 0; + var->setIntValue( amount ); + } + } + +void Player::AmmoAmountChanged + ( + Ammo * ammo, + int ammo_in_clip + ) + { + str fullname; + ScriptVariable * var; + + // + // set our level variables + // + fullname = str( "playerammo_" ) + ammo->getName(); + + var = levelVars.GetVariable( fullname.c_str() ); + if ( !var ) + { + levelVars.SetVariable( fullname.c_str(), ammo->getAmount() + ammo_in_clip ); + } + else + { + var->setIntValue( ammo->getAmount() + ammo_in_clip ); + } + } + + +void Player::StartCoolItem + ( + Event *ev + ) + { + // turn off ai off during the cinematic + level.ai_on = qfalse; + // make sure we don't take damage during this time + takedamage = DAMAGE_NO; + // freeze the player + level.playerfrozen = qtrue; + // turn on cinematic mode + G_StartCinematic(); + + assert( ( Camera * )cool_camera == NULL ); + // start playing the success music + if ( music_current_mood != mood_success ) + { + ChangeMusic( "success", MusicMood_NumToName( music_current_mood ), qfalse ); + } + + // create an orbit cam + cool_camera = new Camera(); + cool_camera->SetOrbitHeight( 150 ); + cool_camera->Orbit( this, 200, this, -90 ); + cool_camera->Cut( NULL ); + SetCamera( cool_camera, 1 ); + } + +void Player::ShowCoolItem + ( + Event *ev + ) + { + Animate * fx; + Vector org; + + org = origin; + org.z += 128; + + fx = new Animate; + + fx->setOrigin( org ); + fx->setModel( "fx_coolitem.tik" ); + fx->RandomAnimate( "idle" ); + fx->PostEvent( EV_Remove, 1 ); + + if ( cool_item ) + { + cool_item->setOrigin( org ); + cool_item->PostEvent( EV_Show, 0.1f ); + // place a lens flare on the object + cool_item->edict->s.renderfx |= RF_VIEWLENSFLARE; + + if ( cool_dialog.length() ) + { + Sound( cool_dialog, CHAN_DIALOG ); + } + } + } + +void Player::HideCoolItem + ( + Event *ev + ) + { + Animate * fx; + Vector org; + + org = origin; + org.z += 128; + + fx = new Animate; + + fx->setOrigin( org ); + fx->setModel( "fx_coolitem_reverse.tik" ); + fx->RandomAnimate( "idle" ); + fx->PostEvent( EV_Remove, 1 ); + + if ( cool_item ) + { + Event * event; + + cool_item->PostEvent( EV_Hide, 1.0f ); + + event = new Event( EV_SetOrigin ); + event->AddVector( vec_zero ); + cool_item->PostEvent( event, 1.0f ); + // remove the lens flare on the object + cool_item->edict->s.renderfx &= ~RF_VIEWLENSFLARE; + } + } + +void Player::StartCoolItemAnim + ( + void + ) + { + movecontrol = MOVECONTROL_ABSOLUTE; + + if ( cool_item && cool_anim.length() ) + { + SetAnim( cool_anim, legs ); + // clear out anim till next time + cool_anim = ""; + } + } + +void Player::StopCoolItem + ( + Event *ev + ) + { + if ( cool_item && cool_anim.length() ) + { + State * newState; + + newState = statemap_Torso->FindState( "DO_COOL_ITEM_ANIM" ); + if ( newState ) + { + currentState_Torso = newState; + return; + } + } + + // turn ai back on + level.ai_on = qtrue; + + // turn damage back on + takedamage = DAMAGE_AIM; + + // unfreeze the player + level.playerfrozen = qfalse; + + // turn off cinematic mode + G_StopCinematic(); + + cool_item = NULL; + + // delete our camera + if ( cool_camera ) + { + SetCamera( NULL, 1 ); + delete cool_camera; + cool_camera = NULL; + } + } + +void Player::WaitForState + ( + Event *ev + ) + { + waitForState = ev->GetString( 1 ); + } + + +void Player::SetDamageMultiplier + ( + Event *ev + ) + { + damage_multiplier = ev->GetFloat( 1 ); + } + +void Player::SetTakePain + ( + Event *ev + ) + + { + take_pain = ev->GetBoolean( 1 ); + } + +void Player::Loaded + ( + void + ) + + { + UpdateWeapons(); + } + +void Player::PlayerShowModel + ( + Event *ev + ) + + { + Entity::showModel(); + UpdateWeapons(); + } + +void Player::showModel + ( + void + ) + + { + Entity::showModel(); + UpdateWeapons(); + } diff --git a/source/source/fgame/player.h b/source/source/fgame/player.h new file mode 100644 index 0000000..36b6bd5 --- /dev/null +++ b/source/source/fgame/player.h @@ -0,0 +1,1682 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/player.h $ +// $Revision:: 174 $ +// $Author:: Aldie $ +// $Date:: 7/29/00 2:28p $ +// +// Copyright (C) 1997 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source is may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/player.h $ +// +// 174 7/29/00 2:28p Aldie +// Added a nosound weapon check +// +// 173 7/26/00 6:06p Steven +// Added some reseting of weapon game vars. +// +// 172 7/25/00 11:32p Aldie +// Made some changes to the memory system and fixed a memory allocation bug in +// Z_TagMalloc. Also changed a lot of classes to subclass from Class. +// +// 171 7/25/00 12:47p Markd +// Added new player sounds +// +// 170 7/23/00 8:49p Aldie +// Added some safety nets to the weapon code in sentient and player +// +// 169 7/22/00 12:52a Markd +// Added can_hang check +// +// 168 7/21/00 3:47p Steven +// Added some showmodel stuff. +// +// 167 7/21/00 1:14a Markd +// fixed fakeplayer again +// +// 166 7/19/00 8:46p Markd +// added checkgroundentity +// +// 165 7/19/00 7:26p Markd +// fixed weapons holstered code +// +// 164 7/19/00 5:10p Steven +// Added Loaded proc, gets called after a loadgame is finished so the player +// can process stuff. +// +// 163 7/19/00 11:02a Markd +// removed weapons_active +// +// 162 7/18/00 5:19p Markd +// added weapons_active boolean +// +// 161 7/18/00 4:25p Markd +// rewrote holstering code +// +// 160 7/17/00 9:51p Aldie +// Added skipcinematic command which is access by pressing the ESC key +// +// 159 7/17/00 7:45p Markd +// made fakeplayer work better +// +// 158 7/17/00 4:19p Aldie +// Changed to using v_angle instead of torsoangles for some aiming stuff. +// +// 157 7/17/00 3:26p Aldie +// Fix for flashbangs, changed detail variable, and added forcetorsostate +// +// 156 7/17/00 11:57a Aldie +// Changed some methods for checking weapons for attack +// +// 155 7/16/00 3:08p Aldie +// Added some holster functions for firing and getting the weapons out. +// +// 154 7/16/00 2:09p Aldie +// Changed some of the player logging +// +// 153 7/16/00 10:46a Steven +// Improved head target stuff. +// +// 152 7/15/00 1:34p Aldie +// Added takepain command. Allows control for taking pain or not. +// +// 151 7/15/00 1:06p Aldie +// Added specialmove stuff for weapons so we can do special movement with some +// dualhanded weapons +// +// 150 7/14/00 8:21p Aldie +// Added logstats +// +// 149 7/12/00 5:36p Markd +// fixed ammo reporting to support bullets in clip +// +// 148 7/12/00 11:27a Steven +// Changed water to a float. +// +// 147 7/10/00 11:54p Markd +// added exit level code +// +// 146 7/10/00 9:27p Markd +// added ammo variables for how much ammo the player has. Added levelvars and +// gamevars commands +// +// 145 7/10/00 8:09p Markd +// fixed cool item pickup problems +// +// 144 7/10/00 10:41a Markd +// added waitforstate +// +// 143 7/06/00 7:17p Aldie +// Added in HAS_ARMORPIECE state command +// +// 142 7/05/00 7:37p Steven +// Added more outfit stuff and added it to the saved PersistantData. +// +// 141 7/05/00 6:15p Steven +// Added a damage multiplier for combos. +// +// 140 7/05/00 4:17p Markd +// fixed cool item stuff +// +// 139 7/04/00 6:45p Markd +// enhanced cool item features +// +// 138 7/04/00 2:25p Markd +// added cool cinematic for new objects +// +// 137 7/03/00 10:23a Steven +// Added some knockback/knockdown stuff. +// +// 136 6/30/00 3:08p Markd +// fixed rise animation issues +// +// 135 6/25/00 11:21a Markd +// fixed slime code for player +// +// 134 6/20/00 7:55p Markd +// fixed camera position when game is being loaded +// +// 133 6/17/00 3:48p Aldie +// +// 132 6/15/00 5:50p Aldie +// Added rise checks +// +// 131 6/15/00 3:54p Aldie +// Took out the legturn command. We don't really need it. +// +// 130 6/15/00 2:54p Aldie +// Fix for the leg turning issue +// +// 129 6/14/00 5:40p Aldie +// Added state ammo check for weapon in hand/mode +// +// 128 6/14/00 2:17p Markd +// fixed compiler warnings for Intel Compiler +// +// 127 6/13/00 6:41p Markd +// Fixed pushing and pulling of objects +// +// 126 6/10/00 1:50p Steven +// Added statemap caching. +// +// 125 6/06/00 12:19p Markd +// working on player movement +// +// 124 6/05/00 3:29p Aldie +// Added flickering to waterstats +// +// 123 6/03/00 3:14p Aldie +// Added damage effects to player and sentient +// +// 122 6/02/00 2:01p Markd +// Fixed client persistant data issues +// +// 121 6/01/00 7:02p Markd +// removed activeWeapon variable +// +// 120 5/31/00 5:06p Aldie +// New aiming method +// +// 119 5/30/00 6:54p Aldie +// Added a muzzle clear check +// +// 118 5/30/00 5:06p Aldie +// Added large shield to prevent knockdowns +// +// 117 5/30/00 4:42p Aldie +// Added direction support and knockdown support to player +// +// 116 5/27/00 5:14p Steven +// Added player head watch stuff. +// +// 115 5/27/00 2:56p Markd +// Save games 2nd pass +// +// 114 5/27/00 9:49a Steven +// Added RemoveTarget stuff. +// +// 113 5/26/00 2:24p Aldie +// Added waitforplayer commands so we can use it for cinematics when waiting +// for player to finish holstering +// +// 112 5/25/00 4:15p Aldie +// Added weapon holstering while crouching +// +// 111 5/24/00 3:14p Markd +// first phase of save/load games +// +// 110 5/15/00 2:19p Aldie +// Added new tempmodel system and added player accumulated pain +// +// 109 5/08/00 3:20p Aldie +// Added initial crosshair work +// +// 108 5/06/00 5:25p Markd +// fixed camera and pipe hang issues +// +// 107 5/04/00 4:59p Markd +// Added setAngles and putawayweapons +// +// 106 5/02/00 3:15p Steven +// Added player watching actors that talk to her. +// +// 105 5/01/00 2:47p Steven +// Added IncreaseActionLevel. +// +// 104 5/01/00 11:31a Markd +// Added SetWaterPower to Player +// +// 103 4/29/00 11:28a Markd +// removed old rope code, cleaned up rope interface +// +// 102 4/24/00 7:07p Aldie +// Removed old code to try and fix inconsistency between legs and torso for +// firing when moving and standing. It's all done in the state machine now. +// +// 101 4/15/00 5:40p Markd +// fixed falling damage and getting into and out of water +// +// 100 4/15/00 1:30p Markd +// added check_was_running code so that player does not always stop short +// +// 99 4/14/00 6:04p Aldie +// Added checksolidforward to state system +// +// 98 4/13/00 5:31p Steven +// Added a checkshgliekdead check +// +// 97 4/10/00 11:18a Markd +// Added new rope code +// +// 96 4/07/00 10:17a Markd +// fixed shgliek pickup and weapon holstering +// +// 95 4/05/00 8:41p Markd +// Added water_level conditional +// +// 94 4/04/00 11:02a Markd +// put in checkcanclimb and feet checks +// +// 93 4/03/00 4:21p Steven +// Changed right_arm_target and left_arm_target to EntityPtrs. +// +// 92 3/31/00 3:19p Markd +// Added UseObject functionality +// +// 91 3/22/00 2:05p Aldie +// Added holster command +// +// 90 3/21/00 6:08p Markd +// Added invehicle check +// +// 89 3/21/00 5:05p Markd +// Added DamageFeedback and vehicle support +// +// 88 3/20/00 6:09p Steven +// Added SetMouthAngle. +// +// 87 3/18/00 3:55p Markd +// working on player turning +// +// 86 3/18/00 2:42p Markd +// added facing up and down slopes +// +// 85 3/17/00 6:37p Markd +// Added chance conditional +// +// 84 3/16/00 3:35p Aldie +// Added checkpain state back instead of forcing it +// +// 83 3/16/00 10:20a Markd +// fixed useanim firing its targets before the animation was completed +// +// 82 3/15/00 4:09p Aldie +// Fixed a bug with using weapons, and added some ability to force a state in +// the player +// +// 81 3/13/00 5:18p Aldie +// Made some changes for usable inventory item stuff +// +// 80 3/04/00 12:29p Jimdose +// separated feet checks into their own functions +// +// 79 3/02/00 11:12a Markd +// Added additional SetReverb function +// +// 78 3/02/00 10:48a Steven +// Changed reverb interface. +// +// 77 3/01/00 8:44p Jimdose +// added turning for monkey bars +// made move checks provide pass/fail results +// added checks for feet and falling when both feet aren't on the ground +// +// 76 2/28/00 6:33p Aldie +// Added more advanced pain state checks +// +// 75 2/26/00 7:09p Jimdose +// added better movement checks for pipecrawl, monkey bars +// added checks to prevent player from going into walk or run animation while +// move is blocked +// fixed setting step height when stepping up +// +// 74 2/26/00 11:50a Jimdose +// added slope checks +// +// 73 2/25/00 7:27p Markd +// Added useanim_numloop support and fixed useanim_orientation +// +// 72 2/25/00 5:02p Aldie +// Changed some reloading and put in a fix for the animation problem with the +// firing of the weapons +// +// 71 2/24/00 7:26p Aldie +// Added dual wielding +// +// 70 2/24/00 4:18p Jimdose +// removed some unused variables +// added ladder movement +// +// 69 2/23/00 5:27p Aldie +// Changed return value of function +// +// 68 2/22/00 1:57p Jimdose +// added pushobjects +// +// 67 2/17/00 6:26p Aldie +// Fixed naming conventions for weapon hand and also added various attachtotag +// functionality for weapons that attach to different tags depending on which +// hand they are wielded in. +// +// 66 2/17/00 4:16p Jimdose +// made statemap_Legs and statemap_Torso part of player instead of global +// removed redundant physics variables +// +// 65 2/16/00 4:01p Aldie +// Added shield functionality +// +// 64 2/15/00 8:57p Jimdose +// changed blocked to moveresult +// +// 63 2/14/00 7:34p Aldie +// Fixed some autotargeting issues +// +// 62 2/14/00 5:41p Jimdose +// got rid of unneeded debugging variables +// +// 61 2/09/00 8:02p Aldie +// Added loopfire weapons +// +// 60 2/08/00 6:35p Aldie +// Added more blocking code to player and sentient +// +// 59 2/08/00 11:34a Steven +// Added picking up of Shgliek. +// +// 58 2/08/00 12:17a Jimdose +// made rope grabbing controlled by state system +// +// 57 2/07/00 7:38p Aldie +// Fixed swiping, also various weapons fixes for sword and for sling +// +// 56 2/04/00 7:28p Aldie +// Combat code - blocking and combos +// +// 55 2/04/00 3:11p Aldie +// Changed sword attack method for water usage +// +// 54 2/03/00 2:56p Aldie +// Sword and water coding +// +// 53 2/02/00 4:28p Aldie +// Added some new state checks for combo help +// +// 52 2/01/00 5:40p Markd +// Fixed Camera cutting issues +// +// 51 2/01/00 5:28p Aldie +// More updates for auto aiming +// +// 50 1/31/00 7:56p Aldie +// Added some new states and improved arm tracking +// +// 49 1/31/00 6:03p Jimdose +// added rope_touch +// +// 48 1/31/00 3:56p Aldie +// working on the auto aim / tracking code +// +// 47 1/29/00 6:17p Aldie +// Fixed some problems when state doesn't exist. +// +// 46 1/29/00 11:27a Jimdose +// made ropes work with state system +// +// 45 1/26/00 3:33p Aldie +// Change Amount to getAmount. Added some 'listinventory' command. Added give +// all cheat to execute the script in global/giveall.txt +// +// 44 1/25/00 8:06p Jimdose +// added hardimpact +// +// 43 1/24/00 6:56p Steven +// Added reverb stuff. +// +// 42 1/24/00 2:50p Jimdose +// added rope checks +// +// 41 1/22/00 4:05p Jimdose +// added pipe crawl and step up +// +// 40 1/20/00 7:11p Jimdose +// added checkcanwallhug +// added movecontrol +// +// 39 1/19/00 10:02p Jimdose +// added airspeed +// +// 38 1/19/00 7:59p Markd +// Rewrote Surface Model Event and also added changeoutfit command to player +// +// 37 1/17/00 10:20p Jimdose +// Rewrote state system initialization. Made conditionals defined with array. +// Made Evaluate functions early exit +// +// 36 1/16/00 5:43p Aldie +// Made weapon tag vars +// +// 35 1/15/00 3:57p Markd +// Eliminated multiple "angle" events and replaced them with EV_SetAngle +// +// 34 1/15/00 1:36p Markd +// Added UseAnim and TouchUseAnim functionality to Player and game +// +// 33 1/14/00 5:07p Markd +// Removed surface num, tri_num and damage_multiplier from multiple functions +// and events +// +// 32 1/12/00 8:06p Markd +// Added CameraCut function +// +// 31 1/12/00 3:17p Aldie +// Added some water functionality +// +// 30 1/10/00 10:30a Jimdose +// removed unused code +// +// 29 1/06/00 11:08p Jimdose +// cleaning up unused code +// +// 28 1/05/00 7:25p Jimdose +// made angle functions all use the same coordinate system +// AngleVectors now returns left instead of right +// no longer need to invert pitch +// +// 27 12/20/99 6:51p Steven +// Moved jumpxy to sentient. +// +// 26 12/20/99 6:37p Markd +// Made camera cutting work properly +// +// 25 12/17/99 8:27p Jimdose +// got rid of unused vars and functions +// +// 24 12/17/99 6:35p Jimdose +// changed spawnarg code +// added Level class for spawning and map control +// got rid of unused or superflous variables +// changed setjmp/longjmp calls to try/throw/catch exception handling +// +// 23 12/14/18 2:44p Jimdose +// added monkey bar movement +// +// 22 12/13/99 10:14a Aldie +// Temp update for bug fixing due to merge +// +// 21 12/10/99 6:11p Jimdose +// added movement check functions +// +// 20 12/10/99 2:54p Aldie +// Added L and R ARM tags +// +// 19 12/10/99 11:17a Jimdose +// got rid of unused movement functions +// +// 18 12/09/99 7:38p Jimdose +// improved grabbing and hanging onto walls +// +// 17 12/08/99 7:00p Aldie +// Wrote some head tracking code +// +// 16 12/01/99 11:26a Aldie +// Couple of fixes for emitters and more ammo stuff +// +// 15 11/29/99 6:32p Aldie +// Lots of changes for ammo system +// +// 14 11/19/99 5:45p Aldie +// Update for primary and alternate fire weapons. Removed PRIMARY and SECONDAY +// mode weapons of Sin, removed SILENCED properties, and changed ammo types to +// use the new system. Still need to fix ammo checking for weapons. +// +// 13 11/11/99 5:25p Jimdose +// added separate torso animation +// +// 12 11/09/99 8:05p Markd +// Added SetViewAngles and also made a SetFOV function +// +// 11 11/05/99 7:31p Aldie +// Angles adjustment +// +// 10 10/29/99 7:21p Aldie +// Rope stuff +// +// 9 10/29/99 6:49p Jimdose +// added SwingAngles and PlayerAngles +// +// 8 10/28/99 6:33p Markd +// Added fakeplayer ability, also added CloneEntity +// +// 7 10/28/99 11:55a Aldie +// Rope stuff +// +// 6 10/28/99 10:42a Aldie +// Added rope functions +// +// 5 10/27/99 12:19p Markd +// added smooth camera lerping +// +// 4 10/19/99 7:53p Markd +// Eliminated 3 part model system +// +// 3 10/18/99 6:10p Jimdose +// got rid of separate state machine for torso and legs +// now use skeletal model for player +// +// 2 10/12/99 2:23p Markd +// Rewrote camera and player movetype system +// +// 1 9/10/99 10:54a Jimdose +// +// 1 9/08/99 3:16p Aldie +// +// 32 9/02/99 7:29p Jimdose +// added checks for doors +// +// 31 9/02/99 4:39p Jimdose +// only get hurt when damage > 15 +// +// 30 9/01/99 1:44p Jimdose +// made DoUse a script called event +// removed CheckButtons +// +// 29 8/31/99 7:40p Jimdose +// added check for if she has a weapon +// added movement speed based on animation +// +// 28 8/30/99 10:26p Jimdose +// added check for jump flip +// +// 27 8/27/99 4:49p Jimdose +// separated state machine into two, one for torso, one for legs +// +// 26 8/23/99 10:16a Jimdose +// added better falling checks +// +// 25 8/18/99 4:15p Jimdose +// added conditionals for health, death, and pain +// +// 24 8/17/99 4:52p Jimdose +// added oldorigin +// added various checks for physics +// added JumpXY +// +// 23 8/12/99 8:04p Jimdose +// working on climbing stuff +// +// 22 8/11/99 7:58p Jimdose +// preliminary climbing code in +// +// 21 8/11/99 11:52a Aldie +// Added giveweapon cheat +// +// 20 8/10/99 6:46p Aldie +// Added some better condition logic and sword attack +// +// 19 8/10/99 11:36a Aldie +// Update of the weapons system +// +// 18 8/10/99 10:48a Jimdose +// added hang_pullup_distance and blocked +// +// 17 8/06/99 6:40p Aldie +// Started moving over to new weapons system +// +// 16 7/30/99 7:53p Markd +// Added jumping ability to the player +// +// 15 7/07/99 2:53p Jimdose +// added ResetState and LoadStateTable +// +// 14 7/06/99 8:33p Jimdose +// removed unused player code +// added state machine for player animation +// +// DESCRIPTION: +// Class definition of the player. +// + +#ifndef __PLAYER_H__ +#define __PLAYER_H__ + +#include "g_local.h" +#include "vector.h" +#include "entity.h" +#include "weapon.h" +#include "sentient.h" +#include "navigate.h" +#include "misc.h" +#include "bspline.h" +#include "camera.h" +#include "specialfx.h" +#include "characterstate.h" +#include "actor.h" +#include "sword.h" +#include "vehicle.h" +#include "rope.h" + +extern Event EV_Player_EndLevel; +extern Event EV_Player_GiveCheat; +extern Event EV_Player_GodCheat; +extern Event EV_Player_NoTargetCheat; +extern Event EV_Player_NoClipCheat; +extern Event EV_Player_GameVersion; +extern Event EV_Player_Fov; +extern Event EV_Player_WhatIs; +extern Event EV_Player_Respawn; +extern Event EV_Player_WatchActor; +extern Event EV_Player_StopWatchingActor; +extern Event EV_Player_DoStats; + +#define HEAD_TAG 0 +#define TORSO_TAG 1 +#define L_ARM_TAG 2 +#define R_ARM_TAG 3 +#define MOUTH_TAG 4 + +enum painDirection_t + { + PAIN_NONE, + PAIN_FRONT, + PAIN_LEFT, + PAIN_RIGHT, + PAIN_REAR + }; + +typedef void ( Player::*movecontrolfunc_t )( void ); + +class ActiveWeapon : public Class + { + public: + WeaponPtr weapon; + weaponhand_t hand; + ActiveWeapon(); + void Archive( Archiver &arc ); + }; + +inline ActiveWeapon::ActiveWeapon + ( + ) + + { + weapon = NULL; + hand = WEAPON_ERROR; + } + +inline void ActiveWeapon::Archive + ( + Archiver &arc + ) + + { + arc.ArchiveObjectPointer( ( Class ** )&weapon ); + ArchiveEnum( hand, weaponhand_t ); + } + +class DualWieldWeapon : public Class + { + public: + str name; + weaponhand_t hand; + void Archive( Archiver &arc ); + }; + +inline void DualWieldWeapon::Archive + ( + Archiver &arc + ) + + { + arc.ArchiveString( &name ); + ArchiveEnum( hand, weaponhand_t ); + } + + +class Player : public Sentient + { + private: + static Condition Conditions[]; + static movecontrolfunc_t MoveStartFuncs[]; + + StateMap *statemap_Legs; + StateMap *statemap_Torso; + + State *currentState_Legs; + State *currentState_Torso; + str last_torso_anim_name; + str last_leg_anim_name; + movecontrol_t movecontrol; + int last_camera_type; + + EntityPtr crosshair; + ActiveWeapon newActiveWeapon; + EntityPtr head_target; + float look_at_time; + EntityPtr right_arm_target; + EntityPtr left_arm_target; + qboolean shield_active; + qboolean crouch_flag; + + qboolean dual_wield_active; + Container dual_wield_weaponlist; + + WeaponPtr holsteredWeapons[MAX_ACTIVE_WEAPONS]; + + str partAnim[ 3 ]; + + bool animdone_Legs; + bool animdone_Torso; + + Vector oldvelocity; + Vector old_v_angle; + Vector oldorigin; + float animspeed; + float airspeed; + + // blend + float blend[ 4 ]; // rgba full screen effect + float fov; // horizontal field of view + + friend class Camera; + friend class Vehicle; + + // vehicle stuff + VehiclePtr vehicle; + + // aiming direction + Vector v_angle; + + int buttons; + int new_buttons; + float respawn_time; + + float water_power; + float max_water_power; + + int last_attack_button; + + // Rope + Rope *rope_grabbed; + Rope *rope_touch; + + // damage blend + float damage_blood; + float damage_alpha; + Vector damage_blend; + Vector damage_from; // the direciton of incoming damage + Vector damage_angles; // the damage angle adjustment that should be applied to the player + float damage_count; // incoming damage which is decayed over time + + float bonus_alpha; + + float next_drown_time; // how long until we drown again + float next_painsound_time; // when we should make a pain sound again + float air_finished; + + int old_waterlevel; + int drown_damage; + + str waitForState; // if not null, than player will clear waitforplayer when this state is hit + CameraPtr camera; + CameraPtr actor_camera; + CameraPtr cool_camera; + ActorPtr actor_to_watch; + qboolean actor_camera_right; + qboolean starting_actor_camera_right; + + // music stuff + + float action_level; + + int music_current_mood; + int music_fallback_mood; + + float music_current_volume; + float music_saved_volume; + float music_volume_fade_time; + + int reverb_type; + float reverb_level; + + qboolean gibbed; + float pain; + painDirection_t pain_dir; + meansOfDeath_t pain_type; + bool take_pain; + float accumulated_pain; + int nextpaintime; + bool knockdown; + + bool canfall; + bool falling; + int feetfalling; + Vector falldir; + + bool hardimpact; + + qboolean music_forced; + + usercmd_t last_ucmd; + + // movement variables + Vector base_righthand_pos; + Vector base_lefthand_pos; + Vector righthand_pos; + Vector lefthand_pos; + + Vector base_rightfoot_pos; + Vector base_leftfoot_pos; + Vector rightfoot_pos; + Vector leftfoot_pos; + + int pm_lastruntime; // the last runtime before Pmove + + float animheight; + + Vector yaw_forward; + Vector yaw_left; + + EntityPtr atobject; + float atobject_dist; + Vector atobject_dir; + + bool pickup_enemy; // set to true when we want to pickup our enemy but are still waiting to put + // away our weapons + bool have_shgliek; + EntityPtr toucheduseanim; + int useanim_numloops; // number of times to loop the animation + EntityPtr useitem_in_use; // used so that we can trigger targets after the useitem is finished + EntityPtr cool_item; // we picked up a cool item and are waiting to show it off + str cool_dialog; // dialog to play when we get it + str cool_anim; // anim to play after the cinematic + + float ledgeheight_left; + float ledgeheight_right; + float monkeybar_left; + float monkeybar_right; + float monkeybar_dir; + EntityPtr horizontalpipe; + float move_left_dist; + float move_right_dist; + float move_backward_dist; + float move_forward_dist; + int moveresult; + qboolean do_rise; // whether or not the player should go into the rise animation + qboolean weapons_holstered_by_code; // whether or not we initiated a holstering for a specific animation + + // leg angles + qboolean yawing; + qboolean yawing_left; + qboolean yawing_right; + qboolean adjust_torso; + + Vector torsoAngles; + Vector headAngles; + Vector headAimAngles; + Vector torsoAimAngles; + Vector rightArmAimAngles; + Vector leftArmAimAngles; + + int oldstats[MAX_STATS]; + + float damage_multiplier; + + int outfit_level; + + // dummyPlayer stuff + qboolean fakePlayer_active; + SafePtr fakePlayer; + + Container legs_conditionals; + Container torso_conditionals; + + public: + qboolean returntrue( Conditional &condition ); + qboolean checkturnleft( Conditional &condition ); + qboolean checkturnright( Conditional &condition ); + qboolean checkforward( Conditional &condition ); + qboolean checkbackward( Conditional &condition ); + qboolean checkstrafeleft( Conditional &condition ); + qboolean checkstraferight( Conditional &condition ); + qboolean checkjump( Conditional &condition ); + qboolean checkcrouch( Conditional &condition ); + qboolean checkjumpflip( Conditional &condition ); + qboolean checkanimdone_legs( Conditional &condition ); + qboolean checkanimdone_torso( Conditional &condition ); + qboolean checkattackleft( Conditional &condition ); + qboolean checkattackright( Conditional &condition ); + qboolean checkattackbuttonleft( Conditional &condition ); + qboolean checkattackbuttonright( Conditional &condition ); + qboolean checksneak( Conditional &condition ); + qboolean checkrun( Conditional &condition ); + qboolean checkwasrunning( Conditional &condition ); + qboolean checkholsterweapon( Conditional &condition ); + qboolean checkuse( Conditional &condition ); + qboolean checkcanturn( Conditional &condition ); + qboolean checkcanmoveright( Conditional &condition ); + qboolean checkcanmoveleft( Conditional &condition ); + qboolean checkcanmovebackward( Conditional &condition ); + qboolean checkcanmoveforward( Conditional &condition ); + qboolean checkcanwallhug( Conditional &condition ); + qboolean checkblocked( Conditional &condition ); + qboolean checkhangatwall( Conditional &condition ); + qboolean checktouchrope( Conditional &condition ); + qboolean checkcanclimbrope( Conditional &condition ); + qboolean checkonrope( Conditional &condition ); + qboolean checkonground( Conditional &condition ); + qboolean check22degreeslope( Conditional &condition ); + qboolean check45degreeslope( Conditional &condition ); + qboolean checkrightleghigh( Conditional &condition ); + qboolean checkleftleghigh( Conditional &condition ); + qboolean checkcanhang( Conditional &condition ); + qboolean checkcanhangleft( Conditional &condition ); + qboolean checkcanhangright( Conditional &condition ); + qboolean checkcanfall( Conditional &condition ); + qboolean checkatdoor( Conditional &condition ); + qboolean checkatshgliek( Conditional &condition ); + qboolean checkhaveshgliek( Conditional &condition ); + qboolean checkshgliekdead( Conditional &condition ); + qboolean checkfalling( Conditional &condition ); + qboolean checkgroundentity( Conditional &condition ); + qboolean checkhardimpact( Conditional &condition ); + qboolean checkcangrabledge( Conditional &condition ); + qboolean checkledgeheight( Conditional &condition ); + qboolean checkcangrabpipe( Conditional &condition ); + qboolean checkcangrabmonkeybar( Conditional &condition ); + qboolean checkcanpullup( Conditional &condition ); + qboolean checkdead( Conditional &condition ); + qboolean checkhealth( Conditional &condition ); + qboolean checkpain( Conditional &condition ); + qboolean checkpaindirection( Conditional &condition ); + qboolean checkaccumulatedpain( Conditional &condition ); + qboolean checkpaintype( Conditional &condition ); + qboolean checkpainthreshold( Conditional &condition ); + qboolean checkknockdown( Conditional &condition ); + qboolean checklegsstate( Conditional &condition ); + qboolean checktorsostate( Conditional &condition ); + qboolean checkatuseanim( Conditional &condition ); + qboolean checktouchuseanim( Conditional &condition ); + qboolean checkatuseobject( Conditional &condition ); + qboolean checkloopuseobject( Conditional &condition ); + qboolean checkuseweaponleft( Conditional &condition ); + qboolean checknewweapon( Conditional &condition ); + qboolean checkuseweapon( Conditional &condition ); + qboolean checkhasweapon( Conditional &condition ); + qboolean checkweaponactive( Conditional &condition ); + qboolean checkweaponreadytofire( Conditional &condition ); + qboolean checkweaponreadytofire_nosound( Conditional &condition ); + qboolean checkmuzzleclear( Conditional &condition ); + qboolean checkputawayleft( Conditional &condition ); + qboolean checkputawayright( Conditional &condition ); + qboolean checkputawayboth( Conditional &condition ); + qboolean checktargetacquired( Conditional &condition ); + qboolean checkanyweaponactive( Conditional &condition ); + qboolean checkstatename( Conditional &condition ); + qboolean checkattackblocked( Conditional &condition ); + qboolean checkblockdelay( Conditional &condition ); + qboolean checkcanstand( Conditional &condition ); + qboolean checkpush( Conditional &condition ); + qboolean checkpull( Conditional &condition ); + qboolean checkladder( Conditional &condition ); + qboolean checkfeetatladder( Conditional &condition ); + qboolean checkcanclimbladder( Conditional &condition ); + qboolean checkdualwield( Conditional &condition ); + qboolean checkdualweapons( Conditional &condition ); + qboolean checkuseanimfinished( Conditional &condition ); + qboolean checkchance( Conditional &condition ); + qboolean checkfacingupslope( Conditional &condition ); + qboolean checkfacingdownslope( Conditional &condition ); + qboolean checkturnedleft( Conditional &condition ); + qboolean checkturnedright( Conditional &condition ); + qboolean checkinvehicle( Conditional &condition ); + qboolean checkwaterlevel( Conditional &condition ); + qboolean checkpickupenemy( Conditional &condition ); + qboolean checksolidforward( Conditional &condition ); + qboolean checkholstercomplete( Conditional &condition ); + qboolean checkweaponhasammo( Conditional &condition ); + qboolean checkrise( Conditional &condition ); + qboolean checkcoolitem( Conditional &condition ); + qboolean checkarmorpiece( Conditional &condition ); + qboolean checkspecialmove( Conditional &condition ); + qboolean checkweaponsholstered( Conditional &condition ); + qboolean checkdualweaponreadytofire( Conditional &condition ); + qboolean checkfakeplayeractive( Conditional &condition ); + qboolean checkfakeplayerholster( Conditional &condition ); + + // movecontrol functions + void StartHang( void ); + void StartPipeCrawl( void ); + void StartMonkeyBars( void ); + void StartStepUp( void ); + void RopeGrab( void ); + void RopeRelease( void ); + void StartPickup( void ); + void StartPush( void ); + void StartClimbWall( void ); + void StartUseAnim( void ); + void StartLoopUseAnim( void ); + void SetupUseObject( void ); + + void StartUseObject( Event *ev ); + void FinishUseObject( Event *ev ); + void FinishUseAnim( Event *ev ); + void PickupShgliek( Event *ev ); + void ThrowShgliek( Event *ev ); + void StepUp( Event *ev ); + void Turn( Event *ev ); + void TurnUpdate( Event *ev ); + void TurnLegs( Event *ev ); + + CLASS_PROTOTYPE( Player ); + + Player(); + ~Player(); + void Init( void ); + + void InitSound( void ); + void InitEdict( void ); + void InitClient( void ); + void InitPhysics( void ); + void InitPowerups( void ); + void InitWorldEffects( void ); + void InitWeapons( void ); + void InitView( void ); + void InitModel( void ); + void InitState( void ); + void InitHealth( void ); + void InitWaterPower( void ); + void InitInventory( void ); + void ChooseSpawnPoint( void ); + + void EndLevel( Event *ev ); + void Respawn( Event *ev ); + + void SetDeltaAngles( void ); + virtual void setAngles( Vector ang ); + + void DoUse( Event *ev ); + void Obituary( Entity *attacker, Entity *inflictor, int meansofdeath ); + void Killed( Event *ev ); + void Dead( Event *ev ); + void Pain( Event *ev ); + + void TouchStuff( pmove_t *pm ); + + void GetMoveInfo( pmove_t *pm ); + void SetMoveInfo( pmove_t *pm, usercmd_t *ucmd ); + pmtype_t GetMovePlayerMoveType( void ); + void ClientMove( usercmd_t *ucmd ); +// qboolean feetOnGround( Vector pos ); +// Vector findBestFallPos( Vector pos ); +// void CheckFeet( void ); + void CheckMoveFlags( void ); + void ClientThink( Event *ev ); + + void LoadStateTable( void ); + void ResetState( Event *ev ); + void EvaluateState( State *forceTorso=NULL, State *forceLegs=NULL ); + + void CheckGround( void ); + void UpdateViewAngles( usercmd_t *cmd ); + qboolean AnimMove( Vector &move, Vector *endpos = NULL ); + qboolean TestMove( Vector &pos, Vector *endpos = NULL ); + qboolean PipeMove( Vector &move, Vector *endpos = NULL ); + qboolean MonkeyBarMove( Vector &move, Vector *endpos = NULL ); + qboolean CheckMove( Vector &move, Vector *endpos = NULL ); + qboolean RopeMove( Vector &move, Vector *endpos = NULL ); + + float CheckMoveDist( Vector &delta ); + float TestMoveDist( Vector &pos ); + + void EndAnim_Legs( Event *ev ); + void EndAnim_Torso( Event *ev ); + void SetAnim( const char *anim, bodypart_t part = legs ); + + void EventUseItem( Event *ev ); + void TouchedUseAnim( Entity * ent ); + + void GiveCheat( Event *ev ); + void GiveWeaponCheat( Event *ev ); + void GiveAllCheat( Event *ev ); + void GodCheat( Event *ev ); + void NoTargetCheat( Event *ev ); + void NoclipCheat( Event *ev ); + void Kill( Event *ev ); + void GibEvent( Event *ev ); + void SpawnEntity( Event *ev ); + void SpawnActor( Event *ev ); + void ListInventoryEvent( Event *ev ); + + void GameVersion( Event *ev ); + void Fov( Event *ev ); + + void GetPlayerView( Vector *pos, Vector *angle ); + + float CalcRoll( void ); + void WorldEffects( void ); + void AddBlend( float r, float g, float b, float a ); + void CalcBlend( void ); + void DamageFeedback( void ); + + void UpdateStats( void ); + void StatCount( int index, int count ); + void UpdateMusic( void ); + void UpdateWeapons( void ); + void UpdateSword( Sword *sword ); + void UpdateReverb( void ); + void UpdateMisc( void ); + + void SetReverb( str type, float level ); + void SetReverb( int type, float level ); + void SetReverb( Event *ev ); + + void SetWaterPower( float water ); + float GetWaterPower( void ); + + Camera *CurrentCamera( void ); + void SetCamera( Camera *ent, float switchTime ); + void CameraCut( void ); + void CameraCut( Camera *ent ); + + void SetPlayerView( Camera * camera, Vector position, float cameraoffset, Vector ang, Vector vel, float camerablend[ 4 ], float camerafov ); + void SetupView( void ); + + void ProcessPmoveEvents( int event ); + + void SwingAngles( float destination, float swingTolerance, float clampTolerance, float speed, float *angle, qboolean *swinging ); + void PlayerAngles( void ); + void FinishMove( void ); + void EndFrame( Event *ev ); + + void TestThread( Event *ev ); + void useWeapon( const char *weaponname, weaponhand_t hand ); + void useWeapon( Weapon *weapon, weaponhand_t hand ); + + void GotKill( Event *ev ); + void SetPowerupTimer( Event *ev ); + void UpdatePowerupTimer( Event *ev ); + + void WhatIs( Event *ev ); + void ActorInfo( Event *ev ); + void Taunt( Event *ev ); + + void ChangeMusic( const char * current, const char * fallback, qboolean force ); + void ChangeMusicVolume( float volume , float fade_time); + void RestoreMusicVolume( float fade_time ); + + void GravityNodes( void ); + void Archive( Archiver &arc ); + void ArchivePersistantData( Archiver &arc ); + + void GiveOxygen( float time ); + + void KillEnt( Event *ev ); + void RemoveEnt( Event *ev ); + void KillClass( Event *ev ); + void RemoveClass( Event *ev ); + + void Jump( Event *ev ); + void JumpXY( Event *ev ); + + void ActivateNewWeapon( Event *ev ); + void ActivateDualWeapons( Event *ev ); + void DeactivateWeapon( Event *ev ); + void PutawayWeapon( Event *ev ); + void SwordAttackEvent( Event *ev ); + void ActivateShield( Event *ev ); + void DeactivateShield( Event *ev ); + qboolean ShieldActive( void ); + qboolean LargeShieldActive( void ); + + void StartFakePlayer( void ); + void FakePlayer( qboolean holster ); + void RemoveFakePlayer( void ); + void SetViewAngles( Vector angles ); + void SetFov( float newFov ); + + bool IsNewActiveWeapon( void ); + Weapon *GetNewActiveWeapon( void ); + weaponhand_t GetNewActiveWeaponHand( void ); + void ClearNewActiveWeapon( void ); + + void AdjustAnglesForAttack( void ); + Entity *FindEnemyInFOV( float fov, float maxdist ); + Entity *FindEnemyInFOVFromTagWithOffset( float fov, float maxdist, str tagname, Vector offset ); + void DumpState( Event *ev ); + void ForceTorsoState( Event *ev ); + + void SetHeadTarget( Event *ev ); + Vector GetAngleToTarget( Entity *ent, str tag, float yawclamp, float pitchclamp, Vector baseangles ); + + void AutoAim( void ); + void AcquireTarget( void ); + void RemoveTarget( Entity *ent_to_remove ); + void AcquireHeadTarget( void ); + Vector CalcArmTracking( int controller_tag, str weapon_tagname, Vector baseAngles, Entity *target, Weapon *weapon ); + + void ChangeOutfit( Event *ev ); + void SetOutfit( int stage ); + int GetOutfit( void ); + void SetCurrentCombo( Event *ev ); + + qboolean GetTagPositionAndOrientation( str tagname, orientation_t *new_or ); + qboolean GetTagPositionAndOrientation( int tagnum, orientation_t *new_or ); + + void DebugWeaponTags( int controller_tag, Weapon *weapon, str weapon_tagname ); + void SwipeOn( Event *ev ); + void SwipeOff( Event *ev ); + void ClearLeftArmTarget( Event *ev ); + void ClearRightArmTarget( Event *ev ); + void AdjustTorso( Event *ev ); + void UseDualWield( Event *ev ); + void DualWield( Event *ev ); + void EvaluateTorsoAnim( Event *ev ); + void CheckReloadWeapons( void ); + void NextPainTime( Event *ev ); + void SetTakePain( Event *ev ); + + void SetMouthAngle( Event *ev ); + + void EnterVehicle( Event *ev ); + void ExitVehicle( Event *ev ); + void Holster( Event *ev ); + void HolsterToggle( Event *ev ); + void SetWaterPower( Event *ev ); + + // rope stuff + void GrabRope( Entity * rope ); + qboolean OnRope( void ); + void TouchRope( Entity * rope ); + + void IncreaseActionLevel( float action_level_increase ); + + void WatchActor( Event *ev ); + void StopWatchingActor( Event *ev ); + void WeaponCommand( Event *ev ); + void PlayerDone( Event *ev ); + painDirection_t Pain_string_to_int( str pain ); + inline Vector GetTorsoAngles( void ) { return torsoAngles; }; + inline Vector GetVAngles( void ){ return v_angle; } + void SpawnDamageEffect( meansOfDeath_t mod ); + virtual void GetStateAnims( Container *c ); + virtual void VelocityModified( void ); + int GetKnockback( int original_knockback, qboolean blocked ); + virtual void ReceivedItem( Item * item ); + virtual void RemovedItem( Item * item ); + virtual void AmmoAmountChanged( Ammo * ammo, int inclip = 0 ); + qboolean WeaponsOut( void ); + void Holster( qboolean putaway ); + void SafeHolster( qboolean putaway ); + + void StartCoolItem( Event *ev ); + void StartCoolItemAnim( void ); + void ShowCoolItem( Event *ev ); + void HideCoolItem( Event *ev ); + void StopCoolItem( Event *ev ); + void WaitForState( Event *ev ); + void SkipCinematic( Event *ev ); + void SetDamageMultiplier( Event *ev ); + void LogStats( Event *ev ); + void WeaponsHolstered( void ); + void WeaponsNotHolstered( void ); + void Loaded( void ); + void PlayerShowModel( Event *ev ); + virtual void showModel( void ); + void ResetHaveItem( Event *ev ); + }; + +inline bool Player::IsNewActiveWeapon + ( + void + ) + + { + return ( newActiveWeapon.weapon != NULL ); + } + +inline weaponhand_t Player::GetNewActiveWeaponHand + ( + void + ) + + { + return newActiveWeapon.hand; + } + +inline Weapon *Player::GetNewActiveWeapon + ( + void + ) + + { + return newActiveWeapon.weapon; + } + +inline void Player::ClearNewActiveWeapon + ( + void + ) + + { + newActiveWeapon.weapon = NULL; + newActiveWeapon.hand = WEAPON_ERROR; + } + +inline void Player::Archive + ( + Archiver &arc + ) + + { + str tempStr; + int i; + int num; + DualWieldWeapon *tempDualWeapon; + + Sentient::Archive( arc ); + + // make sure we have the state machine loaded up + if ( arc.Loading() ) + { + LoadStateTable(); + } + + if ( arc.Saving() ) + { + if ( currentState_Legs ) + { + tempStr = currentState_Legs->getName(); + } + else + { + tempStr = "NULL"; + } + arc.ArchiveString( &tempStr ); + + if ( currentState_Torso ) + { + tempStr = currentState_Torso->getName(); + } + else + { + tempStr = "NULL"; + } + arc.ArchiveString( &tempStr ); + } + else + { + arc.ArchiveString( &tempStr ); + if ( tempStr != "NULL" ) + { + currentState_Legs = statemap_Legs->FindState( tempStr ); + } + else + { + currentState_Legs = NULL; + } + arc.ArchiveString( &tempStr ); + if ( tempStr != "NULL" ) + { + currentState_Torso = statemap_Torso->FindState( tempStr ); + } + else + { + currentState_Torso = NULL; + } + } + arc.ArchiveString( &last_torso_anim_name ); + arc.ArchiveString( &last_leg_anim_name ); + + ArchiveEnum( movecontrol, movecontrol_t ); + + arc.ArchiveInteger( &last_camera_type ); + if ( arc.Loading() ) + { + // make sure the camera gets reset + last_camera_type = -1; + } + + arc.ArchiveSafePointer( &crosshair ); + + newActiveWeapon.Archive( arc ); + + arc.ArchiveSafePointer( &head_target ); + arc.ArchiveFloat( &look_at_time ); + + arc.ArchiveSafePointer( &right_arm_target ); + arc.ArchiveSafePointer( &left_arm_target ); + arc.ArchiveBoolean( &shield_active ); + arc.ArchiveBoolean( &crouch_flag ); + + arc.ArchiveBoolean( &dual_wield_active ); + + if ( arc.Saving() ) + { + num = dual_wield_weaponlist.NumObjects(); + } + else + { + dual_wield_weaponlist.ClearObjectList(); + } + arc.ArchiveInteger( &num ); + for( i = 1; i <= num; i++ ) + { + if ( arc.Saving() ) + { + tempDualWeapon = dual_wield_weaponlist.ObjectAt( i ); + } + else + { + tempDualWeapon = new DualWieldWeapon; + dual_wield_weaponlist.AddObject( tempDualWeapon ); + } + tempDualWeapon->Archive( arc ); + } + for( i = 0; i < MAX_ACTIVE_WEAPONS; i++ ) + { + arc.ArchiveSafePointer( &holsteredWeapons[ i ] ); + } + arc.ArchiveString( &partAnim[ 0 ] ); + arc.ArchiveString( &partAnim[ 1 ] ); + arc.ArchiveString( &partAnim[ 2 ] ); + + arc.ArchiveBool( &animdone_Legs ); + arc.ArchiveBool( &animdone_Torso ); + + arc.ArchiveVector( &oldvelocity ); + arc.ArchiveVector( &old_v_angle ); + arc.ArchiveVector( &oldorigin ); + arc.ArchiveFloat( &animspeed ); + arc.ArchiveFloat( &airspeed ); + + arc.ArchiveRaw( blend, sizeof( blend ) ); + arc.ArchiveFloat( &fov ); + + arc.ArchiveSafePointer( &vehicle ); + arc.ArchiveVector( &v_angle ); + + arc.ArchiveInteger( &buttons ); + arc.ArchiveInteger( &new_buttons ); + arc.ArchiveFloat( &respawn_time ); + + arc.ArchiveFloat( &water_power ); + arc.ArchiveFloat( &max_water_power ); + + arc.ArchiveInteger( &last_attack_button ); + + arc.ArchiveObjectPointer( ( Class ** )&rope_grabbed ); + arc.ArchiveObjectPointer( ( Class ** )&rope_touch ); + + arc.ArchiveFloat( &damage_blood ); + arc.ArchiveFloat( &damage_alpha ); + arc.ArchiveVector( &damage_blend ); + arc.ArchiveVector( &damage_from ); + arc.ArchiveVector( &damage_angles ); + arc.ArchiveFloat( &damage_count ); + + arc.ArchiveFloat( &bonus_alpha ); + + arc.ArchiveFloat( &next_drown_time ); + arc.ArchiveFloat( &next_painsound_time ); + arc.ArchiveFloat( &air_finished ); + + arc.ArchiveInteger( &old_waterlevel ); + arc.ArchiveInteger( &drown_damage ); + + arc.ArchiveSafePointer( &camera ); + arc.ArchiveSafePointer( &actor_camera ); + arc.ArchiveSafePointer( &cool_camera ); + arc.ArchiveSafePointer( &actor_to_watch ); + arc.ArchiveBoolean( &actor_camera_right ); + arc.ArchiveBoolean( &starting_actor_camera_right ); + + arc.ArchiveFloat( &action_level ); + arc.ArchiveInteger( &music_current_mood ); + arc.ArchiveInteger( &music_fallback_mood ); + + arc.ArchiveFloat( &music_current_volume ); + arc.ArchiveFloat( &music_saved_volume ); + arc.ArchiveFloat( &music_volume_fade_time ); + + arc.ArchiveInteger( &reverb_type ); + arc.ArchiveFloat( &reverb_level ); + + arc.ArchiveBoolean( &gibbed ); + arc.ArchiveFloat( &pain ); + + ArchiveEnum( pain_dir, painDirection_t ); + ArchiveEnum( pain_type, meansOfDeath_t ); + arc.ArchiveBool( &take_pain ); + + arc.ArchiveFloat( &accumulated_pain ); + arc.ArchiveInteger( &nextpaintime ); + + arc.ArchiveBool( &knockdown ); + arc.ArchiveBool( &canfall ); + arc.ArchiveBool( &falling ); + arc.ArchiveInteger( &feetfalling ); + arc.ArchiveVector( &falldir ); + + arc.ArchiveBool( &hardimpact ); + + arc.ArchiveBoolean( &music_forced ); + + arc.ArchiveRaw( &last_ucmd, sizeof( last_ucmd ) ); + + arc.ArchiveVector( &base_righthand_pos ); + arc.ArchiveVector( &base_lefthand_pos ); + arc.ArchiveVector( &righthand_pos ); + arc.ArchiveVector( &lefthand_pos ); + + arc.ArchiveVector( &base_rightfoot_pos ); + arc.ArchiveVector( &base_leftfoot_pos ); + arc.ArchiveVector( &rightfoot_pos ); + arc.ArchiveVector( &leftfoot_pos ); + + arc.ArchiveInteger( &pm_lastruntime ); + arc.ArchiveFloat( &animheight ); + + arc.ArchiveVector( &yaw_forward ); + arc.ArchiveVector( &yaw_left ); + + arc.ArchiveSafePointer( &atobject ); + arc.ArchiveFloat( &atobject_dist ); + arc.ArchiveVector( &atobject_dir ); + + arc.ArchiveBool( &pickup_enemy ); + arc.ArchiveBool( &have_shgliek ); + + arc.ArchiveSafePointer( &toucheduseanim ); + arc.ArchiveInteger( &useanim_numloops ); + arc.ArchiveSafePointer( &useitem_in_use ); + arc.ArchiveSafePointer( &cool_item ); + arc.ArchiveString( &cool_anim ); + arc.ArchiveString( &cool_dialog ); + + arc.ArchiveFloat( &ledgeheight_left ); + arc.ArchiveFloat( &ledgeheight_right ); + arc.ArchiveFloat( &monkeybar_left ); + arc.ArchiveFloat( &monkeybar_right ); + arc.ArchiveFloat( &monkeybar_dir ); + + arc.ArchiveSafePointer( &horizontalpipe ); + arc.ArchiveFloat( &move_left_dist ); + arc.ArchiveFloat( &move_right_dist ); + arc.ArchiveFloat( &move_backward_dist ); + arc.ArchiveFloat( &move_forward_dist ); + arc.ArchiveInteger( &moveresult ); + + arc.ArchiveBoolean( &do_rise ); + arc.ArchiveBoolean( &weapons_holstered_by_code ); + arc.ArchiveBoolean( &yawing ); + arc.ArchiveBoolean( &yawing_left ); + arc.ArchiveBoolean( &yawing_right ); + arc.ArchiveBoolean( &adjust_torso ); + + arc.ArchiveVector( &torsoAngles ); + arc.ArchiveVector( &headAngles ); + arc.ArchiveVector( &headAimAngles ); + arc.ArchiveVector( &torsoAimAngles ); + arc.ArchiveVector( &rightArmAimAngles ); + arc.ArchiveVector( &leftArmAimAngles ); + + arc.ArchiveFloat( &damage_multiplier ); + + arc.ArchiveInteger( &outfit_level ); + + arc.ArchiveBoolean( &fakePlayer_active ); + + arc.ArchiveSafePointer( &fakePlayer ); + + if ( arc.Loading() ) + { + UpdateWeapons(); + } + } + +inline Camera *Player::CurrentCamera + ( + void + ) + + { + return camera; + } + +inline void Player::CameraCut + ( + void + ) + + { + // + // toggle the camera cut bit + // + client->ps.camera_flags = + ( ( client->ps.camera_flags & CF_CAMERA_CUT_BIT ) ^ CF_CAMERA_CUT_BIT ) | + ( client->ps.camera_flags & ~CF_CAMERA_CUT_BIT ); + } + +inline void Player::CameraCut + ( + Camera * ent + ) + + { + if ( ent == camera ) + { + // if the camera we are currently looking through cut, than toggle the cut bits + CameraCut(); + } + } + +inline void Player::SetCamera + ( + Camera *ent, + float switchTime + ) + + { + camera = ent; + client->ps.camera_time = switchTime; + if ( switchTime <= 0.0f ) + { + CameraCut(); + } + } + +#endif /* player.h */ diff --git a/source/source/fgame/player_combat.cpp b/source/source/fgame/player_combat.cpp new file mode 100644 index 0000000..20d8b57 --- /dev/null +++ b/source/source/fgame/player_combat.cpp @@ -0,0 +1,916 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/player_combat.cpp $ +// $Revision:: 60 $ +// $Author:: Aldie $ +// $Date:: 7/29/00 9:06p $ +// +// Copyright (C) 1998 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/player_combat.cpp $ +// +// 60 7/29/00 9:06p Aldie +// Added water check to swipeoff +// +// 59 7/29/00 12:55p Aldie +// Added null checks to swipes +// +// 58 7/24/00 12:16p Steven +// Added a smaller distance to look at non-actors and fixed not finding a +// target. +// +// 57 7/23/00 8:49p Aldie +// Added some safety nets to the weapon code in sentient and player +// +// 56 7/18/00 4:25p Markd +// rewrote holstering code +// +// 55 7/16/00 4:37p Steven +// Moved action level stuff to actor pain and killed. +// +// 54 7/16/00 10:46a Steven +// Improved head target stuff. +// +// 53 7/11/00 8:55p Aldie +// Added in an autoaim flag +// +// 52 7/10/00 7:16p Aldie +// Fixed weapon swipes for new water required method +// +// 51 7/10/00 6:33p Aldie +// Added SVF_SENDONCE flag and water power for swiping determination +// +// 50 7/05/00 6:14p Steven +// Added a damage multiplier for combos. +// +// 49 6/28/00 7:56p Aldie +// Added some pain stuff for use with death. +// +// 48 6/14/00 3:50p Markd +// Cleaned up more Intel Compiler warnings +// +// 47 6/08/00 3:03p Steven +// Added a decent priority sceme to player head watch stuff. +// +// 46 6/03/00 10:08a Steven +// Made it so player will not look at actors that are bound or attached to +// something. +// +// 45 6/01/00 7:02p Markd +// removed activeWeapon variable +// +// 44 6/01/00 3:18p Markd +// rewrote giveItem and item management in sentient +// +// 43 5/31/00 5:33p Steven +// Added look at me flag and changed masks used in FindClosestEntityInRadius +// from SHOT to OPAQUE. +// +// 42 5/30/00 5:06p Aldie +// Added large shield to prevent knockdowns +// +// 41 5/27/00 5:14p Steven +// Added player head watch stuff. +// +// 40 5/27/00 2:31p Steven +// Added actor targetable stuff. +// +// 39 5/26/00 2:24p Aldie +// Added waitforplayer commands so we can use it for cinematics when waiting +// for player to finish holstering +// +// 38 5/06/00 10:40a Steven +// Made it so there is action level and means of death variables for each +// weapon mode. +// +// 37 5/05/00 6:04p Steven +// Made melee weapons increment the player's action level. +// +// 36 5/04/00 4:47p Markd +// Added PutawayWeapon event +// +// 35 5/02/00 7:29p Aldie +// Fix a crash bug +// +// 34 4/28/00 5:14p Aldie +// Fixed some warning messages +// +// 33 4/15/00 1:43p Aldie +// Added usenoammo command for a weapon that cannot be used when it has no ammo +// +// 32 4/07/00 10:17a Markd +// fixed shgliek pickup and weapon holstering +// +// 31 3/22/00 2:05p Aldie +// Added holster command +// +// 30 3/15/00 5:52p Aldie +// Added pushsound to func_pushobject and removed a printf. +// +// 29 3/15/00 4:09p Aldie +// Fixed a bug with using weapons, and added some ability to force a state in +// the player +// +// 28 2/24/00 4:18p Jimdose +// removed some unused variables and functions +// +// 27 2/23/00 6:21p Aldie +// More inventory changes +// +// 26 2/18/00 6:28p Aldie +// Removed some prints +// +// 25 2/17/00 6:26p Aldie +// Fixed naming conventions for weapon hand and also added various attachtotag +// functionality for weapons that attach to different tags depending on which +// hand they are wielded in. +// +// 24 2/17/00 12:00p Aldie +// Added command processing to state system with the addition of entrycommands +// and exitcommands. +// +// 23 2/16/00 4:01p Aldie +// Added shield functionality +// +// 22 2/10/00 8:05p Aldie +// Added trace to enemyinfov +// +// 21 2/09/00 8:02p Aldie +// Added loopfire weapons +// +// 20 2/09/00 5:26p Aldie +// Fix for FindClosestEnemyInRadius +// +// 19 2/08/00 11:57a Aldie +// Added in enemy check to the FindClosestEnemyInRadius +// +// 18 2/07/00 7:38p Aldie +// Fixed swiping, also various weapons fixes for sword and for sling +// +// 17 2/04/00 3:11p Aldie +// Changed sword attack method for water usage +// +// 16 2/03/00 2:56p Aldie +// Sword and water coding +// +// 15 2/02/00 7:08p Aldie +// Added new sword code and water damage +// +// 14 2/01/00 6:27p Aldie +// Removed debug line +// +// 13 2/01/00 5:28p Aldie +// More updates for auto aiming +// +// 12 1/29/00 6:17p Aldie +// Fixed some problems when state doesn't exist. +// +// 11 1/29/00 9:33a Markd +// added logic for 2 handed weapons +// +// 10 1/22/00 12:42p Jimdose +// got rid of calls to vec3() +// +// 9 1/16/00 5:43p Aldie +// Made weapon tag vars +// +// 8 1/15/00 9:29a Markd +// rename tag_weapon to tag_weapon_right +// +// 7 1/05/00 7:25p Jimdose +// made angle functions all use the same coordinate system +// AngleVectors now returns left instead of right +// no longer need to invert pitch +// +// 6 12/17/99 8:27p Jimdose +// got rid of unused vars and functions +// +// 5 12/16/99 5:03p Aldie +// Fix for find enemyinfov +// +// 4 12/13/99 10:14a Aldie +// Temp update for bug fixing due to merge +// +// 3 12/09/99 2:31p Aldie +// Head tracking +// +// 2 12/08/99 7:00p Aldie +// Busting up player a bit and wrote some head tracking code +// +// DESCRIPTION: +// Player combat system and combat utility functions +// + +#include "player.h" +#include "sword.h" +#include "weaputils.h" + +static Entity *FindClosestEntityInRadius + ( + Vector origin, + Vector forward, + float fov, + float maxdist + ) + + { + float dist,dot; + float fovdot = cos( fov * 0.5 * M_PI / 180.0 ); + Entity *ent; + Entity *bestent=NULL; + int bestdist = 999999; + qboolean valid_entity; + + // Find closest enemy in radius + ent = findradius( NULL, origin, maxdist ); + + while( ent ) + { + valid_entity = false; + + if ( ent->flags & FL_AUTOAIM ) + { + valid_entity = true; + } + else if ( ent->isSubclassOf( Actor ) && !ent->deadflag ) + { + Actor *actor = ( Actor * )ent; + + if ( actor->actortype == IS_ENEMY && actor->CanTarget() && !actor->bindmaster && actor->edict->s.parent == ENTITYNUM_NONE ) + valid_entity = true; + } + + if ( valid_entity ) + { + // Check to see if the enemy is closest to us + Vector delta = ( ent->centroid ) - origin; + + dist = delta.length(); + + if ( dist < bestdist ) + { + delta.normalize(); + + // It's close, now check to see if it's in our FOV. + dot = DotProduct( forward, delta ); + + if ( dot > fovdot ) + { + trace_t trace; + // Do a trace to see if we can get to it + trace = G_Trace( origin, + vec_zero, + vec_zero, + ent->centroid, + NULL, + MASK_OPAQUE, + false, + "FindClosestEntityInRadius" ); + + if ( ( trace.ent && trace.entityNum == ent->entnum ) || ( trace.fraction == 1 ) ) + { + // dir = delta; + bestent = ent; + bestdist = dist; + } + } + } + } + ent = findradius( ent, origin, maxdist ); + } + return bestent; + } + +static Entity *FindHeadTarget + ( + Vector origin, + Vector forward, + float fov, + float maxdist + ) + + { + float dist,dot; + float fovdot = cos( fov * 0.5 * M_PI / 180.0 ); + Entity *ent; + Entity *bestent=NULL; + int bestdist = 999999; + qboolean valid_entity; + qboolean higher_priority; + + // Find closest enemy in radius + ent = findradius( NULL, origin, maxdist ); + + while( ent ) + { + valid_entity = false; + + if ( ent->isSubclassOf( Actor ) && !ent->deadflag ) + { + Actor *actor = ( Actor * )ent; + + if ( actor->actortype == IS_ENEMY && actor->CanTarget() && !actor->bindmaster && actor->edict->s.parent == ENTITYNUM_NONE ) + valid_entity = true; + } + + if ( !valid_entity ) + { + if ( ent->look_at_me ) + { + if ( ent->isSubclassOf( Item ) ) + { + Item *item = (Item *)ent; + + if ( !item->GetOwner() ) + valid_entity = true; + + if ( item->has_been_looked_at ) + valid_entity = false; + } + else + valid_entity = true; + } + } + + if ( valid_entity ) + { + Actor *bestact = NULL; + Actor *act = NULL; + + // Check to see if the enemy is closest to us + Vector delta = ( ent->centroid ) - origin; + + dist = delta.length(); + + higher_priority = false; + + if ( bestent && bestent->isSubclassOf( Actor ) ) + bestact = (Actor *)bestent; + + if ( ent->isSubclassOf( Actor ) ) + act = (Actor *)ent; + + if ( !ent->isSubclassOf( Actor ) && ( dist > 650 ) ) + higher_priority = false; + else if ( !bestent ) + higher_priority = true; + else if ( ent->isSubclassOf( Actor ) && act->actortype == IS_ENEMY && + bestent->isSubclassOf( Actor ) && bestact->actortype == IS_ENEMY && dist < bestdist ) + higher_priority = true; + else if ( bestent->isSubclassOf( Actor ) && bestact->actortype == IS_ENEMY && + ( bestdist < dist || bestdist < 750 ) ) + higher_priority = false; + else if ( ent->isSubclassOf( Actor ) && act->actortype == IS_ENEMY && + ( dist < bestdist || dist < 750 ) ) + higher_priority = true; + else if ( ent->isSubclassOf( Item ) && bestent->isSubclassOf( Item ) && dist < bestdist ) + higher_priority = true; + else if ( bestent->isSubclassOf( Item ) && ( bestdist < dist || bestdist < 250 ) ) + higher_priority = false; + else if ( ent->isSubclassOf( Item ) && ( dist < bestdist || dist < 250 ) ) + higher_priority = true; + else if ( dist < bestdist ) + higher_priority = true; + + if ( higher_priority ) + { + delta.normalize(); + + // It's close, now check to see if it's in our FOV. Use the v_angle to determine it + dot = DotProduct( forward, delta ); + + if ( dot > fovdot ) + { + trace_t trace; + // Do a trace to see if we can get to it + trace = G_Trace( origin, + vec_zero, + vec_zero, + ent->centroid, + NULL, + MASK_OPAQUE, + false, + "FindClosestEntityInRadius" ); + + if ( ( trace.ent && trace.entityNum == ent->entnum ) || ( trace.fraction == 1 ) ) + { + // dir = delta; + bestent = ent; + bestdist = dist; + } + } + } + } + ent = findradius( ent, origin, maxdist ); + } + return bestent; + } + +Entity *Player::FindEnemyInFOVFromTagWithOffset + ( + float fov, + float maxdist, + str tagname, + Vector offset + ) + + { + vec3_t mat[3]; + orientation_t tag_or; + + GetTagPositionAndOrientation( gi.Tag_NumForName( edict->s.modelindex, tagname ), &tag_or ); + + AnglesToAxis( torsoAngles, mat ); + + //G_DebugLine( tag_or.origin + offset, tag_or.origin + offset + Vector( mat[0] ) * 100, 1,1,1,1 ); + + return FindClosestEntityInRadius( tag_or.origin + offset, mat[0], fov, maxdist ); + } + +//==================== +//FindEnemyInFOV +//Returns entity if an enemy is in the player's FOV +//==================== +Entity *Player::FindEnemyInFOV + ( + float fov, + float maxdist + ) + + { + vec3_t mat[3]; + + AnglesToAxis( headAngles, mat ); + return FindClosestEntityInRadius( this->centroid, mat[0], fov, maxdist ); + } + +//==================== +//AdjustAnglesForAttack +//Adjust the player angles toward an enemy if they are attacking it +//==================== +void Player::AdjustAnglesForAttack + ( + void + ) + + { + /* + Vector dir; + Vector newAngles; + Vector moveToAngles; + + if ( FindEnemyInFOV( 180, 1000 ) ) + { + G_DrawCoordSystem( origin, dir,dir,dir,100 ); + + if ( buttons & ( BUTTON_ATTACKRIGHT|BUTTON_ATTACKLEFT ) ) + { + // Adjust for a percentage of the total + float deltayaw = AngleSubtract( dir.toYaw(), v_angle[YAW] ); + + if ( fabs( deltayaw ) > 5 ) + { + v_angle[YAW] += deltayaw * 0.1f; + client->ps.delta_angles[YAW] += ANGLE2SHORT( deltayaw * 0.1f ); + } + } + } + */ + } + +//==================== +//ActivateNewWeapon +//==================== +void Player::ActivateNewWeapon + ( + Event *ev + ) + + { + // Change the weapon to the currently active weapon as specified by useWeapon + ChangeWeapon( newActiveWeapon.weapon, newActiveWeapon.hand ); + + // Check for water and ammo + UpdateWeapons(); + + // Clear out the newActiveWeapon + ClearNewActiveWeapon(); + + // Clear out the holstered weapons + holsteredWeapons[WEAPON_LEFT] = NULL; + holsteredWeapons[WEAPON_RIGHT] = NULL; + holsteredWeapons[WEAPON_DUAL] = NULL; + + // let the player know that our weapons are not holstered + WeaponsNotHolstered(); + } + +//==================== +//DeactivateWeapon +//==================== +void Player::DeactivateWeapon + ( + Event *ev + ) + + { + // Deactivate the weapon + weaponhand_t hand; + str side; + + side = ev->GetString( 1 ); + + hand = WeaponHandNameToNum( side ); + + if ( hand == WEAPON_ERROR ) + return; + + Sentient::DeactivateWeapon( hand ); + + if ( !GetActiveWeapon( WEAPON_LEFT ) && !GetActiveWeapon( WEAPON_RIGHT ) && !GetActiveWeapon( WEAPON_DUAL ) ) + { + // let the player know our weapons are holstered + WeaponsHolstered(); + } + } + +//==================== +//PutawayWeapon +//==================== +void Player::PutawayWeapon + ( + Event *ev + ) + + { + Weapon * weapon; + weaponhand_t hand; + str side; + + side = ev->GetString( 1 ); + + hand = WeaponHandNameToNum( side ); + + if ( hand == WEAPON_ERROR ) + return; + + weapon = GetActiveWeapon( hand ); + + if ( weapon->isSubclassOf( Weapon ) ) + { + weapon->RandomAnimate( "putaway" ); + } + } + + +//==================== +//useWeapon +//==================== +void Player::useWeapon + ( + const char *weaponname, + weaponhand_t hand + ) + + { + Weapon *weapon; + + weapon = ( Weapon * )FindItem( weaponname ); + + // Check to see if player has the weapon + if ( !weapon ) + { + warning( "Player::useWeapon", "Player does not have weapon %s", weaponname ); + return; + } + + useWeapon( weapon, hand ); + } + +void Player::useWeapon + ( + Weapon *weapon, + weaponhand_t hand + ) + + { + Weapon * activeWeapon; + + if ( !weapon ) + { + warning( "Player::useWeapon", "Null weapon used.\n" ); + return; + } + + // Check to see if we are already in the process of using a new weapon. + if ( newActiveWeapon.weapon ) + { + return; + } + + // Check to see if weapon has ammo and if useNoAmmo is allowed + if ( !weapon->HasAmmo( FIRE_PRIMARY ) && !weapon->HasAmmo( FIRE_ALTERNATE ) && !weapon->GetUseNoAmmo() ) + { + Sound( "snd_noammo" ); + return; + } + + // Check to see if the hand is allowed to have that weapon + + // WEAPON_ANY can be used in WEAPON_LEFT or WEAPON_RIGHT but not as a WEAPON_DUAL, so check for that first + if ( ( hand == WEAPON_DUAL ) && ( weapon->GetHand() != hand ) ) + { + warning( "Player::useWeapon", "Weapon %s is not allowed in %s", weapon->getName().c_str(), WeaponHandNumToName( hand ) ); + return; + } + else if ( ( weapon->GetHand() != WEAPON_ANY ) && ( weapon->GetHand() != hand ) ) + { + warning( "Player::useWeapon", "Weapon %s is not allowed in %s", weapon->getName().c_str(), WeaponHandNumToName( hand ) ); + return; + } + + // If the weapon we are wielding is a WEAPON_DUAL, then put away the left and right ones + if ( weapon->GetHand() == WEAPON_DUAL ) + { + activeWeapon = GetActiveWeapon( WEAPON_LEFT ); + if ( activeWeapon ) + activeWeapon->PutAway(); + activeWeapon = GetActiveWeapon( WEAPON_RIGHT ); + if ( activeWeapon ) + activeWeapon->PutAway(); + } + + // Check to see if a WEAPON_DUAL is being used and put it away if needed + activeWeapon = GetActiveWeapon( WEAPON_DUAL ); + + if ( activeWeapon ) + { + activeWeapon->PutAway(); + // we just want to put the dual handed weapon away + if ( activeWeapon == weapon ) + { + return; + } + } + + // Now get the active weapon in the specified hand + activeWeapon = GetActiveWeapon( hand ); + + // Check to see if this weapon is already being used in this hand and just put it away and return + if ( activeWeapon == weapon ) + { + // Set the putaway flag to true. The state machine will then play the correct animation to put away the active weapon + activeWeapon->PutAway(); + return; + } + + // If activeWeapon is set, and it's not == weapon then put away this weapon + if ( activeWeapon ) + { + // Set the putaway flag to true. The state machine will then play the correct animation to put away the active weapon + activeWeapon->PutAway(); + } + + // Check to see if this weapon is being used in a different hand and put it away as well (if it's in a different hand) + if ( IsActiveWeapon( weapon ) ) + { + weapon->PutAway(); + } + + // Set the newActiveWeapon as the weapon specified, the state machine will play the appropriate animation and + // trigger when to attach it to the player model. + newActiveWeapon.weapon = weapon; + newActiveWeapon.hand = hand; + } + +//==================== +//SwordAttackEvent +//==================== +void Player::SwordAttackEvent + ( + Event *ev + ) + + { + Weapon *weapon; + weaponhand_t hand; + + Vector pos, forward, end; + + // Project a ray from the centroid out + end = this->centroid + Vector( orientation[0] ) * 96; + + hand = WeaponHandNameToNum( ev->GetString( 1 ) ); + + if ( hand == WEAPON_ERROR ) + return; + + weapon = GetActiveWeapon( hand ); + + if ( weapon && weapon->isSubclassOf( Sword ) ) + { + Sword *sword = ( Sword * )weapon; + + SwordAttack( this->centroid, end, sword, this, damage_multiplier ); + } + } + +//==================== +//SwipeOn +//==================== +void Player::SwipeOn + ( + Event *ev + ) + + { + Weapon *weapon; + weaponhand_t hand; + int water_required=0; + + hand = WeaponHandNameToNum( ev->GetString( 1 ) ); + + if ( hand == WEAPON_ERROR ) + return; + + weapon = GetActiveWeapon( hand ); + if ( weapon && weapon->isSubclassOf( Sword ) ) + { + Sword *sword = ( Sword * )weapon; + + water_required = sword->GetWaterRequired(); + } + + if ( weapon && ( water_power >= water_required ) ) + { + weapon->RandomAnimate( "swipeon", NULL ); + } + } + +//==================== +//SwipeOff +//==================== +void Player::SwipeOff + ( + Event *ev + ) + + { + Weapon *weapon; + weaponhand_t hand; + int water_required=0; + + hand = WeaponHandNameToNum( ev->GetString( 1 ) ); + + if ( hand == WEAPON_ERROR ) + return; + + weapon = GetActiveWeapon( hand ); + if ( weapon && weapon->isSubclassOf( Sword ) ) + { + Sword *sword = ( Sword * )weapon; + + water_required = sword->GetWaterRequired(); + } + + if ( weapon && ( water_power >= water_required ) ) + { + weapon->RandomAnimate( "swipeoff", NULL ); + } + } + +//==================== +//ActivateShield +//==================== +void Player::ActivateShield + ( + Event *ev + ) + + { + shield_active = qtrue; + } + +//==================== +//DeactivateShield +//==================== +void Player::DeactivateShield + ( + Event *ev + ) + + { + shield_active = qfalse; + } + +//==================== +//ShieldActive +//==================== +qboolean Player::ShieldActive + ( + void + ) + + { + return shield_active; + } + +//==================== +//LargeShieldActive +//==================== +qboolean Player::LargeShieldActive + ( + void + ) + + { + Weapon *weapon; + qboolean large_shield_active=false; + + weapon = GetActiveWeapon( WEAPON_LEFT ); + if ( weapon && !str::icmp( weapon->item_name, "LargeShield" ) ) + large_shield_active = true; + + return shield_active && large_shield_active; + } + + + +void Player::AcquireHeadTarget + ( + void + ) + + { + vec3_t mat[3]; + Entity *new_head_target; + Entity *ent; + Item *item; + + // Find a good target + + if ( left_arm_target ) + head_target = left_arm_target; + else if ( right_arm_target ) + head_target = right_arm_target; + else + { + AnglesToAxis( headAngles, mat ); + + // Make sure not to look at items too long + + if ( look_at_time <= level.time && head_target && head_target->isSubclassOf( Item ) ) + { + item = (Item *)(Entity *)head_target; + item->has_been_looked_at = true; + } + + // Get the new head target + new_head_target = FindHeadTarget( this->centroid, mat[0], 160, 1000 ); + + if ( !new_head_target ) + { + head_target = NULL; + return; + } + + if ( new_head_target != head_target ) + { + // If we were looking at an item and are not now, mark it as has been looked at + + if ( head_target && head_target->isSubclassOf( Item ) ) + { + item = (Item *)(Entity *)head_target; + item->has_been_looked_at = true; + } + + // Set up new head target + + head_target = new_head_target; + + look_at_time = level.time + 5; + + // Mark items near this one as looked at + + if ( head_target && head_target->isSubclassOf( Item ) ) + { + ent = findradius( NULL, head_target->origin, 50 ); + + while( ent ) + { + if ( ent != head_target && ent->isSubclassOf( Item ) ) + { + item = (Item *)ent; + item->has_been_looked_at = true; + } + + ent = findradius( ent, head_target->origin, 50 ); + } + } + } + } + } diff --git a/source/source/fgame/player_util.cpp b/source/source/fgame/player_util.cpp new file mode 100644 index 0000000..f2424c4 --- /dev/null +++ b/source/source/fgame/player_util.cpp @@ -0,0 +1,687 @@ +//----------------------------------------------------------------------------- +// +// $Logfile:: /fakk2_code/fakk2_new/fgame/player_util.cpp $ +// $Revision:: 20 $ +// $Author:: Aldie $ +// $Date:: 7/29/00 11:23p $ +// +// Copyright (C) 1998 by Ritual Entertainment, Inc. +// All rights reserved. +// +// This source may not be distributed and/or modified without +// expressly written permission by Ritual Entertainment, Inc. +// +// $Log:: /fakk2_code/fakk2_new/fgame/player_util.cpp $ +// +// 20 7/29/00 11:23p Aldie +// Changed to clearfade in SkipCinematic +// +// 19 7/29/00 4:00p Aldie +// Added autofadein for skipping cinematics +// +// 18 7/17/00 9:51p Aldie +// Added skipcinematic command which is access by pressing the ESC key +// +// 17 7/17/00 2:56p Steven +// Fixed a crash with the logfile stuff. +// +// 16 7/17/00 12:36a Markd +// Made sure to close the log file when exiting a level or shutting down a +// server +// +// 15 7/16/00 2:09p Aldie +// Changed some of the player logging +// +// 14 7/14/00 8:21p Aldie +// Added logstats +// +// 13 7/01/00 6:37p Markd +// added areanum to whatis +// +// 12 6/17/00 3:48p Aldie +// +// 11 2/08/00 6:24p Markd +// Added angles printout to whatis +// +// 10 1/29/00 3:35p Markd +// Added contents to whatis command +// +// 9 1/26/00 3:33p Aldie +// Change Amount to getAmount. Added some 'listinventory' command. Added give +// all cheat to execute the script in global/giveall.txt +// +// 8 1/15/00 3:57p Markd +// Eliminated multiple "angle" events and replaced them with EV_SetAngle +// +// 7 1/14/00 5:07p Markd +// Removed surface num, tri_num and damage_multiplier from multiple functions +// and events +// +// 6 1/11/00 5:53p Steven +// Passed a char * into error function instead of a str. +// +// 5 1/07/00 8:12p Jimdose +// cleaning up unused code +// +// 4 1/05/00 7:25p Jimdose +// made angle functions all use the same coordinate system +// AngleVectors now returns left instead of right +// no longer need to invert pitch +// +// 3 12/17/99 6:35p Jimdose +// changed spawnarg code +// added Level class for spawning and map control +// got rid of unused or superflous variables +// changed setjmp/longjmp calls to try/throw/catch exception handling +// +// 2 12/08/99 7:00p Aldie +// Busting up player a bit and wrote some head tracking code +// +// DESCRIPTION: +// This file is used to hold the utility functions that are issued by the +// player at the console. Most of these are developer commands + +#include "player.h" +#include "object.h" + +//==================== +//Player::ActorInfo +//==================== +void Player::ActorInfo + ( + Event *ev + ) + + { + int num; + Entity *ent; + + if ( ev->NumArgs() != 1 ) + { + gi.SendServerCommand( edict-g_entities, "print \"Usage: actorinfo \n\"" ); + return; + } + + num = ev->GetInteger( 1 ); + if ( ( num < 0 ) || ( num >= globals.max_entities ) ) + { + gi.SendServerCommand( edict-g_entities, "print \"Value out of range. Possible values range from 0 to %d.\n\"", globals.max_entities ); + return; + } + + ent = G_GetEntity( num ); + if ( !ent || !ent->isSubclassOf( Actor ) ) + { + gi.SendServerCommand( edict-g_entities, "print \"Entity not an Actor.\n\"" ); + } + else + { + ( ( Actor * )ent )->ShowInfo(); + } + } + +//==================== +//Player::WhatIs +//==================== +void Player::WhatIs + ( + Event *ev + ) + + { + int num; + Entity *ent; + + if ( ev->NumArgs() != 1 ) + { + gi.SendServerCommand( edict-g_entities, "print \"Usage: whatis \n\"" ); + return; + } + + num = ev->GetInteger( 1 ); + if ( ( num < 0 ) || ( num >= globals.max_entities ) ) + { + gi.SendServerCommand( edict-g_entities, "print \"Value out of range. Possible values range from 0 to %d.\n\"", globals.max_entities ); + return; + } + + ent = G_GetEntity( num ); + if ( !ent ) + { + gi.SendServerCommand( edict-g_entities, "print \"Entity not in use.\n\"", globals.max_entities ); + } + else + { + const char * animname; + + animname = NULL; + if ( gi.IsModel( ent->edict->s.modelindex ) ) + { + animname = gi.Anim_NameForNum( ent->edict->s.modelindex, ent->edict->s.anim & ANIM_MASK ); + } + + if ( !animname ) + { + animname = "( N/A )"; + } + + gi.SendServerCommand( edict-g_entities, "print \"" + "Entity # : %d\n" + "Class ID : %s\n" + "Classname : %s\n" + "Targetname : %s\n" + "Modelname : %s\n" + "Animname : %s\n" + "Origin : ( %f, %f, %f )\n" + "Angles : ( %f, %f, %f )\n" + "Bounds : Mins( %.2f, %.2f, %.2f ) Maxs( %.2f, %.2f, %.2f )\n" + "Velocity : ( %f, %f, %f )\n" + "SVFLAGS : %x\n" + "Movetype : %i\n" + "Solidtype : %i\n" + "Contents : %x\n" + "Areanum : %i\n" + "Parent : %i\n" + "Health : %.1f\n" + "Max Health : %.1f\n" + "Edict Owner: %i\n\"", + num, + ent->getClassID(), + ent->getClassname(), + ent->TargetName(), + ent->model.c_str(), + animname, + ent->origin.x, ent->origin.y, ent->origin.z, + ent->angles.x, ent->angles.y, ent->angles.z, + ent->mins.x, ent->mins.y, ent->mins.z, ent->maxs.x, ent->maxs.y, ent->maxs.z, + ent->velocity.x, ent->velocity.y, ent->velocity.z, + ent->edict->svflags, + ent->movetype, + ent->edict->solid, + ent->edict->contents, + ent->edict->areanum, + ent->edict->s.parent, + ent->health, + ent->max_health, + ent->edict->ownerNum + ); + } + } + +//==================== +//Player::KillEnt +//==================== +void Player::KillEnt + ( + Event * ev + ) + + { + int num; + Entity *ent; + + if ( ev->NumArgs() != 1 ) + { + gi.SendServerCommand( edict-g_entities, "print \"Usage: killent \n\"" ); + return; + } + + num = ev->GetInteger( 1 ); + if ( ( num < 0 ) || ( num >= globals.max_entities ) ) + { + gi.SendServerCommand( edict-g_entities, "print \"Value out of range. Possible values range from 0 to %d.\n\"", globals.max_entities ); + return; + } + + ent = G_GetEntity( num ); + ent->Damage( world, world, ent->max_health + 25, origin, vec_zero, vec_zero, 0, 0, 0 ); + } + +//==================== +//Player::RemoveEnt +//==================== +void Player::RemoveEnt + ( + Event * ev + ) + + { + int num; + Entity *ent; + + if ( ev->NumArgs() != 1 ) + { + gi.SendServerCommand( edict-g_entities, "print \"Usage: removeent \n\"" ); + return; + } + + num = ev->GetInteger( 1 ); + if ( ( num < 0 ) || ( num >= globals.max_entities ) ) + { + gi.SendServerCommand( edict-g_entities, "print \"Value out of range. Possible values range from 0 to %d.\n\"", globals.max_entities ); + return; + } + + ent = G_GetEntity( num ); + ent->PostEvent( Event( EV_Remove ), 0 ); + } + +//==================== +//Player::KillClass +//==================== +void Player::KillClass + ( + Event * ev + ) + + { + int except; + str classname; + gentity_t * from; + Entity *ent; + + if ( ev->NumArgs() < 1 ) + { + gi.SendServerCommand( edict-g_entities, "print \"Usage: killclass [except entity number]\n\"" ); + return; + } + + classname = ev->GetString( 1 ); + + except = 0; + if ( ev->NumArgs() == 2 ) + { + except = ev->GetInteger( 1 ); + } + + for ( from = this->edict + 1; from < &g_entities[ globals.num_entities ]; from++ ) + { + if ( !from->inuse ) + { + continue; + } + + assert( from->entity ); + + ent = from->entity; + + if ( ent->entnum == except ) + { + continue; + } + + if ( ent->inheritsFrom( classname.c_str() ) ) + { + ent->Damage( world, world, ent->max_health + 25, origin, vec_zero, vec_zero, 0, 0, 0 ); + } + } + } + +//==================== +//Player::RemoveClass +//==================== +void Player::RemoveClass + ( + Event * ev + ) + + { + int except; + str classname; + gentity_t * from; + Entity *ent; + + if ( ev->NumArgs() < 1 ) + { + gi.SendServerCommand( edict-g_entities, "print \"Usage: removeclass [except entity number]\n\"" ); + return; + } + + classname = ev->GetString( 1 ); + + except = 0; + if ( ev->NumArgs() == 2 ) + { + except = ev->GetInteger( 1 ); + } + + for ( from = this->edict + 1; from < &g_entities[ globals.num_entities ]; from++ ) + { + if ( !from->inuse ) + { + continue; + } + + assert( from->entity ); + + ent = from->entity; + + if ( ent->entnum == except ) + continue; + + if ( ent->inheritsFrom( classname.c_str() ) ) + { + ent->PostEvent( Event( EV_Remove ), 0 ); + } + } + } + +//==================== +//Player::TestThread +//==================== +void Player::TestThread + ( + Event *ev + ) + + { + const char *scriptfile; + const char *label = NULL; + ScriptThread * thread; + + if ( ev->NumArgs() < 1 ) + { + gi.SendServerCommand( edict-g_entities, "print \"Syntax: testthread scriptfile