/*
 * server/Zone_physics.cc:
 *
 * Copyright (C) 2000 John Watson, jwatson@tempusmud.com
 * 
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 * 
 */


#include <cstdio>
#include <cmath>
#include <string>
#include <iomanip>

#include "Zone.h"
#include "../util/Persist.h"
#include "../util/VMath.h"
#include "Sector.h"
#include "SectorSpecial.h"
#include "Script.h"
#include "LineDef.h"
#include "SideDef.h"
#include "Sound.h"
#include "Character.h"

bool endpointCollisionCenter( const class Entity * ent,
                              const float * nearPt,
                              const float * farPt,
                              const float * motionVect,
                              const float * motionUnitVect,
                              const float motionMagnitude,
                              float * colliderNormal,
                              float * scale )
{

        float transformedPoint[2] = {
                nearPt[0] - ent->getPos()[0], 
                nearPt[1] - ent->getPos()[1]
        };

        float distAlongTrajectory;
                                
        float distFromTrajectory = VMath::distFromLine2d( transformedPoint, 
                                                          motionVect, 
                                                          &distAlongTrajectory,
                                                          0 );

        float circleDist = 
                distAlongTrajectory - 
                VMath::triangleSide( distFromTrajectory, ent->getBoundingRadius() );
        
        float C[2] = {
                ent->getPos()[0] + circleDist * motionUnitVect[0],
                ent->getPos()[1] + circleDist * motionUnitVect[1]
        };
        
        float lineVector[2] = {
                farPt[0] - nearPt[0],
                farPt[1] - nearPt[1]
        };
                                
        float colliderVector[2] = {
                nearPt[0] - C[0],
                nearPt[1] - C[1]
        };
                     
        float dotProd = VMath::dotProduct2d( colliderVector, lineVector );
                     
        if ( dotProd > 0 ) {
                *scale = circleDist / motionMagnitude;

                colliderNormal[0] = - colliderVector[0];
                colliderNormal[1] = - colliderVector[1];
                
                return true;
        }
        
        return false;
}
/**
 *
 * if returns true, then scale and colliderNormal wil be set, otherwise untouched
 *
 */
bool Zone::checkWallCollision( class Entity * ent, 
                               float * scale, 
                               float * colliderNormal,
                               bool * skip ) {

        float dst[2] = { 
                ent->_pos[0] + ent->_velocity[0],
                ent->_pos[1] + ent->_velocity[1]
        };
        
        float motionVect[2] = {
                dst[0] - ent->_pos[0],
                dst[1] - ent->_pos[1]
        };

        float motionMagnitude = VMath::length2d( motionVect );
        
        float motionUnitVect[2] = {
                motionVect[0] / motionMagnitude,
                motionVect[1] / motionMagnitude
        };
        
        float motionNormal[2];
        
        VMath::normal2d( motionVect, motionNormal );
        
        motionNormal[0] = motionNormal[0] * ent->getBoundingRadius() / motionMagnitude;
        motionNormal[1] = motionNormal[1] * ent->getBoundingRadius() / motionMagnitude;

        float hullLines[2][2][2] = {
                { { ent->_pos[0] + motionNormal[0],
                    ent->_pos[1] + motionNormal[1] },
                  { ent->_pos[0] + motionNormal[0] + motionVect[0],
                    ent->_pos[1] + motionNormal[1] + motionVect[1] }
                },
                { { ent->_pos[0] - motionNormal[0],
                    ent->_pos[1] - motionNormal[1] },
                  { ent->_pos[0] - motionNormal[0] + motionVect[0],
                    ent->_pos[1] - motionNormal[1] + motionVect[1] }
                }
        };

        bool found = false;
        
        *scale = 1;

        //
        // front facing normal to the line segment in question
        //
        
        float normal[2];
        float hullU[2];
        float lineU[2];

        float rPrime = ent->getBoundingRadius() / motionMagnitude;
        float uThreshold = 1 + rPrime;
        
        vector< class LineDef * > _triggerLines;
        vector< float > _triggerScales;

        for ( int i = 0; i < _lines.length; ++i ) {
                
                class LineDef * line = _lines[i];
                
                float verts[2] = {
                        line->verts[0][0] - line->verts[1][0],
                        line->verts[0][1] - line->verts[1][1]
                };

                VMath::normal2dNeg(  verts, normal );

                float dotprod = VMath::dotProduct2d( normal, ent->_velocity );
                        
                class SideDef * mySide = 0;
                class SideDef * otherSide = 0;
                
                bool isFront = false;
                
                if ( dotprod > 0 ) {
                        mySide    = line->sides[1];
                        otherSide = line->sides[0];
                        
                        //
                        // moving toward the back side of a one-sided line
                        // - or -
                        // moving away from the front side of a one-sided line
                        //

                        if ( mySide == 0 ) 
                                continue;
                }
                
                else {
                        mySide    = line->sides[0];
                        otherSide = line->sides[1];
                        isFront = true;
                }
                
                bool passable = false;
                
                //
                // two-sided, check to see if it is passable
                //

                if ( mySide && otherSide ) {
                        
                        int stepHeight = ent->getStepHeight();
                        
                        if ( ( ( ent->getPos()[2] + stepHeight ) >= otherSide->sector->getFloorHeight() ) &&
                             ( ent->getPos()[2] + ent->getHeight() <= otherSide->sector->getCeilingHeight() ) &&
                             ( otherSide->sector->getFloorHeight() + ent->getHeight() <= otherSide->sector->getCeilingHeight() ) ) {
                                if ( line->isTriggerOk( isFront, true, false ) )
                                        passable = true;
                                else
                                        continue;
                        }
                }


                if ( false && mySide && otherSide ) {
                        cout << " testing interesting line : " 
                             << line->verts[1][0] << ", " << line->verts[1][1] << " -> "
                             << line->verts[0][0] << ", " << line->verts[0][1] << endl
                             << "                       VS : "
                             << ent->_pos[0] << ", " << ent->_pos[1] << " -> "
                             << dst[0] << ", " << dst[1] << endl;
                }

                if ( VMath::linesIntersect2d( hullLines[0][0],
                                              hullLines[0][1],
                                              line->verts[1],
                                              line->verts[0],
                                              &hullU[0], &lineU[0] ) &&
                     VMath::linesIntersect2d( hullLines[1][0],
                                              hullLines[1][1],
                                              line->verts[1],
                                              line->verts[0],
                                              &hullU[1], &lineU[1] ) ) {
                        
                        if ( ! VMath::inRangeInclusive( lineU[0], 0, 1 ) &&
                             ! VMath::inRangeInclusive( lineU[1], 0, 1 ) ) {
                                continue;
                        }

                        int points_inside = 0;
                        
                        //
                        // second vert of line is inside the hull
                        //

                        if ( lineU[0] < 0 || lineU[1] < 0 ) {
                                
                                ++points_inside;
                                
                                // 1. calculate potential circle centerpoint (C)
                                // 2. find dotprod of C-P . V0-V1
                                // 3. if dotprod is > 0 then its a point collision
                                
                                float pointscale = 0;
                                float pointColliderNormal[2];
                                
                                if ( endpointCollisionCenter( ent,
                                                              line->verts[1],
                                                              line->verts[0],
                                                              motionVect,
                                                              motionUnitVect,
                                                              motionMagnitude,
                                                              pointColliderNormal,
                                                              &pointscale ) ) {

                                        if ( pointscale >= 0 && pointscale < *scale ) {
                                                
                                                if ( passable == false ) {
                                                        *scale = pointscale;
                                                        colliderNormal[0] = pointColliderNormal[0];
                                                        colliderNormal[1] = pointColliderNormal[1];
                                                        found = true;
                                                }
                                                
                                                if ( line->isTriggerOk( isFront, true, false ) ) {
                                                        _triggerLines.push_back( line );
                                                        _triggerScales.push_back( pointscale );
                                                }
                                        }
                                        continue;

                                }
                        }

                        //
                        // second vert of line is inside the hull
                        //

                        if ( lineU[0] > 1 || lineU[1] > 1 ) {

                                ++points_inside;
                                
                                // 1. calculate potential circle centerpoint (C)
                                // 2. find dotprod of C-P . V0-V1
                                // 3. if dotprod is > 0 then its a point collision
                                
                                float pointscale = 0;
                                float pointColliderNormal[2];
                                
                                if ( endpointCollisionCenter( ent,
                                                              line->verts[0],
                                                              line->verts[1],
                                                              motionVect,
                                                              motionUnitVect,
                                                              motionMagnitude,
                                                              pointColliderNormal,
                                                              &pointscale ) ) {

                                        if ( pointscale >= 0 && pointscale < *scale ) {

                                                if ( passable == false ) {
                                                        *scale = pointscale;
                                                        colliderNormal[0] = pointColliderNormal[0];
                                                        colliderNormal[1] = pointColliderNormal[1];
                                                        found = true;
                                                }
                                                
                                                if ( line->isTriggerOk( isFront, true, false ) ) {
                                                        _triggerLines.push_back( line );
                                                        _triggerScales.push_back( pointscale );
                                                }
                                        }   
                                        continue;
                                }
                        }

                        if ( //points_inside != 1 &&
                            ( ( hullU[0] >= 0 && hullU[0] <= uThreshold ) ||
                              ( hullU[1] >= 0 && hullU[1] <= uThreshold ) ) ) {
                                
                                if ( lineU[0] < 0 || lineU[0] > 1 ) {
                                        
                                }
                                float intHypot = VMath::hypotenuse( hullU[0] - hullU[1], rPrime * 2 );

                                float H = intHypot / 2;
                                
                                float omega = ( hullU[0] + hullU[1] ) / 2;
                                
                                float d = omega - H;
                                
                                if ( omega < rPrime )
                                        continue;

                                if ( d < *scale ) {
                                        if ( passable == false ) {
                                                *scale = d;
                                                colliderNormal[0] = normal[0];
                                                colliderNormal[1] = normal[1];
                                                found = true;
                                        }

                                        if ( line->isTriggerOk( isFront, true, false ) ) {
                                                _triggerLines.push_back( line );
                                                _triggerScales.push_back( d );
                                        }
                                }
                        }
                }
        }

        for ( unsigned int i = 0; i < _triggerLines.size(); ++i ) {
                if ( _triggerScales[i] <= *scale ) {
                        if ( _triggerLines[i]->script->execute( ent, _cur_tick ) )
                                *skip = true;

                        for ( int j = 0; j < _lines.length; ++j ) {
                
                                class LineDef * line = _lines[j];
                                
                                if ( _triggerLines[i]->script == line->script )
                                        line->trigger_flags |= LineDef::TRIPPED;
                        }
                }

                if ( *skip )
                        break;
        }

        return found;
        
}

