/* ----------------------------------------------------------------------------- This source file is part of OpenSpace3D For the latest info, see https://www.openspace3d.com Copyright (c) 2012 I-maginer This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA, or go to https://www.gnu.org/copyleft/lesser.txt ----------------------------------------------------------------------------- */ /* Authors: Bastien Bourineau */ /* Last update: 01/03/2024 */ /* Version: 1.0 */ //TODO fallback on last anim after hit ? //Chararacter damage ? //Chararacter kill ? //Pursuit reach attack speech ? //Action to stop/enable pursuit struct TanimCrowd = [ ACR_source : SO3_OBJECT, ACR_inipos : [[F F F] [F F F F]], ACR_wAnims : [[SO3_ANIM F] r1], ACR_rAnims : [[SO3_ANIM F] r1], ACR_iAnims : [SO3_ANIM r1], ACR_jAnims : [SO3_ANIM r1], ACR_hAnims : [SO3_ANIM r1], ACR_gAnims : [SO3_ANIM r1], ACR_prevAnims : [SO3_ANIM r1], ACR_aCurrent : SO3_ANIM, ACR_aTarget : SO3_ANIM, ACR_bState : I, ACR_bRun : I, ACR_fCoef : F, ACR_iStopTime : I, ACR_iLastUpdate : I, ACR_iChase : I, ACR_bHit : I, ACR_iTick : I ] mkanimCrowd;; struct TobjCrowd = [ OBCR_inst : PInstance, OBCR_iNum : I, OBCR_h3d : SO3_OBJECT, OBCR_iSrcMode : I, OBCR_iMindex : I, OBCR_lMaterials : [SO3_MATERIAL r1], OBCR_bChaseOnDist : I, OBCR_target : SO3_OBJECT, OBCR_iTargetMode : I, OBCR_fChaseDist : F, OBCR_bRndPose : I, OBCR_bRndStop : I, OBCR_bStopOnHit : I, OBCR_lInstances : [[SO3_OBJECT TanimCrowd] r1], OBCR_vDirection : [F F F], OBCR_fRadius : F, OBCR_fHeight : F, OBCR_fWspeed : F, OBCR_fRspeed : F, OBCR_fRndMinSpeed : F, OBCR_fRndMaxSpeed : F, OBCR_anims : TanimCrowd, OBCR_instName : S, OBCR_fSwitchSpeed : F, OBCR_bChased : I, OBCR_iTick : I, OBCR_bLoaded : I, OBCR_bSpeedEvent : I ] mkobjCrowd;; proto applyRandomRun = fun [TobjCrowd TanimCrowd] I;; proto applyRandomGoal = fun [TobjCrowd TanimCrowd] I;; proto applyRandomIdle = fun [TobjCrowd TanimCrowd] I;; fun isAnimInList(l, anim)= if (l == nil) then 0 else let l -> [elt next] in if (elt == anim) then 1 else isAnimInList tl l anim;; fun cbObjStop(inst, from, action, param, reply, obstr)= SO3ObjectStopCharacter obstr.OBCR_h3d; set obstr.OBCR_anims.ACR_iChase = 0; let obstr.OBCR_lInstances -> l in while (l != nil) do ( let hd l -> [obj apfstr] in ( set apfstr.ACR_iChase = 0; SO3ObjectStopCharacter obj; ); set l = tl l; ); 0;; fun cbObjResume(inst, from, action, param, reply, obstr)= //Force update to the current object position SO3ObjectSetPosition obstr.OBCR_h3d SO3ObjectGetPosition obstr.OBCR_h3d; SO3ObjectResumeCharacter obstr.OBCR_h3d; set obstr.OBCR_anims.ACR_iStopTime = 0; let obstr.OBCR_lInstances -> l in while (l != nil) do ( let hd l -> [obj apfstr] in ( SO3ObjectSetPosition obj SO3ObjectGetPosition obj; SO3ObjectResumeCharacter obj; set apfstr.ACR_iStopTime = 0; ); set l = tl l; ); 0;; fun getViewDir(ovec, tvec, oang, axis, axisstate)= let ovec -> [vx vy vz] in let tvec -> [dx dy dz] in let normalizeVectorF (subVectorF [dx dy dz] ovec) -> dir in let normalizeVectorF (SO3MathsQuatGetDirection oang axis) -> src in let SO3MathsQuatToEulerPYR (SO3MathsGetRotationTo src dir) -> [pitch yaw roll] in let if ((1.0 +. dotVectorF src dir) <. 0.0001) then PIf *. 2.0 else yaw -> yaw in let axisstate -> [ex ey ez] in let multiplyVectorF [pitch yaw roll] [ex ey ez] -> rotaxis in let SO3MathsQuatAdd SO3MathsEulerPYRToQuat rotaxis oang -> nquat in ( nquat; );; fun characterUpdate(obstr, apfstr, dt)= let apfstr.ACR_source -> obj in ( if (_tickcount - apfstr.ACR_iLastUpdate) < 33 then nil else ( set apfstr.ACR_iLastUpdate = _tickcount; if (!obstr.OBCR_bRndPose || apfstr.ACR_iStopTime == 0) then nil else ( let 3000 + (mod rand 10000) -> tm in if ((_tickcount - apfstr.ACR_iStopTime) < tm) then nil else ( SO3ObjectSetPosition obj SO3ObjectGetPosition obj; SO3ObjectResumeCharacter obj; set apfstr.ACR_iStopTime = 0; set apfstr.ACR_bHit = 0; ); ); //Chase if (!obstr.OBCR_bChaseOnDist || (obstr.OBCR_target == nil) || apfstr.ACR_bHit) then nil else ( let if (obstr.OBCR_iTargetMode != 0) then ( let V3DgetDefaultCamera c3dXsession -> curcamera in V3DgetCameraByType c3dXsession curcamera obstr.OBCR_iTargetMode; ) else obstr.OBCR_target -> target in let SO3ObjectGetGlobalPosition obj -> [ox oy oz] in let SO3ObjectGetGlobalPosition target -> [cx cy cz] in let sqrt ((sqr(cx -. ox)) +. (sqr(cy -. oy)) +. (sqr(cz -. oz))) -> cdist in let cdist <=. (obstr.OBCR_fRadius *. 3.0) -> neardist in let (cdist <. obstr.OBCR_fChaseDist) && !neardist -> indist in let cdist <. (obstr.OBCR_fChaseDist *. 2.0) -> pursuitdist in let (apfstr.ACR_iChase && (cdist >. obstr.OBCR_fChaseDist *. 2.0)) -> outdist in //Start or continue chase if ((!apfstr.ACR_iChase && indist) || (apfstr.ACR_iChase && pursuitdist)) then ( //Force update to the current object position /* if (apfstr.ACR_iStopTime == 0) then nil else ( SO3ObjectSetPosition obj SO3ObjectGetPosition obj; set apfstr.ACR_iStopTime = 0; ); */ if (apfstr.ACR_iChase || !indist) then nil else ( set obstr.OBCR_bChased = obstr.OBCR_bChased + 1; if (obstr.OBCR_bChased > 1) then nil else SendPluginEvent obstr.OBCR_inst "Chase in" nil nil; ); if (neardist && (apfstr.ACR_iChase == 1)) then ( set apfstr.ACR_iChase = 2; set apfstr.ACR_bRun = 0; SO3ObjectStopCharacter obj; applyRandomGoal obstr apfstr; SendPluginEvent obstr.OBCR_inst "Chase catched" nil nil; //addLogMessage "fight"; 0; ) else if (!neardist && ((_tickcount - apfstr.ACR_iTick) > 200)) then ( SO3ObjectSetCharacterSpeed obj obstr.OBCR_fRspeed; SO3ObjectSetCharacterDestination obj [cx cy cz] if (cdist <. (obstr.OBCR_fChaseDist *. 0.5)) then 1 else 0; set apfstr.ACR_iChase = 1; set apfstr.ACR_bRun = 1; applyRandomRun obstr apfstr; set apfstr.ACR_iTick = _tickcount; //addLogMessage "course"; 0; ) else if (neardist) then ( let getViewDir [ox oy oz] [cx cy cz] (SO3ObjectGetGlobalOrientation obj) obstr.OBCR_vDirection [0.0 1.0 0.0] -> dirquat in SO3ObjectSetGlobalOrientation obj dirquat; let SO3SceneNodeGetBody obj -> body in if (body == nil) then nil else SO3BodySetOmega body [0.0 0.0 0.0]; ) else nil; ) // Stop chase else if (outdist) then ( set apfstr.ACR_iChase = 0; set apfstr.ACR_iStopTime = _tickcount; applyRandomIdle obstr apfstr; SO3ObjectStopCharacter obj; set obstr.OBCR_bChased = obstr.OBCR_bChased - 1; if (obstr.OBCR_bChased > 0) then nil else SendPluginEvent obstr.OBCR_inst "Chase out" nil nil; //addLogMessage "abandon"; ) else nil; ); ); //Animation transition let obstr.OBCR_fSwitchSpeed -> speed in let apfstr.ACR_aCurrent -> canim in ( if ((apfstr.ACR_aTarget == nil) || (apfstr.ACR_aTarget == apfstr.ACR_aCurrent)) then nil else ( let SO3AnimationGetWeight apfstr.ACR_aCurrent -> weight1 in let SO3AnimationGetWeight apfstr.ACR_aTarget -> weight2 in ( let apfstr.ACR_prevAnims -> lanims in while (lanims != nil) do ( let hd lanims -> oanim in let SO3AnimationGetWeight oanim -> oweight in ( if (oweight == 0.0) then nil else let if (speed == 0.0) then 0.0 else oweight -. (dt /. speed) -> noweight in ( SO3AnimationSetWeight oanim (SO3MathsClampValue noweight 0.0 1.0); if (!SO3AnimationGetEnable oanim) || (noweight >. 0.0) then nil else ( SO3AnimationSetTimePosition oanim SO3AnimationGetLength oanim; SO3AnimationSetPause oanim 1; set apfstr.ACR_prevAnims = remove_from_list apfstr.ACR_prevAnims oanim; ); ); ); set lanims = tl lanims; ); if (weight1 == 0.0) || (apfstr.ACR_aTarget == nil) then nil else let if (speed == 0.0) then 0.0 else weight1 -. (dt /. speed) -> nweight in ( SO3AnimationSetWeight apfstr.ACR_aCurrent (SO3MathsClampValue nweight 0.0 1.0); if (!SO3AnimationGetEnable apfstr.ACR_aCurrent) || (nweight >. 0.0) then nil else ( SO3AnimationSetTimePosition apfstr.ACR_aCurrent SO3AnimationGetLength apfstr.ACR_aCurrent; SO3AnimationSetPause apfstr.ACR_aCurrent 1; ); ); if (weight2 >=. 1.0) then nil else let if (speed == 0.0) then 1.0 else weight2 +. (dt /. speed) -> nweight in ( SO3AnimationSetWeight apfstr.ACR_aTarget (SO3MathsClampValue nweight 0.0 1.0); ); let (weight1 <=. 0.0) && (weight2 >=. 1.0) && apfstr.ACR_prevAnims == nil -> end in if !end then nil else ( set apfstr.ACR_aCurrent = apfstr.ACR_aTarget; set apfstr.ACR_aTarget = nil; ); ); ); ); ); 0;; fun getAnimTransition(obstr, dt)= characterUpdate obstr obstr.OBCR_anims dt; if (!obstr.OBCR_bSpeedEvent) then nil else let SO3ObjectGetCharacterSpeed obstr.OBCR_h3d -> speed in SendPluginEvent obstr.OBCR_inst "Speed" ftoa speed nil; let obstr.OBCR_lInstances -> l in while (l != nil) do ( let hd l -> [obj apfstr] in ( characterUpdate obstr apfstr dt; if (!apfstr.ACR_bState) then nil else let SO3ObjectGetCharacterSpeed obj -> speed in let if (apfstr.ACR_aTarget == nil) then apfstr.ACR_aCurrent else apfstr.ACR_aTarget -> wanim in SO3AnimationSetSpeed wanim speed *. apfstr.ACR_fCoef; ); set l = tl l; ); 0;; fun cbPrerenderPhysic(inst, sessionstr, etime, obstr)= set obstr.OBCR_iTick = obstr.OBCR_iTick + etime; let (1000000 / SO3WorldGetFPS sessionstr.V3D_session) -> phystime in if ((V3DphysGetState c3dXsession) && (obstr.OBCR_iTick < phystime)) then nil else ( let itof (SO3WorldGetFPS sessionstr.V3D_session) -> pfps in let maxf 0.000001 (itof (obstr.OBCR_iTick / 1000)) -> dt in //milliseconds getAnimTransition obstr dt; set obstr.OBCR_iTick = 0; ); 0;; fun switchAnim(obstr, apfstr, anim, rndpos)= if (anim == apfstr.ACR_aTarget) || ((apfstr.ACR_aTarget == nil) && (anim == apfstr.ACR_aCurrent)) then nil else ( // when we call a new switch before a transition end we force the target animation to weight 1.0 if (apfstr.ACR_aTarget == nil) then nil else ( if (obstr.OBCR_fSwitchSpeed == 0.0) then nil else SO3AnimationSetWeight apfstr.ACR_aTarget 1.0; if (isAnimInList apfstr.ACR_prevAnims apfstr.ACR_aCurrent) then nil else set apfstr.ACR_prevAnims = apfstr.ACR_aCurrent::apfstr.ACR_prevAnims; if (!isAnimInList apfstr.ACR_prevAnims apfstr.ACR_aTarget) then nil else set apfstr.ACR_prevAnims = remove_from_list apfstr.ACR_prevAnims apfstr.ACR_aTarget; set apfstr.ACR_aCurrent = apfstr.ACR_aTarget; ); if (!isAnimInList apfstr.ACR_prevAnims anim) then nil else set apfstr.ACR_prevAnims = remove_from_list apfstr.ACR_prevAnims anim; set apfstr.ACR_aTarget = anim; if (((SO3AnimationGetWeight apfstr.ACR_aTarget) != 1.0) || (obstr.OBCR_fSwitchSpeed == 0.0)) then nil else SO3AnimationSetWeight apfstr.ACR_aTarget 0.0; if (!rndpos) then ( SO3AnimationSetTimePosition anim 0.0; ) else ( let SO3AnimationGetLength anim -> length in let 1000.0 -> div in let absf ((itof (mod rand (ftoi (length *. div)) + 1)) /. div) -> pos in SO3AnimationSetTimePosition anim pos; ); SO3AnimationSetEnable apfstr.ACR_aTarget 1; 0; ); 0;; fun stopAllAnims(apfstr)= let apfstr.ACR_wAnims -> l in while (l != nil) do ( let hd l -> [anim _] in ( SO3AnimationSetEnable anim 0; SO3AnimationSetWeight anim 1.0; SO3AnimationSetTimePosition anim 0.0; set l = tl l; ); ); let apfstr.ACR_rAnims -> l in while (l != nil) do ( let hd l -> [anim _] in ( SO3AnimationSetEnable anim 0; SO3AnimationSetWeight anim 1.0; SO3AnimationSetTimePosition anim 0.0; set l = tl l; ); ); let apfstr.ACR_iAnims -> l in while (l != nil) do ( let hd l -> anim in ( SO3AnimationSetEnable anim 0; SO3AnimationSetWeight anim 1.0; SO3AnimationSetTimePosition anim 0.0; set l = tl l; ); ); let apfstr.ACR_jAnims -> l in while (l != nil) do ( let hd l -> anim in ( SO3AnimationSetEnable anim 0; SO3AnimationSetWeight anim 1.0; SO3AnimationSetTimePosition anim 0.0; set l = tl l; ); ); let apfstr.ACR_hAnims -> l in while (l != nil) do ( let hd l -> anim in ( SO3AnimationSetEnable anim 0; SO3AnimationSetWeight anim 1.0; SO3AnimationSetTimePosition anim 0.0; set l = tl l; ); ); let apfstr.ACR_gAnims -> l in while (l != nil) do ( let hd l -> anim in ( SO3AnimationSetEnable anim 0; SO3AnimationSetWeight anim 1.0; SO3AnimationSetTimePosition anim 0.0; set l = tl l; ); ); 0;; fun applyRandomWalk(obstr, apfstr)= let sizelist apfstr.ACR_wAnims -> nb in if (nb == 0) then nil else ( let if (nb == 1) then hd apfstr.ACR_wAnims else let (mod rand nb) -> i in nth_list apfstr.ACR_wAnims i -> [anim weight] in ( set apfstr.ACR_fCoef = weight; switchAnim obstr apfstr anim 1; ); ); 0;; fun applyRandomRun(obstr, apfstr)= let sizelist apfstr.ACR_rAnims -> nb in if (nb == 0) then ( applyRandomWalk obstr apfstr; ) else ( let if (nb == 1) then hd apfstr.ACR_rAnims else let (mod rand nb) -> i in nth_list apfstr.ACR_rAnims i -> [anim weight] in ( set apfstr.ACR_fCoef = weight; switchAnim obstr apfstr anim 1; ); 0; ); 0;; fun applyRandomIdle(obstr, apfstr)= let sizelist apfstr.ACR_iAnims -> nb in if (nb == 0) then nil else ( let if (nb == 1) then hd apfstr.ACR_iAnims else let (mod rand nb) -> i in nth_list apfstr.ACR_iAnims i -> anim in switchAnim obstr apfstr anim 1; ); 0;; fun applyRandomHit(obstr, apfstr)= let sizelist apfstr.ACR_hAnims -> nb in if (nb == 0) then nil else ( let if (nb == 1) then hd apfstr.ACR_hAnims else let (mod rand nb) -> i in nth_list apfstr.ACR_hAnims i -> anim in switchAnim obstr apfstr anim 0; ); 0;; fun applyRandomJump(obstr, apfstr)= let sizelist apfstr.ACR_jAnims -> nb in if (nb == 0) then nil else ( let if (nb == 1) then hd apfstr.ACR_jAnims else let (mod rand nb) -> i in nth_list apfstr.ACR_jAnims i -> anim in switchAnim obstr apfstr anim 0; ); 0;; fun applyRandomGoal(obstr, apfstr)= let sizelist apfstr.ACR_gAnims -> nb in if (nb == 0) then nil else ( let if (nb == 1) then hd apfstr.ACR_gAnims else let (mod rand nb) -> i in nth_list apfstr.ACR_gAnims i -> anim in switchAnim obstr apfstr anim 0; ); 0;; fun animInit(apfstr, anim)= if (apfstr.ACR_aCurrent == anim) then nil else ( let SO3AnimationGetLength anim -> length in let 1000.0 -> div in let absf ((itof (mod rand (ftoi (length *. div)) + 1)) /. div) -> pos in ( SO3AnimationSetEnable apfstr.ACR_aCurrent 0; SO3AnimationSetLoop anim 1; SO3AnimationSetTimePosition anim pos; SO3AnimationSetEnable anim 1; set apfstr.ACR_aCurrent = anim; ); ); 0;; fun applyInitRandomIdle(apfstr)= let sizelist apfstr.ACR_iAnims -> nb in if (nb == 0) then nil else ( let if (nb == 1) then hd apfstr.ACR_iAnims else let (mod rand nb) -> i in nth_list apfstr.ACR_iAnims i -> anim in animInit apfstr anim; ); 0;; fun cbCharacterState(obj, obstr, state)= let if (obj == obstr.OBCR_h3d) then 1 else 0 -> event in let if (obj == obstr.OBCR_h3d) then obstr.OBCR_anims else switch obstr.OBCR_lInstances obj -> apfstr in if (apfstr == nil) then nil else ( if (state == SO3_CHARACTER_MOVING) then ( if (!event) then nil else SendPluginEvent obstr.OBCR_inst "Moving" nil nil; set apfstr.ACR_bState = 1; let SO3ObjectGetCharacterSpeed obj -> speed in set apfstr.ACR_bRun = if (speed <. obstr.OBCR_fRspeed) then 0 else 1; if (!apfstr.ACR_bRun) then applyRandomWalk obstr apfstr else applyRandomRun obstr apfstr; ) else if (state == SO3_CHARACTER_TARGET_REACHED) then ( if (!event) then nil else SendPluginEvent obstr.OBCR_inst "Target reached" nil nil; set apfstr.ACR_bState = 0; //Random stop if (!obstr.OBCR_bRndPose || !obstr.OBCR_bRndStop || apfstr.ACR_iChase) then nil else if ((mod rand 1000) < 250) then nil else ( set apfstr.ACR_iStopTime = _tickcount; SO3ObjectStopCharacter apfstr.ACR_source; ); if (apfstr.ACR_iChase) then nil else applyRandomIdle obstr apfstr; ) else if (state == SO3_CHARACTER_JUMP) then ( if (!event) then nil else SendPluginEvent obstr.OBCR_inst "Jump" nil nil; applyRandomJump obstr apfstr; ) else ( if (!event) then nil else SendPluginEvent obstr.OBCR_inst "Stopped" nil nil; set apfstr.ACR_bState = 0; if (apfstr.ACR_bHit) then applyRandomHit obstr apfstr else if (apfstr.ACR_iChase == 2) then applyRandomGoal obstr apfstr else applyRandomIdle obstr apfstr; ); ); 0;; fun cbSetSpeed(inst, from, action, param, reply, obstr)= if (!strcmp "" (strtrim param)) || (param == nil) then nil else let atof param -> speed in ( SO3ObjectSetCharacterSpeed obstr.OBCR_h3d speed; let obstr.OBCR_lInstances -> l in while (l != nil) do ( let hd l -> [obj _] in SO3ObjectSetCharacterSpeed obj speed; set l = tl l; ); ); 0;; fun cbWalkTo(inst, from, action, param, reply, obstr, p)= let p -> [chase run] in let if param == nil then nil else V3DgetObjectByName c3dXsession param -> dstobject in let let hd strextr param -> lp in let atof hd lp -> px in let atof hd tl lp -> py in let atof hd tl tl lp -> pz in if (px != nil) && (py != nil) && (pz != nil) then [1 [px py pz]] else [0 nil] -> [isvec dvec] in let if isvec then nil else dstobject -> dstobject in let if (isvec) then dvec else SO3ObjectGetGlobalPosition dstobject -> vec in ( //Force update to the current object position if (obstr.OBCR_anims.ACR_iStopTime == 0) then nil else ( SO3ObjectSetPosition obstr.OBCR_h3d SO3ObjectGetPosition obstr.OBCR_h3d; set obstr.OBCR_anims.ACR_iStopTime = 0; ); set obstr.OBCR_anims.ACR_iChase = 0; SO3ObjectSetCharacterSpeed obstr.OBCR_h3d if (run) then obstr.OBCR_fRspeed else obstr.OBCR_fWspeed; SO3ObjectSetCharacterDestination obstr.OBCR_h3d vec chase; set obstr.OBCR_anims.ACR_bRun = run; if (!run) then applyRandomWalk obstr obstr.OBCR_anims else applyRandomRun obstr obstr.OBCR_anims; let obstr.OBCR_lInstances -> l in while (l != nil) do ( let hd l -> [obj apfstr] in ( //Force update to the current object position if (apfstr.ACR_iStopTime == 0) then nil else ( SO3ObjectSetPosition obj SO3ObjectGetPosition obj; set apfstr.ACR_iStopTime = 0; ); set apfstr.ACR_iChase = 0; SO3ObjectSetCharacterSpeed obj if (run) then obstr.OBCR_fRspeed else obstr.OBCR_fWspeed; SO3ObjectSetCharacterDestination obj vec chase; set apfstr.ACR_bRun = run; if (!run) then applyRandomWalk obstr apfstr else applyRandomRun obstr apfstr; ); set l = tl l; ); ); 0;; fun objRelease(obstr)= setPluginInstanceCbScenePreRenderPhysic obstr.OBCR_inst nil; let obstr.OBCR_anims.ACR_inipos -> [vec ang] in ( SO3ObjectSetPosition obstr.OBCR_h3d vec; SO3ObjectSetOrientation obstr.OBCR_h3d ang; obstr.OBCR_anims.ACR_wAnims ); stopAllAnims obstr.OBCR_anims; while (obstr.OBCR_lInstances != nil) do ( let hd obstr.OBCR_lInstances -> [obj _ ] in SO3ObjectDestroy obj; set obstr.OBCR_lInstances = tl obstr.OBCR_lInstances; ); 0;; fun deleteOb(inst, obstr)= SO3ObjectSetNavigationType obstr.OBCR_h3d nil; objRelease obstr; 0;; fun getDirectionFromParam(param)= if (param == 1) then [(-.1.0) 0.0 0.0] else if (param == 2) then [0.0 1.0 0.0] else if (param == 3) then [0.0 (-.1.0) 0.0] else if (param == 4) then [0.0 0.0 1.0] else if (param == 5) then [0.0 0.0 (-.1.0)] else [1.0 0.0 0.0];; fun cbImpulseHit(body, p)= let p -> [obstr obj apfstr] in ( SO3ObjectStopCharacter obj; set apfstr.ACR_iStopTime = _tickcount; set apfstr.ACR_bHit = 1; applyRandomHit obstr apfstr; SendPluginEvent obstr.OBCR_inst "Hit" nil nil; ); 0;; fun clonePhysicBody(obstr, ref, obj, apfstr)= let SO3SceneNodeGetBody ref -> refbody in if (refbody == nil) then nil else ( let SO3BodyGetShapeDefinition refbody -> [btype tolerance [radius height] size offset offsetquat] in let if (btype == SO3_TYPE_BODY_TREE) then SO3BodyCreateCollisionTree obj 1 else if (btype == SO3_TYPE_BODY_ELLIPSOID) then SO3BodyCreateEllipsoidExt obj size offset offsetquat else if (btype == SO3_TYPE_BODY_BOX) then SO3BodyCreateBoxExt obj size offset offsetquat else if (btype == SO3_TYPE_BODY_SHAPE) then SO3BodyCreateShape obj tolerance else if (btype == SO3_TYPE_BODY_CONCAVE) then SO3BodyCreateConcaveShape obj tolerance else if (btype == SO3_TYPE_BODY_CYLINDER) then SO3BodyCreateCylinderExt obj radius height offset offsetquat else if (btype == SO3_TYPE_BODY_CHAMFERCYLINDRE) then SO3BodyCreateChamferCylinderExt obj radius height offset offsetquat else if (btype == SO3_TYPE_BODY_CAPSULE) then SO3BodyCreateCapsuleExt obj radius height offset offsetquat else if (btype == SO3_TYPE_BODY_CONE) then SO3BodyCreateConeExt obj radius height offset offsetquat else if (btype == SO3_TYPE_BODY_PYRAMID) then SO3BodyCreatePyramidExt obj size offset offsetquat else nil -> body in if body == nil then nil else ( SO3BodySetType body (SO3BodyGetType refbody); SO3BodySetMaterial body (SO3BodyGetMaterial refbody); let SO3BodyGetMassMatrix refbody -> [m mx] in SO3BodySetMassMatrix body m mx; //if (!SO3BodyHasBasicJointUpVector refbody) then nil else SO3BodyCreateBasicJointUpVector body [0.0 1.0 0.0]; SO3BodySetGravityEnable body SO3BodyGetGravityEnable refbody; SO3BodySetIgnoreCollision body SO3BodyGetIgnoreCollision refbody; SO3BodySetContiniousCollisionMode body (SO3BodyGetContiniousCollisionMode refbody); SO3BodySetAutoSleep body (SO3BodyGetAutoSleep refbody); SO3BodySetCenterOfMass body (SO3BodyGetCenterOfMass refbody); SO3BodySetFluid body (SO3BodyGetFluid refbody); SO3BodySetFluidVolumeRatio body SO3BodyGetFluidVolumeRatio refbody; SO3BodySetLinearDamping body (SO3BodyGetLinearDamping refbody); SO3BodySetAngularDamping body (SO3BodyGetAngularDamping refbody); SO3BodySetFreeze body (SO3BodyGetFreeze refbody); if (!obstr.OBCR_bStopOnHit) then nil else SO3CbBodyImpulseHit body @cbImpulseHit [obstr obj apfstr]; ); ); 0;; fun applyRandomMaterial(obj, obstr)= let sizelist obstr.OBCR_lMaterials -> nb in if (nb == 0) then nil else ( let if (nb == 1) then hd obstr.OBCR_lMaterials else let (mod rand nb) -> i in nth_list obstr.OBCR_lMaterials i -> mat in ( SO3EntitySetMaterial obj mat (obstr.OBCR_iMindex - 1); ); ); 0;; fun cloneAnimationW(obj, lanim, loop)= let nil -> l in ( while (lanim != nil) do ( let hd lanim -> [anim w] in let SO3ObjectGetAnimation obj SO3AnimationGetName anim -> nanim in if (nanim == nil) then nil else ( SO3AnimationSetLoop nanim loop; SO3AnimationSetWeight nanim 1.0; SO3AnimationSetEnable nanim 0; set l = [nanim w]::l; ); set lanim = tl lanim; ); l; );; fun cloneAnimationB(obj, lanim, loop)= let nil -> l in ( while (lanim != nil) do ( let hd lanim -> anim in let SO3ObjectGetAnimation obj SO3AnimationGetName anim -> nanim in if (nanim == nil) then nil else ( SO3AnimationSetLoop nanim loop; SO3AnimationSetWeight nanim 1.0; SO3AnimationSetEnable nanim 0; set l = nanim::l; ); set lanim = tl lanim; ); l; );; fun cloneNodeHierarchy(obstr, l, parent, idx, apfstr)= if (l == nil) then nil else let hd l -> ref in ( let strcatn (SO3ObjectGetName ref)::"_char_"::obstr.OBCR_instName::"_"::(itoa idx)::nil -> name in let if ((SO3ObjectGetType ref) == SO3_TYPE_ENTITY) then //SO3SceneCreateEntityInstance (V3DgetSession c3dXsession) name ref SO3SceneCloneEntity (V3DgetSession c3dXsession) name ref else SO3SceneNodeCreate (V3DgetSession c3dXsession) name -> obj in ( SO3ObjectLink obj parent; SO3ObjectSetPosition obj SO3ObjectGetPosition ref; SO3ObjectSetOrientation obj SO3ObjectGetOrientation ref; SO3ObjectSetScale obj SO3ObjectGetScale ref; SO3ObjectSetFlags obj (SO3ObjectGetFlags obj)|2048; //Physics clonePhysicBody obstr ref obj apfstr; //Material, SO3EntityAttachSkeleton reset entity materials if ((SO3ObjectGetType ref) != SO3_TYPE_ENTITY) then nil else applyRandomMaterial obj obstr; //anims let obstr.OBCR_anims -> srcanim in ( set apfstr.ACR_wAnims = lcat (cloneAnimationW obj srcanim.ACR_wAnims 1) apfstr.ACR_wAnims; set apfstr.ACR_rAnims = lcat (cloneAnimationW obj srcanim.ACR_rAnims 1) apfstr.ACR_rAnims; set apfstr.ACR_iAnims = lcat (cloneAnimationB obj srcanim.ACR_iAnims 1) apfstr.ACR_iAnims; set apfstr.ACR_jAnims = lcat (cloneAnimationB obj srcanim.ACR_jAnims 0) apfstr.ACR_jAnims; set apfstr.ACR_hAnims = lcat (cloneAnimationB obj srcanim.ACR_hAnims 0) apfstr.ACR_hAnims; set apfstr.ACR_gAnims = lcat (cloneAnimationB obj srcanim.ACR_gAnims 1) apfstr.ACR_gAnims; ); cloneNodeHierarchy obstr (SO3ObjectGetChildren ref) obj idx apfstr; cloneNodeHierarchy obstr (tl l) parent idx apfstr; obj; ); );; fun cloneNode(obstr, idx, apfstr)= cloneNodeHierarchy obstr obstr.OBCR_h3d::nil (SO3ObjectGetParent obstr.OBCR_h3d) idx apfstr;; fun loadMaterials(inst, obstr)= let nil -> ndata in let 0 -> i in ( let getPluginInstanceParam inst (strcat "material_" (itoa i)) -> elem in while (elem != nil) do ( let SO3SceneGetMaterial (V3DgetSession c3dXsession) (getPluginInstanceGroupName inst) elem -> mat in set ndata = mat::ndata; set i = i + 1; set elem = getPluginInstanceParam inst (strcat "material_" (itoa i)); ); set obstr.OBCR_lMaterials = ndata; );; fun loadAnimationsW(inst, type, loop)= let nil -> l in ( let 0 -> i in let strcat type "animation_" -> keyname in let strcat type "aweight_" -> wkeyname in let getPluginInstanceParam inst strcat keyname (itoa i) -> elem in while (elem != nil) do ( let atof (getPluginInstanceParam inst (strcat wkeyname (itoa i))) -> val in let if (val == nil) then 1.0 else val -> val in let V3DgetAnimationByName c3dXsession elem -> anim in ( SO3AnimationSetLoop anim.V3D_anim loop; set l = [anim.V3D_anim val]::l; ); set i = i + 1; set elem = getPluginInstanceParam inst (strcat keyname (itoa i)); ); l; );; fun loadAnimationsB(inst, type, loop)= let nil -> l in ( let 0 -> i in let strcat type "animation_" -> keyname in let getPluginInstanceParam inst strcat keyname (itoa i) -> elem in while (elem != nil) do ( let V3DgetAnimationByName c3dXsession elem -> anim in ( SO3AnimationSetLoop anim.V3D_anim loop; set l = anim.V3D_anim::l; ); set i = i + 1; set elem = getPluginInstanceParam inst (strcat keyname (itoa i)); ); l; );; fun loadAnimations(inst, obstr)= let mkanimCrowd [obstr.OBCR_h3d nil nil nil nil nil nil nil nil nil nil 0 0 1.0 0 0 0 0 0] -> apfstr in ( set apfstr.ACR_inipos = [(SO3ObjectGetPosition obstr.OBCR_h3d) (SO3ObjectGetOrientation obstr.OBCR_h3d)]; set apfstr.ACR_wAnims = loadAnimationsW inst "w" 1; set apfstr.ACR_rAnims = loadAnimationsW inst "r" 1; set apfstr.ACR_iAnims = loadAnimationsB inst "i" 1; set apfstr.ACR_jAnims = loadAnimationsB inst "j" 0; set apfstr.ACR_hAnims = loadAnimationsB inst "h" 0; set apfstr.ACR_gAnims = loadAnimationsB inst "g" 1; set obstr.OBCR_anims = apfstr; ); 0;; fun cbGeneric(inst, type, value, param, obstr)= let (SO3ObjectGetName obstr.OBCR_h3d) -> objname in let nil -> apfstr in if ((strcmpi objname value) && (set apfstr = switch obstr.OBCR_lInstances (V3DgetObjectByName c3dXsession value)) == nil) then nil else let if (apfstr == nil) then obstr.OBCR_anims else apfstr -> apfstr in ( //if (type == 16) then // ray in //else if (type == 17) then // ray out if (type == 21) || (type == 23) then // grabbed or hit ( SO3ObjectStopCharacter apfstr.ACR_source; applyRandomHit obstr apfstr; set apfstr.ACR_iStopTime = _tickcount; set apfstr.ACR_bHit = 1; 0; ) //else if (type == 22) then // ungrabbed else nil; ); 0;; fun cbReset(inst, from, action, param, reply, obstr)= if (!obstr.OBCR_bLoaded) then nil else ( SO3ObjectResumeCharacter obstr.OBCR_h3d; if (obstr.OBCR_bRndPose) then ( SO3ObjectSetCharacterPositionAuto obstr.OBCR_h3d 0; SO3ObjectSetCharacterPositionAuto obstr.OBCR_h3d obstr.OBCR_bRndPose; 0; ) else let obstr.OBCR_anims.ACR_inipos -> [pos quat] in ( SO3ObjectSetPosition obstr.OBCR_h3d pos; SO3ObjectSetOrientation obstr.OBCR_h3d quat; 0; ); let obstr.OBCR_lInstances -> l in while (l != nil) do ( let hd l -> [obj apfstr] in ( SO3ObjectResumeCharacter obj; if (obstr.OBCR_bRndPose) then ( SO3ObjectSetCharacterPositionAuto obj 0; SO3ObjectSetCharacterPositionAuto obj obstr.OBCR_bRndPose; 0; ) else let apfstr.ACR_inipos -> [pos quat] in ( SO3ObjectSetPosition obj pos; SO3ObjectSetOrientation obj quat; 0; ); ); set l = tl l; ); ); 0;; fun cbLoad(inst, from, action, param, reply, obstr)= if (obstr.OBCR_bLoaded) then nil else ( set obstr.OBCR_bLoaded = 1; loadAnimations inst obstr; loadMaterials inst obstr; //SO3SceneUpdateNavigationMesh (V3DgetSession c3dXsession); SO3ObjectSetNavigationType obstr.OBCR_h3d SO3_NAVIGATION_CHARACTER; SO3ObjectSetCharacterSize obstr.OBCR_h3d obstr.OBCR_fRadius obstr.OBCR_fHeight; SO3ObjectSetCharacterPositionAuto obstr.OBCR_h3d obstr.OBCR_bRndPose; SO3ObjectSetCharacterLookingDirection obstr.OBCR_h3d obstr.OBCR_vDirection; SO3ObjectSetCharacterRandomSpeedRange obstr.OBCR_h3d obstr.OBCR_fRndMinSpeed obstr.OBCR_fRndMaxSpeed; SO3CbObjectCharacterEvent obstr.OBCR_h3d @cbCharacterState obstr; applyInitRandomIdle obstr.OBCR_anims; if (!obstr.OBCR_bStopOnHit) then nil else ( let SO3SceneNodeGetBody obstr.OBCR_h3d -> body in SO3CbBodyImpulseHit body @cbImpulseHit [obstr obstr.OBCR_h3d obstr.OBCR_anims]; setPluginInstanceCbGeneric inst mkfun5 @cbGeneric obstr; ); let 0 -> i in while (i < (obstr.OBCR_iNum - 1)) do ( let mkanimCrowd [nil nil nil nil nil nil nil nil nil nil nil 0 0 1.0 0 0 0 0 0] -> apfstr in let cloneNode obstr i apfstr -> instance in ( set apfstr.ACR_source = instance; if (obstr.OBCR_bRndPose) then nil else let SO3SceneGetNavigationRandomPosition (V3DgetSession c3dXsession) -> rndpos in ( set apfstr.ACR_inipos = [rndpos [0.0 0.0 0.0 1.0]]; SO3ObjectSetPosition obstr.OBCR_h3d rndpos; ); SO3ObjectSetNavigationType instance SO3_NAVIGATION_CHARACTER; SO3ObjectSetCharacterSize instance obstr.OBCR_fRadius obstr.OBCR_fHeight; SO3ObjectSetCharacterPositionAuto instance obstr.OBCR_bRndPose; SO3ObjectSetCharacterLookingDirection instance obstr.OBCR_vDirection; SO3ObjectSetCharacterRandomSpeedRange instance obstr.OBCR_fRndMinSpeed obstr.OBCR_fRndMaxSpeed; SO3CbObjectCharacterEvent instance @cbCharacterState obstr; applyInitRandomIdle apfstr; set obstr.OBCR_lInstances = [instance apfstr]::obstr.OBCR_lInstances; ); set i = i + 1; ); setPluginInstanceCbScenePreRenderPhysic inst mkfun4 @cbPrerenderPhysic obstr; SendPluginEvent inst "Loaded" nil nil; ); 0;; fun newOb(inst)= let (getPluginInstanceParam inst "sourceobject") -> sourceobject in let atoi (getPluginInstanceParam inst "num") -> num in let if num == nil then 10 else num -> num in let atoi (getPluginInstanceParam inst "direction") -> direction in let if direction == nil then 0 else direction -> direction in let getDirectionFromParam direction -> vdirection in let atof (getPluginInstanceParam inst "radius") -> radius in let if radius == nil then 0.25 else radius -> radius in let atof (getPluginInstanceParam inst "height") -> height in let if height == nil then 1.75 else height -> height in let atof (getPluginInstanceParam inst "wspeed") -> wspeed in let if wspeed == nil then 1.0 else wspeed -> wspeed in let atof (getPluginInstanceParam inst "rspeed") -> rspeed in let if rspeed == nil then 1.5 else rspeed -> rspeed in let atoi (getPluginInstanceParam inst "randompos") -> randompos in let if randompos == nil then 0 else randompos -> randompos in let atof (getPluginInstanceParam inst "randomminspeed") -> randomminspeed in let if randomminspeed == nil then 0.5 else randomminspeed -> randomminspeed in let atof (getPluginInstanceParam inst "randommaxspeed") -> randommaxspeed in let if randommaxspeed == nil then 1.5 else randommaxspeed -> randommaxspeed in let atoi (getPluginInstanceParam inst "randomstop") -> randomstop in let if randomstop == nil then 0 else randomstop -> randomstop in let atoi (getPluginInstanceParam inst "stoponhit") -> stoponhit in let if stoponhit == nil then 0 else stoponhit -> stoponhit in let (getPluginInstanceParam inst "targetobject") -> targetobject in let atoi (getPluginInstanceParam inst "chasetarget") -> chasetarget in let if chasetarget == nil then 0 else chasetarget -> chasetarget in let atof (getPluginInstanceParam inst "chasedist") -> chasedist in let if chasedist == nil then 1.0 else chasedist -> chasedist in let atoi (getPluginInstanceParam inst "mindex") -> mindex in let if mindex == nil then 0 else mindex -> mindex in let atoi (getPluginInstanceParam inst "init") -> init in let if init == nil then 1 else init -> init in let V3DgetObjectByName c3dXsession sourceobject -> source in let V3DgetObjectTypeByName sourceobject -> isourcemode in let V3DgetObjectByName c3dXsession targetobject -> target in let V3DgetObjectTypeByName targetobject -> itargetmode in let getShortName getPluginInstanceFullname inst -> bname in let (IsInEditor inst) || IsEventLinked inst "Speed" -> bspeedevent in let mkobjCrowd [inst num source isourcemode mindex nil chasetarget target itargetmode chasedist randompos randomstop stoponhit nil vdirection radius height wspeed rspeed randomminspeed randommaxspeed nil bname 300.0 0 0 0 bspeedevent] -> obstr in ( if (!init) then nil else cbLoad inst nil nil nil nil obstr; PluginRegisterAction inst "Load" mkfun6 @cbLoad obstr; PluginRegisterAction inst "Walk to" mkfun6 mkfun7 @cbWalkTo [0 0] obstr; PluginRegisterAction inst "Chase to" mkfun6 mkfun7 @cbWalkTo [0 0] obstr; PluginRegisterAction inst "Run to" mkfun6 mkfun7 @cbWalkTo [0 1] obstr; PluginRegisterAction inst "Stop" mkfun6 @cbObjStop obstr; PluginRegisterAction inst "Resume" mkfun6 @cbObjResume obstr; PluginRegisterAction inst "Set speed" mkfun6 @cbSetSpeed obstr; PluginRegisterAction inst "Reset" mkfun6 @cbReset obstr; //TODO dead character ? //TODO damages ? damage ratio can be change dynamically setPluginInstanceCbDel inst mkfun2 @deleteOb obstr; ); 0;; fun IniPlug(file)= PlugRegister @newOb nil; setPluginEditor @dynamicedit; 0;;