void P_SetupWeapons_ntohton() { unsigned int i; PClassWeapon *cls; Weapons_ntoh.Clear(); Weapons_hton.Clear(); cls = NULL; Weapons_ntoh.Push(cls); // Index 0 is always NULL. for (i = 0; i < PClassActor::AllActorClasses.Size(); ++i) { PClassActor *cls = PClassActor::AllActorClasses[i]; if (cls->IsDescendantOf(RUNTIME_CLASS(AWeapon))) { Weapons_ntoh.Push(static_cast<PClassWeapon *>(cls)); } } qsort(&Weapons_ntoh[1], Weapons_ntoh.Size() - 1, sizeof(Weapons_ntoh[0]), ntoh_cmp); for (i = 0; i < Weapons_ntoh.Size(); ++i) { Weapons_hton[Weapons_ntoh[i]] = i; } }
static FState *CheckState(FScanner &sc, PClass *type) { int v = 0; if (sc.GetString() && !sc.Crossed) { if (sc.Compare("0")) return NULL; else if (sc.Compare("PARENT")) { FState *state = NULL; sc.MustGetString(); PClassActor *info = dyn_cast<PClassActor>(type->ParentClass); if (info != NULL) { state = info->FindState(FName(sc.String)); } if (sc.GetString ()) { if (sc.Compare ("+")) { sc.MustGetNumber (); v = sc.Number; } else { sc.UnGet (); } } if (state == NULL && v==0) { return NULL; } if (v != 0 && state==NULL) { sc.ScriptMessage("Attempt to get invalid state from actor %s\n", type->ParentClass->TypeName.GetChars()); FScriptPosition::ErrorCounter++; return NULL; } state += v; return state; } else { sc.ScriptMessage("Invalid state assignment"); FScriptPosition::ErrorCounter++; } } return NULL; }
PClassActor *PClassActor::GetReplacement(bool lookskill) { FName skillrepname; if (lookskill && AllSkills.Size() > (unsigned)gameskill) { skillrepname = AllSkills[gameskill].GetReplacement(TypeName); if (skillrepname != NAME_None && PClass::FindClass(skillrepname) == NULL) { Printf("Warning: incorrect actor name in definition of skill %s: \n" "class %s is replaced by non-existent class %s\n" "Skill replacement will be ignored for this actor.\n", AllSkills[gameskill].Name.GetChars(), TypeName.GetChars(), skillrepname.GetChars()); AllSkills[gameskill].SetReplacement(TypeName, NAME_None); AllSkills[gameskill].SetReplacedBy(skillrepname, NAME_None); lookskill = false; skillrepname = NAME_None; } } if (Replacement == NULL && (!lookskill || skillrepname == NAME_None)) { return this; } // The Replacement field is temporarily NULLed to prevent // potential infinite recursion. PClassActor *savedrep = Replacement; Replacement = NULL; PClassActor *rep = savedrep; // Handle skill-based replacement here. It has precedence on DECORATE replacement // in that the skill replacement is applied first, followed by DECORATE replacement // on the actor indicated by the skill replacement. if (lookskill && (skillrepname != NAME_None)) { rep = PClass::FindActor(skillrepname); } // Now handle DECORATE replacement chain // Skill replacements are not recursive, contrarily to DECORATE replacements rep = rep->GetReplacement(false); // Reset the temporarily NULLed field Replacement = savedrep; return rep; }
bool PClassActor::SetReplacement(FName replaceName) { // Check for "replaces" if (replaceName != NAME_None) { // Get actor name PClassActor *replacee = PClass::FindActor(replaceName); if (replacee == nullptr) { return false; } if (replacee != nullptr) { replacee->ActorInfo()->Replacement = this; ActorInfo()->Replacee = replacee; } } return true; }
PClassActor *PClassActor::GetReplacee(bool lookskill) { FName skillrepname; if (lookskill && AllSkills.Size() > (unsigned)gameskill) { skillrepname = AllSkills[gameskill].GetReplacedBy(TypeName); if (skillrepname != NAME_None && PClass::FindClass(skillrepname) == NULL) { Printf("Warning: incorrect actor name in definition of skill %s: \n" "non-existent class %s is replaced by class %s\n" "Skill replacement will be ignored for this actor.\n", AllSkills[gameskill].Name.GetChars(), skillrepname.GetChars(), TypeName.GetChars()); AllSkills[gameskill].SetReplacedBy(TypeName, NAME_None); AllSkills[gameskill].SetReplacement(skillrepname, NAME_None); lookskill = false; } } if (Replacee == NULL && (!lookskill || skillrepname == NAME_None)) { return this; } // The Replacee field is temporarily NULLed to prevent // potential infinite recursion. PClassActor *savedrep = Replacee; Replacee = NULL; PClassActor *rep = savedrep; if (lookskill && (skillrepname != NAME_None) && (PClass::FindClass(skillrepname) != NULL)) { rep = PClass::FindActor(skillrepname); } rep = rep->GetReplacee(false); Replacee = savedrep; return rep; }
bool P_Thing_Spawn (int tid, AActor *source, int type, DAngle angle, bool fog, int newtid) { int rtn = 0; PClassActor *kind; AActor *spot, *mobj; FActorIterator iterator (tid); kind = P_GetSpawnableType(type); if (kind == NULL) return false; // Handle decorate replacements. kind = kind->GetReplacement(); if ((GetDefaultByType(kind)->flags3 & MF3_ISMONSTER) && ((dmflags & DF_NO_MONSTERS) || (level.flags2 & LEVEL2_NOMONSTERS))) return false; if (tid == 0) { spot = source; } else { spot = iterator.Next(); } while (spot != NULL) { mobj = Spawn (kind, spot->Pos(), ALLOW_REPLACE); if (mobj != NULL) { ActorFlags2 oldFlags2 = mobj->flags2; mobj->flags2 |= MF2_PASSMOBJ; if (P_TestMobjLocation (mobj)) { rtn++; mobj->Angles.Yaw = (angle != 1000000. ? angle : spot->Angles.Yaw); if (fog) { P_SpawnTeleportFog(mobj, spot->PosPlusZ(TELEFOGHEIGHT), false, true); } if (mobj->flags & MF_SPECIAL) mobj->flags |= MF_DROPPED; // Don't respawn mobj->tid = newtid; mobj->AddToHash (); mobj->flags2 = oldFlags2; } else { // If this is a monster, subtract it from the total monster // count, because it already added to it during spawning. mobj->ClearCounters(); mobj->Destroy (); } } spot = iterator.Next(); } return rtn != 0; }
bool P_Thing_Projectile (int tid, AActor *source, int type, const char *type_name, DAngle angle, double speed, double vspeed, int dest, AActor *forcedest, int gravity, int newtid, bool leadTarget) { int rtn = 0; PClassActor *kind; AActor *spot, *mobj, *targ = forcedest; FActorIterator iterator (tid); int defflags3; if (type_name == NULL) { kind = P_GetSpawnableType(type); } else { kind = PClass::FindActor(type_name); } if (kind == NULL) { return false; } // Handle decorate replacements. kind = kind->GetReplacement(); defflags3 = GetDefaultByType(kind)->flags3; if ((defflags3 & MF3_ISMONSTER) && ((dmflags & DF_NO_MONSTERS) || (level.flags2 & LEVEL2_NOMONSTERS))) return false; if (tid == 0) { spot = source; } else { spot = iterator.Next(); } while (spot != NULL) { FActorIterator tit (dest); if (dest == 0 || (targ = tit.Next())) { do { double z = spot->Z(); if (defflags3 & MF3_FLOORHUGGER) { z = ONFLOORZ; } else if (defflags3 & MF3_CEILINGHUGGER) { z = ONCEILINGZ; } else if (z != ONFLOORZ) { z -= spot->Floorclip; } mobj = Spawn (kind, spot->PosAtZ(z), ALLOW_REPLACE); if (mobj) { mobj->tid = newtid; mobj->AddToHash (); P_PlaySpawnSound(mobj, spot); if (gravity) { mobj->flags &= ~MF_NOGRAVITY; if (!(mobj->flags3 & MF3_ISMONSTER) && gravity == 1) { mobj->Gravity = 1./8; } } else { mobj->flags |= MF_NOGRAVITY; } mobj->target = spot; if (targ != NULL) { DVector3 aim = mobj->Vec3To(targ); aim.Z += targ->Height / 2; if (leadTarget && speed > 0 && !targ->Vel.isZero()) { // Aiming at the target's position some time in the future // is basically just an application of the law of sines: // a/sin(A) = b/sin(B) // Thanks to all those on the notgod phorum for helping me // with the math. I don't think I would have thought of using // trig alone had I been left to solve it by myself. DVector3 tvel = targ->Vel; if (!(targ->flags & MF_NOGRAVITY) && targ->waterlevel < 3) { // If the target is subject to gravity and not underwater, // assume that it isn't moving vertically. Thanks to gravity, // even if we did consider the vertical component of the target's // velocity, we would still miss more often than not. tvel.Z = 0.0; if (targ->Vel.X == 0 && targ->Vel.Y == 0) { goto nolead; } } double dist = aim.Length(); double targspeed = tvel.Length(); double ydotx = -aim | tvel; double a = g_acos (clamp (ydotx / targspeed / dist, -1.0, 1.0)); double multiplier = double(pr_leadtarget.Random2())*0.1/255+1.1; double sinb = -clamp (targspeed*multiplier * g_sin(a) / speed, -1.0, 1.0); // Use the cross product of two of the triangle's sides to get a // rotation vector. DVector3 rv(tvel ^ aim); // The vector must be normalized. rv.MakeUnit(); // Now combine the rotation vector with angle b to get a rotation matrix. DMatrix3x3 rm(rv, g_cos(g_asin(sinb)), sinb); // And multiply the original aim vector with the matrix to get a // new aim vector that leads the target. DVector3 aimvec = rm * aim; // And make the projectile follow that vector at the desired speed. mobj->Vel = aimvec * (speed / dist); mobj->AngleFromVel(); } else { nolead: mobj->Angles.Yaw = mobj->AngleTo(targ); mobj->Vel = aim.Resized (speed); } if (mobj->flags2 & MF2_SEEKERMISSILE) { mobj->tracer = targ; } } else { mobj->Angles.Yaw = angle; mobj->VelFromAngle(speed); mobj->Vel.Z = vspeed; } // Set the missile's speed to reflect the speed it was spawned at. if (mobj->flags & MF_MISSILE) { mobj->Speed = mobj->VelToSpeed(); } // Hugger missiles don't have any vertical velocity if (mobj->flags3 & (MF3_FLOORHUGGER|MF3_CEILINGHUGGER)) { mobj->Vel.Z = 0; } if (mobj->flags & MF_SPECIAL) { mobj->flags |= MF_DROPPED; } if (mobj->flags & MF_MISSILE) { if (P_CheckMissileSpawn (mobj, spot->radius)) { rtn = true; } } else if (!P_TestMobjLocation (mobj)) { // If this is a monster, subtract it from the total monster // count, because it already added to it during spawning. mobj->ClearCounters(); mobj->Destroy (); } else { // It spawned fine. rtn = 1; } } } while (dest != 0 && (targ = tit.Next())); } spot = iterator.Next(); } return rtn != 0; }
void cht_Take (player_t *player, const char *name, int amount) { bool takeall; PClassActor *type; if (player->mo == NULL || player->health <= 0) { return; } takeall = (stricmp (name, "all") == 0); if (!takeall && stricmp (name, "health") == 0) { if (player->mo->health - amount <= 0 || player->health - amount <= 0 || amount == 0) { cht_Suicide (player); if (player == &players[consoleplayer]) C_HideConsole (); return; } if (amount > 0) { if (player->mo) { player->mo->health -= amount; player->health = player->mo->health; } else { player->health -= amount; } } if (!takeall) return; } if (takeall || stricmp (name, "backpack") == 0) { // Take away all types of backpacks the player might own. for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i) { PClass *type = PClassActor::AllActorClasses[i]; if (type->IsDescendantOf(RUNTIME_CLASS (ABackpackItem))) { AInventory *pack = player->mo->FindInventory(static_cast<PClassActor *>(type)); if (pack) pack->Destroy(); } } if (!takeall) return; } if (takeall || stricmp (name, "ammo") == 0) { for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i) { PClass *type = PClassActor::AllActorClasses[i]; if (type->ParentClass == RUNTIME_CLASS (AAmmo)) { AInventory *ammo = player->mo->FindInventory(static_cast<PClassActor *>(type)); if (ammo) ammo->DepleteOrDestroy(); } } if (!takeall) return; } if (takeall || stricmp (name, "armor") == 0) { for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i) { type = PClassActor::AllActorClasses[i]; if (type->IsDescendantOf (RUNTIME_CLASS (AArmor))) { AInventory *armor = player->mo->FindInventory(static_cast<PClassActor *>(type)); if (armor) armor->DepleteOrDestroy(); } } if (!takeall) return; } if (takeall || stricmp (name, "keys") == 0) { for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i) { type = PClassActor::AllActorClasses[i]; if (type->IsDescendantOf (RUNTIME_CLASS (AKey))) { AActor *key = player->mo->FindInventory(static_cast<PClassActor *>(type)); if (key) key->Destroy (); } } if (!takeall) return; } if (takeall || stricmp (name, "weapons") == 0) { for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i) { type = PClassActor::AllActorClasses[i]; if (type != RUNTIME_CLASS(AWeapon) && type->IsDescendantOf (RUNTIME_CLASS (AWeapon))) { AActor *weapon = player->mo->FindInventory(static_cast<PClassActor *>(type)); if (weapon) weapon->Destroy (); player->ReadyWeapon = nullptr; player->PendingWeapon = WP_NOCHANGE; } } if (!takeall) return; } if (takeall || stricmp (name, "artifacts") == 0) { for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i) { type = PClassActor::AllActorClasses[i]; if (type->IsDescendantOf (RUNTIME_CLASS (AInventory))) { if (!type->IsDescendantOf (RUNTIME_CLASS (APuzzleItem)) && !type->IsDescendantOf (RUNTIME_CLASS (APowerup)) && !type->IsDescendantOf (RUNTIME_CLASS (AArmor)) && !type->IsDescendantOf (RUNTIME_CLASS (AWeapon)) && !type->IsDescendantOf (RUNTIME_CLASS (AKey))) { AActor *artifact = player->mo->FindInventory(static_cast<PClassActor *>(type)); if (artifact) artifact->Destroy (); } } } if (!takeall) return; } if (takeall || stricmp (name, "puzzlepieces") == 0) { for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i) { type = PClassActor::AllActorClasses[i]; if (type->IsDescendantOf (RUNTIME_CLASS (APuzzleItem))) { AActor *puzzlepiece = player->mo->FindInventory(static_cast<PClassActor *>(type)); if (puzzlepiece) puzzlepiece->Destroy (); } } if (!takeall) return; } if (takeall) return; type = PClass::FindActor (name); if (type == NULL || !type->IsDescendantOf (RUNTIME_CLASS (AInventory))) { if (player == &players[consoleplayer]) Printf ("Unknown item \"%s\"\n", name); } else { player->mo->TakeInventory(type, amount ? amount : 1); } return; }
void cht_Give (player_t *player, const char *name, int amount) { enum { ALL_NO, ALL_YES, ALL_YESYES } giveall; int i; PClassActor *type; if (player != &players[consoleplayer]) Printf ("%s is a cheater: give %s\n", player->userinfo.GetName(), name); if (player->mo == NULL || player->health <= 0) { return; } giveall = ALL_NO; if (stricmp (name, "all") == 0) { giveall = ALL_YES; } else if (stricmp (name, "everything") == 0) { giveall = ALL_YESYES; } if (stricmp (name, "health") == 0) { if (amount > 0) { player->mo->health += amount; player->health = player->mo->health; } else { player->health = player->mo->health = player->mo->GetMaxHealth(); } } if (giveall || stricmp (name, "backpack") == 0) { // Select the correct type of backpack based on the game type = PClass::FindActor(gameinfo.backpacktype); if (type != NULL) { player->mo->GiveInventory(static_cast<PClassInventory *>(type), 1, true); } if (!giveall) return; } if (giveall || stricmp (name, "ammo") == 0) { // Find every unique type of ammo. Give it to the player if // he doesn't have it already, and set each to its maximum. for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i) { PClassActor *type = PClassActor::AllActorClasses[i]; if (type->ParentClass == RUNTIME_CLASS(AAmmo)) { PClassAmmo *atype = static_cast<PClassAmmo *>(type); AInventory *ammo = player->mo->FindInventory(atype); if (ammo == NULL) { ammo = static_cast<AInventory *>(Spawn (atype)); ammo->AttachToOwner (player->mo); ammo->Amount = ammo->MaxAmount; } else if (ammo->Amount < ammo->MaxAmount) { ammo->Amount = ammo->MaxAmount; } } } if (!giveall) return; } if (giveall || stricmp (name, "armor") == 0) { if (gameinfo.gametype != GAME_Hexen) { ABasicArmorPickup *armor = Spawn<ABasicArmorPickup> (); armor->SaveAmount = 100*deh.BlueAC; armor->SavePercent = gameinfo.Armor2Percent > 0? gameinfo.Armor2Percent : 0.5; if (!armor->CallTryPickup (player->mo)) { armor->Destroy (); } } else { for (i = 0; i < 4; ++i) { AHexenArmor *armor = Spawn<AHexenArmor> (); armor->health = i; armor->Amount = 0; if (!armor->CallTryPickup (player->mo)) { armor->Destroy (); } } } if (!giveall) return; } if (giveall || stricmp (name, "keys") == 0) { for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i) { if (PClassActor::AllActorClasses[i]->IsDescendantOf (RUNTIME_CLASS(AKey))) { AKey *key = (AKey *)GetDefaultByType (PClassActor::AllActorClasses[i]); if (key->KeyNumber != 0) { key = static_cast<AKey *>(Spawn(static_cast<PClassActor *>(PClassActor::AllActorClasses[i]))); if (!key->CallTryPickup (player->mo)) { key->Destroy (); } } } } if (!giveall) return; } if (giveall || stricmp (name, "weapons") == 0) { AWeapon *savedpending = player->PendingWeapon; for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i) { type = PClassActor::AllActorClasses[i]; // Don't give replaced weapons unless the replacement was done by Dehacked. if (type != RUNTIME_CLASS(AWeapon) && type->IsDescendantOf (RUNTIME_CLASS(AWeapon)) && (static_cast<PClassActor *>(type)->GetReplacement() == type || static_cast<PClassActor *>(type)->GetReplacement()->IsDescendantOf(RUNTIME_CLASS(ADehackedPickup)))) { // Give the weapon only if it belongs to the current game or if (player->weapons.LocateWeapon(static_cast<PClassWeapon*>(type), NULL, NULL)) { AWeapon *def = (AWeapon*)GetDefaultByType (type); if (giveall == ALL_YESYES || !(def->WeaponFlags & WIF_CHEATNOTWEAPON)) { player->mo->GiveInventory(static_cast<PClassInventory *>(type), 1, true); } } } } player->PendingWeapon = savedpending; if (!giveall) return; } if (giveall || stricmp (name, "artifacts") == 0) { for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i) { type = PClassActor::AllActorClasses[i]; if (type->IsDescendantOf (RUNTIME_CLASS(AInventory))) { AInventory *def = (AInventory*)GetDefaultByType (type); if (def->Icon.isValid() && def->MaxAmount > 1 && !type->IsDescendantOf (RUNTIME_CLASS(APuzzleItem)) && !type->IsDescendantOf (RUNTIME_CLASS(APowerup)) && !type->IsDescendantOf (RUNTIME_CLASS(AArmor))) { // Do not give replaced items unless using "give everything" if (giveall == ALL_YESYES || type->GetReplacement() == type) { player->mo->GiveInventory(static_cast<PClassInventory *>(type), amount <= 0 ? def->MaxAmount : amount, true); } } } } if (!giveall) return; } if (giveall || stricmp (name, "puzzlepieces") == 0) { for (unsigned int i = 0; i < PClassActor::AllActorClasses.Size(); ++i) { type = PClassActor::AllActorClasses[i]; if (type->IsDescendantOf (RUNTIME_CLASS(APuzzleItem))) { AInventory *def = (AInventory*)GetDefaultByType (type); if (def->Icon.isValid()) { // Do not give replaced items unless using "give everything" if (giveall == ALL_YESYES || type->GetReplacement() == type) { player->mo->GiveInventory(static_cast<PClassInventory *>(type), amount <= 0 ? def->MaxAmount : amount, true); } } } } if (!giveall) return; } if (giveall) return; type = PClass::FindActor(name); if (type == NULL || !type->IsDescendantOf (RUNTIME_CLASS(AInventory))) { if (player == &players[consoleplayer]) Printf ("Unknown item \"%s\"\n", name); } else { player->mo->GiveInventory(static_cast<PClassInventory *>(type), amount, true); } return; }
bool P_UndoPlayerMorph (player_t *activator, player_t *player, int unmorphflag, bool force) { AWeapon *beastweap; APlayerPawn *mo; APlayerPawn *pmo; angle_t angle; pmo = player->mo; // [MH] // Checks pmo as well; the PowerMorph destroyer will // try to unmorph the player; if the destroyer runs // because the level or game is ended while morphed, // by the time it gets executed the morphed player // pawn instance may have already been destroyed. if (pmo == NULL || pmo->tracer == NULL) { return false; } bool DeliberateUnmorphIsOkay = !!(MORPH_STANDARDUNDOING & unmorphflag); if ((pmo->flags2 & MF2_INVULNERABLE) // If the player is invulnerable && ((player != activator) // and either did not decide to unmorph, || (!((player->MorphStyle & MORPH_WHENINVULNERABLE) // or the morph style does not allow it || (DeliberateUnmorphIsOkay))))) // (but standard morph styles always allow it), { // Then the player is immune to the unmorph. return false; } mo = barrier_cast<APlayerPawn *>(pmo->tracer); mo->SetOrigin (pmo->Pos(), false); mo->flags |= MF_SOLID; pmo->flags &= ~MF_SOLID; if (!force && !P_TestMobjLocation (mo)) { // Didn't fit mo->flags &= ~MF_SOLID; pmo->flags |= MF_SOLID; player->morphTics = 2*TICRATE; return false; } pmo->player = NULL; // Remove the morph power if the morph is being undone prematurely. for (AInventory *item = pmo->Inventory, *next = NULL; item != NULL; item = next) { next = item->Inventory; if (item->IsKindOf(RUNTIME_CLASS(APowerMorph))) { static_cast<APowerMorph *>(item)->SetNoCallUndoMorph(); item->Destroy(); } } EndAllPowerupEffects(pmo->Inventory); mo->ObtainInventory (pmo); DObject::StaticPointerSubstitution (pmo, mo); if ((pmo->tid != 0) && (player->MorphStyle & MORPH_NEWTIDBEHAVIOUR)) { mo->tid = pmo->tid; mo->AddToHash (); } mo->angle = pmo->angle; mo->player = player; mo->reactiontime = 18; mo->flags = ActorFlags::FromInt (pmo->special2) & ~MF_JUSTHIT; mo->velx = 0; mo->vely = 0; player->velx = 0; player->vely = 0; mo->velz = pmo->velz; if (!(pmo->special2 & MF_JUSTHIT)) { mo->renderflags &= ~RF_INVISIBLE; } mo->flags = (mo->flags & ~(MF_SHADOW|MF_NOGRAVITY)) | (pmo->flags & (MF_SHADOW|MF_NOGRAVITY)); mo->flags2 = (mo->flags2 & ~MF2_FLY) | (pmo->flags2 & MF2_FLY); mo->flags3 = (mo->flags3 & ~MF3_GHOST) | (pmo->flags3 & MF3_GHOST); mo->Score = pmo->Score; InitAllPowerupEffects(mo->Inventory); PClassActor *exit_flash = player->MorphExitFlash; bool correctweapon = !!(player->MorphStyle & MORPH_LOSEACTUALWEAPON); bool undobydeathsaves = !!(player->MorphStyle & MORPH_UNDOBYDEATHSAVES); player->morphTics = 0; player->MorphedPlayerClass = 0; player->MorphStyle = 0; player->MorphExitFlash = NULL; player->viewheight = mo->ViewHeight; AInventory *level2 = mo->FindInventory (RUNTIME_CLASS(APowerWeaponLevel2), true); if (level2 != NULL) { level2->Destroy (); } if ((player->health > 0) || undobydeathsaves) { player->health = mo->health = mo->SpawnHealth(); } else // killed when morphed so stay dead { mo->health = player->health; } player->mo = mo; if (player->camera == pmo) { player->camera = mo; } // [MH] // If the player that was morphed is the one // taking events, reset up the face, if any; // this is only needed for old-skool skins // and for the original DOOM status bar. if (player == &players[consoleplayer]) { FString face = pmo->GetClass()->Face; if (face.IsNotEmpty() && strcmp(face, "None") != 0) { // Assume root-level base skin to begin with size_t skinindex = 0; // If a custom skin was in use, then reload it // or else the base skin for the player class. if ((unsigned int)player->userinfo.GetSkin() >= PlayerClasses.Size () && (size_t)player->userinfo.GetSkin() < numskins) { skinindex = player->userinfo.GetSkin(); } else if (PlayerClasses.Size () > 1) { const PClass *whatami = player->mo->GetClass(); for (unsigned int i = 0; i < PlayerClasses.Size (); ++i) { if (PlayerClasses[i].Type == whatami) { skinindex = i; break; } } } } } angle = mo->angle >> ANGLETOFINESHIFT; AActor *eflash = NULL; if (exit_flash != NULL) { eflash = Spawn(exit_flash, pmo->Vec3Offset(20*finecosine[angle], 20*finesine[angle], TELEFOGHEIGHT), ALLOW_REPLACE); if (eflash) eflash->target = mo; } mo->SetupWeaponSlots(); // Use original class's weapon slots. beastweap = player->ReadyWeapon; if (player->PremorphWeapon != NULL) { player->PremorphWeapon->PostMorphWeapon (); } else { player->ReadyWeapon = player->PendingWeapon = NULL; } if (correctweapon) { // Better "lose morphed weapon" semantics PClassActor *morphweapon = PClass::FindActor(pmo->MorphWeapon); if (morphweapon != NULL && morphweapon->IsDescendantOf(RUNTIME_CLASS(AWeapon))) { AWeapon *OriginalMorphWeapon = static_cast<AWeapon *>(mo->FindInventory (morphweapon)); if ((OriginalMorphWeapon != NULL) && (OriginalMorphWeapon->GivenAsMorphWeapon)) { // You don't get to keep your morphed weapon. if (OriginalMorphWeapon->SisterWeapon != NULL) { OriginalMorphWeapon->SisterWeapon->Destroy (); } OriginalMorphWeapon->Destroy (); } } } else // old behaviour (not really useful now) { // Assumptions made here are no longer valid if (beastweap != NULL) { // You don't get to keep your morphed weapon. if (beastweap->SisterWeapon != NULL) { beastweap->SisterWeapon->Destroy (); } beastweap->Destroy (); } } pmo->tracer = NULL; pmo->Destroy (); // Restore playerclass armor to its normal amount. AHexenArmor *hxarmor = mo->FindInventory<AHexenArmor>(); if (hxarmor != NULL) { hxarmor->Slots[4] = mo->GetClass()->HexenArmor[0]; } return true; }
bool FLevelLocals::EV_Thing_Projectile (int tid, AActor *source, int type, const char *type_name, DAngle angle, double speed, double vspeed, int dest, AActor *forcedest, int gravity, int newtid, bool leadTarget) { int rtn = 0; PClassActor *kind; AActor *spot, *mobj, *targ = forcedest; auto iterator = GetActorIterator(tid); int defflags3; if (type_name == NULL) { kind = P_GetSpawnableType(type); } else { kind = PClass::FindActor(type_name); } if (kind == NULL) { return false; } // Handle decorate replacements. kind = kind->GetReplacement(this); defflags3 = GetDefaultByType(kind)->flags3; if ((defflags3 & MF3_ISMONSTER) && ((dmflags & DF_NO_MONSTERS) || (flags2 & LEVEL2_NOMONSTERS))) return false; if (tid == 0) { spot = source; } else { spot = iterator.Next(); } while (spot != NULL) { auto tit = GetActorIterator(dest); if (dest == 0 || (targ = tit.Next())) { do { double z = spot->Z(); if (defflags3 & MF3_FLOORHUGGER) { z = ONFLOORZ; } else if (defflags3 & MF3_CEILINGHUGGER) { z = ONCEILINGZ; } else if (z != ONFLOORZ) { z -= spot->Floorclip; } mobj = Spawn (spot->Level, kind, spot->PosAtZ(z), ALLOW_REPLACE); if (mobj) { mobj->tid = newtid; mobj->AddToHash (); P_PlaySpawnSound(mobj, spot); if (gravity) { mobj->flags &= ~MF_NOGRAVITY; if (!(mobj->flags3 & MF3_ISMONSTER) && gravity == 1) { mobj->Gravity = 1./8; } } else { mobj->flags |= MF_NOGRAVITY; } mobj->target = spot; if (targ != nullptr) { VelIntercept(targ, mobj, speed, false, false, leadTarget); if (mobj->flags2 & MF2_SEEKERMISSILE) { mobj->tracer = targ; } } else { mobj->Angles.Yaw = angle; mobj->VelFromAngle(speed); mobj->Vel.Z = vspeed; } // Set the missile's speed to reflect the speed it was spawned at. if (mobj->flags & MF_MISSILE) { mobj->Speed = mobj->VelToSpeed(); } // Hugger missiles don't have any vertical velocity if (mobj->flags3 & (MF3_FLOORHUGGER|MF3_CEILINGHUGGER)) { mobj->Vel.Z = 0; } if (mobj->flags & MF_SPECIAL) { mobj->flags |= MF_DROPPED; } if (mobj->flags & MF_MISSILE) { if (P_CheckMissileSpawn (mobj, spot->radius)) { rtn = true; } } else if (!P_TestMobjLocation (mobj)) { // If this is a monster, subtract it from the total monster // count, because it already added to it during spawning. mobj->ClearCounters(); mobj->Destroy (); } else { // It spawned fine. rtn = 1; } } } while (dest != 0 && (targ = tit.Next())); } spot = iterator.Next(); } return rtn != 0; }
FState *FStateDefinitions::ResolveGotoLabel (AActor *actor, PClassActor *mytype, char *name) { PClassActor *type = mytype; FState *state; char *namestart = name; char *label, *offset, *pt; int v; // Check for classname if ((pt = strstr (name, "::")) != NULL) { const char *classname = name; *pt = '\0'; name = pt + 2; // The classname may either be "Super" to identify this class's immediate // superclass, or it may be the name of any class that this one derives from. if (stricmp (classname, "Super") == 0) { type = dyn_cast<PClassActor>(type->ParentClass); actor = GetDefaultByType(type); } else { // first check whether a state of the desired name exists PClass *stype = PClass::FindClass (classname); if (stype == NULL) { I_Error ("%s is an unknown class.", classname); } if (!stype->IsDescendantOf (RUNTIME_CLASS(AActor))) { I_Error ("%s is not an actor class, so it has no states.", stype->TypeName.GetChars()); } if (!stype->IsAncestorOf (type)) { I_Error ("%s is not derived from %s so cannot access its states.", type->TypeName.GetChars(), stype->TypeName.GetChars()); } if (type != stype) { type = static_cast<PClassActor *>(stype); actor = GetDefaultByType (type); } } } label = name; // Check for offset offset = NULL; if ((pt = strchr (name, '+')) != NULL) { *pt = '\0'; offset = pt + 1; } v = offset ? strtol (offset, NULL, 0) : 0; // Get the state's address. if (type == mytype) { state = FindState (label); } else { state = type->FindStateByString(label, true); } if (state != NULL) { state += v; } else if (v != 0) { I_Error ("Attempt to get invalid state %s from actor %s.", label, type->TypeName.GetChars()); } else { Printf (TEXTCOLOR_RED "Attempt to get invalid state %s from actor %s.\n", label, type->TypeName.GetChars()); } delete[] namestart; // free the allocated string buffer return state; }
//========================================================================== // // Starts a new actor definition // //========================================================================== PClassActor *CreateNewActor(const FScriptPosition &sc, FName typeName, FName parentName, bool native) { PClassActor *replacee = NULL; PClassActor *ti = NULL; PClassActor *parent = RUNTIME_CLASS(AActor); if (parentName != NAME_None) { parent = PClass::FindActor(parentName); PClassActor *p = parent; while (p != NULL) { if (p->TypeName == typeName) { sc.Message(MSG_ERROR, "'%s' inherits from a class with the same name", typeName.GetChars()); break; } p = dyn_cast<PClassActor>(p->ParentClass); } if (parent == NULL) { sc.Message(MSG_ERROR, "Parent type '%s' not found in %s", parentName.GetChars(), typeName.GetChars()); parent = RUNTIME_CLASS(AActor); } else if (!parent->IsDescendantOf(RUNTIME_CLASS(AActor))) { sc.Message(MSG_ERROR, "Parent type '%s' is not an actor in %s", parentName.GetChars(), typeName.GetChars()); parent = RUNTIME_CLASS(AActor); } } if (native) { ti = PClass::FindActor(typeName); if (ti == NULL) { extern void DumpTypeTable(); DumpTypeTable(); sc.Message(MSG_ERROR, "Unknown native actor '%s'", typeName.GetChars()); goto create; } else if (ti != RUNTIME_CLASS(AActor) && ti->ParentClass->NativeClass() != parent->NativeClass()) { sc.Message(MSG_ERROR, "Native class '%s' does not inherit from '%s'", typeName.GetChars(), parentName.GetChars()); parent = RUNTIME_CLASS(AActor); goto create; } else if (ti->Defaults != NULL) { sc.Message(MSG_ERROR, "Redefinition of internal class '%s'", typeName.GetChars()); goto create; } ti->InitializeNativeDefaults(); ti->ParentClass->DeriveData(ti); } else { create: ti = static_cast<PClassActor *>(parent->CreateDerivedClass (typeName, parent->Size)); } ti->Replacee = ti->Replacement = NULL; ti->DoomEdNum = -1; return ti; }