void Zone::physicsUpdateContents( unsigned int tick ) {

        _cur_tick = tick;

        //
        // handle lifts and stuff
        //

        updateSectorSpecials( tick );

        for ( int i = 0; i < _scripts.length; ++i ) {
                if ( _scripts[i]->running ) {
                        _scripts[i]->execute( 0, tick );
                }
        }

        
        bool lightsources_moved = false;
        
        Vector< class Entity * >::const_iterator end = _contents.end();
        for ( Vector< class Entity * >::const_iterator iter = _contents.begin();
              iter != end; ++iter ) {
                
                class Entity * ent = *iter;

                //
                // purge old, stale, dead sounds
                //
                
                ent->purgeDeadSounds();

                setFloorCeilingEntities( ent );

                setEntityIllumination( ent );
                
                //
                // find the position of the floor
                //

                float minZ = ent->getMinZ();
                
                // sanity check

                //if ( minZ > ent->_pos[2] )
                //       ent->_pos[2] = minZ;
                //
                // add the components appropriately
                //
                
                if ( ent->_selfPropulsion[0] || ent->_selfPropulsion[1] || ent->_selfPropulsion[2] ) {

                        const int move_factor = ( isFlagSet( Entity::FLYING ) || minZ >= ent->_pos[2] ) ? 1 : 2;

                        const float add_vel[3] = {
                                ent->_selfPropulsion[0] / move_factor,
                                ent->_selfPropulsion[1] / move_factor,
                                ent->_selfPropulsion[2] / move_factor
                        };

                        for ( int i = 0; i < 3; ++i ) {

                                if ( ent->_velocity[i] > 0 &&
                                     add_vel[i] > 0 ) {
                                        if ( add_vel[i] > ent->_velocity[i] ) {
                                                ent->_velocity[i] = add_vel[i];
                                        }
                                }

                                else if ( ent->_velocity[i] < 0 &&
                                          add_vel[i] < 0 ) {
                                        if ( add_vel[i] < ent->_velocity[i] ) {
                                                ent->_velocity[i] = add_vel[i];
                                        }
                                }
                        
                                else {
                                        ent->_velocity[i] += add_vel[i];
                                }
                        }
                }

                //
                // accelerate downwards
                //
                
                if ( ! ent->isFlagSet( Entity::FLYING | Entity::LEVITATING ) &&
                     minZ < ent->getPos()[2] && ent->_velocity[2] > -60 ) {
                        ent->_velocity[2] -= 4;
                }
                
                //
                // fall upwards or downwards
                //

                if ( ent->_velocity[2] != 0 ) {

                        float maxZ = ent->getMaxZ();
                        float myZ  = ent->getPos()[2] + ent->_velocity[2];

                                //
                                // collide with the floor
                                //

                        if ( myZ <= minZ && ent->_velocity[2] < 0 ) {
                                
                                float diff = ent->getPos()[2] - minZ;
                                
                                ent->setPosition( ent->getPos()[0],
                                                  ent->getPos()[1],
                                                  minZ );
                                float normal[3] = { 0, 0, 1 };
                                
                                if ( diff > 0 && ent->collideWith( 0, normal, tick ) )
                                        continue;
                                
                                const class Sector * floorSect = ent->getFloorSector();
                                
                                // land on a descending lift
                                if ( floorSect ) {                                     
                                        ent->_velocity[2] = min( 0, floorSect->getSurfaceVelocity( Sector::FLOOR ) );
                                }
                                else {
                                        ent->_velocity[2] = 0;
                                }
                        }

                                //
                                // collide with the ceiling
                                //

                        else if ( myZ >= maxZ && ent->_velocity[2] > 0 ) {
                                ent->setPosition( ent->getPos()[0],
                                                  ent->getPos()[1],
                                                  maxZ );
                                
                                float normal[3] = { 0, 0, -1 };

                                if ( ent->collideWith( 0, normal, tick ) )
                                        continue;

                                ent->_velocity[2] = 0; 

                        }

                                //
                                // fall without obstruction
                                //

                        else {
                                
                                ent->setPosition( ent->getPos()[0],
                                                  ent->getPos()[1],
                                                  myZ );
                        }
                        

                                //                        setEntityIllumination( ent );
                        if ( ent->getLight() )
                                lightsources_moved = true;
                        
                }

                //
                // do the thinking AFTER any falling has taken place
                //

                ent->think( tick );

                if ( ent->die )
                        continue;
                
 
                //
                // the physics calculations only handle movement in the x-y plane
                //

                if ( ent->_velocity[0] == 0 && ent->_velocity[1] == 0 )
                        continue;

                //
                // check for entity collisions
                //
                
                float ent_scale = 0;
                float wall_scale = 0;

                bool skip = false;

                float colliderNormal[3] = { 0, 0, 0 };

                class Entity * collider = ent->findCollider( _contents, &ent_scale );
                
                bool wall_collider = checkWallCollision( ent, &wall_scale, colliderNormal, &skip );

                if ( skip )
                        continue;

                // true after collision processing if we need to do a follow-up 'slide' motion
                bool do_slide = false;


                //
                // we've collided with another entity, and it is closer than any wall collision, if any
                //

                if ( collider && ( ent_scale < wall_scale || wall_collider == false )  ) {
                        
                        float result_vel[] = {
                                ent->_velocity[0] * ent_scale,
                                ent->_velocity[1] * ent_scale
                        };
                        
                        ent->moveAbsolute( result_vel[0], result_vel[1], 0 );

                        if ( ent->collideWith( collider, 0, tick ) )
                                continue;

                                //                        setEntityIllumination( ent );
                        lightsources_moved = lightsources_moved || ent->getLight();

                                //
                                // you've gone far enough, no sliding for you!
                                //

                        if ( ent_scale > 0.9 ) {
                                ent->setVelocity( 0, 0, 0 );
                        }

                                //
                                // slide along the colliding ent
                                //

                        else {
                                
                                float a[3] = {
                                        collider->_pos[0] - ent->_pos[0],
                                        collider->_pos[1] - ent->_pos[1],
                                        0
                                };
                        
                                VMath::unitVector2d( a );
                                VMath::crossProduct( a, ent->_velocity, result_vel );
                        
                                float c[3];
                        
                                VMath::crossProduct( result_vel, a, c );
                                
                                // quarter speed slides around entities

                                c[0] /= 4;
                                c[1] /= 4;
                                c[2] /= 4;

                                ent->setVelocity( c[0], c[1], c[2] );

                                if ( c[0] || c[1] )
                                        do_slide = true;
                        }
                }

                //
                // our closest collision is with a wall
                //
                
                else if ( wall_collider ) {
                        
                        float myscale = floor( wall_scale * 100 ) / 100;

                        ent->moveAbsolute( ent->_velocity[0] * myscale,
                                           ent->_velocity[1] * myscale,
                                           0 );
                        
                        if ( ent->collideWith( 0, colliderNormal, tick ) )
                                continue;

                                //
                                // slide along wall, protect against zero-length movement
                                //
                        
                        myscale = 1 - ceil( wall_scale * 100 ) / 100;

                        ent->_velocity[0] *= myscale;
                        ent->_velocity[1] *= myscale;
                        
                        VMath::unitVector2d( colliderNormal );
                        
                        float result_vel[2][3];
                        
                        VMath::crossProduct( colliderNormal, ent->_velocity, result_vel[0] );
                        
                        VMath::crossProduct( result_vel[0], colliderNormal, result_vel[1] );
                        
                        ent->_velocity[0] = result_vel[1][0];
                        ent->_velocity[1] = result_vel[1][1];
                        
                        if ( ent->_velocity[0] == 0 &&
                             ent->_velocity[1] == 0 ) {
                                
                                setFloorCeilingSectors( ent );
                                setFloorCeilingEntities( ent );

                                if ( ent->_floorSector && ent->_floorSector->getFloorHeight() > ent->getPos()[2] ) {
                                        ent->setPosition( ent->getPos()[0], 
                                                          ent->getPos()[1], 
                                                          ent->_floorSector->getFloorHeight() );
                                }
                                
                                //                                setEntityIllumination( ent );
                                lightsources_moved = lightsources_moved || ent->getLight();

                                continue;
                        }

                        do_slide = true;
                        
                }

                //
                // see if we need to check for collisions on the slide motion
                //

                if ( do_slide ) {
                        
                        collider = ent->findCollider( _contents, &ent_scale );
                        
                        wall_collider = checkWallCollision( ent, &wall_scale, colliderNormal, &skip );
                        
                        if ( skip )
                                continue;

                        if ( collider && ( ent_scale < wall_scale || wall_collider == false )  ) {
                                
                                if ( ent->collideWith( collider, 0, tick ) )
                                        continue;
                                
                                ent->setVelocity( ent->_velocity[0] * ent_scale,
                                                  ent->_velocity[1] * ent_scale,
                                                  ent->_velocity[2] );
                        }
                        else {
                                if ( ent->collideWith( 0, colliderNormal, tick ) )
                                        continue;

                                float myscale = floor( wall_scale * 100 ) / 100;

                                ent->setVelocity( ent->_velocity[0] * myscale,
                                                  ent->_velocity[1] * myscale,
                                                  ent->_velocity[2] );
                        }
                }
                
                //
                // this is reached either in the case of no collisions, or
                // on a slide motion
                //

                ent->moveAbsolute( ent->_velocity[0],
                                   ent->_velocity[1],
                                   0 );
                
                //
                // on the floor, slow down, otherwise keep going
                //

                if ( minZ >= ent->_pos[2] ) {
                        ent->_velocity[0] /= 2;
                        ent->_velocity[1] /= 2;
                }
                
                //
                // come to a complete stop at a certain magnitude
                //

                if ( fabs( ent->_velocity[0] ) < 1 )
                        ent->_velocity[0] = 0;

                if ( fabs( ent->_velocity[1] ) < 1 )
                        ent->_velocity[1] = 0;
                
                setFloorCeilingSectors( ent );
                setFloorCeilingEntities( ent );
                
                //
                // see if we made a step up
                //

                if ( ent->_floorSector && ent->_floorSector->getFloorHeight() > ent->getPos()[2] ) {
                        ent->setPosition( ent->getPos()[0], 
                                          ent->getPos()[1], 
                                          ent->_floorSector->getFloorHeight() );
                }
                
                //                setEntityIllumination( ent );

                lightsources_moved = lightsources_moved || ent->getLight();
                        
        }


        //
        // now setup new lightmaps
        //
        
        
        // TODO: if num_lightsources_moved > 0
        // otherwise, leave the lightmaps alone
        
        //        if ( lightsources_moved )
        updateDynamicLightmaps();

        
}


