-- by modelleicher
-- www.schwabenmodding.de
-- date: 22.07.2017
-- logSplitter animation 

-- animationName -> name of the animation
-- speed -> speed the animation will be played at
-- sharedAnimation -> set to true if animation will also be played from other scripts. That way the script will check position of animation first so you don't have to press key twice
-- l10nName -> optional, if left out l10n Text name is "togglelogSplitter" 

-- <logSplitter animationName="" speed="" startState="" triggerIndex="" sharedAnimation="" l10nName="" />

-- FS19 conversion, 17.12.2018
-- final fixes, 16.06.2019

logSplitter = {};

function logSplitter.prerequisitesPresent(specializations)
    return SpecializationUtil.hasSpecialization(AnimatedVehicle, specializations);
end;

function logSplitter.registerEventListeners(vehicleType)
	SpecializationUtil.registerEventListener(vehicleType, "onLoad", logSplitter);
	SpecializationUtil.registerEventListener(vehicleType, "onUpdate", logSplitter);
	SpecializationUtil.registerEventListener(vehicleType, "onDelete", logSplitter);
end;

function logSplitter:TOGGLE_SPLITTING()
	self.spec_logSplitter.isPressed = true;
end;

function logSplitter:onLoad(savegame)
	self.spec_logSplitter = {}
	local spec = self.spec_logSplitter;


    self.setlogSplitter = logSplitter.setlogSplitter;
    self.turnOnLogSplitter = logSplitter.turnOnLogSplitter;
    self.playSplitSound = logSplitter.playSplitSound;
    self.logSplitterTrigger = logSplitter.logSplitterTrigger;
    self.logSplitterSplitShapesTrigger = logSplitter.logSplitterSplitShapesTrigger;
    self.logSplitterSplitShapeCallback = logSplitter.logSplitterSplitShapeCallback;
    
    spec.animationName = getXMLString(self.xmlFile, "vehicle.logSplitter#animationName");
    spec.animationSpeed = Utils.getNoNil(getXMLFloat(self.xmlFile, "vehicle.logSplitter#speed"), 1);
    spec.trigger = I3DUtil.indexToObject(self.components, getXMLString(self.xmlFile, "vehicle.logSplitter#triggerIndex"));
    spec.sharedAnimation = Utils.getNoNil(getXMLBool(self.xmlFile, "vehicle.logSplitter#sharedAnimation"), false);
    
    spec.l10nName = Utils.getNoNil(getXMLString(self.xmlFile, "vehicle.logSplitter#l10nName"),"TOGGLE_logSplitter" );

    spec.currentState = false; -- always use currentState of the animation not wanted state for less confusion
    
    -- reset animation during load
    if spec.sharedAnimation == false then
        self:playAnimation(spec.animationName, -spec.animationSpeed, self:getAnimationTime(spec.animationName), true);
    end;
    
    spec.playerInTrigger = false;
    
    addTrigger(spec.trigger, "logSplitterTrigger", self);    
    
    
    -- log splitter splitting stuff
    spec.splitShapesTrigger = I3DUtil.indexToObject(self.components, getXMLString(self.xmlFile, "vehicle.logSplitter.splitter#splitShapesTrigger"));
    addTrigger(spec.splitShapesTrigger, "logSplitterSplitShapesTrigger", self);    
    
    spec.cutNode = I3DUtil.indexToObject(self.components, getXMLString(self.xmlFile, "vehicle.logSplitter.splitter#cutNode"));
    spec.cutNodeRef1 = I3DUtil.indexToObject(self.components, getXMLString(self.xmlFile, "vehicle.logSplitter.splitter#cutNodeRef1"));
    spec.cutNodeRef2 = I3DUtil.indexToObject(self.components, getXMLString(self.xmlFile, "vehicle.logSplitter.splitter#cutNodeRef2"));
    
    spec.lastSplitShape = nil;
    
    spec.lastSplitShapeSplitted = nil;
    
    spec.isTurnedOn = false;
    spec.isKeyPressedState = false;
    spec.hasSplit = false;
    spec.lastTime = 0;
	
	spec.actionEvents = {};
    
	spec.isPressed = false;
	
	spec.debug = false;
	
	if self.isClient then
		spec.samples = {}
		spec.samples.work = g_soundManager:loadSampleFromXML(self.xmlFile, "vehicle.logSplitter.sounds", "work", self.baseDirectory, self.components, 0, AudioGroup.VEHICLE, self.i3dMappings, self)
		spec.isWorkSamplePlaying = false
		
		spec.samples.split1 = g_soundManager:loadSampleFromXML(self.xmlFile, "vehicle.logSplitter.sounds", "split1", self.baseDirectory, self.components, 1, AudioGroup.VEHICLE, self.i3dMappings, self)
		spec.samples.split2 = g_soundManager:loadSampleFromXML(self.xmlFile, "vehicle.logSplitter.sounds", "split2", self.baseDirectory, self.components, 1, AudioGroup.VEHICLE, self.i3dMappings, self)
		spec.samples.split3 = g_soundManager:loadSampleFromXML(self.xmlFile, "vehicle.logSplitter.sounds", "split3", self.baseDirectory, self.components, 1, AudioGroup.VEHICLE, self.i3dMappings, self)
		spec.samples.split4 = g_soundManager:loadSampleFromXML(self.xmlFile, "vehicle.logSplitter.sounds", "split4", self.baseDirectory, self.components, 1, AudioGroup.VEHICLE, self.i3dMappings, self)
		spec.samples.split5 = g_soundManager:loadSampleFromXML(self.xmlFile, "vehicle.logSplitter.sounds", "split5", self.baseDirectory, self.components, 1, AudioGroup.VEHICLE, self.i3dMappings, self)
	end	
  
