/*
Copyright 2012 Jan Ove Saltvedt
This file is part of KBot.
KBot 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 3 of the License, or
(at your option) any later version.
KBot 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 KBot. If not, see <http://www.gnu.org/licenses/>.
*/
package com.kbotpro.scriptsystem.input.jobs;
import com.kbotpro.scriptsystem.input.internal.mouse.EventFactory;
import com.kbotpro.scriptsystem.input.internal.mouse.Vector2D;
import com.kbotpro.scriptsystem.input.internal.mouse.MouseForceModifier;
import com.kbotpro.scriptsystem.input.callbacks.MouseMoveListener;
import com.kbotpro.scriptsystem.interfaces.MouseTarget;
import com.kbotpro.scriptsystem.Calculations;
import com.kbotpro.bot.BotEnvironment;
import com.kbotpro.hooks.Mouse;
import com.kbotpro.scriptsystem.various.KTimer;
import java.util.List;
import java.util.ArrayList;
import java.awt.event.MouseEvent;
import java.awt.*;
/**
* This mouse job moves the mouse to target and starts hovering.
*/
public class MouseHoverJob extends MouseJob {
protected Vector2D velocity = new Vector2D();
protected Vector2D lastAcceleration = new Vector2D();
protected MouseMoveListener callback;
protected MouseTarget target;
protected boolean finished = false;
protected boolean paused = false;
protected boolean drag = false;
protected List<MouseForceModifier> forceModifiers = new ArrayList<MouseForceModifier>();
private double speedMultiplier = 1.0D;
private KTimer timeLimit = null;
public MouseHoverJob(EventFactory eventFactory, BotEnvironment botEnvironment, final MouseMoveListener callback, final MouseTarget target) {
super(eventFactory, botEnvironment);
runnable = new Runnable() {
public void run() {
while(!finished){
if (timeLimit != null && timeLimit.isDone()) {
break;
}
if(paused){
sleep(8, 10);
continue;
}
Mouse mouse = getMouse();
Point point = target.get();
if(point.x < 0 || point.y < 0){
finished = true;
break;
}
if(target.isOver(mouse.getMouseX(), mouse.getMouseY())){
callback.onMouseOverTarget(MouseHoverJob.this);
}
if(finished){
break;
}
double deltaTime = Calculations.random(8D, 10D)/1000D;
applyForces(deltaTime);
moveMouse(deltaTime);
int millis = (int) (deltaTime * 1000);
sleep(millis);
}
callback.onFinished(MouseHoverJob.this);
botEnv.mouse.removeMouseJobInternally(MouseHoverJob.this);
}
};
this.callback = callback;
this.target = target;
forceModifiers.add(new MouseForceModifier() {
// TARGET GRAVITY
public Vector2D applyForce(double deltaTime, MouseJob mouseJob) {
Vector2D force = new Vector2D();
Vector2D toTarget = new Vector2D();
Point pTarget = MouseHoverJob.this.target.get();
Mouse mouse = virtualMouse;
toTarget.xUnits = pTarget.x-mouse.getMouseX();
toTarget.yUnits = pTarget.y-mouse.getMouseY();
if(toTarget.xUnits == 0 && toTarget.yUnits == 0){
return null;
}
double alpha = toTarget.getAngle();
double acc = Calculations.random(1500, 2000)*speedMultiplier;
force.xUnits = Math.cos(alpha)*acc;
force.yUnits = Math.sin(alpha)*acc;
return force;
}
});
forceModifiers.add(new MouseForceModifier() {
// "friction"
public Vector2D applyForce(double deltaTime, MouseJob mouseJob) {
return velocity.multiply(-1);
}
});
forceModifiers.add(new MouseForceModifier() {
private int offset = Calculations.random(300, 500);
private double offsetAngle = -1;
// Offset
public Vector2D applyForce(double deltaTime, MouseJob mouseJob) {
if(offsetAngle == -1){
offsetAngle = Calculations.random(-Math.PI, Math.PI);
}
Vector2D toTarget = new Vector2D();
Point pTarget = MouseHoverJob.this.target.get();
Mouse mouse = virtualMouse;
toTarget.xUnits = pTarget.x-mouse.getMouseX();
toTarget.yUnits = pTarget.y-mouse.getMouseY();
if(offset > 0 && toTarget.getLength() > Calculations.random(25, 55)){
Vector2D force = new Vector2D();
force.xUnits = Math.cos(offsetAngle)*offset;
force.yUnits = Math.sin(offsetAngle)*offset;
offset -= Calculations.random(0, 6);
return force;
}
return null;
}
});
forceModifiers.add(new MouseForceModifier() {
// correction when close
public Vector2D applyForce(double deltaTime, MouseJob mouseJob) {
Vector2D toTarget = new Vector2D();
Point pTarget = MouseHoverJob.this.target.get();
Mouse mouse = virtualMouse;
toTarget.xUnits = pTarget.x-mouse.getMouseX();
toTarget.yUnits = pTarget.y-mouse.getMouseY();
double length = toTarget.getLength();
if(length < Calculations.random(75, 125)){
Vector2D force = new Vector2D();
double speed = velocity.getLength();
double rh = speed*speed;
double s = toTarget.xUnits * toTarget.xUnits + toTarget.yUnits * toTarget.yUnits;
if(s == 0){
return null;
}
double f = rh/ s;
f = Math.sqrt(f);
Vector2D adjustedToTarget = toTarget.multiply(f);
force.xUnits = (adjustedToTarget.xUnits-velocity.xUnits)/(deltaTime);
force.yUnits = (adjustedToTarget.yUnits-velocity.yUnits)/(deltaTime);
double v = 4D / length;
if(v < 1D){
force = force.multiply(v);
}
if(length < 10){
force = force.multiply(0.5D);
}
return force;
}
return null;
}
});
forceModifiers.add(new MouseForceModifier() {
// correction when close
public Vector2D applyForce(double deltaTime, MouseJob mouseJob) {
Point pTarget = MouseHoverJob.this.target.get();
Mouse mouse = virtualMouse;
int mouseX = mouse.getMouseX();
int mouseY = mouse.getMouseY();
//if(mouseX > pTarget.x-2 && mouseX < pTarget.x+2 && mouseY > pTarget.y-2 && mouseY < pTarget.y+2){
if(mouseX == pTarget.x && mouseY == pTarget.y){
velocity.xUnits = 0;
velocity.yUnits = 0;
}
return null;
}
});
}
protected void applyForces(double deltaTime){
Vector2D force = new Vector2D();
for(MouseForceModifier modifier: forceModifiers){
Vector2D f = modifier.applyForce(deltaTime, this);
if(f == null){
continue;
}
force.add(f);
}
if(Double.isNaN(force.xUnits) || Double.isNaN(force.yUnits)){
return;
}
lastAcceleration = force;
velocity.add(force.multiply(deltaTime));
}
protected void moveMouse(double deltaTime){
Mouse mouse = getMouse();
int mouseX = mouse.getMouseX();
int mouseY = mouse.getMouseY();
Vector2D deltaPosition = velocity.multiply(deltaTime);
int newX = mouseX + (int) deltaPosition.xUnits;
int newY = mouseY + (int) deltaPosition.yUnits;
if(newX == virtualMouse.getMouseX() && newY == virtualMouse.getMouseY()){
return;
}
setVirtualMousePos(newX, newY);
if(!paused && !finished){
MouseEvent mouseEvent;
if (drag) {
mouseEvent = eventFactory.createMouseDragged(newX, newY, true);
} else {
mouseEvent = eventFactory.createMoveMouse(newX, newY);
}
dispatchEvent(mouseEvent);
}
}
/**
* Makes the bot click at the current mouse position
* @param button
*/
public void doMouseClick(boolean button){
boolean wasPaused = paused;
if(wasPaused){
paused = true;
}
int mouseX = virtualMouse.getMouseX();
int mouseY = virtualMouse.getMouseY();
MouseEvent mouseEvent = eventFactory.createMousePress(mouseX, mouseY, button);
dispatchEvent(mouseEvent);
sleep(50, 100);
mouseEvent = eventFactory.createMouseRelease(virtualMouse.getMouseX(), mouseY, button);
dispatchEvent(mouseEvent);
mouseEvent = eventFactory.createMouseClicked(virtualMouse.getMouseX(), mouseY, button);
dispatchEvent(mouseEvent);
if(wasPaused){
paused = false;
}
}
protected void onCancelled() {
finished = true;
callback.onFinished(this);
super.botEnv.mouse.resumeAllJobs();
}
protected void onStart() {
super.botEnv.mouse.pauseAllJobs();
finished = false;
paused = false;
}
public synchronized void pause(){
paused = true;
}
public synchronized void resume(){
paused = false;
}
public void stop() {
finished = true;
botEnv.mouse.removeMouseJobInternally(this);
}
public synchronized MouseTarget getTarget() {
return target;
}
public synchronized boolean isPaused(){
return paused;
}
public synchronized void setDrag(boolean drag) {
this.drag = drag;
}
public synchronized void setTimeLimit(KTimer timeLimit) {
this.timeLimit = timeLimit;
}
/**
* 1.0 is normal speed
* @return
*/
public synchronized double getSpeedMultiplier() {
return speedMultiplier;
}
/**
* 1.0 is normal speed
* @param speedMultiplier
*/
public synchronized void setSpeedMultiplier(double speedMultiplier) {
this.speedMultiplier = speedMultiplier;
}
}