void Zone::updateSectorSpecials( unsigned int tick ) {

        //        cout << " void Zone::updateSectorSpecials( unsigned int tick ) {" << endl;
        //        return;
        for ( int i = 0; i < _sectSpecials.length; ++i ) {
                class SectorSpecial * spec = _sectSpecials[i];
                
                if ( spec->sect == 0 || spec->iterations == 0 || spec->wait_tick > tick ) {
                        //                        cout << " NO SECTOR" << endl;
                        continue;
                }

                int move = 0;
                        
                if ( spec->isExtending() && spec->cur_travel < spec->travel ) {
                        move = min( spec->travel - spec->cur_travel, (int) spec->speed );
                }
                else if ( spec->isRetracting() && spec->cur_travel > 0 ) {
                        move = -min( spec->cur_travel, (short) spec->speed );
                }
                else {
                        spec->reverseDirection(); 
                        if ( spec->iterations == 0 )
                                spec->halt();
                        else
                                spec->performDelay( tick );
                        continue;
                }
                   
                if ( ( spec->sound->die || spec->sound->index != Sound::SND_LIFT_MOVE ) && spec->sound_type )
                        spec->sound->init( Sound::SND_LIFT_MOVE, 200, -1, false );
                                
                class Entity * damage_ent = 0;
                // check for blockage during extension
                
                if ( move > 0 ) {
                        for ( unsigned int i = 0; i < _contents.size(); ++i ) {
                                if ( spec->sect == _contents[i]->_ceilingSector ) {
                                        int margin = (int) ( spec->sect->getCeilingHeight() -
                                                             _contents[i]->getHeight() -
                                                             _contents[i]->getMinZ() );
                                        if ( margin < move ) {
                                                damage_ent = _contents[i];
                                                move = margin;
                                        }
                                }
                        }
                                
                        if ( damage_ent ) {
                                if ( spec->damage > 0 ) {
                                        cout << " damage" << endl;
                                        // do damage
                                }
                                else if ( spec->damage < 0 ) {
                                        // reverse travel
                                        spec->reverseDirection();
                                }
                        }
                }
                        
                spec->cur_travel += move;

                if ( spec->isDoor() ) {
                        spec->sect->_surfaceHeights[ Sector::CEILING ] -= move;
                } 
                else {
                        spec->sect->_surfaceHeights[ Sector::FLOOR ] += move;
                        if ( move > 0 ) {
                                for ( unsigned int i = 0; i < _contents.size(); ++i ) {
                                        if ( spec->sect == _contents[i]->_floorSector &&
                                             _contents[i]->getMinZ() > _contents[i]->getPos()[2] &&
                                             _contents[i]->_velocity[2] < move ) {
                                                _contents[i]->_velocity[2] = move;
                                        }
                                }
                        }
                }

                for ( int i = 0; i < spec->sect->_myLines.length; ++i ) {
                        _lines[ spec->sect->_myLines[i] ]->modified = true;
                }
        }
}