end;


function logSplitter:logSplitterSplitShapesTrigger(triggerId, otherId, onEnter, onLeave, onStay)
    local spec = self.spec_logSplitter;
    if onEnter and otherId ~= 0 and g_currentMission.player ~= nil and otherId ~= g_currentMission.player.rootNode and getName(otherId) ~= "PlayerCCT" then
        local splitType = getSplitType(otherId);
        if splitType ~= nil then
            -- found split shape..
            spec.lastSplitShape = otherId;
			if spec.debug then
				print("Logsplitter Debug: found splitShape with ID: "..tostring(otherId).." and splitType: "..tostring(splitType));
			end;
    
        end;
    end;
    
end;

function logSplitter:logSplitterTrigger(triggerId, otherId, onEnter, onLeave, onStay)
    -- basic player in trigger code
	local spec = self.spec_logSplitter;
    if onEnter and g_currentMission.controlPlayer and g_currentMission.player ~= nil and otherId == g_currentMission.player.rootNode then
        spec.playerInTrigger = true;
		local _, actionEventId = self:addActionEvent(spec.actionEvents, InputAction.TOGGLE_SPLITTING, self, logSplitter.TOGGLE_SPLITTING, false, false, true, true, nil);
    elseif onLeave and g_currentMission.player ~= nil and otherId == g_currentMission.player.rootNode then
        spec.playerInTrigger = false;
		self:removeActionEvent(spec.actionEvents, InputAction.TOGGLE_SPLITTING);
    end;
    
end;
function logSplitter:logSplitterSplitShapeCallback(shape, isBelow, isAbove, minY, maxY, minZ, maxZ)

    local spec = self.spec_logSplitter;
	
	if spec.debug then	
		print("Logsplitter Debug: SplitShape Callback - SplitShape Attributes: ");
	    print("-shape: "..tostring(shape));
		print("-isBelow, isAbove: "..tostring(isBelow).." - "..tostring(isAbove));
		print("-minY, maxY: "..tostring(minY).." - "..tostring(maxY));
		print("-minZ, maxZ: "..tostring(minZ).." - "..tostring(maxZ));	
	end;
	
    spec.lastSplitShapeSplitted = shape;
    
    self:playSplitSound();
    
    spec.hasSplit = true;
end;

function logSplitter:playSplitSound(noEventSend)
	playSplitSoundEvent.sendEvent(self, noEventSend);
	local spec = self.spec_logSplitter;
	local random1 = math.random(1, 5);
	if random1 == 1 then
		g_soundManager:playSample(spec.samples.split1, 1)
	elseif random1 == 2 then
		g_soundManager:playSample(spec.samples.split2, 1)
	elseif random1 == 3 then
		g_soundManager:playSample(spec.samples.split3, 1)		
	elseif random1 == 4 then
		g_soundManager:playSample(spec.samples.split4, 1)				
	else
		g_soundManager:playSample(spec.samples.split5, 1)
	end;
end;

function logSplitter:onUpdate(dt)   

    if self.spec_turnOnVehicle.isTurnedOn then -- check if log splitter is active
		local spec = self.spec_logSplitter;
		
        if self.isServer then
            local newTime = self:getAnimationTime(spec.animationName);
            if newTime > 0.5 and newTime > spec.lastTime then -- going forward
                if spec.lastSplitShape ~= nil and entityExists(spec.lastSplitShape) and not spec.hasSplit then
                    
					if spec.debug then
						print("Logsplitter Debug: last Splitshape returned true, start splitting");
					end;
                    
                    local x, y, z = getWorldTranslation(spec.cutNode);
                    local nx,ny,nz = localDirectionToWorld(spec.cutNode, 1,0,0);
                    local yx,yy,yz = localDirectionToWorld(spec.cutNode, 0,1.3,0);                    
                    splitShape(spec.lastSplitShape, x,y,z, nx,ny,nz, yx,yy,yz, 1.5, 1.5, "logSplitterSplitShapeCallback", self);    
                    
                end;
            else
               spec.hasSplit = false;
            end;
            spec.lastTime = newTime;
        end;
		
		if self.isClient then
			if self:getIsAnimationPlaying(spec.animationName) then
				g_soundManager:playSample(spec.samples.work);
			else
				g_soundManager:stopSample(spec.samples.work);
			end;
		end;
    
        if spec.playerInTrigger then -- check if player is in the trigger
    
            if spec.animationName ~= nil then -- check if the logSplitter has its animation
            
                if spec.isPressed then
                    if not spec.currentState then
                        self:setlogSplitter(true);
                    end;
                else
                    if spec.currentState then
                        self:setlogSplitter(false);
                    end;
                end;    
                
                -- help text
                if g_currentMission.controlPlayer then
                    g_currentMission:addHelpButtonText(g_i18n:getText(spec.l10nName), InputBinding.TOGGLE_logSplitter); 
                end;    
            
            end;
        end;
        
    end;
	
	self.spec_logSplitter.isPressed = false;
