//----------------------------------------------------------------------------- // Purpose: Counts words which have either a valid start or end byte // Input : *outwords - // Output : int //----------------------------------------------------------------------------- int CountUnuseableWords( CSentence& outwords ) { int count = 0; int numwords = outwords.m_Words.Size(); // Nothing to do if ( numwords <= 0 ) return count; for ( int i = 0; i < numwords; i++ ) { CWordTag *word = outwords.m_Words[ i ]; if ( IsUseable( word ) ) continue; count++; } return count; }
int FindFirstUsableWord( CSentence& outwords ) { int numwords = outwords.m_Words.Size(); if ( numwords < 1 ) { Assert( 0 ); return -1; } for ( int i = 0; i < numwords; i++ ) { CWordTag *check = outwords.m_Words[ i ]; if ( IsUseable( check ) ) { return i; } } return -1; }
void CBasePlayerWeapon::ItemPostFrame( void ) { if ((m_fInReload) && ( m_pPlayer->m_flNextAttack <= UTIL_WeaponTimeBase() ) ) { // Pcjoe: Regular HL weapon if(!MMWeapon()) { // complete the reload. int j = min( iMaxClip() - m_iClip, m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]); // Add them to the clip m_iClip += j; // Removed by Pcjoe /* m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] -= j; m_pPlayer->TabulateAmmo();*/ } // Pcjoe: Reload MM weapon else if(((CMMWeapon*)this)->RapidFireWeapon()) { CBaseRapidFireGun *pWeapon = (CBaseRapidFireGun*)this; // Reload ammo for non-power weapons if(!pWeapon->UsePowerPrimary()) { pWeapon->m_iPrimaryCur = pWeapon->MaxRounds(); pWeapon->m_iClip = pWeapon->MaxRounds(); } if(!pWeapon->UsePowerSecondary()) { pWeapon->m_iSecondaryCur = pWeapon->m_iSecondaryMax; } } m_fInReload = FALSE; } // Edited by Pcjoe // if ((m_pPlayer->pev->button & IN_ATTACK2) && CanAttack( m_flNextSecondaryAttack, gpGlobals->time, UseDecrement() ) ) if ((m_pPlayer->pev->button & IN_ATTACK2) && !m_pPlayer->m_fImpact && !m_pPlayer->m_fBoost && CanAttack( m_flNextSecondaryAttack, gpGlobals->time, UseDecrement() ) ) { if ( pszAmmo2() && !m_pPlayer->m_rgAmmo[SecondaryAmmoIndex()] ) { m_fFireOnEmpty = TRUE; } // Removed by Pcjoe // m_pPlayer->TabulateAmmo(); SecondaryAttack(); m_pPlayer->pev->button &= ~IN_ATTACK2; } // Edited by Pcjoe // else if ((m_pPlayer->pev->button & IN_ATTACK) && CanAttack( m_flNextPrimaryAttack, gpGlobals->time, UseDecrement() ) ) else if ((m_pPlayer->pev->button & IN_ATTACK) && !m_pPlayer->m_fImpact && !m_pPlayer->m_fBoost && CanAttack( m_flNextPrimaryAttack, gpGlobals->time, UseDecrement() ) ) { if ( (m_iClip == 0 && pszAmmo1()) || (iMaxClip() == -1 && !m_pPlayer->m_rgAmmo[PrimaryAmmoIndex()] ) ) { m_fFireOnEmpty = TRUE; } // Removed by Pcjoe // m_pPlayer->TabulateAmmo(); PrimaryAttack(); } else if ( m_pPlayer->pev->button & IN_RELOAD && iMaxClip() != WEAPON_NOCLIP && !m_fInReload ) { // reload when reload is pressed, or if no buttons are down and weapon is empty. Reload(); } else if ( !(m_pPlayer->pev->button & (IN_ATTACK|IN_ATTACK2) ) ) { // no fire buttons down m_fFireOnEmpty = FALSE; if ( !IsUseable() && m_flNextPrimaryAttack < ( UseDecrement() ? 0.0 : gpGlobals->time ) ) { // weapon isn't useable, switch. if ( !(iFlags() & ITEM_FLAG_NOAUTOSWITCHEMPTY) && g_pGameRules->GetNextBestWeapon( m_pPlayer, this ) ) { m_flNextPrimaryAttack = ( UseDecrement() ? 0.0 : gpGlobals->time ) + 0.3; return; } } else { // weapon is useable. Reload if empty and weapon has waited as long as it has to after firing if ( m_iClip == 0 && !(iFlags() & ITEM_FLAG_NOAUTORELOAD) && m_flNextPrimaryAttack < ( UseDecrement() ? 0.0 : gpGlobals->time ) ) { Reload(); // Pcjoe: Allow mm weapons to call idle if(!MMWeapon()) { return; } } } WeaponIdle( ); return; } // catch all if ( ShouldWeaponIdle() ) { WeaponIdle(); } }
void CBasePlayerWeapon::ItemPostFrame( void ) { if ((m_fInReload) && ( m_pPlayer->m_flNextAttack <= UTIL_WeaponTimeBase() ) ) { // complete the reload. int j = min( iMaxClip() - m_iClip, m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType]); // Add them to the clip m_iClip += j; m_pPlayer->m_rgAmmo[m_iPrimaryAmmoType] -= j; m_pPlayer->TabulateAmmo(); m_fInReload = FALSE; } if ( !(m_pPlayer->pev->button & IN_ATTACK ) ) { m_flLastFireTime = 0.0f; } if ((m_pPlayer->pev->button & IN_ATTACK2) && CanAttack( m_flNextSecondaryAttack, gpGlobals->time, UseDecrement() ) ) { if ( pszAmmo2() && !m_pPlayer->m_rgAmmo[SecondaryAmmoIndex()] ) { m_fFireOnEmpty = TRUE; } m_pPlayer->TabulateAmmo(); SecondaryAttack(); m_pPlayer->pev->button &= ~IN_ATTACK2; } else if ((m_pPlayer->pev->button & IN_ATTACK) && CanAttack( m_flNextPrimaryAttack, gpGlobals->time, UseDecrement() ) ) { if ( (m_iClip == 0 && pszAmmo1()) || (iMaxClip() == -1 && !m_pPlayer->m_rgAmmo[PrimaryAmmoIndex()] ) ) { m_fFireOnEmpty = TRUE; } m_pPlayer->TabulateAmmo(); PrimaryAttack(); } else if ( m_pPlayer->pev->button & IN_RELOAD && iMaxClip() != WEAPON_NOCLIP && !m_fInReload ) { // reload when reload is pressed, or if no buttons are down and weapon is empty. Reload(); } else if ( !(m_pPlayer->pev->button & (IN_ATTACK|IN_ATTACK2) ) ) { // no fire buttons down m_fFireOnEmpty = FALSE; if ( !IsUseable() && m_flNextPrimaryAttack < ( UseDecrement() ? 0.0 : gpGlobals->time ) ) { // weapon isn't useable, switch. if ( !(iFlags() & ITEM_FLAG_NOAUTOSWITCHEMPTY) && g_pGameRules->GetNextBestWeapon( m_pPlayer, this ) ) { m_flNextPrimaryAttack = ( UseDecrement() ? 0.0 : gpGlobals->time ) + 0.3; return; } } else { // weapon is useable. Reload if empty and weapon has waited as long as it has to after firing if ( m_iClip == 0 && !(iFlags() & ITEM_FLAG_NOAUTORELOAD) && m_flNextPrimaryAttack < ( UseDecrement() ? 0.0 : gpGlobals->time ) ) { Reload(); return; } } WeaponIdle( ); return; } // catch all if ( ShouldWeaponIdle() ) { WeaponIdle(); } }
void CWeaponDODBase::ItemPostFrame() { if ( m_flSmackTime > 0 && gpGlobals->curtime > m_flSmackTime ) { Smack(); m_flSmackTime = -1; } CBasePlayer *pPlayer = GetPlayerOwner(); if ( !pPlayer ) return; #ifdef _DEBUG CDODGameRules *mp = DODGameRules(); #endif assert( mp ); if ((m_bInReload) && (pPlayer->m_flNextAttack <= gpGlobals->curtime)) { // complete the reload. int j = min( GetMaxClip1() - m_iClip1, pPlayer->GetAmmoCount( m_iPrimaryAmmoType ) ); // Add them to the clip m_iClip1 += j; pPlayer->RemoveAmmo( j, m_iPrimaryAmmoType ); m_bInReload = false; FinishReload(); } if ((pPlayer->m_nButtons & IN_ATTACK2) && (m_flNextSecondaryAttack <= gpGlobals->curtime)) { if ( m_iClip2 != -1 && !pPlayer->GetAmmoCount( GetSecondaryAmmoType() ) ) { m_bFireOnEmpty = TRUE; } SecondaryAttack(); pPlayer->m_nButtons &= ~IN_ATTACK2; } else if ((pPlayer->m_nButtons & IN_ATTACK) && (m_flNextPrimaryAttack <= gpGlobals->curtime ) && !m_bInAttack ) { if ( (m_iClip1 == 0/* && pszAmmo1()*/) || (GetMaxClip1() == -1 && !pPlayer->GetAmmoCount( GetPrimaryAmmoType() ) ) ) { m_bFireOnEmpty = TRUE; } if( CanAttack() ) PrimaryAttack(); } else if ( pPlayer->m_nButtons & IN_RELOAD && GetMaxClip1() != WEAPON_NOCLIP && !m_bInReload && m_flNextPrimaryAttack < gpGlobals->curtime) { // reload when reload is pressed, or if no buttons are down and weapon is empty. Reload(); } else if ( !(pPlayer->m_nButtons & (IN_ATTACK|IN_ATTACK2) ) ) { // no fire buttons down m_bFireOnEmpty = false; m_bInAttack = false; //reset semi-auto if ( !IsUseable() && m_flNextPrimaryAttack < gpGlobals->curtime ) { // Intentionally blank -- used to switch weapons here } else if( ShouldAutoReload() ) { // weapon is useable. Reload if empty and weapon has waited as long as it has to after firing if ( m_iClip1 == 0 && !(GetWeaponFlags() & ITEM_FLAG_NOAUTORELOAD) && m_flNextPrimaryAttack < gpGlobals->curtime ) { Reload(); return; } } WeaponIdle( ); return; } }
void CWeaponCSBase::ItemPostFrame() { CCSPlayer *pPlayer = GetPlayerOwner(); //GOOSEMAN : Return zoom level back to previous zoom level before we fired a shot. This is used only for the AWP. if ( (m_flNextPrimaryAttack <= gpGlobals->curtime) && (pPlayer->m_bResumeZoom == TRUE) ) { #ifndef CLIENT_DLL pPlayer->SetFOV( pPlayer->m_iLastZoom ); if ( pPlayer->GetFOV() == pPlayer->m_iLastZoom ) { // return the fade level in zoom. pPlayer->m_bResumeZoom = false; } #endif } //GOOSEMAN : Delayed shell ejection code.. if ( (pPlayer->m_flEjectBrass != 0.0) && (pPlayer->m_flEjectBrass <= gpGlobals->curtime ) ) { pPlayer->m_flEjectBrass = 0.0; EjectBrassLate(); } if ((m_bInReload) && (pPlayer->m_flNextAttack <= gpGlobals->curtime)) { // complete the reload. int j = min( GetMaxClip1() - m_iClip1, pPlayer->GetAmmoCount( m_iPrimaryAmmoType ) ); // Add them to the clip m_iClip1 += j; pPlayer->RemoveAmmo( j, m_iPrimaryAmmoType ); m_bInReload = false; } if ((pPlayer->m_nButtons & IN_ATTACK2) && (m_flNextSecondaryAttack <= gpGlobals->curtime)) { if ( m_iClip2 != -1 && !pPlayer->GetAmmoCount( GetSecondaryAmmoType() ) ) { m_bFireOnEmpty = TRUE; } SecondaryAttack(); pPlayer->m_nButtons &= ~IN_ATTACK2; } else if ((pPlayer->m_nButtons & IN_ATTACK) && (m_flNextPrimaryAttack <= gpGlobals->curtime )) { if ( (m_iClip1 == 0/* && pszAmmo1()*/) || (GetMaxClip1() == -1 && !pPlayer->GetAmmoCount( GetPrimaryAmmoType() ) ) ) { m_bFireOnEmpty = TRUE; } // Can't shoot during the freeze period // Ken: Always allow firing in single player //--- if ( !CSGameRules()->IsFreezePeriod() && !pPlayer->m_bIsDefusing && pPlayer->State_Get() == STATE_JOINED ) { PrimaryAttack(); } //--- } else if ( pPlayer->m_nButtons & IN_RELOAD && GetMaxClip1() != WEAPON_NOCLIP && !m_bInReload && m_flNextPrimaryAttack < gpGlobals->curtime) { // reload when reload is pressed, or if no buttons are down and weapon is empty. //MIKETODO: add code for shields... //if ( !FBitSet( m_iWeaponState, WPNSTATE_SHIELD_DRAWN ) ) Reload(); } else if ( !(pPlayer->m_nButtons & (IN_ATTACK|IN_ATTACK2) ) ) { // no fire buttons down // The following code prevents the player from tapping the firebutton repeatedly // to simulate full auto and retaining the single shot accuracy of single fire if (m_bDelayFire == TRUE) { m_bDelayFire = FALSE; if (m_iShotsFired > 15) m_iShotsFired = 15; m_flDecreaseShotsFired = gpGlobals->curtime + 0.4; } m_bFireOnEmpty = FALSE; // if it's a pistol then set the shots fired to 0 after the player releases a button if ( IsPistol() ) { m_iShotsFired = 0; } else { if ( (m_iShotsFired > 0) && (m_flDecreaseShotsFired < gpGlobals->curtime) ) { m_flDecreaseShotsFired = gpGlobals->curtime + 0.0225; m_iShotsFired--; } } #ifndef CLIENT_DLL if ( !IsUseable() && m_flNextPrimaryAttack < gpGlobals->curtime ) { // Intentionally blank -- used to switch weapons here } else #endif { // weapon is useable. Reload if empty and weapon has waited as long as it has to after firing if ( m_iClip1 == 0 && !(GetFlags() & ITEM_FLAG_NOAUTORELOAD) && m_flNextPrimaryAttack < gpGlobals->curtime ) { Reload(); return; } } WeaponIdle( ); return; } }
/* ===================== CBasePlayerWeapon::ItemPostFrame Handles weapon firing, reloading, etc. ===================== */ void CBasePlayerWeapon::ItemPostFrame( void ) { WeaponTick(); if( ( m_fInReload ) && ( m_pPlayer->m_flNextAttack <= UTIL_WeaponTimeBase() ) ) { #ifdef SERVER_DLL // FIXME, need ammo on client to make this work right // complete the reload. int j = min( iMaxClip() - m_iClip, m_pPlayer->m_rgAmmo[ PrimaryAmmoIndex() ] ); // Add them to the clip m_iClip += j; m_pPlayer->m_rgAmmo[ PrimaryAmmoIndex() ] -= j; #else m_iClip += 10; #endif m_fInReload = false; } #ifdef SERVER_DLL if( !m_pPlayer->GetButtons().Any( IN_ATTACK ) ) { m_flLastFireTime = 0.0f; } #endif if( m_pPlayer->GetButtons().Any( IN_ATTACK2 ) && CanAttack( m_flNextSecondaryAttack, gpGlobals->time, IsPredicted() ) ) { if( pszAmmo2() && !m_pPlayer->m_rgAmmo[ SecondaryAmmoIndex() ] ) { m_bFireOnEmpty = true; } SecondaryAttack(); m_pPlayer->GetButtons().ClearFlags( IN_ATTACK2 ); } else if( m_pPlayer->GetButtons().Any( IN_ATTACK ) && CanAttack( m_flNextPrimaryAttack, gpGlobals->time, IsPredicted() ) ) { if( ( m_iClip == 0 && pszAmmo1() ) || ( iMaxClip() == -1 && !m_pPlayer->m_rgAmmo[ PrimaryAmmoIndex() ] ) ) { m_bFireOnEmpty = true; } PrimaryAttack(); } else if( m_pPlayer->GetButtons().Any( IN_RELOAD ) && iMaxClip() != WEAPON_NOCLIP && !m_fInReload ) { // reload when reload is pressed, or if no buttons are down and weapon is empty. Reload(); } else if( !m_pPlayer->GetButtons().Any( IN_ATTACK | IN_ATTACK2 ) ) { // no fire buttons down m_bFireOnEmpty = false; //Only the server checks for weapon switching. - Solokiller #ifdef SERVER_DLL if( !IsUseable() && m_flNextPrimaryAttack < ( IsPredicted() ? 0.0 : gpGlobals->time ) ) { // weapon isn't useable, switch. if( !( iFlags() & ITEM_FLAG_NOAUTOSWITCHEMPTY ) && g_pGameRules->GetNextBestWeapon( m_pPlayer, this ) ) { m_flNextPrimaryAttack = ( IsPredicted() ? 0.0 : gpGlobals->time ) + 0.3; return; } } else #endif { // weapon is useable. Reload if empty and weapon has waited as long as it has to after firing if( m_iClip == 0 && !( iFlags() & ITEM_FLAG_NOAUTORELOAD ) && CanReload( m_flNextPrimaryAttack, gpGlobals->time, IsPredicted() ) ) { Reload(); return; } } WeaponIdle(); return; } // catch all if( ShouldWeaponIdle() ) { WeaponIdle(); } }
void ComputeMissingByteSpans( int numsamples, CSentence& outwords ) { int numwords = outwords.m_Words.Size(); // Nothing to do if ( numwords <= 0 ) return; int interationcount = 1; while( 1 ) { Log( "\nCompute %i\n", interationcount++ ); LogWords( outwords ); int wordNumber; // Done! if ( !CountUnuseableWords( outwords ) ) { FixupZeroLengthWords( outwords ); break; } if ( !CountUsableWords( outwords ) ) { // Evenly space words across full sample time PartitionWords( outwords, 0, numwords - 1, 0, numsamples ); break; } wordNumber = FindFirstUsableWord( outwords ); // Not the first word if ( wordNumber > 0 ) { // Repartition all of the unusables and the first one starting at zero over the range CWordTag *firstUsable = outwords.m_Words[ wordNumber ]; Assert( firstUsable ); if ( firstUsable->m_uiStartByte != 0 ) { PartitionWords( outwords, 0, wordNumber - 1, 0, firstUsable->m_uiStartByte ); } else { PartitionWords( outwords, 0, wordNumber, 0, firstUsable->m_uiEndByte ); } // Start over continue; } wordNumber = FindLastUsableWord( outwords ); // Not the last word if ( wordNumber >= 0 && wordNumber < numwords - 1 ) { // Repartition all of the unusables and the first one starting at zero over the range CWordTag *lastUsable = outwords.m_Words[ wordNumber ]; Assert( lastUsable ); if ( lastUsable->m_uiEndByte != (unsigned int)numsamples ) { PartitionWords( outwords, wordNumber + 1, numwords-1, lastUsable->m_uiEndByte, numsamples ); } else { PartitionWords( outwords, wordNumber, numwords-1, lastUsable->m_uiStartByte, numsamples ); } // Start over continue; } // If we get here it means that the start and end of the list are okay and we just have to // iterate across the list and fix things in the middle int startByte = 0; int endByte = 0; for ( int i = 0; i < numwords ; i++ ) { CWordTag *word = outwords.m_Words[ i ]; if ( IsUseable( word ) ) { startByte = word->m_uiEndByte; continue; } // Found the start of a chain of 1 or more unusable words // Find the startbyte of the next usable word and count how many words we check int wordCount = 1; for ( int j = i + 1; j < numwords; j++ ) { CWordTag *next = outwords.m_Words[ j ]; if ( IsUseable( next ) ) { endByte = next->m_uiStartByte; break; } wordCount++; } // Now partition words across the gap and go to start again PartitionWords( outwords, i, i + wordCount - 1, startByte, endByte ); break; } } }
void SWrapMod::ModifyObject( TimeValue t, ModContext &mc, ObjectState *os, INode *node) { SWrapObject *obj = (SWrapObject *)GetWSMObject(t); INode *pnode; TriObject *towrapOb=NULL;Object *pobj=NULL; if (obj) pnode=obj->custnode; if (obj && nodeRef && pnode) { Interval valid = FOREVER; if (!obj->cmValid.InInterval(t)) { pobj = pnode->EvalWorldState(t).obj; obj->cmValid=pobj->ObjectValidity(t); Matrix3 tm=pnode->GetObjectTM(t,&(obj->cmValid)); TriObject *wrapOb=IsUseable(pobj,t); if (wrapOb) { if (obj->cmesh) delete obj->cmesh; obj->cmesh=new Mesh; obj->cmesh->DeepCopy(&wrapOb->GetMesh(), PART_GEOM|SELECT_CHANNEL|PART_SUBSEL_TYPE|PART_TOPO|TM_CHANNEL); for (int ic=0;ic<obj->cmesh->getNumVerts();ic++) obj->cmesh->verts[ic]=obj->cmesh->verts[ic]*tm; GetVFLst(obj->cmesh,&obj->vnorms,&obj->fnorms); if (wrapOb!=pobj) wrapOb->DeleteThis(); } } if (!obj->cmesh) return; if ((obj->cmesh->getNumVerts()==0)||(obj->cmesh->getNumFaces()==0)) return; // Matrix3 invtm=Inverse(obj->tm); valid=obj->cmValid; Matrix3 ctm; ctm = nodeRef->GetNodeTM(t,&valid); Ray ray; Point3 v=-ctm.GetRow(2); // Matrix3 nooff=invtm;nooff.NoTrans(); ray.dir=v;//*nooff; int selverts; float kdef,standoff; obj->pblock->GetValue(PB_USESELVERTS,t,selverts,valid); obj->pblock->GetValue(PB_KIDEFAULT,t,kdef,valid); obj->pblock->GetValue(PB_STANDOFF,t,standoff,valid); BezierShape stowrapOb; int found=0; Matrix3 towtm(1); if (os->GetTM()) towtm=*(os->GetTM()); Matrix3 invtowtm=Inverse(towtm); Point3 vert; Class_ID cid=os->obj->ClassID(),es=EDITABLE_SURF_CLASS_ID,efp=FITPOINT_PLANE_CLASS_ID,ecv=EDITABLE_CVCURVE_CLASS_ID,ecfp=EDITABLE_FPCURVE_CLASS_ID; if (((cid==EDITABLE_SURF_CLASS_ID)||(cid==FITPOINT_PLANE_CLASS_ID))||((cid==EDITABLE_CVCURVE_CLASS_ID)||(cid==EDITABLE_FPCURVE_CLASS_ID))) { Object* nurbobj=os->obj; int num=nurbobj->NumPoints(); for (int i=0;i<num;i++) { vert=DoIntersect(nurbobj->GetPoint(i)*towtm,ray,obj->cmesh,kdef,standoff,&found,v,obj->vnorms,obj->fnorms); nurbobj->SetPoint(i,(vert*invtowtm)); } } #ifndef NO_PATCHES else if (os->obj->IsSubClassOf(patchObjectClassID)) { PatchObject* patchob=(PatchObject *)os->obj; PatchMesh *pm=&(patchob->patch); int nv=pm->getNumVerts(); BitArray sel = pm->VertSel(); for (int i=0;i<nv;i++) { if (!selverts||sel[i]) { vert=DoIntersect(pm->getVert(i).p*towtm,ray,obj->cmesh,kdef,standoff,&found,v,obj->vnorms,obj->fnorms); vert=vert*invtowtm; pm->setVert(i,vert); } } /* pm->buildLinkages(); pm->computeInteriors(); pm->InvalidateGeomCache();*/ } #endif // NO_PATCHES else if (towrapOb=IsUseable(os->obj,t)) { Point3 tvector; float dist; float *vssel = NULL; if (selverts) vssel = towrapOb->GetMesh().getVSelectionWeights(); for (int i=0;i<towrapOb->GetMesh().getNumVerts();i++) { if ((!selverts)||(towrapOb->GetMesh().vertSel[i]) ||(vssel&&vssel[i])) { vert = DoIntersect(towrapOb->GetMesh().verts[i]*towtm,ray,obj->cmesh,kdef,standoff,&found,v,obj->vnorms,obj->fnorms); vert = vert*invtowtm; if (vssel&&vssel[i]) { tvector = vert - towrapOb->GetMesh().verts[i]; dist = Length(tvector); if ((float)fabs(dist) > EPSILON) tvector = tvector/dist; else tvector = Zero; vert = towrapOb->GetMesh().verts[i] + dist*vssel[i]*tvector; } towrapOb->GetMesh().verts[i] = vert; } } if (towrapOb!=os->obj) towrapOb->DeleteThis(); } else if((os->obj->IsSubClassOf(splineShapeClassID))||(os->obj->CanConvertToType(splineShapeClassID))) { SplineShape *attSplShape = (SplineShape *)os->obj->ConvertToType(t,splineShapeClassID); if (attSplShape) { stowrapOb=attSplShape->shape; for (int poly=0; poly<stowrapOb.splineCount; ++poly) { Spline3D *spline = stowrapOb.GetSpline(poly); int verts = spline->Verts(); int knots = spline->KnotCount(); BitArray sel = stowrapOb.VertexTempSel(poly); Point3 cknot,cknot2; { for(int k=0; k<knots; ++k) { int vert = k * 3 + 1; if (!selverts||sel[vert]) { cknot=DoIntersect(spline->GetKnotPoint(k)*towtm,ray,obj->cmesh,kdef,standoff,&found,v,obj->vnorms,obj->fnorms); attSplShape->shape.SetVert(poly,vert,cknot*invtowtm); if (found) { int knotType = spline->GetKnotType(k); if(knotType & KTYPE_BEZIER) { cknot2= DoIntersect(spline->GetInVec(k)*towtm,ray,obj->cmesh,kdef,standoff,&found,v,obj->vnorms,obj->fnorms); attSplShape->shape.SetVert(poly,vert-1,(found?cknot2:cknot)*invtowtm); cknot2= DoIntersect(spline->GetOutVec(k)*towtm,ray,obj->cmesh,kdef,standoff,&found,v,obj->vnorms,obj->fnorms); attSplShape->shape.SetVert(poly,vert+1,(found?cknot2:cknot)*invtowtm); } } } } } } if (attSplShape!=os->obj) attSplShape->DeleteThis(); } } // os->obj->PointsWereChanged(); os->obj->UpdateValidity(GEOM_CHAN_NUM,valid); // NotifyDependents(FOREVER, PART_ALL, REFMSG_CHANGE); } }