void C4Object::GrabContents(C4Object *pFrom) { // create a temp list of all objects and transfer it // this prevents nasty deadlocks caused by RejectEntrance-scripts C4ObjectList tmpList; tmpList.Copy(pFrom->Contents); for (C4Object *obj : tmpList) if (obj->Status) obj->Enter(this); }
int32_t C4FindObject::Count(const C4ObjectList &Objs) { // Trivial cases if (IsImpossible()) return 0; if (IsEnsured()) return Objs.ObjectCount(); // Count int32_t iCount = 0; for (C4ObjectLink *pLnk = Objs.First; pLnk; pLnk = pLnk->Next) if (pLnk->Obj->Status) if (Check(pLnk->Obj)) iCount++; return iCount; }
int32_t C4FindObject::Count(const C4ObjectList &Objs) { // Trivial cases if (IsImpossible()) return 0; if (IsEnsured()) return Objs.ObjectCount(); // Count int32_t iCount = 0; for (C4Object *obj : Objs) if (obj->Status && Check(obj)) iCount++; return iCount; }
int32_t C4FindObject::Count(const C4ObjectList &Objs, const C4LSectors &Sct) { // Trivial cases if (IsImpossible()) return 0; if (IsEnsured()) return Objs.ObjectCount(); // Check bounds C4Rect *pBounds = GetBounds(); if (!pBounds) return Count(Objs); else if (UseShapes()) { // Get area C4LArea Area(&::Objects.Sectors, *pBounds); C4LSector *pSct; C4ObjectList *pLst = Area.FirstObjectShapes(&pSct); // Check if a single-sector check is enough if (!Area.Next(pSct)) return Count(pSct->ObjectShapes); // Create marker, count over all areas uint32_t iMarker = ::Objects.GetNextMarker(); int32_t iCount = 0; for (; pLst; pLst=Area.NextObjectShapes(pLst, &pSct)) for (C4Object *obj : Objs) if (obj->Status) if (obj->Marker != iMarker) { obj->Marker = iMarker; if (Check(obj)) iCount++; } return iCount; } else { // Count objects per area C4LArea Area(&::Objects.Sectors, *pBounds); C4LSector *pSct; int32_t iCount = 0; for (C4ObjectList *pLst=Area.FirstObjects(&pSct); pLst; pLst=Area.NextObjects(pLst, &pSct)) iCount += Count(*pLst); return iCount; } }
void C4GameObjects::CrossCheck() // Every Tick1 by ExecObjects { C4Object *obj1 = nullptr, *obj2 = nullptr; DWORD ocf1, ocf2, focf, tocf; // AtObject-Check: Checks for first match of obj1 at obj2 // Checks for this frame focf = tocf = OCF_None; // Medium level: Fight if (!Tick5) { focf |= OCF_FightReady; tocf |= OCF_FightReady; } // Very low level: Incineration if (!Tick35) { focf |= OCF_OnFire; tocf |= OCF_Inflammable; } if (focf && tocf) for (C4ObjectList::iterator iter = begin(); iter != end() && (obj1 = *iter); ++iter) if (obj1->Status && !obj1->Contained) if (obj1->OCF & focf) { ocf1 = obj1->OCF; ocf2 = tocf; if (obj2 = AtObject(obj1->x, obj1->y, ocf2, obj1)) { // Incineration if ((ocf1 & OCF_OnFire) && (ocf2 & OCF_Inflammable)) if (!Random(obj2->Def->ContactIncinerate)) { obj2->Incinerate(obj1->GetFireCausePlr(), FALSE, obj1); continue; } // Fight if ((ocf1 & OCF_FightReady) && (ocf2 & OCF_FightReady)) if (Game.Players.Hostile(obj1->Owner, obj2->Owner)) { // RejectFight callback C4AulParSet parset1(C4VObj(obj2)); C4AulParSet parset2(C4VObj(obj1)); if (obj1->Call(PSF_RejectFight, &parset1).getBool()) continue; if (obj2->Call(PSF_RejectFight, &parset2).getBool()) continue; ObjectActionFight(obj1, obj2); ObjectActionFight(obj2, obj1); continue; } } } // Reverse area check: Checks for all obj2 at obj1 focf = tocf = OCF_None; // High level: Collection, Hit if (!Tick3) { focf |= OCF_Collection; tocf |= OCF_Carryable; } focf |= OCF_Alive; tocf |= OCF_HitSpeed2; if (focf && tocf) for (C4ObjectList::iterator iter = begin(); iter != end() && (obj1 = *iter); ++iter) if (obj1->Status && !obj1->Contained && (obj1->OCF & focf)) { uint32_t Marker = GetNextMarker(); C4LSector *pSct; for (C4ObjectList *pLst = obj1->Area.FirstObjects(&pSct); pLst; pLst = obj1->Area.NextObjects(pLst, &pSct)) for (C4ObjectList::iterator iter2 = pLst->begin(); iter2 != pLst->end() && (obj2 = *iter2); ++iter2) if (obj2->Status && !obj2->Contained && (obj2 != obj1) && (obj2->OCF & tocf)) if (Inside<int32_t>(obj2->x - (obj1->x + obj1->Shape.x), 0, obj1->Shape.Wdt - 1)) if (Inside<int32_t>(obj2->y - (obj1->y + obj1->Shape.y), 0, obj1->Shape.Hgt - 1)) if (obj1->pLayer == obj2->pLayer) { // handle collision only once if (obj2->Marker == Marker) continue; obj2->Marker = Marker; // Hit if ((obj2->OCF & OCF_HitSpeed2) && (obj1->OCF & OCF_Alive) && (obj2->Category & C4D_Object)) if (!obj1->Call(PSF_QueryCatchBlow, &C4AulParSet(C4VObj(obj2)))) { if (true /* "realistic" hit energy */) { FIXED dXDir = obj2->xdir - obj1->xdir, dYDir = obj2->ydir - obj1->ydir; int32_t iHitEnergy = fixtoi( (dXDir * dXDir + dYDir * dYDir) * obj2->Mass / 5); iHitEnergy = Max<int32_t>( iHitEnergy / 3, !!iHitEnergy); // hit energy reduced to 1/3rd, // but do not drop to zero because // of this division obj1->DoEnergy(-iHitEnergy / 5, false, C4FxCall_EngObjHit, obj2->Controller); int tmass = Max<int32_t>(obj1->Mass, 50); if (!Tick3 || (obj1->Action.Act >= 0 && obj1->Def->ActMap[obj1->Action.Act].Procedure != DFA_FLIGHT)) obj1->Fling(obj2->xdir * 50 / tmass, -Abs(obj2->ydir / 2) * 50 / tmass, false, obj2->Controller); obj1->Call(PSF_CatchBlow, &C4AulParSet(C4VInt(-iHitEnergy / 5), C4VObj(obj2))); } else { obj1->DoEnergy(-obj2->Mass / 5, false, C4FxCall_EngObjHit, obj2->Controller); int tmass = Max<int32_t>(obj1->Mass, 50); obj1->Fling(obj2->xdir * 50 / tmass, -Abs(obj2->ydir / 2) * 50 / tmass, false, obj2->Controller); obj1->Call(PSF_CatchBlow, &C4AulParSet(C4VInt(-obj2->Mass / 5), C4VObj(obj2))); } // obj1 might have been tampered with if (!obj1->Status || obj1->Contained || !(obj1->OCF & focf)) goto out1; continue; } // Collection if ((obj1->OCF & OCF_Collection) && (obj2->OCF & OCF_Carryable)) if (Inside<int32_t>( obj2->x - (obj1->x + obj1->Def->Collection.x), 0, obj1->Def->Collection.Wdt - 1)) if (Inside<int32_t>( obj2->y - (obj1->y + obj1->Def->Collection.y), 0, obj1->Def->Collection.Hgt - 1)) { // if(!pLst->First) BREAKPOINT_HERE; obj1->Collect(obj2); // if(!pLst->First) BREAKPOINT_HERE; // obj1 might have been tampered with if (!obj1->Status || obj1->Contained || !(obj1->OCF & focf)) goto out1; } } out1: ; } // Contained-Check: Checks for matching Contained // Checks for this frame focf = tocf = OCF_None; // Low level: Fight if (!Tick10) { focf |= OCF_FightReady; tocf |= OCF_FightReady; } if (focf && tocf) for (C4ObjectList::iterator iter = begin(); iter != end() && (obj1 = *iter); ++iter) if (obj1->Status && obj1->Contained && (obj1->OCF & focf)) { for (C4ObjectList::iterator iter2 = obj1->Contained->Contents.begin(); iter2 != end() && (obj2 = *iter2); ++iter2) if (obj2->Status && obj2->Contained && (obj2 != obj1) && (obj2->OCF & tocf)) if (obj1->pLayer == obj2->pLayer) { ocf1 = obj1->OCF; ocf2 = obj2->OCF; // Fight if ((ocf1 & OCF_FightReady) && (ocf2 & OCF_FightReady)) if (Game.Players.Hostile(obj1->Owner, obj2->Owner)) { ObjectActionFight(obj1, obj2); ObjectActionFight(obj2, obj1); // obj1 might have been tampered with if (!obj1->Status || obj1->Contained || !(obj1->OCF & focf)) goto out2; continue; } } out2: ; } }
C4ObjectList::iterator::iterator(const C4ObjectList & List, const C4ObjectLink * pLink, bool reverse): List(List), link(pLink ? *pLink : NULL_LINK), reverse(reverse) { Next=List.AddIter(this); }