end;


function logSplitter:setlogSplitter(wantedState, noEventSend)
    setlogSplitterEvent.sendEvent(self, wantedState, noEventSend);
	local spec = self.spec_logSplitter;
    if wantedState then -- if currentState is true (max) then play animation to min
        self:playAnimation(spec.animationName, spec.animationSpeed, self:getAnimationTime(spec.animationName), true);
        spec.currentState = true;
    else    
        self:playAnimation(spec.animationName, -spec.animationSpeed, self:getAnimationTime(spec.animationName), true);
        spec.currentState = false;
    end;
end;
function logSplitter:onDelete()
	local spec = self.spec_logSplitter
    if spec.animationName ~= nil then
        removeTrigger(spec.trigger);
    end;
	if spec.splitShapesTrigger ~= nil then
		removeTrigger(spec.splitShapesTrigger)
	end;
	if self.isClient then
	   g_soundManager:deleteSamples(spec.samples)
	end;
end;



playSplitSoundEvent = {};
playSplitSoundEvent_mt = Class(playSplitSoundEvent, Event);
InitEventClass(playSplitSoundEvent, "playSplitSoundEvent");

function playSplitSoundEvent:emptyNew()  
    local self = Event:new(playSplitSoundEvent_mt );
    self.className="playSplitSoundEvent";
    return self;
end;
function playSplitSoundEvent:new(vehicle, state) 
    self.vehicle = vehicle;
    return self;
end;
function playSplitSoundEvent:readStream(streamId, connection)  
    self.vehicle = NetworkUtil.readNodeObject(streamId);
    self:run(connection);  
end;
function playSplitSoundEvent:writeStream(streamId, connection)   
	NetworkUtil.writeNodeObject(streamId, self.vehicle);     
end;
function playSplitSoundEvent:run(connection) 
    self.vehicle:playSplitSound(true);
    if not connection:getIsServer() then  
        g_server:broadcastEvent(playSplitSoundEvent:new(self.vehicle), nil, connection, self.object);
    end;
end;
function playSplitSoundEvent.sendEvent(vehicle, noEventSend)  
    if noEventSend == nil or noEventSend == false then
        if g_server ~= nil then   
            g_server:broadcastEvent(playSplitSoundEvent:new(vehicle), nil, nil, vehicle);
        else 
            g_client:getServerConnection():sendEvent(playSplitSoundEvent:new(vehicle));
        end;
    end;
end;

setlogSplitterEvent = {};
setlogSplitterEvent_mt = Class(setlogSplitterEvent, Event);
InitEventClass(setlogSplitterEvent, "setlogSplitterEvent");

function setlogSplitterEvent:emptyNew()  
    local self = Event:new(setlogSplitterEvent_mt );
    self.className="setlogSplitterEvent";
    return self;
end;
function setlogSplitterEvent:new(vehicle, state) 
    self.vehicle = vehicle;
    self.state = state;
    return self;
end;
function setlogSplitterEvent:readStream(streamId, connection)  
    self.vehicle = NetworkUtil.readNodeObject(streamId); 
    self.state = streamReadBool(streamId); 
    self:run(connection);  
end;
function setlogSplitterEvent:writeStream(streamId, connection)   
	NetworkUtil.writeNodeObject(streamId, self.vehicle);   
    streamWriteBool(streamId, self.state );   
end;
function setlogSplitterEvent:run(connection) 
    self.vehicle:setlogSplitter(self.state, true);
    if not connection:getIsServer() then  
        g_server:broadcastEvent(setlogSplitterEvent:new(self.vehicle, self.state), nil, connection, self.object);
    end;
end;
function setlogSplitterEvent.sendEvent(vehicle, state, noEventSend)  
    if noEventSend == nil or noEventSend == false then
        if g_server ~= nil then   
            g_server:broadcastEvent(setlogSplitterEvent:new(vehicle, state), nil, nil, vehicle);
        else 
            g_client:getServerConnection():sendEvent(setlogSplitterEvent:new(vehicle, state));
        end;
    end;
end;


