void C4RoundResults::EvaluateGoals(C4IDList &GoalList, C4IDList &FulfilledGoalList, int32_t iPlayerNumber)
{
	// clear prev
	GoalList.Clear(); FulfilledGoalList.Clear();
	// Items
	int32_t cnt; C4ID idGoal;
	for (cnt=0; (idGoal=::Objects.GetListID(C4D_Goal,cnt)); cnt++)
	{
		// determine if the goal is fulfilled - do the calls even if the menu is not to be opened to ensure synchronization
		bool fFulfilled = false;;
		C4Object *pObj = C4Id2Def(idGoal) ? ::Objects.Find(::Definitions.ID2Def(idGoal)) : NULL;
		if (pObj)
		{
			// Check fulfilled per player, this enables the possibility of rivalry.
			C4AulParSet pars(C4VInt(iPlayerNumber));
			fFulfilled = !!pObj->Call(PSF_IsFulfilled, &pars);
		}
		GoalList.SetIDCount(idGoal, cnt, true);
		if (fFulfilled) FulfilledGoalList.SetIDCount(idGoal, 1, true);
	}
}
Exemple #2
0
void C4Effect::ClearAll(C4Object *pObj, int32_t iClearFlag)
{
	// simply remove access all effects recursively, and do removal calls
	// this does not regard lower-level effects being added in the removal calls,
	// because this could hang the engine with poorly coded effects
	if (pNext) pNext->ClearAll(pObj, iClearFlag);
	if ((pObj && !pObj->Status) || IsDead()) return;
	int32_t iPrevPrio = iPriority;
	SetDead();
	if (pFnStop)
		if (pFnStop->Exec(CommandTarget, &C4AulParSet(C4VObj(pObj), C4VPropList(this), C4VInt(iClearFlag))).getInt() == C4Fx_Stop_Deny)
		{
			// this stop-callback might have deleted the object and then denied its own removal
			// must not modify self in this case...
			if (pObj && !pObj->Status) return;
			// effect denied to be removed: recover it
			iPriority = iPrevPrio;
		}
	// Update OnFire cache
	if (pObj && WildcardMatch(C4Fx_AnyFire, GetName()) && IsDead())
		if (!Get(C4Fx_AnyFire))
			pObj->SetOnFire(false);
}
Exemple #3
0
void C4Effect::Kill(C4Object *pObj)
{
	// active?
	C4Effect *pLastRemovedEffect=NULL;
	if (IsActive())
		// then temp remove all higher priority effects
		TempRemoveUpperEffects(pObj, false, &pLastRemovedEffect);
	else
		// otherwise: temp reactivate before real removal
		// this happens only if a lower priority effect removes an upper priority effect in its add- or removal-call
		if (pFnStart && iPriority!=1) pFnStart->Exec(CommandTarget, &C4AulParSet(C4VObj(pObj), C4VPropList(this), C4VInt(C4FxCall_TempAddForRemoval)));
	// remove this effect
	int32_t iPrevPrio = iPriority; SetDead();
	if (pFnStop)
		if (pFnStop->Exec(CommandTarget, &C4AulParSet(C4VObj(pObj), C4VPropList(this), C4VInt(C4FxCall_Normal))).getInt() == C4Fx_Stop_Deny)
			// effect denied to be removed: recover
			iPriority = iPrevPrio;
	// reactivate other effects
	TempReaddUpperEffects(pObj, pLastRemovedEffect);
	// Update OnFire cache
	if (pObj && WildcardMatch(C4Fx_AnyFire, GetName()))
		if (!Get(C4Fx_AnyFire))
			pObj->SetOnFire(false);
}
Exemple #4
0
C4Value C4Effect::DoCall(C4Object *pObj, const char *szFn, C4Value &rVal1,
                         C4Value &rVal2, C4Value &rVal3, C4Value &rVal4,
                         C4Value &rVal5, C4Value &rVal6, C4Value &rVal7) {
  // def script or global only?
  C4AulScript *pSrcScript;
  C4Def *pDef;
  if (pCommandTarget) {
    pSrcScript = &pCommandTarget->Def->Script;
    // overwrite ID for sync safety in runtime join
    idCommandTarget = pCommandTarget->id;
  } else if (idCommandTarget && (pDef = Game.Defs.ID2Def(idCommandTarget)))
    pSrcScript = &pDef->Script;
  else
    pSrcScript = &Game.ScriptEngine;
  // compose function name
  char fn[C4AUL_MAX_Identifier + 1];
  sprintf(fn, PSF_FxCustom, Name, szFn);
  // call it
  C4AulFunc *pFn = pSrcScript->GetFuncRecursive(fn);
  if (!pFn) return C4Value();
  return pFn->Exec(pCommandTarget,
                   &C4AulParSet(C4VObj(pObj), C4VInt(iNumber), rVal1, rVal2,
                                rVal3, rVal4, rVal5, rVal6, rVal7));
}
Exemple #5
0
void C4Object::DoMovement()
{
	int32_t iContact=0;
	bool fAnyContact=false; int iContacts = 0;
	BYTE fTurned=0,fRedirectYR=0,fNoAttach=0;
	// Restrictions
	if (Def->NoHorizontalMove) xdir=0;
	// Dig free target area
	C4PropList* pActionDef = GetAction();
	if (pActionDef)
		if (pActionDef->GetPropertyInt(P_DigFree))
		{
			int ctcox, ctcoy;
			// Shape size square
			if (pActionDef->GetPropertyInt(P_DigFree)==1)
			{
				ctcox=fixtoi(fix_x+xdir); ctcoy=fixtoi(fix_y+ydir);
				::Landscape.DigFreeRect(ctcox+Shape.GetX(),ctcoy+Shape.GetY(),Shape.Wdt,Shape.Hgt,this);
			}
			// Free size round (variable size)
			else
			{
				ctcox=fixtoi(fix_x+xdir); ctcoy=fixtoi(fix_y+ydir);
				int32_t rad = pActionDef->GetPropertyInt(P_DigFree);
				if (Con<FullCon) rad = rad*6*Con/5/FullCon;
				::Landscape.DigFree(ctcox,ctcoy-1,rad,this);
			}
		}

	// store previous movement and ocf
	C4Real oldxdir(xdir), oldydir(ydir);
	uint32_t old_ocf = OCF;

	bool fMoved = false;
	C4Real new_x = fix_x + xdir;
	C4Real new_y = fix_y + ydir;
	SideBounds(new_x);

	if (!Action.t_attach) // Unattached movement  = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
	{
		// Horizontal movement - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
		// Move to target
		while (fixtoi(new_x) != fixtoi(fix_x))
		{
			// Next step
			int step = Sign(new_x - fix_x);
			uint32_t border_hack_contacts = 0;
			iContact=ContactCheck(GetX() + step, GetY(), &border_hack_contacts);
			if (iContact || border_hack_contacts)
			{
				fAnyContact=true; iContacts |= t_contact | border_hack_contacts;
			}
			if (iContact)
			{
				// Abort horizontal movement
				new_x = fix_x;
				// Vertical redirection (always)
				RedirectForce(xdir,ydir,-1);
				ApplyFriction(ydir,ContactVtxFriction(this));
			}
			else // Free horizontal movement
			{
				DoMotion(step, 0);
				fMoved = true;
			}
		}
		// Vertical movement - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
		// Movement target
		new_y = fix_y + ydir;
		// Movement bounds (vertical)
		VerticalBounds(new_y);
		// Move to target
		while (fixtoi(new_y) != fixtoi(fix_y))
		{
			// Next step
			int step = Sign(new_y - fix_y);
			if ((iContact=ContactCheck(GetX(), GetY() + step, nullptr, ydir > 0)))
			{
				fAnyContact=true; iContacts |= t_contact;
				new_y = fix_y;
				// Vertical contact horizontal friction
				ApplyFriction(xdir,ContactVtxFriction(this));
				// Redirection slide or rotate
				if (!ContactVtxCNAT(this,CNAT_Left))
					RedirectForce(ydir,xdir,-1);
				else if (!ContactVtxCNAT(this,CNAT_Right))
					RedirectForce(ydir,xdir,+1);
				else
				{
					// living things are always capable of keeping their rotation
					if (OCF & OCF_Rotate) if (iContact==1) if (!Alive)
							{
								RedirectForce(ydir,rdir,-ContactVtxWeight(this));
								fRedirectYR=1;
							}
					ydir=0;
				}
			}
			else // Free vertical movement
			{
				DoMotion(0,step);
				fMoved = true;
			}
		}
	}
	if (Action.t_attach) // Attached movement = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
	{
		VerticalBounds(new_y);
		// Move to target
		do
		{
			// Set next step target
			int step_x = 0, step_y = 0;
			if (fixtoi(new_x) != GetX())
				step_x = Sign(fixtoi(new_x) - GetX());
			else if (fixtoi(new_y) != GetY())
				step_y = Sign(fixtoi(new_y) - GetY());
			int32_t ctx = GetX() + step_x;
			int32_t cty = GetY() + step_y;
			// Attachment check
			if (!Shape.Attach(ctx,cty,Action.t_attach))
				fNoAttach=1;
			else
			{
				// Attachment change to ctx/cty overrides target
				if (ctx != GetX() + step_x)
				{
					xdir = Fix0; new_x = itofix(ctx);
				}
				if (cty != GetY() + step_y)
				{
					ydir = Fix0; new_y = itofix(cty);
				}
			}
			// Contact check & evaluation
			uint32_t border_hack_contacts = 0;
			iContact=ContactCheck(ctx,cty,&border_hack_contacts);
			if (iContact || border_hack_contacts)
			{
				fAnyContact=true; iContacts |= border_hack_contacts | t_contact;
			}
			if (iContact)
			{
				// Abort movement
				if (ctx != GetX())
				{
					ctx = GetX(); new_x = fix_x;
				}
				if (cty != GetY())
				{
					cty = GetY(); new_y = fix_y;
				}
			}
			DoMotion(ctx - GetX(), cty - GetY());
			fMoved = true;
		}
		while (fixtoi(new_x) != GetX() || fixtoi(new_y) != GetY());
	}

	if(fix_x != new_x || fix_y != new_y)
	{
		fMoved = true;
		if (pSolidMaskData) pSolidMaskData->Remove(true);
		fix_x = new_x;
		fix_y = new_y;
	}
	// Rotation  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
	if (OCF & OCF_Rotate && !!rdir)
	{
		C4Real target_r = fix_r + rdir * 5;
		// Rotation limit
		if (Def->Rotateable>1)
		{
			if (target_r > itofix(Def->Rotateable))
				{ target_r = itofix(Def->Rotateable); rdir=0; }
			if (target_r < itofix(-Def->Rotateable))
				{ target_r = itofix(-Def->Rotateable); rdir=0; }
		}
		int32_t ctx=GetX(); int32_t cty=GetY();
		// Move to target
		while (fixtoi(fix_r) != fixtoi(target_r))
		{
			// Save step undos
			C4Real lcobjr = fix_r; C4Shape lshape=Shape;
			// Try next step
			fix_r += Sign(target_r - fix_r);
			UpdateShape();
			// attached rotation: rotate around attachment pos
			if (Action.t_attach && !fNoAttach)
			{
				// more accurately, attachment should be evaluated by a rotation around the attachment vertex
				// however, as long as this code is only used for some surfaces adjustment for large vehicles,
				// it's enough to assume rotation around the center
				ctx=GetX(); cty=GetY();
				// evaluate attachment, but do not bother about attachment loss
				// that will then be done in next execution cycle
				Shape.Attach(ctx,cty,Action.t_attach);
			}
			// check for contact
			if ((iContact=ContactCheck(ctx,cty))) // Contact
			{
				fAnyContact=true; iContacts |= t_contact;
				// Undo step and abort movement
				Shape=lshape;
				target_r = fix_r = lcobjr;
				// last UpdateShape-call might have changed sector lists!
				UpdatePos();
				// Redirect to GetY()
				if (iContact==1) if (!fRedirectYR)
						RedirectForce(rdir,ydir,-1);
				// Stop rotation
				rdir=0;
			}
			else
			{
				fTurned=1;
				if (ctx != GetX() || cty != GetY())
				{
					fix_x = itofix(ctx); fix_y = itofix(cty);
				}
			}
		}
		// Circle bounds
		if (target_r < -FixHalfCircle) { target_r += FixFullCircle; }
		if (target_r > +FixHalfCircle) { target_r -= FixFullCircle; }
		fix_r = target_r;
	}
	// Reput solid mask if moved by motion
	if (fMoved || fTurned) UpdateSolidMask(true);
	// Misc checks ===========================================================================================
	// InLiquid check
	// this equals C4Object::UpdateLiquid, but the "fNoAttach=false;"-line
	if (IsInLiquidCheck()) // In Liquid
	{
		if (!InLiquid) // Enter liquid
		{
			if (OCF & OCF_HitSpeed2) if (Mass>3)
					Splash(GetX(),GetY()+1,std::min(Shape.Wdt*Shape.Hgt/10,20),this);
			fNoAttach=false;
			InLiquid=1;
		}
	}
	else // Out of liquid
	{
		if (InLiquid) // Leave liquid
			InLiquid=0;
	}
	// Contact Action
	if (fAnyContact)
	{
		t_contact = iContacts;
		ContactAction();
	}
	// Attachment Loss Action
	if (fNoAttach)
		NoAttachAction();
	// Movement Script Execution
	if (fAnyContact)
	{
		C4AulParSet pars(C4VInt(fixtoi(oldxdir, 100)), C4VInt(fixtoi(oldydir, 100)));
		if (old_ocf & OCF_HitSpeed1) Call(PSF_Hit, &pars);
		if (old_ocf & OCF_HitSpeed2) Call(PSF_Hit2, &pars);
		if (old_ocf & OCF_HitSpeed3) Call(PSF_Hit3, &pars);
	}
	// Rotation gfx
	if (fTurned)
		UpdateFace(true);
	else
		// pos changed?
		if (fMoved) UpdatePos();
}
Exemple #6
0
void C4MapScriptHost::InitFunctionMap(C4AulScriptEngine *pEngine)
{
	// Register script host. Add Map and MapLayer prototypes, related constants and engine functions
	assert(pEngine && pEngine->GetPropList());
	Clear();
	LayerPrototype = new C4PropListStaticMember(NULL, NULL, ::Strings.RegString("MapLayer"));
	MapPrototype = new C4PropListStaticMember(LayerPrototype, NULL, ::Strings.RegString("Map"));
	LayerPrototype->SetName("MapLayer");
	MapPrototype->SetName("Map");
	::ScriptEngine.RegisterGlobalConstant("MapLayer", C4VPropList(LayerPrototype));
	::ScriptEngine.RegisterGlobalConstant("Map", C4VPropList(MapPrototype));
	::ScriptEngine.RegisterGlobalConstant("MAPALGO_Layer", C4VInt(MAPALGO_Layer));
	::ScriptEngine.RegisterGlobalConstant("MAPALGO_RndChecker", C4VInt(MAPALGO_RndChecker));
	::ScriptEngine.RegisterGlobalConstant("MAPALGO_And", C4VInt(MAPALGO_And));
	::ScriptEngine.RegisterGlobalConstant("MAPALGO_Or", C4VInt(MAPALGO_Or));
	::ScriptEngine.RegisterGlobalConstant("MAPALGO_Xor", C4VInt(MAPALGO_Xor));
	::ScriptEngine.RegisterGlobalConstant("MAPALGO_Not", C4VInt(MAPALGO_Not));
	::ScriptEngine.RegisterGlobalConstant("MAPALGO_Scale", C4VInt(MAPALGO_Scale));
	::ScriptEngine.RegisterGlobalConstant("MAPALGO_Rotate", C4VInt(MAPALGO_Rotate));
	::ScriptEngine.RegisterGlobalConstant("MAPALGO_Offset", C4VInt(MAPALGO_Offset));
	::ScriptEngine.RegisterGlobalConstant("MAPALGO_Rect", C4VInt(MAPALGO_Rect));
	::ScriptEngine.RegisterGlobalConstant("MAPALGO_Ellipsis", C4VInt(MAPALGO_Ellipsis));
	::ScriptEngine.RegisterGlobalConstant("MAPALGO_Polygon", C4VInt(MAPALGO_Polygon));
	::ScriptEngine.RegisterGlobalConstant("MAPALGO_Lines", C4VInt(MAPALGO_Lines));
	::ScriptEngine.RegisterGlobalConstant("MAPALGO_Turbulence", C4VInt(MAPALGO_Turbulence));
	::ScriptEngine.RegisterGlobalConstant("MAPALGO_Border", C4VInt(MAPALGO_Border));
	::ScriptEngine.RegisterGlobalConstant("MAPALGO_Filter", C4VInt(MAPALGO_Filter));
	Reg2List(pEngine);
	AddEngineFunctions();
}
Exemple #7
0
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:
        ;
      }
}
Exemple #8
0
int32_t FnFxFireStart(C4AulContext *ctx, C4Object *pObj, int32_t iNumber,
                      int32_t iTemp, int32_t iCausedBy, bool fBlasted,
                      C4Object *pIncineratingObject) {
  // safety
  if (!pObj)
    return -1;
  // temp readd
  if (iTemp) {
    pObj->SetOnFire(true);
    return 1;
  }
  // fail if already on fire
  if (pObj->GetOnFire())
    return -1;
  // get associated effect
  C4Effect *pEffect;
  if (!(pEffect = pObj->pEffects))
    return -1;
  if (!(pEffect = pEffect->Get(iNumber, true)))
    return -1;
  // structures must eject contents now, because DoCon is not guaranteed to be
  // executed!
  // In extinguishing material
  BOOL fFireCaused = TRUE;
  int32_t iMat;
  if (MatValid(iMat = GBackMat(pObj->x, pObj->y)))
    if (Game.Material.Map[iMat].Extinguisher) {
      // blasts should changedef in water, too!
      if (fBlasted)
        if (pObj->Def->BurnTurnTo != C4ID_None)
          pObj->ChangeDef(pObj->Def->BurnTurnTo);
      // no fire caused
      fFireCaused = FALSE;
    }
  // BurnTurnTo
  if (fFireCaused)
    if (pObj->Def->BurnTurnTo != C4ID_None)
      pObj->ChangeDef(pObj->Def->BurnTurnTo);
  // eject contents
  C4Object *cobj;
  if (!pObj->Def->IncompleteActivity && !pObj->Def->NoBurnDecay)
    while (cobj = pObj->Contents.GetObject()) {
      cobj->Controller = iCausedBy; // update controller, so incinerating a hut
                                    // full of flints attributes the damage to
                                    // the incinerator
      if (pObj->Contained)
        cobj->Enter(pObj->Contained);
      else
        cobj->Exit(cobj->x, cobj->y);
    }
  // Detach attached objects
  cobj = 0;
  if (!pObj->Def->IncompleteActivity && !pObj->Def->NoBurnDecay)
    while (cobj = Game.FindObject(0, 0, 0, 0, 0, OCF_All, 0, pObj, 0, 0,
                                  ANY_OWNER, cobj))
      if ((cobj->Action.Act > ActIdle) &&
          (cobj->Def->ActMap[cobj->Action.Act].Procedure == DFA_ATTACH))
        cobj->SetAction(ActIdle);
  // fire caused?
  if (!fFireCaused) {
    // if object was blasted but not incinerated (i.e., inside extinguisher)
    // do a script callback
    if (fBlasted)
      pObj->Call(PSF_IncinerationEx, &C4AulParSet(C4VInt(iCausedBy)));
    return -1;
  }
  // determine fire appearance
  int32_t iFireMode;
  if (!(iFireMode = pObj->Call(PSF_FireMode).getInt())) {
    // set default fire modes
    DWORD dwCat = pObj->Category;
    if (dwCat & (C4D_Living | C4D_StaticBack)) // Tiere, Bäume
      iFireMode = C4Fx_FireMode_LivingVeg;
    else if (dwCat & (C4D_Structure | C4D_Vehicle)) // Gebäude und Fahrzeuge
                                                    // sind unten meist kantig
      iFireMode = C4Fx_FireMode_StructVeh;
    else
      iFireMode = C4Fx_FireMode_Object;
  } else if (!Inside<int32_t>(iFireMode, 1, C4Fx_FireMode_Last)) {
    DebugLogF("Warning: FireMode %d of object %s (%s) is invalid!", iFireMode,
              pObj->GetName(), pObj->Def->GetName());
    iFireMode = C4Fx_FireMode_Object;
  }
  // store causes in effect vars
  FxFireVarMode(pEffect).SetInt(iFireMode);
  FxFireVarCausedBy(pEffect)
      .SetInt(iCausedBy); // used in C4Object::GetFireCause and timer!
  FxFireVarBlasted(pEffect).SetBool(fBlasted);
  FxFireVarIncineratingObj(pEffect).SetObject(pIncineratingObject);
  // Set values
  pObj->SetOnFire(true);
  pObj->FirePhase = Random(MaxFirePhase);
  if (pObj->Shape.Wdt * pObj->Shape.Hgt > 500)
    StartSoundEffect("Inflame", false, 100, pObj);
  if (pObj->Def->Mass >= 100)
    StartSoundEffect("Fire", true, 100, pObj);
  // Engine script call
  pObj->Call(PSF_Incineration, &C4AulParSet(C4VInt(iCausedBy)));
  // Done, success
  return C4Fx_OK;
}
Exemple #9
0
C4Effect::C4Effect(C4Object *pForObj, const char *szName, int32_t iPrio,
                   int32_t iTimerIntervall, C4Object *pCmdTarget,
                   C4ID idCmdTarget, C4Value &rVal1, C4Value &rVal2,
                   C4Value &rVal3, C4Value &rVal4, bool fDoCalls,
                   int32_t &riStoredAsNumber)
    : EffectVars(0) {
  C4Effect *pPrev, *pCheck;
  // assign values
  SCopy(szName, Name, C4MaxDefString);
  iPriority = 0; // effect is not yet valid; some callbacks to other effects are
                 // done before
  riStoredAsNumber = 0;
  iIntervall = iTimerIntervall;
  iTime = 0;
  pCommandTarget = pCmdTarget;
  idCommandTarget = idCmdTarget;
  AssignCallbackFunctions();
  // get effect target
  C4Effect **ppEffectList = pForObj ? &pForObj->pEffects : &Game.pGlobalEffects;
  // assign a unique number for that object
  iNumber = 1;
  for (pCheck = *ppEffectList; pCheck; pCheck = pCheck->pNext)
    if (pCheck->iNumber >= iNumber)
      iNumber = pCheck->iNumber + 1;
  // register into object
  pPrev = *ppEffectList;
  if (pPrev && Abs(pPrev->iPriority) < iPrio) {
    while (pCheck = pPrev->pNext)
      if (Abs(pCheck->iPriority) >= iPrio)
        break;
      else
        pPrev = pCheck;
    // insert after previous
    pNext = pPrev->pNext;
    pPrev->pNext = this;
  } else {
    // insert as first effect
    pNext = *ppEffectList;
    *ppEffectList = this;
  }
  // no calls to be done: finished here
  if (!fDoCalls)
    return;
  // ask all effects with higher priority first - except for prio 1 effects,
  // which are considered out of the priority call chain (as per doc)
  bool fRemoveUpper = (iPrio != 1);
  // note that apart from denying the creation of this effect, higher priority
  // effects may also remove themselves
  // or do other things with the effect list
  // (which does not quite make sense, because the effect might be denied by
  // another effect)
  // so the priority is assigned after this call, marking this effect dead
  // before it's definitely valid
  if (fRemoveUpper && pNext) {
    int32_t iResult = pNext->Check(pForObj, Name, iPrio, iIntervall, rVal1,
                                   rVal2, rVal3, rVal4);
    if (iResult) {
      // effect denied (iResult = -1), added to an effect (iResult = Number of
      // that effect)
      // or added to an effect that destroyed itself (iResult = -2)
      if (iResult != C4Fx_Effect_Deny)
        riStoredAsNumber = iResult;
      // effect is still marked dead
      return;
    }
  }
  // init effect
  // higher-priority effects must be deactivated temporarily, and then
  // reactivated regarding the new effect
  // higher-level effects should not be inserted during the process of removing
  // or adding a lower-level effect
  // because that would cause a wrong initialization order
  // (hardly ever causing trouble, however...)
  C4Effect *pLastRemovedEffect = NULL;
  if (fRemoveUpper && pNext && pFnStart)
    TempRemoveUpperEffects(pForObj, false, &pLastRemovedEffect);
  // bad things may happen
  if (pForObj && !pForObj->Status)
    return;          // this will be invalid!
  iPriority = iPrio; // validate effect now
  if (pFnStart)
    if (pFnStart->Exec(pCommandTarget,
                       &C4AulParSet(C4VObj(pForObj), C4VInt(iNumber), C4VInt(0),
                                    rVal1, rVal2, rVal3, rVal4)).getInt() ==
        C4Fx_Start_Deny)
      // the effect denied to start: assume it hasn't, and mark it dead
      SetDead();
  if (fRemoveUpper && pNext && pFnStart)
    TempReaddUpperEffects(pForObj, pLastRemovedEffect);
  if (pForObj && !pForObj->Status)
    return; // this will be invalid!
  // this effect has been created; hand back the number
  riStoredAsNumber = iNumber;
}
Exemple #10
0
C4Effect * C4Effect::New(C4Object * pForObj, C4String * szName, int32_t iPrio, int32_t iTimerInterval, C4Object * pCmdTarget, C4ID idCmdTarget, const C4Value &rVal1, const C4Value &rVal2, const C4Value &rVal3, const C4Value &rVal4)
{
	C4Effect * pEffect = new C4Effect(pForObj, szName, iPrio, iTimerInterval, pCmdTarget, idCmdTarget, rVal1, rVal2, rVal3, rVal4);
	// ask all effects with higher priority first - except for prio 1 effects, which are considered out of the priority call chain (as per doc)
	bool fRemoveUpper = (iPrio != 1);
	// note that apart from denying the creation of this effect, higher priority effects may also remove themselves
	// or do other things with the effect list
	// (which does not quite make sense, because the effect might be denied by another effect)
	// so the priority is assigned after this call, marking this effect dead before it's definitely valid
	if (fRemoveUpper && pEffect->pNext)
	{
		C4Effect * pEffect2 = pEffect->pNext->Check(pForObj, szName->GetCStr(), iPrio, iTimerInterval, rVal1, rVal2, rVal3, rVal4);
		if (pEffect2)
		{
			// effect denied (iResult = -1), added to an effect (iResult = Number of that effect)
			// or added to an effect that destroyed itself (iResult = -2)
			if (pEffect2 != (C4Effect*)C4Fx_Effect_Deny && pEffect2 != (C4Effect*)C4Fx_Effect_Annul) return pEffect2;
			// effect is still marked dead
			return 0;
		}
	}
	// init effect
	// higher-priority effects must be deactivated temporarily, and then reactivated regarding the new effect
	// higher-level effects should not be inserted during the process of removing or adding a lower-level effect
	// because that would cause a wrong initialization order
	// (hardly ever causing trouble, however...)
	C4Effect *pLastRemovedEffect=NULL;
	if (fRemoveUpper && pEffect->pNext && pEffect->pFnStart)
		pEffect->TempRemoveUpperEffects(pForObj, false, &pLastRemovedEffect);
	// bad things may happen
	if (pForObj && !pForObj->Status) return 0; // this will be invalid!
	pEffect->iPriority = iPrio; // validate effect now
	if (pEffect->pFnStart)
		if (pEffect->pFnStart->Exec(pCmdTarget, &C4AulParSet(C4VObj(pForObj), C4VPropList(pEffect), C4VInt(0), rVal1, rVal2, rVal3, rVal4)).getInt() == C4Fx_Start_Deny)
			// the effect denied to start: assume it hasn't, and mark it dead
			pEffect->SetDead();
	if (fRemoveUpper && pEffect->pNext && pEffect->pFnStart)
		pEffect->TempReaddUpperEffects(pForObj, pLastRemovedEffect);
	if (pForObj && !pForObj->Status) return 0; // this will be invalid!
	// Update OnFire cache
	if (!pEffect->IsDead() && pForObj && WildcardMatch(C4Fx_AnyFire, szName->GetCStr()))
		pForObj->SetOnFire(true);
	return pEffect;
}
Exemple #11
0
void C4Effect::TempReaddUpperEffects(C4Object *pObj, C4Effect *pLastReaddEffect)
{
	// nothing to do? - this will also happen if TempRemoveUpperEffects did nothing due to priority==1
	if (!pLastReaddEffect) return;
	if (pObj && !pObj->Status) return; // this will be invalid!
	// simply activate all following, inactive effects
	for (C4Effect *pEff = pNext; pEff; pEff = pEff->pNext)
	{
		if (pEff->IsInactiveAndNotDead())
		{
			pEff->FlipActive();
			if (pEff->pFnStart && pEff->iPriority!=1) pEff->pFnStart->Exec(pEff->CommandTarget, &C4AulParSet(C4VObj(pObj), C4VPropList(pEff), C4VInt(C4FxCall_Temp)));
			if (pObj && WildcardMatch(C4Fx_AnyFire, pEff->GetName()))
				pObj->SetOnFire(true);
		}
		// done?
		if (pEff == pLastReaddEffect) break;
	}
}
Exemple #12
0
void C4Effect::TempRemoveUpperEffects(C4Object *pObj, bool fTempRemoveThis, C4Effect **ppLastRemovedEffect)
{
	if (pObj && !pObj->Status) return; // this will be invalid!
	// priority=1: no callbacks
	if (iPriority == 1) return;
	// remove from high to low priority
	// recursive implementation...
	C4Effect *pEff = pNext;
		while (pEff) if (pEff->IsActive()) break; else pEff = pEff->pNext;
	// temp remove active effects with higher priority
	if (pEff) pEff->TempRemoveUpperEffects(pObj, true, ppLastRemovedEffect);
	// temp remove this
	if (fTempRemoveThis)
	{
		FlipActive();
		// Update OnFire cache
		if (pObj && WildcardMatch(C4Fx_AnyFire, GetName()))
			if (!Get(C4Fx_AnyFire))
				pObj->SetOnFire(false);
		// temp callbacks only for higher priority effects
		if (pFnStop && iPriority!=1) pFnStop->Exec(CommandTarget, &C4AulParSet(C4VObj(pObj), C4VPropList(this), C4VInt(C4FxCall_Temp), C4VBool(true)));
		if (!*ppLastRemovedEffect) *ppLastRemovedEffect = this;
	}
}
Exemple #13
0
void C4Effect::DoDamage(C4Object *pObj, int32_t &riDamage, int32_t iDamageType, int32_t iCausePlr)
{
	// ask all effects for damage adjustments
	C4Effect *pEff = this;
	do
	{
		if (!pEff->IsDead() && pEff->pFnDamage)
			riDamage = pEff->pFnDamage->Exec(pEff->CommandTarget, &C4AulParSet(C4VObj(pObj), C4VPropList(pEff), C4VInt(riDamage), C4VInt(iDamageType), C4VInt(iCausePlr))).getInt();
		if (pObj && !pObj->Status) return;
	}
	while ((pEff = pEff->pNext) && riDamage);
}
Exemple #14
0
void C4Effect::Execute(C4Object *pObj)
{
	// get effect list
	C4Effect **ppEffectList = pObj ? &pObj->pEffects : &Game.pGlobalEffects;
	// execute all effects not marked as dead
	C4Effect *pEffect = this, **ppPrevEffect=ppEffectList;
	do
	{
		// effect dead?
		if (pEffect->IsDead())
		{
			// delete it, then
			C4Effect *pNextEffect = pEffect->pNext;
			pEffect->pNext = NULL;
			delete pEffect;
			// next effect
			*ppPrevEffect = pEffect = pNextEffect;
		}
		else
		{
			// execute effect: time elapsed
			++pEffect->iTime;
			// check timer execution
			if (pEffect->iInterval && !(pEffect->iTime % pEffect->iInterval))
			{
				if (pEffect->pFnTimer)
				{
					if (pEffect->pFnTimer->Exec(pEffect->CommandTarget, &C4AulParSet(C4VObj(pObj), C4VPropList(pEffect), C4VInt(pEffect->iTime))).getInt() == C4Fx_Execute_Kill)
					{
						// safety: this class got deleted!
						if (pObj && !pObj->Status) return;
						// timer function decided to finish it
						pEffect->Kill(pObj);
					}
					// safety: this class got deleted!
					if (pObj && !pObj->Status) return;
				}
				else
					// no timer function: mark dead after time elapsed
					pEffect->Kill(pObj);
			}
			// next effect
			ppPrevEffect = &pEffect->pNext;
			pEffect = pEffect->pNext;
		}
	}
	while (pEffect);
}
Exemple #15
0
TEST_F(AulTest, Eval)
{
	EXPECT_EQ(C4VInt(42), RunExpr("eval(\"42\")"));
	EXPECT_EQ(C4VInt(42), RunCode("local i = 42; func Main() { return eval(\"this.i\"); }", false));
	EXPECT_EQ(C4VInt(42), RunCode("local i; func Main() { eval(\"this.i = 42\"); return i; }", false));
}