/* PNJ Client Plugin - DMS - junary 2008 - by Bastien BOURINEAU */ // TODO anim par defaut si anim alors autostart /******************************************************************************* ******************************************************************************** ******************************************************************************** COMMON PART ******************************************************************************** ******************************************************************************** *******************************************************************************/ typeof telnetBAP = TELNET ;; var iPnjDlPrior = 15;; var IPNJANIM = 1;; var IPNJSOUND = 2;; var IPNJRADAR = 3;; var IPNJTRANS = 4;; var IPNJCLICK = 5;; // - Struct 3D sound - struct Tsnd3d = [ SND3D_file : S, // sound path SND3D_asnd : AsSnd, // sound SND3D_as3dSound : H3d, // 3d sound emitter SND3D_minDist : I, // 3d minimum distance SND3D_maxDist : I, // 3d maximum distance SND3D_loop : I, // played in loop SND3D_status : I // status 0 | 1 ] mkSnd3d ;; // - Struct Interpolate translation - struct TinterpolateTrans = [ TRANS_name : S, TRANS_currentPos : [[F F F] [F F F]], TRANS_targetPos : [[[F F F] [F F F] [F F F] F] r1], TRANS_angcoef : F, TRANS_coef : F, TRANS_angstep : F, TRANS_tick : I, TRANS_kps : I, TRANS_nbKeys : I, TRANS_oldindex : I, TRANS_loop : I, TRANS_status : I // status 0 | 1 ] mkInterpolateTrans ;; // - Struct Anims - struct TetatAnim = [ ETATANIM_name : S, ETATANIM_actif : I, /* vaut 1 si l'animation est active et 0 si non. */ ETATANIM_lecture : I, /* vaut 0 si l'animation est stoppée, 1 si lecture simple, 2 si boucle */ ETATANIM_startframe : I, ETATANIM_stopframe : I, ETATANIM_size : I, /* Taille de l'animation, en nombre de frames */ ETATANIM_frame : I, /* Numéro de frame en cours de lecture. */ ETATANIM_frame_zero : I, /* Permet de savoir si la frame zero est active (0) ou pas (1)*/ ETATANIM_tick : I ] mkEtatAnim ;; // - Struct scripting - struct TscriptingRule = [ SCRIPT_inType : I, // radar anim trans SCRIPT_inName : S, // action in/out anim1 ... SCRIPT_inParam : S, // param distance key pos SCRIPT_outType : I, // radar anim trans SCRIPT_outName : S, // event anim1 sound1 trans1 ... SCRIPT_outparam : S, // param start|stop SCRIPT_state : I // script status (for radar) ] mkScriptingRule ;; // - Struct 3D - struct Tpnj = [ PNJ_ob : Ob, // Ob instance PNJ_file : S, // path m3d PNJ_theoFramerate : I, PNJ_fileAnim : S, // animation m3d path PNJ_soundsBrut : [[S r1] r1], PNJ_transBrut : [[S r1] r1], PNJ_scriptBrut : [[S r1] r1], PNJ_father : H3d, // father shell PNJ_mesh : H3d, // skin object PNJ_skl : H3d, // squelette PNJ_bone : H3d, // possible attached mesh PNJ_anim : TetatAnim, PNJ_animList : [[S r1] r1], // animation PNJ_3dsnd : [Tsnd3d r1], // 3d sounds PNJ_trans : [TinterpolateTrans r1], // trans list PNJ_scriptRules : [TscriptingRule r1], PNJ_timer : Timer, // testing events ... radar + M3calcProj for testing the object visibility PNJ_lastDistance : I, PNJ_totalDl : I ] mkPnj ;; proto PnjGetScriptRule = fun [Tpnj I S S] I;; /******************************************************************************* Variables *******************************************************************************/ typeof sClass = S;; fun brwSearchLastpoint(s)= if s == nil then nil else let (strlen s) - 1 -> i in ( while (i >= 0) && ((nth_char s i) != '.) do ( set i = i - 1; ); i );; fun getFileWithoutExtension(file)= let brwSearchLastpoint file -> i in substr file 0 i;; fun getPathFile (longfile, file)= if (longfile==nil) || (strlen longfile)==0 || (nth_char longfile ((strlen longfile)-1)) == '/ then [longfile file] else getPathFile substr longfile 0 (strlen longfile)-1 strcat substr longfile ((strlen longfile)-1) 1 file;; fun getFileNameFromPath(path)= if path == nil then nil else let strlen path -> size in let 0 -> pos in let 0 -> prevpos in ( while pos != nil && pos < size do ( set prevpos = pos; let strfind "/" path pos -> npos in set pos = if npos != nil then npos + 1 else nil; ); substr path prevpos (size - prevpos); );; fun convertScolAngToRad(ang)= ((2.0 *. PIf) *. (itof ang)) /. 65536.0;; fun convertDegFAngToRad(ang)= ((2.0 *. PIf) *. ang) /. 360.0;; fun permutXYvec(vec)= let vec -> [x y z] in [y x z];; fun addVectorsF(vec1, vec2)= let vec1 -> [x1 y1 z1] in let vec2 -> [x2 y2 z2] in [(x1 +. x2) (y1 +. y2) (z1 +. z2)] ;; // 2t3 - 3t2 + 1 fun H1(coef)= (2.0 *. (pow coef 3.0)) -. (3.0 *. (pow coef 2.0)) +. 1.0;; // -2t3 + 3t2 fun H2(coef)= (-. 2.0 *. (pow coef 3.0)) +. (3.0 *. (pow coef 2.0));; // t3 - 2t2 +t fun H3(coef)= (pow coef 3.0) -. (2.0 *. (pow coef 2.0)) +. coef;; // t3 - t2 fun H4(coef)= (pow coef 3.0) -. (pow coef 2.0);; fun getInterpolateCurve(vec1, vec2, ang1, ang2, coef)= let vec1 -> [x1 y1 z1] in let vec2 -> [x2 y2 z2] in let ang1 -> [ax1 ay1 az1] in let ang2 -> [ax2 ay2 az2] in let ((H1 coef) *. x1) +. ((H2 coef) *. x2) +. ((H3 coef) *. ax1) +. ((H4 coef) *. ax2) -> x in let ((H1 coef) *. y1) +. ((H2 coef) *. y2) +. ((H3 coef) *. ay1) +. ((H4 coef) *. ay2) -> y in let ((H1 coef) *. z1) +. ((H2 coef) *. z2) +. ((H3 coef) *. az1) +. ((H4 coef) *. az2) -> z in [x y z] ;; fun getPosTime(pos)= let pos -> [[x y z] _ [t c b] ti] in ti;; fun getPosTension(pos)= let pos -> [[x y z] _ [t c b] ti] in t;; fun getPosContinuity(pos)= let pos -> [[x y z] _ [t c b] ti] in c;; fun getPosBias(pos)= let pos -> [[x y z] _ [t c b] ti] in b;; fun getPosX(pos)= let pos -> [[x y z] _ [t c b] ti] in x;; fun getPosY(pos)= let pos -> [[x y z] _ [t c b] ti] in y;; fun getPosZ(pos)= let pos -> [[x y z] _ [t c b] ti] in z;; fun getPosXYZ(pos)= let pos -> [[x y z] _ [t c b] ti] in [x y z];; fun getInterpolateTCB(lpos, t)= let sizelist lpos -> size in let size - 1 -> sizeminus in let 0 -> i in let nil -> outvec in ( while i < size && outvec == nil do ( let nth_list lpos i -> nextpos in if t <. (getPosTime nextpos) then ( let if i == 0 then nth_list lpos (sizeminus - 1) else nth_list lpos (i - 1) -> curpos in let if i == 0 then nth_list lpos (sizeminus - 2) else if i == 1 then nth_list lpos (sizeminus - 1) else nth_list lpos (i - 2) -> prevpos in let if i == sizeminus then nth_list lpos 0 else nth_list lpos (i + 1) -> nextnextpos in let ((t -. (getPosTime curpos)) /. ((getPosTime nextpos) -. (getPosTime curpos))) -> coef in //Update values from TCB let (1.0 -. (getPosTension curpos)) -> OneMinusTension in let (1.0 -. (getPosContinuity curpos)) -> OneMinusContinuity in let (1.0 +. (getPosContinuity curpos)) -> OnePlusContinuity in let (1.0 -. (getPosBias curpos)) -> OneMinusBias in let (1.0 +. (getPosBias curpos)) -> OnePlusBias in let 0.5 *. ((OneMinusTension *. OneMinusContinuity *. OneMinusBias *. ((getPosX nextpos) -. (getPosX curpos) )) +. (OneMinusTension *. OnePlusContinuity *. OnePlusBias *. ( (getPosX curpos) -. (getPosX prevpos) ))) -> tancurposx in let 0.5 *. ((OneMinusTension *. OneMinusContinuity *. OneMinusBias *. ((getPosY nextpos) -. (getPosY curpos) )) +. (OneMinusTension *. OnePlusContinuity *. OnePlusBias *. ( (getPosY curpos) -. (getPosY prevpos) ))) -> tancurposy in let 0.5 *. ((OneMinusTension *. OneMinusContinuity *. OneMinusBias *. ((getPosZ nextpos) -. (getPosZ curpos) )) +. (OneMinusTension *. OnePlusContinuity *. OnePlusBias *. ( (getPosZ curpos) -. (getPosZ prevpos) ))) -> tancurposz in let 0.5 *. ((OneMinusTension *. OnePlusContinuity *. OneMinusBias *. ((getPosX nextpos) -. (getPosX curpos) )) +. (OneMinusTension *. OneMinusContinuity *. OnePlusBias *. ( (getPosX nextnextpos) -. (getPosX nextpos) ))) -> tannextposx in let 0.5 *. ((OneMinusTension *. OnePlusContinuity *. OneMinusBias *. ((getPosY nextpos) -. (getPosY curpos) )) +. (OneMinusTension *. OneMinusContinuity *. OnePlusBias *. ( (getPosY nextnextpos) -. (getPosY nextpos) ))) -> tannextposy in let 0.5 *. ((OneMinusTension *. OnePlusContinuity *. OneMinusBias *. ((getPosZ nextpos) -. (getPosZ curpos) )) +. (OneMinusTension *. OneMinusContinuity *. OnePlusBias *. ( (getPosZ nextnextpos) -. (getPosZ nextpos) ))) -> tannextposz in let getInterpolateCurve (getPosXYZ curpos) (getPosXYZ nextpos) [tancurposx tancurposy tancurposz] [tannextposx tannextposy tannextposz] coef -> [x y z] in set outvec = [i [x y z]]; 0; ) else nil; set i = i + 1; ); outvec; );; /******************************************************************************* OptSingleAngle() - Optimizing single position's angle p -> I : Source angle q -> I : Destination original angle <- I : Optimized destination angle *******************************************************************************/ fun OptSingleAngle(p, q) = let (absf (q -. p)) -> path1 in let (absf (q +. (2.0 *. PIf) -. p)) -> path2 in let (absf (q -. (2.0 *. PIf) -. p)) -> path3 in let min ftoi path1 min ftoi path2 ftoi path3 -> minpath in if (minpath == ftoi path1) then q else if (minpath == ftoi path2) then (q +. (2.0 *. PIf)) else (q -. (2.0 *. PIf));; /******************************************************************************* OptimizeDestinationOrientation() - Optimizing position orientation ap -> I : Source angle a aq -> I : Destination original angle a bp -> I : Source angle b bq -> I : Destination original angle b cp -> I : Source angle c cq -> I : Destination original angle c <- [I I I] : Optimized destination orientation *******************************************************************************/ fun OptimizeDestinationOrientation(ap, aq, bp, bq, cp, cq) = [(OptSingleAngle ap aq) (OptSingleAngle bp bq) (OptSingleAngle cp cq)];; fun getGlobalAngle(obj)= let [0.0 0.0 0.0] -> [x y z] in ( while (M3getFather session obj) != nil do ( let M3getObjAngF session obj -> [nx ny nz] in ( set x = x +. nx; set y = y +. ny; set z = z +. nz; ); set obj = M3getFather session obj; ); [x y z]; );; /* fun cbPnjPlayTrans(strTrans, strPnj)= if !strTrans.TRANS_status then nil else ( if (strTrans.TRANS_coef == nil) || (strTrans.TRANS_coef >. 1.0) then ( // event objname if strTrans.TRANS_posindex == 0 then nil else PnjGetScriptRule strPnj IPNJTRANS strTrans.TRANS_name (M3objName session (nth_list strTrans.TRANS_sources (strTrans.TRANS_posindex - 1))); let nth_list strTrans.TRANS_sources strTrans.TRANS_posindex -> objpos in if objpos != nil then ( M3calcMat session objpos; let M3calcPosRefF session objpos shell -> [vec mat] in let getGlobalAngle objpos -> [aq bq cq] in let strTrans.TRANS_currentPos -> [_ [ap bp cp]] in let OptimizeDestinationOrientation ap aq bp bq cp cq -> ang in set strTrans.TRANS_targetPos = [vec ang]; set strTrans.TRANS_startPos = strTrans.TRANS_currentPos; // calcul du step let strTrans.TRANS_startPos -> [[xa ya za] _] in let strTrans.TRANS_targetPos -> [[xb yb zb] _] in let sqrt ( (sqr(xa -. xb)) +. (sqr(ya -. yb)) +. (sqr(za -. zb)) ) -> dist in ( if dist == 0.0 then ( set strTrans.TRANS_step = 1.0; set strTrans.TRANS_coef = 1.0; ) else let if strTrans.TRANS_linear then (1.0 /. (dist /. ((itof strTrans.TRANS_speed) /. (itof strPnj.PNJ_theoFramerate)))) else (1.0 /. (itof strTrans.TRANS_speed)) -> step in ( //_fooS strcatn ">>>>>>>>>>>>>>> start : x > "::(ftoa xa)::" y > "::(ftoa ya)::" z > "::(ftoa za)::nil; //_fooS strcatn ">>>>>>>>>>>>>>> target : x > "::(ftoa xb)::" y > "::(ftoa yb)::" z > "::(ftoa zb)::nil; //_fooS strcatn ">>>>>>>>>>>>>>> dist : "::(ftoa dist)::nil; //_fooS strcatn ">>>>>>>>>>>>>>> step : "::(ftoa step)::nil; set strTrans.TRANS_step = step; set strTrans.TRANS_coef = step; ); // prépare la position suivante set strTrans.TRANS_posindex = strTrans.TRANS_posindex + 1; ); ) else ( if strTrans.TRANS_loop then ( set strTrans.TRANS_posindex = 0; ) else ( set strTrans.TRANS_posindex = 0; set strTrans.TRANS_coef = nil; set strTrans.TRANS_status = 0; ); ); ) else nil; if strTrans.TRANS_targetPos == nil || !strTrans.TRANS_status then nil else ( // calcul de la position courante let strTrans.TRANS_startPos -> [veca anga] in let strTrans.TRANS_targetPos -> [vecb angb] in // use M3interpVecF / M3interpAngF doesn't work on 90° let M3interpVecF anga angb strTrans.TRANS_coef -> newang in let M3interpVecF veca vecb strTrans.TRANS_coef -> newvec in let [newvec newang] -> [[nxv nyv nzv] [nxa nya nza]] in // récupère l'angle courant dans le repère de l'objet let M3getObjAngF session strPnj.PNJ_father -> [ao bo co] in let [(ao-.nxa) (bo-.nya) (co-.nza)] -> angref in ( M3setObjVecF session strPnj.PNJ_father newvec; M3setObjAngF session strPnj.PNJ_father newang; //M3rotateObjF session strPnj.PNJ_father rot; //M3movObjF session strPnj.PNJ_father move; //_fooS strcatn ">>>>>>>>>>>>>>> ang : x > "::(ftoa nxa)::" y > "::(ftoa nya)::" z > "::(ftoa nza)::nil; //_fooS strcatn ">>>>>>>>>>>>>>>>> coef : "::(ftoa strTrans.TRANS_coef)::nil; let if newvec == nil || newang == nil then let M3calcPosRefF session strPnj.PNJ_father shell -> [vec mat] in let getGlobalAngle strPnj.PNJ_father -> ang in [vec ang] else [newvec newang] -> cpos in set strTrans.TRANS_currentPos = cpos; ); set strTrans.TRANS_coef = strTrans.TRANS_coef +. strTrans.TRANS_step; ); ); 0;; */ fun cbPnjPlayTrans(strTrans, strPnj)= if !strTrans.TRANS_status then nil else ( let (strTrans.TRANS_kps * (_tickcount - strTrans.TRANS_tick)) / 1000 -> rtick in if rtick < 1 then nil else ( if (strTrans.TRANS_coef >=. 1.0) then ( // event set strTrans.TRANS_status = 0; let itoa ((sizelist strTrans.TRANS_targetPos) - 1) -> evntpos in if evntpos == nil then nil else PnjGetScriptRule strPnj IPNJTRANS strTrans.TRANS_name evntpos; set strTrans.TRANS_oldindex = nil; if !strTrans.TRANS_loop then nil else ( let M3calcPosRefF session strPnj.PNJ_father shell -> [vec _] in let getGlobalAngle strPnj.PNJ_father -> ang in set strTrans.TRANS_currentPos = [vec ang]; set strTrans.TRANS_coef = nil; set strTrans.TRANS_coef = 0.0; set strTrans.TRANS_angcoef = 0.0; set strTrans.TRANS_status = 1; ); //exec cbend with [strcam]; 0; ) else ( let (itof rtick) *. (1.0 /. (itof strTrans.TRANS_nbKeys)) -> nstep in set strTrans.TRANS_coef = if (strTrans.TRANS_coef +. nstep) >. 1.0 then 1.0 else strTrans.TRANS_coef +. nstep; let getInterpolateTCB strTrans.TRANS_targetPos strTrans.TRANS_coef -> [index tvec] in let nth_list strTrans.TRANS_targetPos (index - 1) -> [spos sang _ t1] in let nth_list strTrans.TRANS_targetPos index -> [dpos dang _ t2] in ( if strTrans.TRANS_oldindex != index then ( let (if t1 == nil then 0.0 else t1) -> t1 in let (if t2 == nil then 1.0 else t2) -> t2 in let t2 -. t1 -> lenght in let lenght /. (1.0 /. (itof strTrans.TRANS_nbKeys)) -> nbk in set strTrans.TRANS_angstep = 1.0 /. nbk; set strTrans.TRANS_angcoef = 0.0; set strTrans.TRANS_oldindex = index; let itoa (index - 1) -> evntpos in if evntpos == nil then nil else PnjGetScriptRule strPnj IPNJTRANS strTrans.TRANS_name evntpos; ) else nil; let (itof rtick) *. strTrans.TRANS_angstep -> nangstep in set strTrans.TRANS_angcoef = if (strTrans.TRANS_angcoef +. nangstep) >. 1.0 then 1.0 else strTrans.TRANS_angcoef +. nangstep; let sang -> [ax ay az] in let dang -> [tx ty tz] in let OptimizeDestinationOrientation ax tx ay ty az tz -> oang in let M3interpVecF sang oang strTrans.TRANS_angcoef -> tang in ( M3setObjVecF session strPnj.PNJ_father tvec; M3setObjAngF session strPnj.PNJ_father tang;//[an bn cn]; 0; ); ); ); set strTrans.TRANS_tick = _tickcount; ); ); 0;; // prevoir pause / play / stop fun PnjPlayTrans(strTrans, strPnj)= if strTrans.TRANS_oldindex != nil then nil else ( // recup de la position et de l'angle dans le monde let M3calcPosRefF session strPnj.PNJ_father shell -> [vec _] in let getGlobalAngle strPnj.PNJ_father -> ang in set strTrans.TRANS_currentPos = [vec ang]; set strTrans.TRANS_coef = nil; set strTrans.TRANS_coef = 0.0; set strTrans.TRANS_angcoef = 0.0; ); set strTrans.TRANS_tick = _tickcount; set strTrans.TRANS_status = 1; 0;; fun PnjStopTrans(strTrans)= set strTrans.TRANS_oldindex = nil; set strTrans.TRANS_status = 0; set strTrans.TRANS_coef = nil; 0;; fun PnjPauseTrans(strTrans)= set strTrans.TRANS_status = 0; 0;; fun PnjGetTransByName(strPnj, name)= let sizelist strPnj.PNJ_trans -> size in let nil -> ndata in let 0 -> i in ( while i < size && ndata == nil do ( let nth_list strPnj.PNJ_trans i -> elem in if !strcmp name elem.TRANS_name then set ndata = elem else nil; set i = i + 1; ); ndata; );; fun PnjAddTrans(strPnj, name, nbk, kps, ldots, loop, status)= let mkInterpolateTrans [name nil ldots nil nil nil nil kps nbk nil loop status] -> strTrans in ( set strPnj.PNJ_trans = listcat strPnj.PNJ_trans strTrans::nil; if !strTrans.TRANS_status then nil else PnjPlayTrans strTrans strPnj; ); 0;; /******************************************************************************* Functions 3D sounds *******************************************************************************/ fun cbPnjSndEnd(asnd, p)= let p -> [strPnj str3dSnd] in PnjGetScriptRule strPnj IPNJSOUND (getFileWithoutExtension getFileNameFromPath str3dSnd.SND3D_file) "end"; 0;; fun PnjPlaySnd(strPnj, str3dSnd)= if (asSndIsPlaying str3dSnd.SND3D_asnd) then nil else ( as3dSndEnable session str3dSnd.SND3D_as3dSound; asSndSetCallbackTime str3dSnd.SND3D_asnd @cbPnjSndEnd [strPnj str3dSnd] AS_SND_END_REFLEX::nil; asSndPlay str3dSnd.SND3D_asnd if str3dSnd.SND3D_loop then AS_SND_LOOP else nil; set str3dSnd.SND3D_status = 1; ); 0;; fun PnjStopSnd(str3dSnd)= asSndStop str3dSnd.SND3D_asnd; as3dSndDisable session str3dSnd.SND3D_as3dSound; set str3dSnd.SND3D_status = 0; 0;; fun PnjSetSndVolume(str3dSnd, vol)= asSndSetVolume str3dSnd.SND3D_asnd vol; 0;; fun PnjGetSndByName(strPnj, name)= let sizelist strPnj.PNJ_3dsnd -> size in let nil -> ndata in let 0 -> i in ( while i < size && ndata == nil do ( let nth_list strPnj.PNJ_3dsnd i -> elem in let getFileWithoutExtension getFileNameFromPath elem.SND3D_file -> fname in if !strcmp name fname then set ndata = elem else nil; set i = i + 1; ); ndata; );; fun PnjAddSound(strPnj, file, mindist, maxdist, loop, status)= let mkSnd3d [file nil nil mindist maxdist loop status] -> str3dSnd in ( set str3dSnd.SND3D_asnd = asSndCreate _channel if mindist == maxdist then nil else AS_SND_CTRL3D; set str3dSnd.SND3D_as3dSound = as3dSndCreate session str3dSnd.SND3D_asnd AS_SND_LINKED_TO_H3D; // link the sound source to the pnj mesh M3link session str3dSnd.SND3D_as3dSound strPnj.PNJ_father; asSndLoad str3dSnd.SND3D_asnd (_checkpack file) AS_SND_STATIC; asSndSetVolume str3dSnd.SND3D_asnd 100; as3dSndSetDistance session str3dSnd.SND3D_as3dSound str3dSnd.SND3D_minDist str3dSnd.SND3D_maxDist; set strPnj.PNJ_3dsnd = listcat strPnj.PNJ_3dsnd str3dSnd::nil; if !str3dSnd.SND3D_status then nil else PnjPlaySnd strPnj str3dSnd; ); 0;; /******************************************************************************* Functions Anims *******************************************************************************/ // Lecture d'une animation fun PNJ_playAnim(strPnj)= if strPnj.PNJ_anim.ETATANIM_lecture != 2 then nil else if strPnj.PNJ_anim.ETATANIM_frame >= strPnj.PNJ_anim.ETATANIM_stopframe then ( if strPnj.PNJ_anim.ETATANIM_frame_zero == 0 then set strPnj.PNJ_anim.ETATANIM_frame = -1 else set strPnj.PNJ_anim.ETATANIM_frame = strPnj.PNJ_anim.ETATANIM_startframe; ) else nil; if strPnj.PNJ_anim.ETATANIM_frame >= strPnj.PNJ_anim.ETATANIM_stopframe then ( set strPnj.PNJ_anim.ETATANIM_frame = strPnj.PNJ_anim.ETATANIM_startframe; set strPnj.PNJ_anim.ETATANIM_actif = 0; 0; ) else ( set strPnj.PNJ_anim.ETATANIM_frame = strPnj.PNJ_anim.ETATANIM_frame + 1; // get script rule anim anim key PnjGetScriptRule strPnj IPNJANIM strPnj.PNJ_anim.ETATANIM_name itoa strPnj.PNJ_anim.ETATANIM_frame; M3setSKLAnimKey session strPnj.PNJ_skl strPnj.PNJ_mesh strPnj.PNJ_anim.ETATANIM_frame; 0; ); set strPnj.PNJ_anim.ETATANIM_tick = _tickcount; 0;; fun PNJ_setAnimLenght(strPnj, size)= set strPnj.PNJ_anim.ETATANIM_size = size; set strPnj.PNJ_anim.ETATANIM_stopframe = size; 0;; // Initialise ou update les paramètres d'animation fun PNJ_setAnimObj(strPnj, state, mode, startframe)= if strPnj.PNJ_fileAnim == nil then nil else M3loadAnimationFileWithSKL session strPnj.PNJ_fileAnim strPnj.PNJ_skl; // initialisation anim let M3getAnimLength session strPnj.PNJ_skl -> size in ( //_fooS strcatn ">>>>>>>>>>>>>>>>>> Anim skelet : "::strPnj.PNJ_fileAnim::" >> size : "::(itoa size)::nil; if strPnj.PNJ_anim == nil then let mkEtatAnim [ (getFileWithoutExtension getFileNameFromPath strPnj.PNJ_fileAnim) state mode startframe size size startframe 0 _tickcount ] -> animstr in ( set strPnj.PNJ_anim = animstr; 0; ) else ( set strPnj.PNJ_anim.ETATANIM_name = (getFileWithoutExtension getFileNameFromPath strPnj.PNJ_fileAnim); set strPnj.PNJ_anim.ETATANIM_actif = state; set strPnj.PNJ_anim.ETATANIM_lecture = mode; set strPnj.PNJ_anim.ETATANIM_startframe = startframe; set strPnj.PNJ_anim.ETATANIM_stopframe = size; set strPnj.PNJ_anim.ETATANIM_size = size; set strPnj.PNJ_anim.ETATANIM_frame = 0; set strPnj.PNJ_anim.ETATANIM_frame_zero = 0; set strPnj.PNJ_anim.ETATANIM_tick = _tickcount; 0; ); ); 0;; fun PNJ_startstopAnimObj(strPnj)= //if strPnj.PNJ_anim == nil then // nil // else if strPnj.PNJ_anim.ETATANIM_actif == 0 then ( set strPnj.PNJ_anim.ETATANIM_actif = 1; if strPnj.PNJ_anim.ETATANIM_frame >= strPnj.PNJ_anim.ETATANIM_stopframe then set strPnj.PNJ_anim.ETATANIM_frame = 0 else nil; set strPnj.PNJ_anim.ETATANIM_tick = _tickcount; 0; ) else ( set strPnj.PNJ_anim.ETATANIM_actif = 0; 0; ); 0;; // Action changement d'animation fun PNJ_chgAnimation(file, loop, strPnj)= set strPnj.PNJ_fileAnim = file; PNJ_setAnimObj strPnj 0 loop 0; 0;; // Action forçage sur la longueur d'une animation fun PNJ_animationSizeForced(o, param, strPnj)= PNJ_setAnimLenght strPnj atoi param; 0;; fun PnjGetAnimFileFromName(strPnj, name)= let sizelist strPnj.PNJ_animList -> size in let nil -> ndata in let 0 -> i in ( while i < size && ndata == nil do ( let nth_list strPnj.PNJ_animList i -> elem in let getFileWithoutExtension getFileNameFromPath hd elem -> fname in if !strcmpi name fname then set ndata = elem else nil; set i = i + 1; ); ndata; );; /******************************************************************************* Functions Script *******************************************************************************/ fun PnjAddScript(strPnj, intype, inname, inparam, outtype, outname, outparam)= let mkScriptingRule [intype inname inparam outtype outname outparam 0] -> strScript in set strPnj.PNJ_scriptRules = listcat strPnj.PNJ_scriptRules strScript::nil; 0;; fun PnjExecScript(strPnj, strScript)= if strScript.SCRIPT_outType == IPNJANIM then // Anim ( //_fooS strcat ">>>>>>>>>>>>>>>> Start Script Anim " strScript.SCRIPT_outName; let PnjGetAnimFileFromName strPnj strScript.SCRIPT_outName -> animfile in PNJ_chgAnimation (hd animfile) (if (atoi (hd tl animfile)) == 1 then 2 else 1) strPnj; if (!strcmpi strScript.SCRIPT_outparam "start") || (!strcmpi strScript.SCRIPT_outparam "play") then ( if strPnj.PNJ_anim.ETATANIM_actif != 0 then nil else PNJ_startstopAnimObj strPnj; 0; ) else if (!strcmpi strScript.SCRIPT_outparam "stop") then ( if strPnj.PNJ_anim.ETATANIM_actif == 0 then nil else PNJ_startstopAnimObj strPnj; 0; ) else nil; //_fooS strcat ">>>>>>>>>>>>>>>> End Script Anim " strScript.SCRIPT_outName; 0; ) else if strScript.SCRIPT_outType == IPNJSOUND then // Sound ( let PnjGetSndByName strPnj strScript.SCRIPT_outName -> str3dSnd in if (!strcmpi strScript.SCRIPT_outparam "start") || (!strcmpi strScript.SCRIPT_outparam "play") then PnjPlaySnd strPnj str3dSnd else if (!strcmpi strScript.SCRIPT_outparam "stop") then PnjStopSnd str3dSnd else nil; 0; ) else if strScript.SCRIPT_outType == IPNJTRANS then // Translation ( //_fooS strcat ">>>>>>>>>>>>>>>> Start Script Trans " strScript.SCRIPT_outName; let PnjGetTransByName strPnj strScript.SCRIPT_outName -> strTrans in if (!strcmpi strScript.SCRIPT_outparam "start") || (!strcmpi strScript.SCRIPT_outparam "play") then PnjPlayTrans strTrans strPnj else if (!strcmpi strScript.SCRIPT_outparam "stop") then PnjStopTrans strTrans else if (!strcmpi strScript.SCRIPT_outparam "pause") then PnjPauseTrans strTrans else nil; //_fooS strcat ">>>>>>>>>>>>>>>> End Script Trans " strScript.SCRIPT_outName; 0; ) else nil; 0;; fun PnjGetScriptRule(strPnj, type, name, param)= let sizelist strPnj.PNJ_scriptRules -> size in let 0 -> i in ( while i < size do ( let nth_list strPnj.PNJ_scriptRules i -> elem in ( // common if (elem.SCRIPT_inType != IPNJRADAR) && (elem.SCRIPT_inType == type) && (!strcmpi elem.SCRIPT_inName name) && ((!strcmpi elem.SCRIPT_inParam param) || (param == nil)) then ( PnjExecScript strPnj elem; ) // radar determine in or out else if (elem.SCRIPT_inType == IPNJRADAR) && (elem.SCRIPT_inType == type) then ( if ((atoi param) > (atoi elem.SCRIPT_inParam)) && (!strcmpi name "out") && elem.SCRIPT_state then ( set elem.SCRIPT_state = 0; if (!strcmpi elem.SCRIPT_inName name) then PnjExecScript strPnj elem else nil; ) else if ((atoi param) < (atoi elem.SCRIPT_inParam)) && (!strcmpi name "in") && !elem.SCRIPT_state then ( set elem.SCRIPT_state = 1; if (!strcmpi elem.SCRIPT_inName name) then PnjExecScript strPnj elem else nil; ) else nil; ) else nil; ); set i = i + 1; ); ); 0;; /******************************************************************************* ******************************************************************************** ******************************************************************************** MAIN PLUGIN PART ******************************************************************************** ******************************************************************************** *******************************************************************************/ /******************************************************************************* Functions *******************************************************************************/ fun cbBAPread(cnx, strPnj)= let _TELNETGetBuffer cnx -> buffer in if (buffer == nil) then ( _TELNETSend "0" cnx; ) else ( _fooS strcat ">>>>>>>>>>>>>> " buffer; M3animFeed session buffer strPnj.PNJ_skl; _TELNETSend "1" cnx; ); 0;; fun openBAPport(strPnj, ip, port)= if (telnetBAP == nil) then nil else ( _TELNETClose telnetBAP; set telnetBAP = nil; ); //_showconsole; _fooS strcat ">>>>>>>>>>>>>> connection : " strcatn ip::":"::(itoa port)::nil; set telnetBAP = _TELNETConnect _channel strcatn ip::":"::(itoa port)::nil; if telnetBAP != nil then nil else _fooS strcat ">>>>>>>>>>>>>> connection Failed : " strcatn ip::":"::(itoa port)::nil; _TELNETrflRead telnetBAP @cbBAPread strPnj; PNJ_chgAnimation nil 1 strPnj; 0;; // renome tous les H3D du noeud frères du noeud compris fun renameHierarchy(father, id)= if father == nil then nil else ( M3renameObj session father strcatn (M3objName session father)::"_"::id::nil; //_DLGMessageBox _channel nil "renameSklHierarchy" strcat ">> " (M3objName session father) 0; renameHierarchy (M3getFirstSon session father) id; renameHierarchy (M3getBrother session father) id; ); 0;; // for debug fun listH3d(father, p)= if father == nil then nil else ( _fooS strcat ">>>>>>>>>>>>>> - : " M3objName session father; listH3d M3getFirstSon session father 1; if !p then nil else listH3d M3getBrother session father 1; ); 0;; fun PnjGetMeshAndSkelete(strPnj)= let M3createShell session -> tmpload in ( if strPnj.PNJ_skl == nil then nil else M3delObj session strPnj.PNJ_skl; if strPnj.PNJ_mesh == nil then nil else M3delObj session strPnj.PNJ_mesh; M3load session strPnj.PNJ_file tmpload; renameHierarchy tmpload strcatn (itoa strPnj.PNJ_ob.idOb)::"_"::(itoa (mod rand 100))::nil; //listH3d tmpload nil; let M3getFirstSon session tmpload -> son in let M3getBrother session son -> bro in ( set strPnj.PNJ_mesh = hd M3listMeshFromNode session tmpload; if ((M3getObjType session son) == 0) then ( set strPnj.PNJ_skl = M3getObj session M3objName session bro; //set strPnj.PNJ_mesh = son; ) else ( set strPnj.PNJ_skl = M3getObj session M3objName session son; //set strPnj.PNJ_mesh = bro; ); //_DLGMessageBox _channel nil "son" itoa (M3getObjType session son) 0; //_DLGMessageBox _channel nil "bro" itoa (M3getObjType session bro) 0; ); M3recursFillMatObj session strPnj.PNJ_mesh; M3unLink session strPnj.PNJ_skl; M3unLink session strPnj.PNJ_mesh; M3delObj session tmpload; // lie l'avatar M3link session strPnj.PNJ_skl shell; M3link session strPnj.PNJ_mesh strPnj.PNJ_father; let M3isShaderEnable -> avShader in if !avShader then nil else let 0 -> found in ( // Recherche une animation par défaut let sizelist strPnj.PNJ_animList -> size in let 0 -> i in while i < size && !found do ( let nth_list strPnj.PNJ_animList i -> animfile in let atoi (hd tl tl animfile) -> start in if start != 1 then nil else ( PNJ_chgAnimation (hd animfile) (if (atoi (hd tl animfile)) == 1 then 2 else 1) strPnj; set found = 1; ); set i = i + 1; ); if found then nil else let hd strPnj.PNJ_animList -> animfile in ( PNJ_chgAnimation (hd animfile) (if (atoi (hd tl animfile)) == 1 then 2 else 1) strPnj; ); // initialisation et link du mesh au squelette M3AttachMeshWithSKL session strPnj.PNJ_mesh strPnj.PNJ_skl; // force la clef 1 de l'animation set strPnj.PNJ_anim.ETATANIM_frame = 1; M3setSKLAnimKey session strPnj.PNJ_skl strPnj.PNJ_mesh strPnj.PNJ_anim.ETATANIM_frame; M3InitializeMpeg4SKL session strPnj.PNJ_mesh strPnj.PNJ_skl; // lancement anim PNJ_startstopAnimObj strPnj; // BAP connexion openBAPport strPnj "192.168.0.107" 4586; ); ); 0;; fun PnjGetTypeFromName(name)= if !strcmpi name "anim" then IPNJANIM else if !strcmpi name "sound" then IPNJSOUND else if !strcmpi name "radar" then IPNJRADAR else if !strcmpi name "trans" then IPNJTRANS else if !strcmpi name "click" then IPNJCLICK else 0 ;; // Radar | Trans fun cbPnjTimer(trm, strPnj)= // radar let M3distance session (M3getFather session ObGetMain owner) strPnj.PNJ_father -> idist in ( if idist < strPnj.PNJ_lastDistance then PnjGetScriptRule strPnj IPNJRADAR "in" itoa idist else if idist > strPnj.PNJ_lastDistance then PnjGetScriptRule strPnj IPNJRADAR "out" itoa idist else nil; set strPnj.PNJ_lastDistance = idist; ); 0;; fun getStringDots(ldots)= let sizelist ldots -> size in let nil -> ndata in let 0 -> i in ( while i < size do ( let nth_list ldots i -> dot in let atof (nth_list dot 0) -> x in let atof (nth_list dot 1) -> y in let atof (nth_list dot 2) -> z in let convertDegFAngToRad (atof (nth_list dot 3)) -> ax in let convertDegFAngToRad (atof (nth_list dot 4)) -> ay in let convertDegFAngToRad (atof (nth_list dot 5)) -> az in let atof (nth_list dot 6) -> t in let atof (nth_list dot 7) -> c in let atof (nth_list dot 8) -> b in let atof (nth_list dot 9) -> ts in set ndata = listcat ndata [[x y z] (permutXYvec [ax ay az]) [t c b] ts]::nil; set i = i + 1; ); ndata; );; /* change the avatar mesh*/ fun SetPnj(strPnj)= PnjGetMeshAndSkelete strPnj; let sizelist strPnj.PNJ_transBrut -> size in let 0 -> i in while i < size do ( let nth_list strPnj.PNJ_transBrut i -> elem in PnjAddTrans strPnj (nth_list elem 0) (atoi (nth_list elem 1)) (atoi (nth_list elem 2)) (getStringDots (strextr (nth_list elem 5))) (atoi (nth_list elem 3)) (atoi (nth_list elem 4)); set i = i + 1; ); let sizelist strPnj.PNJ_soundsBrut -> size in let 0 -> i in while i < size do ( let nth_list strPnj.PNJ_soundsBrut i -> elem in PnjAddSound strPnj (hd elem) (atoi (nth_list elem 1)) (atoi (nth_list elem 2)) (atoi (nth_list elem 3)) (atoi (nth_list elem 4)); set i = i + 1; ); let sizelist strPnj.PNJ_scriptBrut -> size in let 0 -> i in while i < size do ( let nth_list strPnj.PNJ_scriptBrut i -> elem in PnjAddScript strPnj (PnjGetTypeFromName (hd elem)) (nth_list elem 1) (nth_list elem 2) (PnjGetTypeFromName (nth_list elem 3)) (nth_list elem 4) (nth_list elem 5); set i = i + 1; ); /* PnjAddScript strPnj IPNJANIM "test" "50" IPNJSOUND "fikn-fight" "play"; PnjAddScript strPnj IPNJANIM "anim3" "1" IPNJSOUND "gunfight" "play"; PnjAddScript strPnj IPNJANIM "anim1" "1" IPNJSOUND "footstep" "play"; PnjAddScript strPnj IPNJANIM "anim1" "25" IPNJSOUND "footstep" "play"; //PnjAddScript strPnj IPNJANIM "anim1" "40" IPNJANIM "anim2" "play"; //PnjAddScript strPnj IPNJANIM "anim2" "80" IPNJANIM "anim1" "play"; //PnjAddScript strPnj IPNJANIM "anim2" "40" IPNJSOUND "click" "play"; PnjAddScript strPnj IPNJRADAR "in" "500" IPNJTRANS "trans1" "play"; PnjAddScript strPnj IPNJRADAR "out" "500" IPNJTRANS "trans1" "pause"; //PnjAddScript strPnj IPNJRADAR "in" "1000" IPNJANIM "anim1" "play"; //PnjAddScript strPnj IPNJRADAR "out" "1000" IPNJANIM "anim1" "stop"; PnjAddScript strPnj IPNJTRANS "trans1" "1e.dummy" IPNJSOUND "click" "play"; PnjAddScript strPnj IPNJSOUND "click" "end" IPNJANIM "anim2" "play"; PnjAddScript strPnj IPNJTRANS "trans1" "2.dummy" IPNJANIM "test" "play"; PnjAddScript strPnj IPNJTRANS "trans1" "1d.dummy" IPNJANIM "anim3" "play"; */ set strPnj.PNJ_soundsBrut = nil; set strPnj.PNJ_transBrut = nil; set strPnj.PNJ_scriptBrut = nil; set strPnj.PNJ_timer = _rfltimer _starttimer _channel 200 @cbPnjTimer strPnj; M3freeMemory session; 0;; /******************************************************************************* Functions: Downloading avatars and related textures *******************************************************************************/ fun cbFileDownloaded(f, strPnj) = set strPnj.PNJ_totalDl = strPnj.PNJ_totalDl - 1; if strPnj.PNJ_totalDl > 0 then nil else SetPnj strPnj; 0;; /* Downloading textures */ fun DownloadFiles(l, strPnj) = if (l == nil) then nil else ( _RSCdownloadP this (hd l) (hd l) mknode @cbFileDownloaded strPnj 0 iPnjDlPrior; DownloadFiles tl l strPnj; 0; );; fun cbSetServerParams(ui, action, param, strPnj) = // Paramètres du serveur let lineextr unzip param -> files in ( set strPnj.PNJ_totalDl = sizelist files; DownloadFiles files strPnj; ); 0;; fun cbAnimPlay (o, from, action, param, reply, p)= let p -> [anim strPnj] in ( if !strcmp strPnj.PNJ_fileAnim (hd anim) then ( if strPnj.PNJ_anim.ETATANIM_actif == 1 then nil else PNJ_startstopAnimObj strPnj; ) else ( PNJ_chgAnimation (hd anim) (if (atoi (hd tl anim)) == 1 then 2 else 1) strPnj; set strPnj.PNJ_anim.ETATANIM_actif = 0; PNJ_startstopAnimObj strPnj; ); ); 0;; fun cbAnimStop (o, from, action, param, reply, p)= let p -> [anim strPnj] in ( if strPnj.PNJ_anim.ETATANIM_actif == 0 then nil else PNJ_startstopAnimObj strPnj; ); 0;; fun cbSoundPlay (o, from, action, param, reply, p)= let p -> [name strPnj] in ( let PnjGetSndByName strPnj name -> str3dSnd in PnjPlaySnd strPnj str3dSnd; ); 0;; fun cbSoundStop (o, from, action, param, reply, p)= let p -> [name strPnj] in ( let PnjGetSndByName strPnj name -> str3dSnd in PnjStopSnd str3dSnd; ); 0;; fun cbTransPlay (o, from, action, param, reply, p)= let p -> [name strPnj] in ( let PnjGetTransByName strPnj name -> strTrans in PnjPlayTrans strTrans strPnj; ); 0;; fun cbTransStop (o, from, action, param, reply, p)= let p -> [name strPnj] in ( let PnjGetTransByName strPnj name -> strTrans in PnjStopTrans strTrans; ); 0;; fun destroy(o, strPnj)= // snd let sizelist strPnj.PNJ_3dsnd -> size in let 0 -> i in while i < size do ( let nth_list strPnj.PNJ_3dsnd i -> elem in ( PnjStopSnd elem; M3delObj session elem.SND3D_as3dSound; asSndDestroy elem.SND3D_asnd; ); set i = i + 1; ); ObCbAnim strPnj.PNJ_ob nil; if strPnj.PNJ_timer == nil then nil else ( _deltimer strPnj.PNJ_timer; set strPnj.PNJ_timer = nil; ); M3delObj session strPnj.PNJ_mesh; M3delObj session strPnj.PNJ_skl; M3delObj session strPnj.PNJ_bone; 0;; /******************************************************************************* Defines the callbacks of the links in the anchor, and return the list of them <- [[H3d HMat3d S ObjCursor fun [Ob H3d HMat3d I] I fun [Ob H3d HMat3d I] I fun [Ob H3d HMat3d] I] r1] *******************************************************************************/ proto GetLinks = fun [[Anchor r1] Tpnj] [[H3d HMat3d S ObjCursor fun [Ob H3d HMat3d I] I fun [Ob H3d HMat3d I] I fun [Ob H3d HMat3d] I] r1];; fun cbClickLink(o, obj, mat, but, strPnj) = if but == 1 then ( _DMSeventTag this (strcat (ObName o) ".leftClick") nil nil nil; PnjGetScriptRule strPnj IPNJCLICK "Left" "_"; ) else if but == 2 then ( _DMSeventTag this (strcat (ObName o) ".rightClick") nil nil nil; PnjGetScriptRule strPnj IPNJCLICK "Right" "_"; ) else nil; 0;; fun GetLinks(l, strPnj)= if l==nil then nil else match hd l with (objAnchor [ah am name _] -> ([ah am nil HandCursor (mkfun5 @cbClickLink strPnj) nil nil]::(GetLinks tl l strPnj))) | (_->(GetLinks tl l strPnj)) ;; fun cbRenderAnim(o, strPnj)= // trans apply_on_list strPnj.PNJ_trans @cbPnjPlayTrans strPnj; M3playAnimationBAPFile session strPnj.PNJ_skl; set strPnj.PNJ_anim.ETATANIM_actif = 1; set strPnj.PNJ_anim.ETATANIM_frame_zero = 0; set strPnj.PNJ_anim.ETATANIM_frame = 0; set strPnj.PNJ_anim.ETATANIM_startframe = 0; set strPnj.PNJ_anim.ETATANIM_stopframe = 2; // anims if !strPnj.PNJ_anim.ETATANIM_actif then nil else ( let (strPnj.PNJ_theoFramerate * (_tickcount - strPnj.PNJ_anim.ETATANIM_tick)) / 1000 -> rtick in if rtick < 1 then nil else ( PNJ_playAnim strPnj; ); ); 0;; /* cbNewOb */ fun cbNewOb(o)= _DMSeventTag this (strcat (ObName o) ".entering") nil nil nil; let ObUi o -> ui in let mkPnj [ o nil 30 nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil nil ] -> strPnj in let UgetParams ObUi o -> l in let atoi getInfo l "frameR" -> frmrate in let strextr getInfo l "anims" -> lanims in let strextr getInfo l "trans" -> ltrans in let strextr getInfo l "sounds" -> lsounds in let strextr getInfo l "script" -> lscript in let getInfo l "m3dpath" -> m3dpath in ( set strPnj.PNJ_file = m3dpath; set strPnj.PNJ_soundsBrut = lsounds; set strPnj.PNJ_transBrut = ltrans; set strPnj.PNJ_scriptBrut = lscript; set strPnj.PNJ_animList = lanims; if frmrate == nil then nil else set strPnj.PNJ_theoFramerate = frmrate; let match hd (ObAnchor o) with (objAnchor [h _ _ _] -> h ) |(_->nil) -> father in set strPnj.PNJ_father = father; let sizelist lanims -> size in let 0 -> i in while i < size do ( let nth_list lanims i -> elem in let getFileWithoutExtension getFileNameFromPath hd elem -> name in ( ObRegisterAction o (strcatn (ObName o)::".anim_"::name::".play"::nil) mkfun6 @cbAnimPlay [elem strPnj]; ObRegisterAction o (strcatn (ObName o)::".anim_"::name::".stop"::nil) mkfun6 @cbAnimStop [elem strPnj]; ); set i = i + 1; ); let sizelist lsounds -> size in let 0 -> i in while i < size do ( let nth_list lsounds i -> elem in let getFileWithoutExtension getFileNameFromPath hd elem -> name in ( ObRegisterAction o (strcatn (ObName o)::".sound_"::name::".play"::nil) mkfun6 @cbSoundPlay [name strPnj]; ObRegisterAction o (strcatn (ObName o)::".sound_"::name::".stop"::nil) mkfun6 @cbSoundStop [name strPnj]; ); set i = i + 1; ); let sizelist ltrans -> size in let 0 -> i in while i < size do ( let nth_list ltrans i -> elem in let hd elem -> name in ( ObRegisterAction o (strcatn (ObName o)::".trans_"::name::".play"::nil) mkfun6 @cbTransPlay [name strPnj]; ObRegisterAction o (strcatn (ObName o)::".trans_"::name::".stop"::nil) mkfun6 @cbTransStop [name strPnj]; ); set i = i + 1; ); ObCbDestroy o mkfun2 @destroy strPnj; ObSetLinks o GetLinks ObAnchor o strPnj; UcbMessage ObUi o ["setServerParams" mkfun4 @cbSetServerParams strPnj]:: nil; UsendMessage ObUi o "getServerParams" nil; ObCbAnim strPnj.PNJ_ob mkfun2 @cbRenderAnim strPnj; ); _DMSeventTag this (strcat (ObName o) ".in") nil nil nil; 0;; /* IniPlug */ fun IniPlug(file)= srand _tickcount; set sClass = getInfo strextr _getpack _checkpack file "name"; PLUGsetinfo thisplug PLUGIN_ONLINE_EDITING|PLUGIN_NOTRESERVED|PLUGIN_OBJECT; PLUGdefineEditor thisplug @dynamicedit; PlugRegister sClass @cbNewOb nil; 0;;