Advertisement
inkoalawetrust

GZDoom's native Tick() virtual code.

Mar 23rd, 2021
867
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 15.49 KB | None | 0 0
  1. void AActor::Tick ()
  2. {
  3.     // [RH] Data for Heretic/Hexen scrolling sectors
  4.     static const int8_t HexenCompatSpeeds[] = {-25, 0, -10, -5, 0, 5, 10, 0, 25 };
  5.     static const int8_t HexenScrollies[24][2] =
  6.     {
  7.         {  0,  1 }, {  0,  2 }, {  0,  4 },
  8.         { -1,  0 }, { -2,  0 }, { -4,  0 },
  9.         {  0, -1 }, {  0, -2 }, {  0, -4 },
  10.         {  1,  0 }, {  2,  0 }, {  4,  0 },
  11.         {  1,  1 }, {  2,  2 }, {  4,  4 },
  12.         { -1,  1 }, { -2,  2 }, { -4,  4 },
  13.         { -1, -1 }, { -2, -2 }, { -4, -4 },
  14.         {  1, -1 }, {  2, -2 }, {  4, -4 }
  15.     };
  16.  
  17.     static const uint8_t HereticScrollDirs[4] = { 6, 9, 1, 4 };
  18.     static const uint8_t HereticSpeedMuls[5] = { 5, 10, 25, 30, 35 };
  19.  
  20.  
  21.     AActor *onmo;
  22.  
  23.     //assert (state != NULL);
  24.     if (state == NULL)
  25.     {
  26.         Printf("Actor of type %s at (%f,%f) left without a state\n", GetClass()->TypeName.GetChars(), X(), Y());
  27.         Destroy();
  28.         return;
  29.     }
  30.  
  31.     if (flags5 & MF5_NOINTERACTION)
  32.     {
  33.         // only do the minimally necessary things here to save time:
  34.         // Check the time freezer
  35.         // apply velocity
  36.         // ensure that the actor is not linked into the blockmap
  37.  
  38.         //Added by MC: Freeze mode.
  39.         if (isFrozen())
  40.         {
  41.             // Boss cubes shouldn't be accelerated by timefreeze
  42.             if (flags6 & MF6_BOSSCUBE)
  43.             {
  44.                 special2++;
  45.             }
  46.             return;
  47.         }
  48.  
  49.         if (!Vel.isZero() || !(flags & MF_NOBLOCKMAP))
  50.         {
  51.             FLinkContext ctx;
  52.             UnlinkFromWorld(&ctx);
  53.             flags |= MF_NOBLOCKMAP;
  54.             SetXYZ(Vec3Offset(Vel));
  55.             CheckPortalTransition(false);
  56.             LinkToWorld(&ctx);
  57.         }
  58.         flags8 &= ~MF8_INSCROLLSEC;
  59.     }
  60.     else
  61.     {
  62.  
  63.         if (!player || !(player->cheats & CF_PREDICTING))
  64.         {
  65.             // Handle powerup effects here so that the order is controlled
  66.             // by the order in the inventory, not the order in the thinker table
  67.             AActor *item = Inventory;
  68.            
  69.             while (item != NULL)
  70.             {
  71.                 IFVIRTUALPTRNAME(item, NAME_Inventory, DoEffect)
  72.                 {
  73.                     VMValue params[1] = { item };
  74.                     VMCall(func, params, 1, nullptr, 0);
  75.                 }
  76.                 item = item->Inventory;
  77.             }
  78.         }
  79.  
  80.         if (flags & MF_UNMORPHED)
  81.         {
  82.             return;
  83.         }
  84.  
  85.         if (isFrozen())
  86.         {
  87.             // Boss cubes shouldn't be accelerated by timefreeze
  88.             if (flags6 & MF6_BOSSCUBE)
  89.             {
  90.                 special2++;
  91.             }
  92.             return;
  93.         }
  94.  
  95.         if (effects & FX_ROCKET)
  96.         {
  97.             if (++smokecounter == 4)
  98.             {
  99.                 // add some smoke behind the rocket
  100.                 smokecounter = 0;
  101.                 AActor *th = Spawn(Level, "RocketSmokeTrail", Vec3Offset(-Vel), ALLOW_REPLACE);
  102.                 if (th)
  103.                 {
  104.                     th->tics -= pr_rockettrail()&3;
  105.                     if (th->tics < 1) th->tics = 1;
  106.                     if (!(cl_rockettrails & 2)) th->renderflags |= RF_INVISIBLE;
  107.                 }
  108.             }
  109.         }
  110.         else if (effects & FX_GRENADE)
  111.         {
  112.             if (++smokecounter == 8)
  113.             {
  114.                 smokecounter = 0;
  115.                 DAngle moveangle = Vel.Angle();
  116.                 double xo = -moveangle.Cos() * radius * 2 + pr_rockettrail() / 64.;
  117.                 double yo = -moveangle.Sin() * radius * 2 + pr_rockettrail() / 64.;
  118.                 double zo = -Height * Vel.Z / 8. + Height * (2 / 3.);
  119.                 AActor * th = Spawn(Level, "GrenadeSmokeTrail", Vec3Offset(xo, yo, zo), ALLOW_REPLACE);
  120.                 if (th)
  121.                 {
  122.                     th->tics -= pr_rockettrail()&3;
  123.                     if (th->tics < 1) th->tics = 1;
  124.                     if (!(cl_rockettrails & 2)) th->renderflags |= RF_INVISIBLE;
  125.                 }
  126.             }
  127.         }
  128.  
  129.         double oldz = Z();
  130.  
  131.         // [RH] Give the pain elemental vertical friction
  132.         // This used to be in APainElemental::Tick but in order to use
  133.         // A_PainAttack with other monsters it has to be here
  134.         if (flags4 & MF4_VFRICTION)
  135.         {
  136.             if (health >0)
  137.             {
  138.                 if (fabs (Vel.Z) < 0.25)
  139.                 {
  140.                     Vel.Z = 0;
  141.                     flags4 &= ~MF4_VFRICTION;
  142.                 }
  143.                 else
  144.                 {
  145.                     Vel.Z *= (0xe800 / 65536.);
  146.                 }
  147.             }
  148.         }
  149.  
  150.         // [RH] Pulse in and out of visibility
  151.         if (effects & FX_VISIBILITYPULSE)
  152.         {
  153.             if (visdir > 0)
  154.             {
  155.                 Alpha += 1/32.;
  156.                 if (Alpha >= 1.)
  157.                 {
  158.                     Alpha = 1.;
  159.                     visdir = -1;
  160.                 }
  161.             }
  162.             else
  163.             {
  164.                 Alpha -= 1/32.;
  165.                 if (Alpha <= 0.25)
  166.                 {
  167.                     Alpha = 0.25;
  168.                     visdir = 1;
  169.                 }
  170.             }
  171.         }
  172.         else if (flags & MF_STEALTH)
  173.         {
  174.             // [RH] Fade a stealth monster in and out of visibility
  175.             RenderStyle.Flags &= ~STYLEF_Alpha1;
  176.             if (visdir > 0)
  177.             {
  178.                 Alpha += 2./TICRATE;
  179.                 if (Alpha > 1.)
  180.                 {
  181.                     Alpha = 1.;
  182.                     visdir = 0;
  183.                 }
  184.             }
  185.             else if (visdir < 0)
  186.             {
  187.                 Alpha -= 1.5/TICRATE;
  188.                 if (Alpha < StealthAlpha)
  189.                 {
  190.                     Alpha = StealthAlpha;
  191.                     visdir = 0;
  192.                 }
  193.             }
  194.         }
  195.  
  196.         if (Level->BotInfo.botnum && !demoplayback &&
  197.             ((flags & (MF_SPECIAL|MF_MISSILE)) || (flags3 & MF3_ISMONSTER)))
  198.         {
  199.             Level->BotInfo.BotTick(this);
  200.         }
  201.  
  202.         // [RH] Consider carrying sectors here
  203.         DVector2 cumm(0, 0);
  204.  
  205.         if ((((flags8 & MF8_INSCROLLSEC) && Level->Scrolls.Size() > 0) || player != NULL) && !(flags & MF_NOCLIP) && !(flags & MF_NOSECTOR))
  206.         {
  207.             double height, waterheight; // killough 4/4/98: add waterheight
  208.             const msecnode_t *node;
  209.             int countx, county;
  210.  
  211.             // Clear the flag for the next frame.
  212.             flags8 &= ~MF8_INSCROLLSEC;
  213.  
  214.             // killough 3/7/98: Carry things on floor
  215.             // killough 3/20/98: use new sector list which reflects true members
  216.             // killough 3/27/98: fix carrier bug
  217.             // killough 4/4/98: Underwater, carry things even w/o gravity
  218.  
  219.             // Move objects only if on floor or underwater,
  220.             // non-floating, and clipped.
  221.  
  222.             countx = county = 0;
  223.  
  224.             for (node = touching_sectorlist; node; node = node->m_tnext)
  225.             {
  226.                 sector_t *sec = node->m_sector;
  227.                 DVector2 scrollv;
  228.  
  229.                 if (Level->Scrolls.Size() > unsigned(sec->Index()))
  230.                 {
  231.                     scrollv = Level->Scrolls[sec->Index()];
  232.                 }
  233.                 else
  234.                 {
  235.                     scrollv.Zero();
  236.                 }
  237.  
  238.                 if (player != NULL)
  239.                 {
  240.                     int scrolltype = sec->special;
  241.  
  242.                     if (scrolltype >= Scroll_North_Slow &&
  243.                         scrolltype <= Scroll_SouthWest_Fast)
  244.                     { // Hexen scroll special
  245.                         scrolltype -= Scroll_North_Slow;
  246.                         if (Level->i_compatflags&COMPATF_RAVENSCROLL)
  247.                         {
  248.                             scrollv.X -= HexenCompatSpeeds[HexenScrollies[scrolltype][0]+4] * (1. / (32 * CARRYFACTOR));
  249.                             scrollv.Y += HexenCompatSpeeds[HexenScrollies[scrolltype][1]+4] * (1. / (32 * CARRYFACTOR));
  250.  
  251.                         }
  252.                         else
  253.                         {
  254.                             // Use speeds that actually match the scrolling textures!
  255.                             scrollv.X -= HexenScrollies[scrolltype][0] * 0.5;
  256.                             scrollv.Y += HexenScrollies[scrolltype][1] * 0.5;
  257.                         }
  258.                     }
  259.                     else if (scrolltype >= Carry_East5 &&
  260.                              scrolltype <= Carry_West35)
  261.                     { // Heretic scroll special
  262.                         scrolltype -= Carry_East5;
  263.                         uint8_t dir = HereticScrollDirs[scrolltype / 5];
  264.                         double carryspeed = HereticSpeedMuls[scrolltype % 5] * (1. / (32 * CARRYFACTOR));
  265.                         if (scrolltype < 5 && !(Level->i_compatflags&COMPATF_RAVENSCROLL))
  266.                         {
  267.                             // Use speeds that actually match the scrolling textures!
  268.                             carryspeed = (1 << ((scrolltype % 5) + 15)) / 65536.;
  269.                         }
  270.                         scrollv.X += carryspeed * ((dir & 3) - 1);
  271.                         scrollv.Y += carryspeed * (((dir & 12) >> 2) - 1);
  272.                     }
  273.                     else if (scrolltype == dScroll_EastLavaDamage)
  274.                     { // Special Heretic scroll special
  275.                         if (Level->i_compatflags&COMPATF_RAVENSCROLL)
  276.                         {
  277.                             scrollv.X += 28. / (32*CARRYFACTOR);
  278.                         }
  279.                         else
  280.                         {
  281.                             // Use a speed that actually matches the scrolling texture!
  282.                             scrollv.X += 12. / (32 * CARRYFACTOR);
  283.                         }
  284.                     }
  285.                     else if (scrolltype == Scroll_StrifeCurrent)
  286.                     { // Strife scroll special
  287.                         int anglespeed = Level->GetFirstSectorTag(sec) - 100;
  288.                         double carryspeed = (anglespeed % 10) / (16 * CARRYFACTOR);
  289.                         DAngle angle = ((anglespeed / 10) * 45.);
  290.                         scrollv += angle.ToVector(carryspeed);
  291.                     }
  292.                 }
  293.  
  294.                 if (scrollv.isZero())
  295.                 {
  296.                     continue;
  297.                 }
  298.                 sector_t *heightsec = sec->GetHeightSec();
  299.                 if (flags & MF_NOGRAVITY && heightsec == NULL)
  300.                 {
  301.                     continue;
  302.                 }
  303.                 DVector3 pos = PosRelative(sec);
  304.                 height = sec->floorplane.ZatPoint (pos);
  305.                 double height2 = sec->floorplane.ZatPoint(this);
  306.                 if (isAbove(height))
  307.                 {
  308.                     if (heightsec == NULL)
  309.                     {
  310.                         continue;
  311.                     }
  312.  
  313.                     waterheight = heightsec->floorplane.ZatPoint (pos);
  314.                     if (waterheight > height && Z() >= waterheight)
  315.                     {
  316.                         continue;
  317.                     }
  318.                 }
  319.  
  320.                 cumm += scrollv;
  321.                 if (scrollv.X) countx++;
  322.                 if (scrollv.Y) county++;
  323.             }
  324.  
  325.             // Some levels designed with Boom in mind actually want things to accelerate
  326.             // at neighboring scrolling sector boundaries. But it is only important for
  327.             // non-player objects.
  328.             if (player != NULL || !(Level->i_compatflags & COMPATF_BOOMSCROLL))
  329.             {
  330.                 if (countx > 1)
  331.                 {
  332.                     cumm.X /= countx;
  333.                 }
  334.                 if (county > 1)
  335.                 {
  336.                     cumm.Y /= county;
  337.                 }
  338.             }
  339.         }
  340.  
  341.         // [RH] If standing on a steep slope, fall down it
  342.         if ((flags & MF_SOLID) && !(flags & (MF_NOCLIP|MF_NOGRAVITY)) &&
  343.             !(flags & MF_NOBLOCKMAP) &&
  344.             Vel.Z <= 0 &&
  345.             floorz == Z())
  346.         {
  347.             secplane_t floorplane;
  348.  
  349.             // Check 3D floors as well
  350.             floorplane = P_FindFloorPlane(floorsector, PosAtZ(floorz));
  351.  
  352.             if (floorplane.fC() < MaxSlopeSteepness &&
  353.                 floorplane.ZatPoint (PosRelative(floorsector)) <= floorz)
  354.             {
  355.                 const msecnode_t *node;
  356.                 bool dopush = true;
  357.  
  358.                 if (floorplane.fC() > MaxSlopeSteepness*2/3)
  359.                 {
  360.                     for (node = touching_sectorlist; node; node = node->m_tnext)
  361.                     {
  362.                         const sector_t *sec = node->m_sector;
  363.                         if (sec->floorplane.fC() >= MaxSlopeSteepness)
  364.                         {
  365.                             if (floorplane.ZatPoint(PosRelative(node->m_sector)) >= Z() - MaxStepHeight)
  366.                             {
  367.                                 dopush = false;
  368.                                 break;
  369.                             }
  370.                         }
  371.                     }
  372.                 }
  373.                 if (dopush)
  374.                 {
  375.                     Vel += floorplane.Normal().XY();
  376.                 }
  377.             }
  378.         }
  379.  
  380.         // [RH] Missiles moving perfectly vertical need some X/Y movement, or they
  381.         // won't hurt anything. Don't do this if damage is 0! That way, you can
  382.         // still have missiles that go straight up and down through actors without
  383.         // damaging anything.
  384.         // (for backwards compatibility this must check for lack of damage function, not for zero damage!)
  385.         if ((flags & MF_MISSILE) && Vel.X == 0 && Vel.Y == 0 && !IsZeroDamage())
  386.         {
  387.             VelFromAngle(MinVel);
  388.         }
  389.  
  390.         // Handle X and Y velocities
  391.         BlockingMobj = nullptr;
  392.         sector_t* oldBlockingCeiling = BlockingCeiling;
  393.         sector_t* oldBlockingFloor = BlockingFloor;
  394.         Blocking3DFloor = nullptr;
  395.         BlockingFloor = nullptr;
  396.         BlockingCeiling = nullptr;
  397.         double oldfloorz = P_XYMovement (this, cumm);
  398.         if (ObjectFlags & OF_EuthanizeMe)
  399.         { // actor was destroyed
  400.             return;
  401.         }
  402.         // [ZZ] trigger hit floor/hit ceiling actions from XY movement
  403.         if (BlockingFloor && BlockingFloor != oldBlockingFloor && (!player || !(player->cheats & CF_PREDICTING)) && BlockingFloor->SecActTarget)
  404.             BlockingFloor->TriggerSectorActions(this, SECSPAC_HitFloor);
  405.         if (BlockingCeiling && BlockingCeiling != oldBlockingCeiling && (!player || !(player->cheats & CF_PREDICTING)) && BlockingCeiling->SecActTarget)
  406.             BlockingCeiling->TriggerSectorActions(this, SECSPAC_HitCeiling);
  407.         if (Vel.X == 0 && Vel.Y == 0) // Actors at rest
  408.         {
  409.             if (flags2 & MF2_BLASTED)
  410.             { // Reset to not blasted when velocities are gone
  411.                 flags2 &= ~MF2_BLASTED;
  412.             }
  413.             if ((flags6 & MF6_TOUCHY) && !IsSentient())
  414.             { // Arm a mine which has come to rest
  415.                 flags6 |= MF6_ARMED;
  416.             }
  417.  
  418.         }
  419.         if (Vel.Z != 0 || BlockingMobj || Z() != floorz)
  420.         {   // Handle Z velocity and gravity
  421.             if (((flags2 & MF2_PASSMOBJ) || (flags & MF_SPECIAL)) && !(Level->i_compatflags & COMPATF_NO_PASSMOBJ))
  422.             {
  423.                 if (!(onmo = P_CheckOnmobj (this)))
  424.                 {
  425.                     P_ZMovement (this, oldfloorz);
  426.                     flags2 &= ~MF2_ONMOBJ;
  427.                 }
  428.                 else
  429.                 {
  430.                     if (player)
  431.                     {
  432.                         if (Vel.Z < Level->gravity * Sector->gravity * (-1./100)// -655.36f)
  433.                             && !(flags&MF_NOGRAVITY))
  434.                         {
  435.                             PlayerLandedOnThing (this, onmo);
  436.                         }
  437.                     }
  438.                     if (onmo->Top() - Z() <= MaxStepHeight)
  439.                     {
  440.                         if (player && player->mo == this)
  441.                         {
  442.                             player->viewheight -= onmo->Top() - Z();
  443.                             double deltaview = player->GetDeltaViewHeight();
  444.                             if (deltaview > player->deltaviewheight)
  445.                             {
  446.                                 player->deltaviewheight = deltaview;
  447.                             }
  448.                         }
  449.                         SetZ(onmo->Top());
  450.                     }
  451.                     // Check for MF6_BUMPSPECIAL
  452.                     // By default, only players can activate things by bumping into them
  453.                     // We trigger specials as long as we are on top of it and not just when
  454.                     // we land on it. This could be considered as gravity making us continually
  455.                     // bump into it, but it also avoids having to worry about walking on to
  456.                     // something without dropping and not triggering anything.
  457.                     if ((onmo->flags6 & MF6_BUMPSPECIAL) && ((player != NULL)
  458.                         || ((onmo->activationtype & THINGSPEC_MonsterTrigger) && (flags3 & MF3_ISMONSTER))
  459.                         || ((onmo->activationtype & THINGSPEC_MissileTrigger) && (flags & MF_MISSILE))
  460.                         ) && (Level->maptime > onmo->lastbump)) // Leave the bumper enough time to go away
  461.                     {
  462.                         if (player == NULL || !(player->cheats & CF_PREDICTING))
  463.                         {
  464.                             if (P_ActivateThingSpecial(onmo, this))
  465.                                 onmo->lastbump = Level->maptime + TICRATE;
  466.                         }
  467.                     }
  468.                     if (Vel.Z != 0 && (BounceFlags & BOUNCE_Actors))
  469.                     {
  470.                         bool res = P_BounceActor(this, onmo, true);
  471.                         // If the bouncer is a missile and has hit the other actor it needs to be exploded here
  472.                         // to be in line with the case when an actor's side is hit.
  473.                         if (!res && (flags & MF_MISSILE))
  474.                         {
  475.                             P_DoMissileDamage(this, onmo);
  476.                             P_ExplodeMissile(this, nullptr, onmo);
  477.                         }
  478.                     }
  479.                     else
  480.                     {
  481.                         flags2 |= MF2_ONMOBJ;
  482.                         Vel.Z = 0;
  483.                         Crash();
  484.                     }
  485.                 }
  486.             }
  487.             else
  488.             {
  489.                 P_ZMovement (this, oldfloorz);
  490.             }
  491.  
  492.             if (ObjectFlags & OF_EuthanizeMe)
  493.                 return;     // actor was destroyed
  494.         }
  495.         else if (Z() <= floorz)
  496.         {
  497.             Crash();
  498.             if (ObjectFlags & OF_EuthanizeMe)
  499.                 return;     // actor was destroyed
  500.         }
  501.  
  502.         CheckPortalTransition(true);
  503.  
  504.         UpdateWaterLevel ();
  505.  
  506.         // [RH] Don't advance if predicting a player
  507.         if (player && (player->cheats & CF_PREDICTING))
  508.         {
  509.             return;
  510.         }
  511.  
  512.         // Check for poison damage, but only once per PoisonPeriod tics (or once per second if none).
  513.         if (PoisonDurationReceived && (Level->time % (PoisonPeriodReceived ? PoisonPeriodReceived : TICRATE) == 0))
  514.         {
  515.             P_DamageMobj(this, NULL, Poisoner, PoisonDamageReceived, PoisonDamageTypeReceived != NAME_None ? PoisonDamageTypeReceived : (FName)NAME_Poison, 0);
  516.  
  517.             --PoisonDurationReceived;
  518.  
  519.             // Must clear damage when duration is done, otherwise it
  520.             // could be added to with ADDITIVEPOISONDAMAGE.
  521.             if (!PoisonDurationReceived) PoisonDamageReceived = 0;
  522.         }
  523.     }
  524.  
  525.     assert (state != NULL);
  526.     if (state == NULL)
  527.     {
  528.         Destroy();
  529.         return;
  530.     }
  531.     if (!CheckNoDelay())
  532.         return; // freed itself
  533.     // cycle through states, calling action functions at transitions
  534.  
  535.     UpdateRenderSectorList();
  536.  
  537.     if (tics != -1)
  538.     {
  539.         // [RH] Use tics <= 0 instead of == 0 so that spawnstates
  540.         // of 0 tics work as expected.
  541.         if (--tics <= 0)
  542.         {
  543.             if (!SetState(state->GetNextState()))
  544.                 return;         // freed itself
  545.         }
  546.     }
  547.  
  548.     if (tics == -1 || state->GetCanRaise())
  549.     {
  550.         int respawn_monsters = G_SkillProperty(SKILLP_Respawn);
  551.         // check for nightmare respawn
  552.         if (!(flags5 & MF5_ALWAYSRESPAWN))
  553.         {
  554.             if (!respawn_monsters || !(flags3 & MF3_ISMONSTER) || (flags2 & MF2_DORMANT) || (flags5 & MF5_NEVERRESPAWN))
  555.                 return;
  556.  
  557.             int limit = G_SkillProperty (SKILLP_RespawnLimit);
  558.             if (limit > 0 && skillrespawncount >= limit)
  559.                 return;
  560.         }
  561.  
  562.         movecount++;
  563.  
  564.         if (movecount < respawn_monsters)
  565.             return;
  566.  
  567.         if (Level->time & 31)
  568.             return;
  569.  
  570.         if (pr_nightmarerespawn() > 4)
  571.             return;
  572.  
  573.         P_NightmareRespawn (this);
  574.     }
  575. }
  576.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement