diff --git a/src/info.c b/src/info.c index 5c013173b..e867c0c41 100644 --- a/src/info.c +++ b/src/info.c @@ -14426,7 +14426,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 0, // display offset 1000, // mass 0, // damage - sfx_None, // activesound + sfx_crumbl, // activesound MF_NOBLOCKMAP|MF_NOCLIPTHING|MF_SCENERY|MF_NOCLIPHEIGHT, // flags S_NULL // raisestate }, @@ -14453,7 +14453,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 0, // display offset 1000, // mass 0, // damage - sfx_None, // activesound + sfx_crumbl, // activesound MF_NOBLOCKMAP|MF_NOCLIPTHING|MF_SCENERY|MF_NOCLIPHEIGHT, // flags S_NULL // raisestate }, @@ -14480,7 +14480,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 0, // display offset 1000, // mass 0, // damage - sfx_None, // activesound + sfx_crumbl, // activesound MF_NOBLOCKMAP|MF_NOCLIPTHING|MF_SCENERY|MF_NOCLIPHEIGHT, // flags S_NULL // raisestate }, @@ -14507,7 +14507,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 0, // display offset 1000, // mass 0, // damage - sfx_None, // activesound + sfx_crumbl, // activesound MF_NOBLOCKMAP|MF_NOCLIPTHING|MF_SCENERY|MF_NOCLIPHEIGHT, // flags S_NULL // raisestate }, @@ -14534,7 +14534,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 0, // display offset 1000, // mass 0, // damage - sfx_None, // activesound + sfx_crumbl, // activesound MF_NOBLOCKMAP|MF_NOCLIPTHING|MF_SCENERY|MF_NOCLIPHEIGHT, // flags S_NULL // raisestate }, @@ -14561,7 +14561,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 0, // display offset 1000, // mass 0, // damage - sfx_None, // activesound + sfx_crumbl, // activesound MF_NOBLOCKMAP|MF_NOCLIPTHING|MF_SCENERY|MF_NOCLIPHEIGHT, // flags S_NULL // raisestate }, @@ -14588,7 +14588,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 0, // display offset 1000, // mass 0, // damage - sfx_None, // activesound + sfx_crumbl, // activesound MF_NOBLOCKMAP|MF_NOCLIPTHING|MF_SCENERY|MF_NOCLIPHEIGHT, // flags S_NULL // raisestate }, @@ -14615,7 +14615,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 0, // display offset 1000, // mass 0, // damage - sfx_None, // activesound + sfx_crumbl, // activesound MF_NOBLOCKMAP|MF_NOCLIPTHING|MF_SCENERY|MF_NOCLIPHEIGHT, // flags S_NULL // raisestate }, @@ -14642,7 +14642,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 0, // display offset 1000, // mass 0, // damage - sfx_None, // activesound + sfx_crumbl, // activesound MF_NOBLOCKMAP|MF_NOCLIPTHING|MF_SCENERY|MF_NOCLIPHEIGHT, // flags S_NULL // raisestate }, @@ -14669,7 +14669,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 0, // display offset 1000, // mass 0, // damage - sfx_None, // activesound + sfx_crumbl, // activesound MF_NOBLOCKMAP|MF_NOCLIPTHING|MF_SCENERY|MF_NOCLIPHEIGHT, // flags S_NULL // raisestate }, @@ -14696,7 +14696,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 0, // display offset 1000, // mass 0, // damage - sfx_None, // activesound + sfx_crumbl, // activesound MF_NOBLOCKMAP|MF_NOCLIPTHING|MF_SCENERY|MF_NOCLIPHEIGHT, // flags S_NULL // raisestate }, @@ -14723,7 +14723,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 0, // display offset 1000, // mass 0, // damage - sfx_None, // activesound + sfx_crumbl, // activesound MF_NOBLOCKMAP|MF_NOCLIPTHING|MF_SCENERY|MF_NOCLIPHEIGHT, // flags S_NULL // raisestate }, @@ -14750,7 +14750,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 0, // display offset 1000, // mass 0, // damage - sfx_None, // activesound + sfx_crumbl, // activesound MF_NOBLOCKMAP|MF_NOCLIPTHING|MF_SCENERY|MF_NOCLIPHEIGHT, // flags S_NULL // raisestate }, @@ -14777,7 +14777,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 0, // display offset 1000, // mass 0, // damage - sfx_None, // activesound + sfx_crumbl, // activesound MF_NOBLOCKMAP|MF_NOCLIPTHING|MF_SCENERY|MF_NOCLIPHEIGHT, // flags S_NULL // raisestate }, @@ -14804,7 +14804,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 0, // display offset 1000, // mass 0, // damage - sfx_None, // activesound + sfx_crumbl, // activesound MF_NOBLOCKMAP|MF_NOCLIPTHING|MF_SCENERY|MF_NOCLIPHEIGHT, // flags S_NULL // raisestate }, @@ -14831,7 +14831,7 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 0, // display offset 1000, // mass 0, // damage - sfx_None, // activesound + sfx_crumbl, // activesound MF_NOBLOCKMAP|MF_NOCLIPTHING|MF_SCENERY|MF_NOCLIPHEIGHT, // flags S_NULL // raisestate }, diff --git a/src/p_enemy.c b/src/p_enemy.c index c5e8278b9..08a79b8cf 100644 --- a/src/p_enemy.c +++ b/src/p_enemy.c @@ -2135,13 +2135,15 @@ void A_Boss1Laser(mobj_t *actor) if (!(actor->spawnpoint && actor->spawnpoint->options & MTF_AMBUSH)) { point = P_SpawnMobj(x + P_ReturnThrustX(actor, actor->angle, actor->radius), y + P_ReturnThrustY(actor, actor->angle, actor->radius), actor->z - actor->height / 2, MT_EGGMOBILE_TARGET); + point->angle = actor->angle; point->fuse = actor->tics+1; P_SetTarget(&point->target, actor->target); P_SetTarget(&actor->target, point); } } + /* -- the following was relevant when the MT_EGGMOBILE_TARGET was allowed to move left and right from its path else if (actor->target && !(actor->spawnpoint && actor->spawnpoint->options & MTF_AMBUSH)) - actor->angle = R_PointToAngle2(x, y, actor->target->x, actor->target->y); + actor->angle = R_PointToAngle2(x, y, actor->target->x, actor->target->y);*/ if (actor->spawnpoint && actor->spawnpoint->options & MTF_AMBUSH) angle = FixedAngle(FixedDiv(actor->tics*160*FRACUNIT, actor->state->tics*FRACUNIT) + 10*FRACUNIT); @@ -2191,11 +2193,16 @@ void A_Boss1Laser(mobj_t *actor) // var1: // 0 - accelerative focus with friction // 1 - steady focus with fixed movement speed -// var2 = unused +// anything else - don't move +// var2: +// 0 - don't trace target, just move forwards +// & 1 - change horizontal angle +// & 2 - change vertical angle // void A_FocusTarget(mobj_t *actor) { INT32 locvar1 = var1; + INT32 locvar2 = var2; #ifdef HAVE_BLUA if (LUA_CallAction("A_FocusTarget", actor)) return; @@ -2204,9 +2211,9 @@ void A_FocusTarget(mobj_t *actor) if (actor->target) { fixed_t speed = FixedMul(actor->info->speed, actor->scale); - fixed_t dist = R_PointToDist2(actor->x, actor->y, actor->target->x, actor->target->y); - angle_t vangle = R_PointToAngle2(actor->z , 0, actor->target->z + (actor->target->height>>1), dist); - angle_t hangle = R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y); + fixed_t dist = (locvar2 ? R_PointToDist2(actor->x, actor->y, actor->target->x, actor->target->y) : speed+1); + angle_t hangle = ((locvar2 & 1) ? R_PointToAngle2(actor->x, actor->y, actor->target->x, actor->target->y) : actor->angle); + angle_t vangle = ((locvar2 & 2) ? R_PointToAngle2(actor->z , 0, actor->target->z + (actor->target->height>>1), dist) : ANGLE_90); switch(locvar1) { case 0: @@ -3535,41 +3542,49 @@ void A_ScoreRise(mobj_t *actor) // Function: A_ParticleSpawn // -// Description: Spawns a particle at a specified interval +// Description: Hyper-specialised function for spawning a particle for MT_PARTICLEGEN. // -// var1 = type (if 0, defaults to MT_PARTICLE) +// var1 = unused // var2 = unused // void A_ParticleSpawn(mobj_t *actor) { - INT32 locvar1 = var1; - fixed_t speed; - mobjtype_t type; + INT32 i = 0; mobj_t *spawn; #ifdef HAVE_BLUA if (LUA_CallAction("A_ParticleSpawn", actor)) return; #endif - if (!actor->spawnpoint) - { - P_RemoveMobj(actor); + if (!actor->health) return; + + if (!actor->lastlook) + return; + + if (!actor->threshold) + return; + + for (i = 0; i < actor->lastlook; i++) + { + spawn = P_SpawnMobj( + actor->x + FixedMul(FixedMul(actor->friction, actor->scale), FINECOSINE(actor->angle>>ANGLETOFINESHIFT)), + actor->y + FixedMul(FixedMul(actor->friction, actor->scale), FINESINE(actor->angle>>ANGLETOFINESHIFT)), + actor->z, + (mobjtype_t)actor->threshold); + P_SetScale(spawn, actor->scale); + spawn->momz = FixedMul(actor->movefactor, spawn->scale); + spawn->destscale = spawn->scale/100; + spawn->scalespeed = spawn->scale/actor->health; + spawn->tics = (tic_t)actor->health; + spawn->flags2 |= (actor->flags2 & MF2_OBJECTFLIP); + spawn->angle += P_RandomKey(36)*ANG10; // irrelevant for default objects but might make sense for some custom ones + if (spawn->frame & FF_ANIMATE) + spawn->frame += P_RandomKey(spawn->state->var1); + + actor->angle += actor->movedir; } - - if (locvar1) - type = (mobjtype_t)locvar1; - else - type = MT_PARTICLE; - - speed = FixedMul((actor->spawnpoint->angle >> 12)<scale); - - spawn = P_SpawnMobj(actor->x, actor->y, actor->z, type); - P_SetScale(spawn, actor->scale); - spawn->momz = speed; - spawn->destscale = FixedDiv(spawn->scale<scalespeed = FixedDiv(((actor->spawnpoint->angle >> 8) & 63) << FRACBITS, 100<tics = actor->spawnpoint->extrainfo + 1; + actor->angle += (angle_t)actor->movecount; } // Function: A_BunnyHop diff --git a/src/p_floor.c b/src/p_floor.c index 96d854a10..f401271d1 100644 --- a/src/p_floor.c +++ b/src/p_floor.c @@ -13,7 +13,11 @@ #include "doomdef.h" #include "doomstat.h" +#include "m_random.h" #include "p_local.h" +#ifdef ESLOPE +#include "p_slopes.h" +#endif #include "r_state.h" #include "s_sound.h" #include "z_zone.h" @@ -1141,6 +1145,7 @@ void T_MarioBlock(levelspecthink_t *block) block->sector->ceilingdata = NULL; block->sector->floorspeed = 0; block->sector->ceilspeed = 0; + block->direction = 0; } for (i = -1; (i = P_FindSectorFromTag((INT16)block->vars[0], i)) >= 0 ;) @@ -1800,10 +1805,24 @@ static mobj_t *SearchMarioNode(msecnode_t *node) void T_MarioBlockChecker(levelspecthink_t *block) { line_t *masterline = block->sourceline; + if (block->vars[2] == 1) // Don't update the textures when the block's being bumped upwards. + return; if (SearchMarioNode(block->sector->touching_thinglist)) - sides[masterline->sidenum[0]].midtexture = sides[masterline->sidenum[0]].bottomtexture; + { + sides[masterline->sidenum[0]].midtexture = sides[masterline->sidenum[0]].bottomtexture; // Update textures + if (masterline->backsector) + { + block->sector->ceilingpic = block->sector->floorpic = masterline->backsector->ceilingpic; // Update flats to be backside's ceiling + } + } else + { sides[masterline->sidenum[0]].midtexture = sides[masterline->sidenum[0]].toptexture; + if (masterline->backsector) + { + block->sector->ceilingpic = block->sector->floorpic = masterline->backsector->floorpic; // Update flats to be backside's floor + } + } } // This is the Thwomp's 'brain'. It looks around for players nearby, and if @@ -2523,6 +2542,29 @@ void T_CameraScanner(elevator_t *elevator) } } +void T_PlaneDisplace(planedisplace_t *pd) +{ + sector_t *control, *target; + INT32 direction; + fixed_t diff; + + control = §ors[pd->control]; + target = §ors[pd->affectee]; + + if (control->floorheight == pd->last_height) + return; // no change, no movement + + direction = (control->floorheight > pd->last_height) ? 1 : -1; + diff = FixedMul(control->floorheight-pd->last_height, pd->speed); + + if (pd->type == pd_floor || pd->type == pd_both) + T_MovePlane(target, INT32_MAX/2, target->floorheight+diff, 0, 0, direction); // move floor + if (pd->type == pd_ceiling || pd->type == pd_both) + T_MovePlane(target, INT32_MAX/2, target->ceilingheight+diff, 0, 1, direction); // move ceiling + + pd->last_height = control->floorheight; +} + // // EV_DoFloor // @@ -2880,18 +2922,41 @@ void EV_CrumbleChain(sector_t *sec, ffloor_t *rover) size_t topmostvertex = 0, bottommostvertex = 0; fixed_t leftx, rightx; fixed_t topy, bottomy; - fixed_t topz; + fixed_t topz, bottomz; + fixed_t widthfactor, heightfactor; fixed_t a, b, c; mobjtype_t type = MT_ROCKCRUMBLE1; + fixed_t spacing = (32<master->frontsector->special, 3) >= 8) - type = MT_ROCKCRUMBLE1+(GETSECSPECIAL(rover->master->frontsector->special, 3)-7); +#define controlsec rover->master->frontsector + + if (controlsec->tag != 0) + { + INT32 tagline = P_FindSpecialLineFromTag(14, controlsec->tag, -1); + if (tagline != -1) + { + if (sides[lines[tagline].sidenum[0]].toptexture) + type = (mobjtype_t)sides[lines[tagline].sidenum[0]].toptexture; // Set as object type in p_setup.c... + if (sides[lines[tagline].sidenum[0]].textureoffset) + spacing = sides[lines[tagline].sidenum[0]].textureoffset; + if (sides[lines[tagline].sidenum[0]].rowoffset) + { + if (sides[lines[tagline].sidenum[0]].rowoffset>>FRACBITS != -1) + lifetime = (sides[lines[tagline].sidenum[0]].rowoffset>>FRACBITS); + else + lifetime = 0; + } + flags = lines[tagline].flags; + } + } + +#undef controlsec // soundorg z height never gets set normally, so MEH. sec->soundorg.z = sec->floorheight; - S_StartSound(&sec->soundorg, sfx_crumbl); + S_StartSound(&sec->soundorg, mobjinfo[type].activesound); // Find the outermost vertexes in the subsector for (i = 0; i < sec->linecount; i++) @@ -2910,23 +2975,46 @@ void EV_CrumbleChain(sector_t *sec, ffloor_t *rover) bottommostvertex = i; } - leftx = sec->lines[leftmostvertex]->v1->x+(16<lines[leftmostvertex]->v1->x+(spacing>>1); rightx = sec->lines[rightmostvertex]->v1->x; - topy = sec->lines[topmostvertex]->v1->y-(16<lines[topmostvertex]->v1->y-(spacing>>1); bottomy = sec->lines[bottommostvertex]->v1->y; - topz = *rover->topheight-(16<topheight-(spacing>>1); + bottomz = *rover->bottomheight; + + if (flags & ML_EFFECT1) { - for (b = topy; b > bottomy; b -= (32<>3; + heightfactor = (topz - *rover->bottomheight)>>2; + } + + for (a = leftx; a < rightx; a += spacing) + { + for (b = topy; b > bottomy; b -= spacing) { if (R_PointInSubsector(a, b)->sector == sec) { mobj_t *spawned = NULL; - for (c = topz; c > *rover->bottomheight; c -= (32<t_slope) + topz = P_GetZAt(*rover->t_slope, a, b) - (spacing>>1); + if (*rover->b_slope) + bottomz = P_GetZAt(*rover->b_slope, a, b); +#endif + + for (c = topz; c > bottomz; c -= spacing) { spawned = P_SpawnMobj(a, b, c, type); - spawned->fuse = 3*TICRATE; + spawned->angle += P_RandomKey(36)*ANG10; // irrelevant for default objects but might make sense for some custom ones + + if (flags & ML_EFFECT1) + { + P_InstaThrust(spawned, R_PointToAngle2(sec->soundorg.x, sec->soundorg.y, a, b), FixedDiv(P_AproxDistance(a - sec->soundorg.x, b - sec->soundorg.y), widthfactor)); + P_SetObjectMomZ(spawned, FixedDiv((c - bottomz), heightfactor), false); + } + + spawned->fuse = lifetime; } } } @@ -3086,8 +3174,10 @@ INT32 EV_StartCrumble(sector_t *sec, ffloor_t *rover, boolean floating, return 1; } -INT32 EV_MarioBlock(sector_t *sec, sector_t *roversector, fixed_t topheight, mobj_t *puncher) +INT32 EV_MarioBlock(ffloor_t *rover, sector_t *sector, mobj_t *puncher) { + sector_t *roversec = rover->master->frontsector; + fixed_t topheight = *rover->topheight; levelspecthink_t *block; mobj_t *thing; fixed_t oldx = 0, oldy = 0, oldz = 0; @@ -3095,11 +3185,14 @@ INT32 EV_MarioBlock(sector_t *sec, sector_t *roversector, fixed_t topheight, mob I_Assert(puncher != NULL); I_Assert(puncher->player != NULL); - if (sec->floordata || sec->ceilingdata) + if (roversec->floordata || roversec->ceilingdata) return 0; + if (!(rover->flags & FF_SOLID)) + rover->flags |= (FF_SOLID|FF_RENDERALL|FF_CUTLEVEL); + // Find an item to pop out! - thing = SearchMarioNode(sec->touching_thinglist); + thing = SearchMarioNode(roversec->touching_thinglist); // Found something! if (thing) @@ -3109,13 +3202,13 @@ INT32 EV_MarioBlock(sector_t *sec, sector_t *roversector, fixed_t topheight, mob block = Z_Calloc(sizeof (*block), PU_LEVSPEC, NULL); P_AddThinker(&block->thinker); - sec->floordata = block; - sec->ceilingdata = block; + roversec->floordata = block; + roversec->ceilingdata = block; block->thinker.function.acp1 = (actionf_p1)T_MarioBlock; // Set up the fields - block->sector = sec; - block->vars[0] = roversector->tag; // actionsector + block->sector = roversec; + block->vars[0] = sector->tag; // actionsector block->vars[1] = 4*FRACUNIT; // speed block->vars[2] = 1; // Up // direction block->vars[3] = block->sector->floorheight; // floorwasheight @@ -3131,8 +3224,8 @@ INT32 EV_MarioBlock(sector_t *sec, sector_t *roversector, fixed_t topheight, mob } P_UnsetThingPosition(thing); - thing->x = roversector->soundorg.x; - thing->y = roversector->soundorg.y; + thing->x = sector->soundorg.x; + thing->y = sector->soundorg.y; thing->z = topheight; thing->momz = FixedMul(6*FRACUNIT, thing->scale); P_SetThingPosition(thing); @@ -3149,7 +3242,7 @@ INT32 EV_MarioBlock(sector_t *sec, sector_t *roversector, fixed_t topheight, mob { if (thing->type == MT_EMMY && thing->spawnpoint && (thing->spawnpoint->options & MTF_OBJECTSPECIAL)) { - mobj_t *tokenobj = P_SpawnMobj(roversector->soundorg.x, roversector->soundorg.y, topheight, MT_TOKEN); + mobj_t *tokenobj = P_SpawnMobj(sector->soundorg.x, sector->soundorg.y, topheight, MT_TOKEN); P_SetTarget(&thing->tracer, tokenobj); P_SetTarget(&tokenobj->target, thing); P_SetMobjState(tokenobj, mobjinfo[MT_TOKEN].seestate); diff --git a/src/p_mobj.c b/src/p_mobj.c index ee1e4c38f..3028146f3 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -564,7 +564,7 @@ boolean P_SetPlayerMobjState(mobj_t *mobj, statenum_t state) // Adjust the player's animation speed to match their velocity. if (!(disableSpeedAdjust || player->charflags & SF_NOSPEEDADJUST)) { - fixed_t speed;// = FixedDiv(player->speed, mobj->scale); + fixed_t speed;// = FixedDiv(player->speed, FixedMul(mobj->scale, player->mo->movefactor)); if (player->panim == PA_FALL) { speed = FixedDiv(abs(mobj->momz), mobj->scale); @@ -590,7 +590,7 @@ boolean P_SetPlayerMobjState(mobj_t *mobj, statenum_t state) } else { - speed = FixedDiv(player->speed, mobj->scale); + speed = FixedDiv(player->speed, FixedMul(mobj->scale, player->mo->movefactor)); if (player->panim == PA_ROLL || player->panim == PA_JUMP) { if (speed > 16<friction = FRACUNIT - 0x100; - mo->movefactor = ((0x10092 - mo->friction)*(0x70))/0x158; } else mo->friction = ORIG_FRICTION; @@ -1900,7 +1898,7 @@ static void P_XYFriction(mobj_t *mo, fixed_t oldx, fixed_t oldy) // spinning friction if (player->pflags & PF_SPINNING && (player->rmomx || player->rmomy) && !(player->pflags & PF_STARTDASH)) { - const fixed_t ns = FixedDiv(549*FRICTION,500*FRACUNIT); + const fixed_t ns = FixedDiv(549*ORIG_FRICTION,500*FRACUNIT); mo->momx = FixedMul(mo->momx, ns); mo->momy = FixedMul(mo->momy, ns); } @@ -2409,14 +2407,16 @@ static void P_AdjustMobjFloorZ_FFloors(mobj_t *mo, sector_t *sector, UINT8 motyp topheight = P_GetFOFTopZ(mo, sector, rover, mo->x, mo->y, NULL); bottomheight = P_GetFOFBottomZ(mo, sector, rover, mo->x, mo->y, NULL); - if (mo->player && (P_CheckSolidLava(mo, rover) || P_CanRunOnWater(mo->player, rover))) // only the player should be affected + if (mo->player && (P_CheckSolidLava(mo, rover) || P_CanRunOnWater(mo->player, rover))) // only the player should stand on lava or run on water ; else if (motype != 0 && rover->flags & FF_SWIMMABLE) // "scenery" only continue; else if (rover->flags & FF_QUICKSAND) // quicksand ; - else if (!((rover->flags & FF_BLOCKPLAYER && mo->player) // solid to players? - || (rover->flags & FF_BLOCKOTHERS && !mo->player))) // solid to others? + else if (!( // if it's not either of the following... + (rover->flags & (FF_BLOCKPLAYER|FF_MARIO) && mo->player) // ...solid to players? (mario blocks are always solid from beneath to players) + || (rover->flags & FF_BLOCKOTHERS && !mo->player) // ...solid to others? + )) // ...don't take it into account. continue; if (rover->flags & FF_QUICKSAND) { @@ -2441,7 +2441,9 @@ static void P_AdjustMobjFloorZ_FFloors(mobj_t *mo, sector_t *sector, UINT8 motyp delta1 = mo->z - (bottomheight + ((topheight - bottomheight)/2)); delta2 = thingtop - (bottomheight + ((topheight - bottomheight)/2)); + if (topheight > mo->floorz && abs(delta1) < abs(delta2) + && (rover->flags & FF_SOLID) // Non-FF_SOLID Mario blocks are only solid from bottom && !(rover->flags & FF_REVERSEPLATFORM) && ((P_MobjFlip(mo)*mo->momz >= 0) || (!(rover->flags & FF_PLATFORM)))) // In reverse gravity, only clip for FOFs that are intangible from their bottom (the "top" you're falling through) if you're coming from above ("below" in your frame of reference) { @@ -2449,7 +2451,7 @@ static void P_AdjustMobjFloorZ_FFloors(mobj_t *mo, sector_t *sector, UINT8 motyp } if (bottomheight < mo->ceilingz && abs(delta1) >= abs(delta2) && !(rover->flags & FF_PLATFORM) - && ((P_MobjFlip(mo)*mo->momz >= 0) || (!(rover->flags & FF_REVERSEPLATFORM)))) // In normal gravity, only clip for FOFs that are intangible from the top if you're coming from below + && ((P_MobjFlip(mo)*mo->momz >= 0) || ((rover->flags & FF_SOLID) && !(rover->flags & FF_REVERSEPLATFORM)))) // In normal gravity, only clip for FOFs that are intangible from the top if you're coming from below { mo->ceilingz = bottomheight; } @@ -2934,7 +2936,6 @@ static boolean P_ZMovement(mobj_t *mo) // Stolen from P_SpawnFriction mo->friction = FRACUNIT - 0x100; - mo->movefactor = ((0x10092 - mo->friction)*(0x70))/0x158; } else if (mo->type == MT_FALLINGROCK) { @@ -3389,8 +3390,13 @@ nightsdone: if (rover->flags & FF_MARIO && !(mo->eflags & MFE_VERTICALFLIP) // if you were flipped, your head isn't actually hitting your ceilingz is it? && *rover->bottomheight == mo->ceilingz) // The player's head hit the bottom! + { // DO THE MARIO! - EV_MarioBlock(rover->master->frontsector, node->m_sector, *rover->topheight, mo); + if (rover->flags & FF_SHATTERBOTTOM) // Brick block! + EV_CrumbleChain(node->m_sector, rover); + else // Question block! + EV_MarioBlock(rover, node->m_sector, mo); + } } } // Ugly ugly billions of braces! Argh! } @@ -4551,7 +4557,15 @@ static void P_Boss1Thinker(mobj_t *mobj) return; } - if (mobj->state != &states[mobj->info->spawnstate] && mobj->health > 0 && mobj->flags & MF_FLOAT && !(mobj->flags2 & MF2_SKULLFLY)) + if (mobj->flags2 & MF2_SKULLFLY) + { + fixed_t dist = (mobj->eflags & MFE_VERTICALFLIP) + ? ((mobj->ceilingz-(2*mobj->height)) - (mobj->z+mobj->height)) + : (mobj->z - (mobj->floorz+(2*mobj->height))); + if (dist > 0 && P_MobjFlip(mobj)*mobj->momz > 0) + mobj->momz = FixedMul(mobj->momz, FRACUNIT - (dist>>12)); + } + else if (mobj->state != &states[mobj->info->spawnstate] && mobj->health > 0 && mobj->flags & MF_FLOAT) mobj->momz = FixedMul(mobj->momz,7*FRACUNIT/8); if (mobj->state == &states[mobj->info->meleestate] @@ -8255,7 +8269,7 @@ mobj_t *P_SpawnMobj(fixed_t x, fixed_t y, fixed_t z, mobjtype_t type) mobj->friction = ORIG_FRICTION; - mobj->movefactor = ORIG_FRICTION_FACTOR; + mobj->movefactor = FRACUNIT; // All mobjs are created at 100% scale. mobj->scale = FRACUNIT; @@ -9766,6 +9780,85 @@ ML_NOCLIMB : Direction not controllable } break; } + case MT_PARTICLEGEN: + { + fixed_t radius, speed, bottomheight, topheight; + INT32 type, numdivisions, time, anglespeed; + angle_t angledivision; + size_t line; + const size_t mthingi = (size_t)(mthing - mapthings); + + for (line = 0; line < numlines; line++) + { + if (lines[line].special == 15 && lines[line].tag == mthing->angle) + break; + } + + if (line == numlines) + { + CONS_Debug(DBG_GAMELOGIC, "Particle generator (mapthing #%s) needs tagged to a #15 parameter line (trying to find tag %d).\n", sizeu1(mthingi), mthing->angle); + return; + } + + if (sides[lines[line].sidenum[0]].toptexture) + type = sides[lines[line].sidenum[0]].toptexture; // Set as object type in p_setup.c... + else + type = (INT32)MT_PARTICLE; + + speed = abs(sides[lines[line].sidenum[0]].textureoffset); + bottomheight = lines[line].frontsector->floorheight; + topheight = lines[line].frontsector->ceilingheight - mobjinfo[(mobjtype_t)type].height; + + numdivisions = (mthing->options >> ZSHIFT); + + if (numdivisions) + { + radius = R_PointToDist2(lines[line].v1->x, lines[line].v1->y, lines[line].v2->x, lines[line].v2->y); + anglespeed = (sides[lines[line].sidenum[0]].rowoffset >> FRACBITS) % 360; + angledivision = 360/numdivisions; + } + else + { + numdivisions = 1; // Simple trick to make A_ParticleSpawn simpler. + radius = 0; + anglespeed = 0; + angledivision = 0; + } + + if ((speed) && (topheight > bottomheight)) + time = (INT32)(FixedDiv((topheight - bottomheight), speed) >> FRACBITS); + else + time = 1; // There's no reasonable way to set it, so just show the object for one tic and move on. + + if (mthing->options & MTF_OBJECTFLIP) + { + mobj->z = topheight; + speed *= -1; + } + else + mobj->z = bottomheight; + + CONS_Debug(DBG_GAMELOGIC, "Particle Generator (mapthing #%s):\n" + "Radius is %d\n" + "Speed is %d\n" + "Anglespeed is %d\n" + "Numdivisions is %d\n" + "Angledivision is %d\n" + "Time is %d\n" + "Type is %d\n", + sizeu1(mthingi), radius, speed, anglespeed, numdivisions, angledivision, time, type); + + mobj->angle = 0; + mobj->movefactor = speed; + mobj->lastlook = numdivisions; + mobj->movedir = angledivision*ANG1; + mobj->movecount = anglespeed*ANG1; + mobj->health = time; + mobj->friction = radius; + mobj->threshold = type; + + break; + } case MT_ROCKSPAWNER: mobj->threshold = mthing->angle; mobj->movecount = mthing->extrainfo; diff --git a/src/p_saveg.c b/src/p_saveg.c index bdeb6ff97..6abb4d14c 100644 --- a/src/p_saveg.c +++ b/src/p_saveg.c @@ -974,6 +974,7 @@ typedef enum tc_noenemies, tc_eachtime, tc_disappear, + tc_planedisplace, #ifdef POLYOBJECTS tc_polyrotate, // haleyjd 03/26/06: polyobjects tc_polymove, @@ -1097,7 +1098,7 @@ static void SaveMobjThinker(const thinker_t *th, const UINT8 type) diff |= MD_TRACER; if (mobj->friction != ORIG_FRICTION) diff |= MD_FRICTION; - if (mobj->movefactor != ORIG_FRICTION_FACTOR) + if (mobj->movefactor != FRACUNIT) diff |= MD_MOVEFACTOR; if (mobj->fuse) diff |= MD_FUSE; @@ -1537,6 +1538,21 @@ static void SaveDisappearThinker(const thinker_t *th, const UINT8 type) WRITEINT32(save_p, ht->exists); } +// +// SavePlaneDisplaceThinker +// +// Saves a planedisplace_t thinker +// +static void SavePlaneDisplaceThinker(const thinker_t *th, const UINT8 type) +{ + const planedisplace_t *ht = (const void *)th; + WRITEUINT8(save_p, type); + WRITEINT32(save_p, ht->affectee); + WRITEINT32(save_p, ht->control); + WRITEFIXED(save_p, ht->last_height); + WRITEFIXED(save_p, ht->speed); + WRITEUINT8(save_p, ht->type); +} #ifdef POLYOBJECTS // @@ -1818,6 +1834,12 @@ static void P_NetArchiveThinkers(void) SaveDisappearThinker(th, tc_disappear); continue; } + + else if (th->function.acp1 == (actionf_p1)T_PlaneDisplace) + { + SavePlaneDisplaceThinker(th, tc_planedisplace); + continue; + } #ifdef POLYOBJECTS else if (th->function.acp1 == (actionf_p1)T_PolyObjRotate) { @@ -2083,7 +2105,7 @@ static void LoadMobjThinker(actionf_p1 thinker) if (diff & MD_MOVEFACTOR) mobj->movefactor = READFIXED(save_p); else - mobj->movefactor = ORIG_FRICTION_FACTOR; + mobj->movefactor = FRACUNIT; if (diff & MD_FUSE) mobj->fuse = READINT32(save_p); if (diff & MD_WATERTOP) @@ -2486,6 +2508,23 @@ static inline void LoadDisappearThinker(actionf_p1 thinker) P_AddThinker(&ht->thinker); } +// +// LoadPlaneDisplaceThinker +// +// Loads a planedisplace_t thinker +// +static inline void LoadPlaneDisplaceThinker(actionf_p1 thinker) +{ + planedisplace_t *ht = Z_Malloc(sizeof (*ht), PU_LEVSPEC, NULL); + ht->thinker.function.acp1 = thinker; + ht->affectee = READINT32(save_p); + ht->control = READINT32(save_p); + ht->last_height = READFIXED(save_p); + ht->speed = READFIXED(save_p); + ht->type = READUINT8(save_p); + P_AddThinker(&ht->thinker); +} + #ifdef POLYOBJECTS // @@ -2769,6 +2808,10 @@ static void P_NetUnArchiveThinkers(void) case tc_disappear: LoadDisappearThinker((actionf_p1)T_Disappear); break; + + case tc_planedisplace: + LoadPlaneDisplaceThinker((actionf_p1)T_PlaneDisplace); + break; #ifdef POLYOBJECTS case tc_polyrotate: LoadPolyrotatetThinker((actionf_p1)T_PolyObjRotate); diff --git a/src/p_setup.c b/src/p_setup.c index 6bb47f419..6df103255 100644 --- a/src/p_setup.c +++ b/src/p_setup.c @@ -1561,6 +1561,8 @@ static void P_LoadSideDefs2(lumpnum_t lumpnum) sd->text[6] = 0; break; } + + case 4: // Speed pad parameters case 414: // Play SFX { sd->toptexture = sd->midtexture = sd->bottomtexture = 0; @@ -1574,6 +1576,8 @@ static void P_LoadSideDefs2(lumpnum_t lumpnum) break; } + case 14: // Bustable block parameters + case 15: // Fan particle spawner parameters case 425: // Calls P_SetMobjState on calling mobj case 434: // Custom Power case 442: // Calls P_SetMobjState on mobjs of a given type in the tagged sectors diff --git a/src/p_spec.c b/src/p_spec.c index 38185745e..b4380bb4b 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -51,6 +51,9 @@ mobj_t *skyboxmo[2]; // Amount (dx, dy) vector linedef is shifted right to get scroll amount #define SCROLL_SHIFT 5 +// This must be updated whenever we up the max flat size - quicker to assume rather than figuring out the sqrt of the specific flat's filesize. +#define MAXFLATSIZE (2048<sidenum[0]].toptexture; //P_AproxDistance(line->dx, line->dy)>>FRACBITS; + sfxnum = sides[line->sidenum[0]].toptexture; if (line->tag != 0 && line->flags & ML_EFFECT5) { @@ -3683,14 +3687,13 @@ DoneSection2: // Process Section 3 switch (special) { - case 1: // Ice/Sludge + case 1: // Unused case 2: // Wind/Current - case 3: // Ice/Sludge and Wind/Current + case 3: // Unused case 4: // Conveyor Belt break; - case 5: // Speed pad w/o spin - case 6: // Speed pad w/ spin + case 5: // Speed pad if (player->powers[pw_flashing] != 0 && player->powers[pw_flashing] < TICRATE/2) break; @@ -3700,9 +3703,16 @@ DoneSection2: { angle_t lineangle; fixed_t linespeed; + fixed_t sfxnum; lineangle = R_PointToAngle2(lines[i].v1->x, lines[i].v1->y, lines[i].v2->x, lines[i].v2->y); - linespeed = P_AproxDistance(lines[i].v2->x-lines[i].v1->x, lines[i].v2->y-lines[i].v1->y); + linespeed = sides[lines[i].sidenum[0]].textureoffset; + + if (linespeed == 0) + { + CONS_Debug(DBG_GAMELOGIC, "ERROR: Speed pad (tag %d) at zero speed.\n", sector->tag); + break; + } player->mo->angle = lineangle; @@ -3732,7 +3742,7 @@ DoneSection2: P_InstaThrust(player->mo, player->mo->angle, linespeed); - if (GETSECSPECIAL(sector->special, 3) == 6 && (player->charability2 == CA2_SPINDASH)) + if ((lines[i].flags & ML_EFFECT5) && (player->charability2 == CA2_SPINDASH)) // Roll! { if (!(player->pflags & PF_SPINNING)) player->pflags |= PF_SPINNING; @@ -3741,19 +3751,26 @@ DoneSection2: } player->powers[pw_flashing] = TICRATE/3; - S_StartSound(player->mo, sfx_spdpad); + + sfxnum = sides[lines[i].sidenum[0]].toptexture; + + if (!sfxnum) + sfxnum = sfx_spdpad; + + S_StartSound(player->mo, sfxnum); } break; - case 7: // Bustable block sprite parameter - case 8: - case 9: - case 10: - case 11: - case 12: - case 13: - case 14: - case 15: + case 6: // Unused + case 7: // Unused + case 8: // Unused + case 9: // Unused + case 10: // Unused + case 11: // Unused + case 12: // Unused + case 13: // Unused + case 14: // Unused + case 15: // Unused break; } @@ -3923,8 +3940,14 @@ DoneSection2: } // Grab speed and sequence values - speed = abs(lines[lineindex].dx)/8; - sequence = abs(lines[lineindex].dy)>>FRACBITS; + speed = abs(sides[lines[lineindex].sidenum[0]].textureoffset)/8; + sequence = abs(sides[lines[lineindex].sidenum[0]].rowoffset)>>FRACBITS; + + if (speed == 0) + { + CONS_Debug(DBG_GAMELOGIC, "ERROR: Waypoint sequence %d at zero speed.\n", sequence); + break; + } // scan the thinkers // to find the first waypoint @@ -3996,8 +4019,14 @@ DoneSection2: } // Grab speed and sequence values - speed = -(abs(lines[lineindex].dx)/8); // Negative means reverse - sequence = abs(lines[lineindex].dy)>>FRACBITS; + speed = -abs(sides[lines[lineindex].sidenum[0]].textureoffset)/8; // Negative means reverse + sequence = abs(sides[lines[lineindex].sidenum[0]].rowoffset)>>FRACBITS; + + if (speed == 0) + { + CONS_Debug(DBG_GAMELOGIC, "ERROR: Waypoint sequence %d at zero speed.\n", sequence); + break; + } // scan the thinkers // to find the last waypoint @@ -4037,6 +4066,7 @@ DoneSection2: player->speed = speed; player->pflags |= PF_SPINNING; player->pflags &= ~(PF_JUMPED|PF_GLIDING|PF_SLIDING|PF_CANCARRY); + player->climbing = 0; if (player->mo->state-states != S_PLAY_SPIN) { @@ -4135,8 +4165,14 @@ DoneSection2: } // Grab speed and sequence values - speed = abs(lines[lineindex].dx)/8; - sequence = abs(lines[lineindex].dy)>>FRACBITS; + speed = abs(sides[lines[lineindex].sidenum[0]].textureoffset)/8; + sequence = abs(sides[lines[lineindex].sidenum[0]].rowoffset)>>FRACBITS; + + if (speed == 0) + { + CONS_Debug(DBG_GAMELOGIC, "ERROR: Waypoint sequence %d at zero speed.\n", sequence); + break; + } // Find the closest waypoint // Find the preceding waypoint @@ -4983,7 +5019,8 @@ static ffloor_t *P_AddFakeFloor(sector_t *sec, sector_t *sec2, line_t *master, f if ((flags & FF_MARIO)) { - P_AddBlockThinker(sec2, master); + if (!(flags & FF_SHATTERBOTTOM)) // Don't change the textures of a brick block, just a question block + P_AddBlockThinker(sec2, master); CheckForMarioBlocks = true; } @@ -5083,6 +5120,33 @@ static inline void P_AddBridgeThinker(line_t *sourceline, sector_t *sec) } */ +/** + * Adds a plane displacement thinker. + * Whenever the "control" sector moves, + * the "affectee" sector's floor or ceiling plane moves too! + * + * \param speed Rate of movement relative to control sector + * \param control Control sector. + * \param affectee Target sector. + * \sa P_SpawnSpecials, T_PlaneDisplace + * \author Monster Iestyn + */ +static void P_AddPlaneDisplaceThinker(INT32 type, fixed_t speed, INT32 control, INT32 affectee) +{ + planedisplace_t *displace; + + // create and initialize new displacement thinker + displace = Z_Calloc(sizeof (*displace), PU_LEVSPEC, NULL); + P_AddThinker(&displace->thinker); + + displace->thinker.function.acp1 = (actionf_p1)T_PlaneDisplace; + displace->affectee = affectee; + displace->control = control; + displace->last_height = sectors[control].floorheight; + displace->speed = speed; + displace->type = type; +} + /** Adds a Mario block thinker, which changes the block's texture between blank * and ? depending on whether it has contents. * Needed in case objects respawn inside. @@ -5321,7 +5385,7 @@ static inline void P_AddCameraScanner(sector_t *sourcesec, sector_t *actionsecto elevator->distance = FixedInt(AngleFixed(angle)); } -static const ffloortype_e laserflags = FF_EXISTS|FF_RENDERALL|FF_NOSHADE|FF_EXTRA|FF_CUTEXTRA; +static const ffloortype_e laserflags = FF_EXISTS|FF_RENDERALL|FF_NOSHADE|FF_EXTRA|FF_CUTEXTRA|FF_TRANSLUCENT; /** Flashes a laser block. * @@ -5341,10 +5405,12 @@ void T_LaserFlash(laserthink_t *flash) if (!ffloor || !(ffloor->flags & FF_EXISTS)) return; - if (leveltime & 1) - ffloor->flags |= FF_RENDERALL; + if (leveltime & 2) + //ffloor->flags |= FF_RENDERALL; + ffloor->alpha = 0xB0; else - ffloor->flags &= ~FF_RENDERALL; + //ffloor->flags &= ~FF_RENDERALL; + ffloor->alpha = 0x90; sourcesec = ffloor->master->frontsector; // Less to type! @@ -5572,32 +5638,27 @@ void P_SpawnSpecials(INT32 fromnetsave) // Init line EFFECTs for (i = 0; i < numlines; i++) { - // set line specials to 0 here too, same reason as above - if (netgame || multiplayer) + if (lines[i].special != 7) // This is a hack. I can at least hope nobody wants to prevent flat alignment with arbitrary skin setups... { - // future: nonet flag? - } - else if ((lines[i].flags & ML_NETONLY) == ML_NETONLY) - { - lines[i].special = 0; - continue; - } - else - { - if (players[consoleplayer].charability == CA_THOK && (lines[i].flags & ML_NOSONIC)) + // set line specials to 0 here too, same reason as above + if (netgame || multiplayer) + { + // future: nonet flag? + } + else if ((lines[i].flags & ML_NETONLY) == ML_NETONLY) { lines[i].special = 0; continue; } - if (players[consoleplayer].charability == CA_FLY && (lines[i].flags & ML_NOTAILS)) + else { - lines[i].special = 0; - continue; - } - if (players[consoleplayer].charability == CA_GLIDEANDCLIMB && (lines[i].flags & ML_NOKNUX)) - { - lines[i].special = 0; - continue; + if ((players[consoleplayer].charability == CA_THOK && (lines[i].flags & ML_NOSONIC)) + || (players[consoleplayer].charability == CA_FLY && (lines[i].flags & ML_NOTAILS)) + || (players[consoleplayer].charability == CA_GLIDEANDCLIMB && (lines[i].flags & ML_NOKNUX))) + { + lines[i].special = 0; + continue; + } } } @@ -5643,47 +5704,53 @@ void P_SpawnSpecials(INT32 fromnetsave) break; #endif - case 7: // Flat alignment - if (lines[i].flags & ML_EFFECT4) // Align angle + case 7: // Flat alignment - redone by toast + if ((lines[i].flags & (ML_NOSONIC|ML_NOTAILS)) != (ML_NOSONIC|ML_NOTAILS)) // If you can do something... { - if (!(lines[i].flags & ML_EFFECT5)) // Align floor unless ALLTRIGGER flag is set + angle_t flatangle = InvAngle(R_PointToAngle2(lines[i].v1->x, lines[i].v1->y, lines[i].v2->x, lines[i].v2->y)); + fixed_t xoffs; + fixed_t yoffs; + + if (lines[i].flags & ML_NOKNUX) // Set offset through x and y texture offsets if NOKNUX flag is set { - for (s = -1; (s = P_FindSectorFromLineTag(lines + i, s)) >= 0 ;) - sectors[s].spawn_flrpic_angle = sectors[s].floorpic_angle = R_PointToAngle2(lines[i].v1->x, lines[i].v1->y, lines[i].v2->x, lines[i].v2->y); + xoffs = sides[lines[i].sidenum[0]].textureoffset; + yoffs = sides[lines[i].sidenum[0]].rowoffset; + } + else // Otherwise, set calculated offsets such that line's v1 is the apparent origin + { + fixed_t cosinecomponent = FINECOSINE(flatangle>>ANGLETOFINESHIFT); + fixed_t sinecomponent = FINESINE(flatangle>>ANGLETOFINESHIFT); + xoffs = (-FixedMul(lines[i].v1->x, cosinecomponent) % MAXFLATSIZE) + (FixedMul(lines[i].v1->y, sinecomponent) % MAXFLATSIZE); // No danger of overflow thanks to the strategically placed modulo operations. + yoffs = (FixedMul(lines[i].v1->x, sinecomponent) % MAXFLATSIZE) + (FixedMul(lines[i].v1->y, cosinecomponent) % MAXFLATSIZE); // Ditto. } - if (!(lines[i].flags & ML_BOUNCY)) // Align ceiling unless BOUNCY flag is set + for (s = -1; (s = P_FindSectorFromLineTag(lines + i, s)) >= 0 ;) { - for (s = -1; (s = P_FindSectorFromLineTag(lines + i, s)) >= 0 ;) - sectors[s].spawn_ceilpic_angle = sectors[s].ceilingpic_angle = R_PointToAngle2(lines[i].v1->x, lines[i].v1->y, lines[i].v2->x, lines[i].v2->y); - } - } - else // Do offsets - { - if (!(lines[i].flags & ML_BLOCKMONSTERS)) // Align floor unless BLOCKMONSTERS flag is set - { - for (s = -1; (s = P_FindSectorFromLineTag(lines + i, s)) >= 0 ;) + if (!(lines[i].flags & ML_NOSONIC)) // Modify floor flat alignment unless NOSONIC flag is set { - sectors[s].floor_xoffs += lines[i].dx; - sectors[s].floor_yoffs += lines[i].dy; + sectors[s].spawn_flrpic_angle = sectors[s].floorpic_angle = flatangle; + sectors[s].floor_xoffs += xoffs; + sectors[s].floor_yoffs += yoffs; // saved for netgames sectors[s].spawn_flr_xoffs = sectors[s].floor_xoffs; sectors[s].spawn_flr_yoffs = sectors[s].floor_yoffs; } - } - if (!(lines[i].flags & ML_NOCLIMB)) // Align ceiling unless NOCLIMB flag is set - { - for (s = -1; (s = P_FindSectorFromLineTag(lines + i, s)) >= 0 ;) + if (!(lines[i].flags & ML_NOTAILS)) // Modify ceiling flat alignment unless NOTAILS flag is set { - sectors[s].ceiling_xoffs += lines[i].dx; - sectors[s].ceiling_yoffs += lines[i].dy; + sectors[s].spawn_ceilpic_angle = sectors[s].ceilingpic_angle = flatangle; + sectors[s].ceiling_xoffs += xoffs; + sectors[s].ceiling_yoffs += yoffs; // saved for netgames sectors[s].spawn_ceil_xoffs = sectors[s].ceiling_xoffs; sectors[s].spawn_ceil_yoffs = sectors[s].ceiling_yoffs; } } } + else // Otherwise, print a helpful warning. Can I do no less? + CONS_Alert(CONS_WARNING, + M_GetText("Flat alignment linedef (tag %d) doesn't have anything to do.\nConsider changing the linedef's flag configuration or removing it entirely.\n"), + lines[i].tag); break; case 8: // Sector Parameters @@ -5795,6 +5862,19 @@ void P_SpawnSpecials(INT32 fromnetsave) P_AddBridgeThinker(&lines[i], §ors[s]);*/ break; + case 66: // Displace floor by front sector + for (s = -1; (s = P_FindSectorFromLineTag(lines + i, s)) >= 0 ;) + P_AddPlaneDisplaceThinker(pd_floor, P_AproxDistance(lines[i].dx, lines[i].dy)>>8, sides[lines[i].sidenum[0]].sector-sectors, s); + break; + case 67: // Displace ceiling by front sector + for (s = -1; (s = P_FindSectorFromLineTag(lines + i, s)) >= 0 ;) + P_AddPlaneDisplaceThinker(pd_ceiling, P_AproxDistance(lines[i].dx, lines[i].dy)>>8, sides[lines[i].sidenum[0]].sector-sectors, s); + break; + case 68: // Displace both floor AND ceiling by front sector + for (s = -1; (s = P_FindSectorFromLineTag(lines + i, s)) >= 0 ;) + P_AddPlaneDisplaceThinker(pd_both, P_AproxDistance(lines[i].dx, lines[i].dy)>>8, sides[lines[i].sidenum[0]].sector-sectors, s); + break; + case 100: // FOF (solid, opaque, shadows) P_AddFakeFloorsByLine(i, FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_CUTLEVEL, secthinkers); break; @@ -5809,11 +5889,8 @@ void P_SpawnSpecials(INT32 fromnetsave) // Draw the 'insides' of the block too if (lines[i].flags & ML_NOCLIMB) { - ffloorflags |= FF_CUTLEVEL; - ffloorflags |= FF_BOTHPLANES; - ffloorflags |= FF_ALLSIDES; - ffloorflags &= ~FF_EXTRA; - ffloorflags &= ~FF_CUTEXTRA; + ffloorflags |= FF_CUTLEVEL|FF_BOTHPLANES|FF_ALLSIDES; + ffloorflags &= ~(FF_EXTRA|FF_CUTEXTRA); } P_AddFakeFloorsByLine(i, ffloorflags, secthinkers); @@ -5920,11 +5997,8 @@ void P_SpawnSpecials(INT32 fromnetsave) // Draw the 'insides' of the block too if (lines[i].flags & ML_EFFECT2) { - ffloorflags |= FF_CUTLEVEL; - ffloorflags |= FF_BOTHPLANES; - ffloorflags |= FF_ALLSIDES; - ffloorflags &= ~FF_EXTRA; - ffloorflags &= ~FF_CUTEXTRA; + ffloorflags |= FF_CUTLEVEL|FF_BOTHPLANES|FF_ALLSIDES; + ffloorflags &= ~(FF_EXTRA|FF_CUTEXTRA); } P_AddFakeFloorsByLine(i, ffloorflags, secthinkers); @@ -5938,11 +6012,8 @@ void P_SpawnSpecials(INT32 fromnetsave) // Draw the 'insides' of the block too if (lines[i].flags & ML_EFFECT2) { - ffloorflags |= FF_CUTLEVEL; - ffloorflags |= FF_BOTHPLANES; - ffloorflags |= FF_ALLSIDES; - ffloorflags &= ~FF_EXTRA; - ffloorflags &= ~FF_CUTEXTRA; + ffloorflags |= FF_CUTLEVEL|FF_BOTHPLANES|FF_ALLSIDES; + ffloorflags &= ~(FF_EXTRA|FF_CUTEXTRA); } P_AddFakeFloorsByLine(i, ffloorflags, secthinkers); @@ -5966,11 +6037,8 @@ void P_SpawnSpecials(INT32 fromnetsave) // Draw the 'insides' of the block too if (lines[i].flags & ML_EFFECT2) { - ffloorflags |= FF_CUTLEVEL; - ffloorflags |= FF_BOTHPLANES; - ffloorflags |= FF_ALLSIDES; - ffloorflags &= ~FF_EXTRA; - ffloorflags &= ~FF_CUTEXTRA; + ffloorflags |= FF_CUTLEVEL|FF_BOTHPLANES|FF_ALLSIDES; + ffloorflags &= ~(FF_EXTRA|FF_CUTEXTRA); } P_AddFakeFloorsByLine(i, ffloorflags, secthinkers); @@ -5984,11 +6052,8 @@ void P_SpawnSpecials(INT32 fromnetsave) // Draw the 'insides' of the block too if (lines[i].flags & ML_EFFECT2) { - ffloorflags |= FF_CUTLEVEL; - ffloorflags |= FF_BOTHPLANES; - ffloorflags |= FF_ALLSIDES; - ffloorflags &= ~FF_EXTRA; - ffloorflags &= ~FF_CUTEXTRA; + ffloorflags |= FF_CUTLEVEL|FF_BOTHPLANES|FF_ALLSIDES; + ffloorflags &= ~(FF_EXTRA|FF_CUTEXTRA); } P_AddFakeFloorsByLine(i, ffloorflags, secthinkers); @@ -6166,7 +6231,13 @@ void P_SpawnSpecials(INT32 fromnetsave) break; case 250: // Mario Block - P_AddFakeFloorsByLine(i, FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_CUTLEVEL|FF_MARIO, secthinkers); + ffloorflags = FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_CUTLEVEL|FF_MARIO; + if (lines[i].flags & ML_NOCLIMB) + ffloorflags |= FF_SHATTERBOTTOM; + if (lines[i].flags & ML_EFFECT1) + ffloorflags &= ~(FF_SOLID|FF_RENDERALL|FF_CUTLEVEL); + + P_AddFakeFloorsByLine(i, ffloorflags, secthinkers); break; case 251: // A THWOMP! @@ -6180,10 +6251,11 @@ void P_SpawnSpecials(INT32 fromnetsave) break; case 252: // Shatter block (breaks when touched) + ffloorflags = FF_EXISTS|FF_RENDERALL|FF_BUSTUP|FF_SHATTER; if (lines[i].flags & ML_NOCLIMB) - P_AddFakeFloorsByLine(i, FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_BUSTUP|FF_SHATTER|FF_SHATTERBOTTOM, secthinkers); - else - P_AddFakeFloorsByLine(i, FF_EXISTS|FF_RENDERALL|FF_BUSTUP|FF_SHATTER, secthinkers); + ffloorflags |= FF_SOLID|FF_SHATTERBOTTOM; + + P_AddFakeFloorsByLine(i, ffloorflags, secthinkers); break; case 253: // Translucent shatter block (see 76) @@ -6191,10 +6263,11 @@ void P_SpawnSpecials(INT32 fromnetsave) break; case 254: // Bustable block + ffloorflags = FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_BUSTUP; if (lines[i].flags & ML_NOCLIMB) - P_AddFakeFloorsByLine(i, FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_BUSTUP|FF_ONLYKNUX, secthinkers); - else - P_AddFakeFloorsByLine(i, FF_EXISTS|FF_SOLID|FF_RENDERALL|FF_BUSTUP, secthinkers); + ffloorflags |= FF_ONLYKNUX; + + P_AddFakeFloorsByLine(i, ffloorflags, secthinkers); break; case 255: // Spin bust block (breaks when jumped or spun downwards onto) @@ -6206,10 +6279,11 @@ void P_SpawnSpecials(INT32 fromnetsave) break; case 257: // Quicksand + ffloorflags = FF_EXISTS|FF_QUICKSAND|FF_RENDERALL|FF_ALLSIDES|FF_CUTSPRITES; if (lines[i].flags & ML_EFFECT5) - P_AddFakeFloorsByLine(i, FF_EXISTS|FF_QUICKSAND|FF_RENDERALL|FF_ALLSIDES|FF_CUTSPRITES|FF_RIPPLE, secthinkers); - else - P_AddFakeFloorsByLine(i, FF_EXISTS|FF_QUICKSAND|FF_RENDERALL|FF_ALLSIDES|FF_CUTSPRITES, secthinkers); + ffloorflags |= FF_RIPPLE; + + P_AddFakeFloorsByLine(i, ffloorflags, secthinkers); break; case 258: // Laser block @@ -6970,7 +7044,6 @@ void T_Disappear(disappear_t *d) /** Adds friction thinker. * * \param friction Friction value, 0xe800 is normal. - * \param movefactor Inertia factor. * \param affectee Target sector. * \param roverfriction FOF or not * \sa T_Friction, P_SpawnFriction @@ -7008,22 +7081,10 @@ void T_Friction(friction_t *f) sec = sectors + f->affectee; - // Make sure the sector type hasn't changed + // Get FOF control sector if (f->roverfriction) - { referrer = sectors + f->referrer; - if (!(GETSECSPECIAL(referrer->special, 3) == 1 - || GETSECSPECIAL(referrer->special, 3) == 3)) - return; - } - else - { - if (!(GETSECSPECIAL(sec->special, 3) == 1 - || GETSECSPECIAL(sec->special, 3) == 3)) - return; - } - // Assign the friction value to players on the floor, non-floating, // and clipped. Normally the object's friction value is kept at // ORIG_FRICTION and this thinker changes it for icy or muddy floors. @@ -7053,14 +7114,16 @@ void T_Friction(friction_t *f) || (f->friction < thing->friction)) { thing->friction = f->friction; - thing->movefactor = f->movefactor; + if (thing->player) + thing->movefactor = f->movefactor; } } else if (P_GetSpecialBottomZ(thing, sec, sec) == thing->floorz && (thing->friction == ORIG_FRICTION // normal friction? || f->friction < thing->friction)) { thing->friction = f->friction; - thing->movefactor = f->movefactor; + if (thing->player) + thing->movefactor = f->movefactor; } } node = node->m_thinglist_next; @@ -7076,33 +7139,32 @@ static void P_SpawnFriction(void) size_t i; line_t *l = lines; register INT32 s; - fixed_t length; // line length controls magnitude + fixed_t strength; // frontside texture offset controls magnitude fixed_t friction; // friction value to be applied during movement INT32 movefactor; // applied to each player move to simulate inertia for (i = 0; i < numlines; i++, l++) if (l->special == 540) { - length = P_AproxDistance(l->dx, l->dy)>>FRACBITS; - friction = (0x1EB8*length)/0x80 + 0xD000; + strength = sides[l->sidenum[0]].textureoffset>>FRACBITS; + if (strength > 0) // sludge + strength = strength*2; // otherwise, the maximum sludginess value is +967... + + // The following might seem odd. At the time of movement, + // the move distance is multiplied by 'friction/0x10000', so a + // higher friction value actually means 'less friction'. + friction = ORIG_FRICTION - (0x1EB8*strength)/0x80; // ORIG_FRICTION is 0xE800 if (friction > FRACUNIT) friction = FRACUNIT; if (friction < 0) friction = 0; - // The following check might seem odd. At the time of movement, - // the move distance is multiplied by 'friction/0x10000', so a - // higher friction value actually means 'less friction'. - - if (friction > ORIG_FRICTION) // ice - movefactor = ((0x10092 - friction)*(0x70))/0x158; + movefactor = FixedDiv(ORIG_FRICTION, friction); + if (movefactor < FRACUNIT) + movefactor = 8*movefactor - 7*FRACUNIT; else - movefactor = ((friction - 0xDB34)*(0xA))/0x80; - - // killough 8/28/98: prevent odd situations - if (movefactor < 32) - movefactor = 32; + movefactor = FRACUNIT; for (s = -1; (s = P_FindSectorFromLineTag(l, s)) >= 0 ;) Add_Friction(friction, movefactor, s, -1); @@ -7352,12 +7414,10 @@ void T_Pusher(pusher_t *p) { referrer = §ors[p->referrer]; - if (!(GETSECSPECIAL(referrer->special, 3) == 2 - || GETSECSPECIAL(referrer->special, 3) == 3)) + if (GETSECSPECIAL(referrer->special, 3) != 2) return; } - else if (!(GETSECSPECIAL(sec->special, 3) == 2 - || GETSECSPECIAL(sec->special, 3) == 3)) + else if (GETSECSPECIAL(sec->special, 3) != 2) return; // For constant pushers (wind/current) there are 3 situations: diff --git a/src/p_spec.h b/src/p_spec.h index 23e4cfdf9..0c77eb19f 100644 --- a/src/p_spec.h +++ b/src/p_spec.h @@ -325,7 +325,7 @@ INT32 EV_StartCrumble(sector_t *sector, ffloor_t *rover, INT32 EV_DoContinuousFall(sector_t *sec, sector_t *pbacksector, fixed_t spd, boolean backwards); -INT32 EV_MarioBlock(sector_t *sector, sector_t *roversector, fixed_t topheight, mobj_t *puncher); +INT32 EV_MarioBlock(ffloor_t *rover, sector_t *sector, mobj_t *puncher); void T_MoveFloor(floormove_t *movefloor); @@ -388,7 +388,7 @@ typedef struct { thinker_t thinker; ///< Thinker structure for friction. INT32 friction; ///< Friction value, 0xe800 = normal. - INT32 movefactor; ///< Inertia factor when adding to momentum. + INT32 movefactor; ///< Inertia factor when adding to momentum, FRACUNIT = normal. INT32 affectee; ///< Number of affected sector. INT32 referrer; ///< If roverfriction == true, then this will contain the sector # of the control sector where the effect was applied. UINT8 roverfriction; ///< flag for whether friction originated from a FOF or not @@ -450,6 +450,26 @@ void T_Disappear(disappear_t *d); void T_Pusher(pusher_t *p); mobj_t *P_GetPushThing(UINT32 s); +// Plane displacement +typedef struct +{ + thinker_t thinker; ///< Thinker structure for plane displacement effect. + INT32 affectee; ///< Number of affected sector. + INT32 control; ///< Control sector used to control plane positions. + fixed_t last_height; ///< Last known height of control sector. + fixed_t speed; ///< Plane movement speed. + /** Types of plane displacement effects. + */ + enum + { + pd_floor, ///< Displace floor. + pd_ceiling, ///< Displace ceiling. + pd_both, ///< Displace both floor AND ceiling. + } type; +} planedisplace_t; + +void T_PlaneDisplace(planedisplace_t *pd); + void P_CalcHeight(player_t *player); sector_t *P_ThingOnSpecial3DFloor(mobj_t *mo); diff --git a/src/p_user.c b/src/p_user.c index 2e1cecbd9..3e1456a00 100644 --- a/src/p_user.c +++ b/src/p_user.c @@ -4797,6 +4797,9 @@ static void P_3dMovement(player_t *player) acceleration = player->accelstart + (FixedDiv(player->speed, player->mo->scale)>>FRACBITS) * player->acceleration; } + if (player->mo->movefactor != FRACUNIT) // Friction-scaled acceleration... + acceleration = FixedMul(acceleration<mo->movefactor)>>FRACBITS; + // Forward movement if (player->climbing) { @@ -6453,7 +6456,7 @@ static void P_SkidStuff(player_t *player) // If your push angle is more than this close to a full 180 degrees, trigger a skid. if (dang > ANGLE_157h) { - player->skidtime = TICRATE/2; + player->skidtime = (player->mo->movefactor == FRACUNIT) ? TICRATE/2 : (FixedDiv(35<<(FRACBITS-1), FixedSqrt(player->mo->movefactor)))>>FRACBITS; S_StartSound(player->mo, sfx_skid); if (player->panim != PA_WALK) P_SetPlayerMobjState(player->mo, S_PLAY_WALK); @@ -6490,6 +6493,9 @@ static void P_MovePlayer(player_t *player) cmd = &player->cmd; runspd = FixedMul(player->runspeed, player->mo->scale); + // Let's have some movement speed fun on low-friction surfaces, JUST for players... (high friction surfaces shouldn't have any adjustment, since the acceleration in this game is super high and that ends up cheesing high-friction surfaces.) + runspd = FixedMul(runspd, player->mo->movefactor); + // Control relinquishing stuff! if (player->powers[pw_ingoop]) player->pflags |= PF_FULLSTASIS; @@ -6680,6 +6686,7 @@ static void P_MovePlayer(player_t *player) if (!player->mo->momx && !player->mo->momy && !player->mo->momz && player->panim == PA_WALK) P_SetPlayerMobjState(player->mo, S_PLAY_STND); + player->mo->movefactor = FRACUNIT; // We're not going to do any more with this, so let's change it back for the next frame. ////////////////// //GAMEPLAY STUFF//