/src/game/object/C4GameObjects.cpp
C++ | 1008 lines | 737 code | 80 blank | 191 comment | 249 complexity | 560831bb82e903f953ea439bc942c9cb MD5 | raw file
Possible License(s): WTFPL, 0BSD, LGPL-2.1, CC-BY-3.0
- /*
- * OpenClonk, http://www.openclonk.org
- *
- * Copyright (c) 2001-2002, 2004-2008 Sven Eberhardt
- * Copyright (c) 2004 Matthes Bender
- * Copyright (c) 2004, 2006-2008 Peter Wortmann
- * Copyright (c) 2005-2008 G?nther Brammer
- * Copyright (c) 2001-2009, RedWolf Design GmbH, http://www.clonk.de
- *
- * Portions might be copyrighted by other authors who have contributed
- * to OpenClonk.
- *
- * Permission to use, copy, modify, and/or distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- * See isc_license.txt for full license and disclaimer.
- *
- * "Clonk" is a registered trademark of Matthes Bender.
- * See clonk_trademark_license.txt for full license.
- */
- // game object lists
- #include <C4Include.h>
- #include <C4GameObjects.h>
- #ifndef BIG_C4INCLUDE
- #include <C4Object.h>
- #include <C4ObjectCom.h>
- #include <C4Random.h>
- #include <C4SolidMask.h>
- #include <C4Network2Stats.h>
- #include <C4Game.h>
- #include <C4Log.h>
- #include <C4PlayerList.h>
- #include <C4Record.h>
- #endif
- C4GameObjects::C4GameObjects()
- {
- Default();
- }
- C4GameObjects::~C4GameObjects()
- {
- Sectors.Clear();
- }
- void C4GameObjects::Default()
- {
- ResortProc=NULL;
- Sectors.Clear();
- LastUsedMarker = 0;
- BackObjects.Default();
- ForeObjects.Default();
- }
- void C4GameObjects::Init(int32_t iWidth, int32_t iHeight)
- {
- // init sectors
- Sectors.Init(iWidth, iHeight);
- }
- bool C4GameObjects::Add(C4Object *nObj)
- {
- // add inactive objects to the inactive list only
- if (nObj->Status == C4OS_INACTIVE)
- return InactiveObjects.Add(nObj, C4ObjectList::stMain);
- // if this is a background object, add it to the list
- if (nObj->Category & C4D_Background)
- ::Objects.BackObjects.Add(nObj, C4ObjectList::stMain);
- // if this is a foreground object, add it to the list
- if (nObj->Category & C4D_Foreground)
- ::Objects.ForeObjects.Add(nObj, C4ObjectList::stMain);
- // manipulate main list
- if(!C4ObjectList::Add(nObj, C4ObjectList::stMain))
- return false;
- // add to sectors
- Sectors.Add(nObj, this);
- return true;
- }
- bool C4GameObjects::Remove(C4Object *pObj)
- {
- // if it's an inactive object, simply remove from the inactiv elist
- if (pObj->Status == C4OS_INACTIVE) return InactiveObjects.Remove(pObj);
- // remove from sectors
- Sectors.Remove(pObj);
- // remove from backlist
- ::Objects.BackObjects.Remove(pObj);
- // remove from forelist
- ::Objects.ForeObjects.Remove(pObj);
- // manipulate main list
- return C4ObjectList::Remove(pObj);
- }
- C4ObjectList &C4GameObjects::ObjectsAt(int ix, int iy)
- {
- return Sectors.SectorAt(ix, iy)->ObjectShapes;
- }
- void C4GameObjects::CrossCheck() // Every Tick1 by ExecObjects
- {
- C4Object *obj1,*obj2;
- 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 (!::Game.iTick5)
- { focf|=OCF_FightReady; tocf|=OCF_FightReady; }
- // Very low level: Incineration
- if (!::Game.iTick35)
- { 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->GetX(),obj1->GetY(),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 (::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 (!::Game.iTick3)
- { 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))
- {
- unsigned int Marker = ++LastUsedMarker;
- 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->GetX()-(obj1->GetX()+obj1->Shape.x),0,obj1->Shape.Wdt-1))
- if (Inside<int32_t>(obj2->GetY()-(obj1->GetY()+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 (!::Game.iTick3 || (obj1->Action.pActionDef && obj1->Action.pActionDef->GetPropertyInt(P_Procedure) != DFA_FLIGHT))
- obj1->Fling(obj2->xdir*50/tmass,-Abs(obj2->ydir/2)*50/tmass, false);
- 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);
- 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->GetX()-(obj1->GetX()+obj1->Def->Collection.x),0,obj1->Def->Collection.Wdt-1))
- if (Inside<int32_t>(obj2->GetY()-(obj1->GetY()+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 (!::Game.iTick10)
- { 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 (::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: ;
- }
- }