_=[[                             toggleAnimParts.lua
--------------------------------------------------------------------------------------------------------------------
Author: Sven777b (ICQ#95176001)
Konzept & Betatests : Desperados93
Version 1.0 - 12.04.2010 
Version 1.3 - 19.04.2010

frei verwendbar - keine erlaubnis nötig  |  free for use - no permission needed.
Modifikationen erst nach Rücksprache!    |  modifications only with my permission.

Hinweis: das Kopieren von Sourcecode ist strafbar nach UrhG §2.1
--------------------------------------------------------------------------------------------------------------------

Fahrzeug XML:

<animParts>
  <animPart index="1" id="dachfenster" showHelp="true" rotMin="0 0 0" rotMax="15 0 0" moveTime="3" />
  <animPart index="2" id="fenster_links" transMin="0 0 0" transMax="0 0.4 0" moveTime="3" />
  <animPart index="3" id="fenster_rechts" scaleMin="1 0.5 1" scaleMax="1 1 1" moveTime="3" />
</animParts>

=================================================================
id : frei vergebener Name - ist gleichzeitig Bezeichner für l10n Text und InputBinding
showHelp : true/false - Hilfetext anzeigen oder nicht
rotMin/rotMax : rotation auf 3 Achsen
transMin/transMax : bewegung auf 3 Achsen
scaleMin/scaleMax : skalierung auf 3 Achsen - alles kombinierbar
moveTime : Laufzeit in Sekunden in der die Bewegung abgeschlossen wird.
autoReturn : true/false - wenn true, dann kehrt die Animation zurück sobald der Knopf losgelassen wird.
=================================================================

moddesc:
<specialization name="Fenster" className="toggleAnimatedParts" filename="toggleAnimatedParts.lua"/>

<inputBindings>
  <input name="dachfenster" key1="KEY_5" button="" />
  <input name="fenster_links" key1="KEY_6" button="" />
  <input name="fenster_rechts" key1="KEY_7" button="" />
</inputBindings>
]]

toggleAnimatedParts = {};

function toggleAnimatedParts.prerequisitesPresent(specializations)
    return true;
end;

function toggleAnimatedParts:load(savegame)
    self.toggle = SpecializationUtil.callSpecializationsFunction("toggle");
    self.animParts = {};
    local c = 0;
    while true do
        local baseString = string.format("vehicle.animParts.animPart(%d)#",c);
        local index = getXMLString(xmlFile,baseString.."index");
        local id = getXMLString(xmlFile,baseString.."id");
        if index == nil or id == nil or InputBinding[id] == nil then
            break;
        end;
        local part = {};
        part.index = Utils.indexToObject(self.components, index);
        part.id = id;
        
        local rotMin = getXMLString(xmlFile,baseString.."rotMin");
        local rotMax = getXMLString(xmlFile,baseString.."rotMax");
        if rotMin ~= nil and rotMax ~= nil then
            local x,y,z = Utils.getVectorFromString(rotMin);
            part.rotMin = {math.rad(Utils.getNoNil(x,0)),math.rad(Utils.getNoNil(y,0)),math.rad(Utils.getNoNil(z,0))};
            local x,y,z = Utils.getVectorFromString(rotMax);
            part.rotMax = {math.rad(Utils.getNoNil(x,0)),math.rad(Utils.getNoNil(y,0)),math.rad(Utils.getNoNil(z,0))};
        end;
        
        local transMin = getXMLString(xmlFile,baseString.."transMin");
        local transMax = getXMLString(xmlFile,baseString.."transMax");
        if transMin ~= nil and transMax ~= nil then
            local x,y,z = Utils.getVectorFromString(transMin);
            part.transMin = {Utils.getNoNil(x,0),Utils.getNoNil(y,0),Utils.getNoNil(z,0)};
            local x,y,z = Utils.getVectorFromString(transMax);
            part.transMax = {Utils.getNoNil(x,0),Utils.getNoNil(y,0),Utils.getNoNil(z,0)};
        end;
        
        local scaleMin = getXMLString(xmlFile,baseString.."scaleMin");
        local scaleMax = getXMLString(xmlFile,baseString.."scaleMax");
        if scaleMin ~= nil and scaleMax ~= nil then
            local x,y,z = Utils.getVectorFromString(scaleMin);
            part.scaleMin = {Utils.getNoNil(x,1),Utils.getNoNil(y,1),Utils.getNoNil(z,1)};
            local x,y,z = Utils.getVectorFromString(scaleMax);
            part.scaleMax = {Utils.getNoNil(x,1),Utils.getNoNil(y,1),Utils.getNoNil(z,1)};
        end;
        
        part.moveTime = Utils.getNoNil(getXMLFloat(xmlFile,baseString.."moveTime"),1)*1000;
        part.helpText = Utils.getNoNil(getXMLBool(xmlFile, baseString.."showHelp"),false);
        part.autoReturn = Utils.getNoNil(getXMLBool(xmlFile, baseString.."autoReturn"),false);
        part.toMax = false;
        part.move = false;
        table.insert(self.animParts,part);
        c=c+1;
    end;
end;

function toggleAnimatedParts:delete()
end;

function toggleAnimatedParts:mouseEvent(posX, posY, isDown, isUp, button)
end;

function toggleAnimatedParts:keyEvent(unicode, sym, modifier, isDown)
end;

function toggleAnimatedParts:update(dt)
if self.inrange or self.isEntered then
        for nr,part in ipairs(self.animParts) do
            if not part.autoReturn then
                if InputBinding.hasEvent(InputBinding[part.id]) then
                    self:toggle(nr,not part.toMax); 
                end;
            else
                if InputBinding.isPressed(InputBinding[part.id]) then
                    if not part.toMax then
                        self:toggle(nr,true); 
                    end;
                else
                    if part.toMax then
                        self:toggle(nr,false); 
                    end;
                end;
            end;
        end;
        for _,part in ipairs(self.animParts) do
            if part.move then
                part.move = false;
                if part.rotMin ~= nil then
                    local curRot = {getRotation(part.index)};
                    local newRot = Utils.getMovedLimitedValues(curRot, part.rotMax, part.rotMin, 3, part.moveTime, dt, not part.toMax);
                    setRotation(part.index, unpack(newRot));
                    for i=1,3 do
                        if math.abs(newRot[i]-curRot[i]) > 0.001 then
                            part.move = true;
                        end;
                    end;
                end;
                if part.transMin ~= nil then
                    local curTrans = {getTranslation(part.index)};
                    local newTrans = Utils.getMovedLimitedValues(curTrans, part.transMax, part.transMin, 3, part.moveTime, dt, not part.toMax);
                    setTranslation(part.index, unpack(newTrans));
                    for i=1,3 do
                        if math.abs(newTrans[i]-curTrans[i]) > 0.001 then
                            part.move = true;
                        end;
                    end;
                end;
                if part.scaleMin ~= nil then
                    local curScale = {getScale(part.index)};
                    local newScale = Utils.getMovedLimitedValues(curScale, part.scaleMax, part.scaleMin, 3, part.moveTime, dt, not part.toMax);
                    setScale(part.index, unpack(newScale));
                    for i=1,3 do
                        if math.abs(newScale[i]-curScale[i]) > 0.001 then
                            part.move = true;
                        end;
                    end;
                end;
            end;
        end;
end;
end;

function toggleAnimatedParts:updateTick(dt)

    if g_currentMission.player ~= nil then
        -- Getting the distance between the player and the implement 
        local nearestDistance = 6.0; --max distance allowed
        local px, py, pz = getWorldTranslation(self.rootNode); 
        local vx, vy, vz = getWorldTranslation(g_currentMission.player.rootNode);
        local distance = Utils.vector3Length(px-vx, py-vy, pz-vz);    
        if distance < nearestDistance then
            self.inrange = true; 
        else
            self.inrange = false; 
        end;
    end;

end;

function toggleAnimatedParts:draw()
    if self.inrange or self.isEntered then
        for _,part in ipairs(self.animParts) do
            if part.helpText then
                g_currentMission:addHelpButtonText(g_i18n:getText(part.id), InputBinding[part.id]);
            end;
        end;
    end;
end;

function toggleAnimatedParts:toggle(id,state,nes)
    toggleAnimEvent.sendEvent(self,id,state,nes);
    self.animParts[id].toMax = state;
    self.animParts[id].move = true;
end;

function toggleAnimatedParts:readStream(streamId, connection)
    for nr,part in ipairs(self.animParts) do
        local state = streamReadBool(streamId);
        self:toggle(nr,state,true);
    end;
end;
        
    
function toggleAnimatedParts:writeStream(streamId, connection)
    for nr,part in ipairs(self.animParts) do
        streamWriteBool(streamId,part.toMax);
    end;
end;

toggleAnimEvent = {};
toggleAnimEvent_mt = Class(toggleAnimEvent, Event);
InitEventClass(toggleAnimEvent, "toggleAnimEvent");

function toggleAnimEvent:emptyNew()
    local self = Event:new(toggleAnimEvent_mt);
    self.className="toggleAnimEvent";
    return self;
end;

function toggleAnimEvent:new(object, id, state)
        local self = toggleAnimEvent:emptyNew()
        self.object = object;
        self.id = id;
        self.state = state;
        return self;
end;

function toggleAnimEvent:readStream(streamId, connection)
    self.object = networkGetObject(streamReadInt32(streamId));
        self.id  = streamReadInt8(streamId);
    self.state = streamReadBool(streamId);
    self:run(connection);
end;

function toggleAnimEvent:writeStream(streamId, connection)
            streamWriteInt32(streamId, networkGetObjectId(self.object));
        streamWriteInt8(streamId, self.id);
        streamWriteBool(streamId, self.state);
end;

function toggleAnimEvent:run(connection)
    self.object:toggle(self.id,self.state, true);
  if not connection:getIsServer() then
      g_server:broadcastEvent(toggleAnimEvent:new(self.object, self.id, self.state), nil, connection, self.object);
  end;    
end;

function toggleAnimEvent.sendEvent(vehicle, id, state, nes)
    if nes == nil or nes == false then
        if g_server ~= nil then
            g_server:broadcastEvent(toggleAnimEvent:new(vehicle, id, state), nil, nil, vehicle);
        else
            g_client:getServerConnection():sendEvent(toggleAnimEvent:new(vehicle, id, state));
        end;
    end;
end;