void Zone::triggerSectorSpecials( int tag, int value ) {
        for ( int i = 0; i < _sectSpecials.length; ++i ) {
                class SectorSpecial * spec = _sectSpecials[i];
                if ( spec->tag == tag )
                        spec->triggerSpecial( value );
        }
}

void Zone::triggerLine( class Entity * ent, const class LineDef * line ) {

        
        line->script->execute( ent, _cur_tick );

        /*
          switch ( lspec->type ) {
          case LineSpecial::DOOR_LIFT:
                
          for ( int i = 0; i < _sectSpecials.length; ++i ) {
          class SectorSpecial * spec = _sectSpecials[i];
                        
          if ( lspec->target != spec->tag )
          continue;

          if ( lspec->value == -1 ) {
          spec->iterations = lspec->value;
          } 
          else if ( lspec->value == 0 ) {
          if ( spec->iterations != 0 )
          spec->halt();
          }
          else if ( lspec->value == -2 ) {

          if ( spec->flags & SectorSpecial::START_EXTENDED ) {
          if ( spec->cur_travel == spec->travel ) {
          if ( spec->iterations )
          spec->halt();
          }
          else if ( spec->isExtending() )
          spec->iterations = 1;
          else
          spec->iterations = 2;
          }
          else if ( spec->cur_travel == 0 ) {
          if ( spec->iterations )
          spec->halt();
          }
          else if ( spec->isExtending() )
          spec->iterations = 2;
          else
          spec->iterations = 1;
          }
          else if ( lspec->value > 0 && ( spec->iterations <= 0 || spec->iterations > lspec->value ) )
          spec->iterations = lspec->value;


          //                        cout << " spec->iterations now=" << (int)spec->iterations << endl;
          }
          break;
          }
        */
}
