Ranking up bots.
I’ve made some progress over the last few days at the moment one bot can gain 20 levels a day, the program is capable of running 100s of bots at a time , am looking for the community to help me out with the harder tasks, I need some help understanding the AS3 code, and how the projectile system works, and how the collision detection system works.
Below is code from the 17.2 flash client for the projectile system including collision detection, I’ve spent a few hours commenting it and working out what’s it’s doing, I could do with someone to help in this endeavour, am busy over the next few days, so can’t help much into Friday or Saturday, or Sunday please think about contributing towards the understanding of the obfuscated AS3 code.
DONE
Levelling up can be achieved by standing still and not shooting anything DONE
Auto nexus and using nexus fountains, using stat like hp, level etc in the newtick packet "hp" and update packet "level" DONE
Create class other then the wizard when dead based of class unlocked DONE
Loading the char id from account xml DONE
Loading the class unlocked DONE
Handling Reconnect packet DONE
Handling death packet DONE
Using map info packet to determine what server where in, nexus, realm etc DONE
Use ability not pointless as some class use different abilities like heal etc DONE
Disable auto nexus when a new class is unlocked, die and create the new unlocked class DONE
Current support class "Rogue” "Archer ”Wizard” “Priest" "Warrior”
Move to the top of the nexus to find the realms, select a random realm to enter DONE
STILL TODO
Auto aim and shoot at enemies TODO easy
Tracking enemies TODO easy
Tracking projectiles TODO easy
Moving enemies with the correct entity interpolation TODO Medium
Moving projectiles with the correct Behaviour TODO hard
Collision detection with enemies and projectiles sending the enemy hit packet TODO hard
Research I did earlier in the year looking at how the projectile system works you might find this thread of interest
http://www.mpgh.net/forum/654-realm-...mechanics.html
Code:
//com.company.assembleegameclient.objects.Projectile
package com.company.assembleegameclient.objects{
import flash.utils.Dictionary;
import flash.display.BitmapData;
import com.company.assembleegameclient.engine3d._-0Nr;
import flash.geom.Point;
import flash.geom.Vector3D;
import flash.display.GraphicsGradientFill;
import flash.display.GraphicsPath;
import flash.display.GradientType;
import flash.geom.Matrix;
import com.company.util._-Bq;
import com.company.util.Trig;
import com.company.assembleegameclient.parameters.Parameters;
import com.company.assembleegameclient.map.Map;
import com.company.assembleegameclient.map.Square;
import com.company.assembleegameclient.util._-0A2;
import __AS3__.vec.Vector;
import com.company.assembleegameclient.util._-1aX;
import _-RV.HitEffect;
import com.company.assembleegameclient.tutorial.doneAction;
import com.company.assembleegameclient.tutorial.Tutorial;
import com.company.assembleegameclient.util.TextureRedrawer;
import _-RV._-0jZ;
import com.company.assembleegameclient.util._-1eQ;
import flash.display.IGraphicsData;
import com.company.assembleegameclient.map._-17X;
import __AS3__.vec.*;
public class Projectile extends BasicObject {
private static var _-1J9:Dictionary = new Dictionary();
public var props_:ObjectProperties;
public var _-11O:ObjectProperties;
public var _-1So:_-0Ol; //com.company.assembleegameclient.objects._-0Ol
public var texture_:BitmapData; //bitmapdata width height rect transparent, methods get pixel etc
public var bulletId_:uint;
public var ownerId_:int;
public var containerType_:int;
public var bulletType_:uint;
public var _-1Rp:Boolean;
public var _-1JT:Boolean;
public var damage_:int;
public var _-oP:String;
public var _-017:Number; // looks to be the x and y could be starting position or current position
public var _-1fL:Number; // looks to be the x and y could be starting position or current position
public var startTime_:int;
public var angle_:Number = 0;
public var _-K1:Dictionary;
public var _-08T:_-0Nr; //unknown
private var _-bJ:Point; //this is another position variable not sure because there at least two of them
private var _-J1:Vector3D;
protected var _-Gg:GraphicsGradientFill;
protected var _-17K:GraphicsPath;
public function Projectile(){
this._-08T = new _-0Nr(100); //unknown
this._-bJ = new Point();
this._-J1 = new Vector3D();
this._-Gg = new GraphicsGradientFill(GradientType.RADIAL, [0, 0], [0.5, 0], null, new Matrix());
this._-17K = new GraphicsPath(_-Bq._-S, new Vector.<Number>());
super();
}
public static function _-A-(_arg1:int, _arg2:uint):int{
return (_-1J9[((_arg2 << 24) | _arg1)]);
}
public static function _-0Hd(_arg1:int, _arg2:uint):int{ //args owner id, bullet id
var _local3:int = _-dN();
_-1J9[((_arg2 << 24) | _arg1)] = _local3;
return (_local3);
}
public static function _-15v(_arg1:int, _arg2:uint):void{
delete _-1J9[((_arg2 << 24) | _arg1)];
}
public static function dispose():void{
_-1J9 = new Dictionary();
}
public function reset(_arg1:int, _arg2:int, _arg3:int, _arg4:int, _arg5:Number, _arg6:int):void{
var _local8:Number;
clear();
this.containerType_ = _arg1;
this.bulletType_ = _arg2;
this.ownerId_ = _arg3;
this.bulletId_ = _arg4;
this.angle_ = Trig._-0SO(_arg5);
this.startTime_ = _arg6;
objectId_ = _-0Hd(this.ownerId_, this.bulletId_);
z_ = 0.5;
this._-11O = ObjectLibrary._-0tZ[this.containerType_];
this._-1So = this._-11O._-f5[_arg2];
this.props_ = ObjectLibrary._-0be(this._-1So.objectId_);
_-0aC = (this.props_._-0a5 > 0);
var _local7:_-pf = ObjectLibrary._-0nD[this.props_.type_];
this.texture_ = _local7.getTexture(objectId_);
this._-1JT = this._-11O.isEnemy_;
this._-1Rp = !(this._-1JT);
this._-oP = this._-11O._-1GV;
this._-K1 = ((this._-1So._-0Bn) ? new Dictionary() : null);
if (this._-1So.size_ >= 0){
_local8 = this._-1So.size_;
}
else {
_local8 = ObjectLibrary._-1VM(this.containerType_);
};
this._-08T.setSize((8 * (_local8 / 100)));
this.damage_ = 0;
}
public function _-02V(_arg1:int):void{
this.damage_ = _arg1;
}
override public function addTo(_arg1:Map, _arg2:Number, _arg3:Number):Boolean{
var _local4:Player;
this._-017 = _arg2;
this._-1fL = _arg3;
if (!super.addTo(_arg1, _arg2, _arg3)){
return (false);
};
if (((!(this._-11O.flying_)) && (_-0U3.sink_))){
z_ = 0.1;
}
else {
_local4 = (_arg1.goDict_[this.ownerId_] as Player);
if (((!((_local4 == null))) && ((_local4._-Tb > 0)))){
z_ = (0.5 - (0.4 * (_local4._-Tb / Parameters._-18c)));
};
};
return (true);
}
public function moveTo(_arg1:Number, _arg2:Number):Boolean{ //_arg1 x, _arg2 y
var _local3:Square = map_.getSquare(_arg1, _arg2);
if (_local3 == null){
return (false);
};
x_ = _arg1;
y_ = _arg2;
_-0U3 = _local3;
return (true);
}
override public function removeFromMap():void{
super.removeFromMap();
_-15v(this.ownerId_, this.bulletId_);
this._-K1 = null;
_-0A2._-0U6(this);
}
private function _-Fx(_arg1:int, _arg2:Point):void{ //_arg1 is Elapsed time in milliseconds
//This function is using values from the xml data for each projectile type
//_-1So.speed
//_-1So.lifetime in milliseconds
//unknows "-1So._-7D" , "_-1So._-1nH" , "-1So._-1EK" , "-1So._-13q" , "_-1So._-0so" , "_-1So._-0uf"
//-1So._-7D "Wavy"
//_-1So._-1nH "Parametric"
//-1So._-1EK "Magnitude" default 3
//-1So._-13q "Boomerang"
//_-1So._-0so "Amplitude" default 0
//_-1So._-0uf "Frequency" default 1
var _local5:Number;
var _local6:Number;
var _local7:Number;
var _local8:Number;
var _local9:Number;
var _local10:Number;
var _local11:Number;
var _local12:Number;
var _local13:Number;
var _local14:Number;
_arg2.x = this._-017; //arg2 is overridden why pass it in, unless variable scope is outside of this function as3 code?
_arg2.y = this._-1fL; //arg2 is overridden why pass it in, unless variable scope is outside of this function as3 code?
var _local3:Number = (_arg1 * (this._-1So.speed_ / 10000)); //(Elapsed time * (speed /10000))
var _local4:Number = ((((this.bulletId_ % 2))==0) ? 0 : Math.PI); //am guessing this choose 0 or pi, is_odd(bulletId) function ?
if (this._-1So._-7D){ //"Wavy"
_local5 = (6 * Math.PI); //constant 18.84955592
_local6 = (Math.PI / 64); //constant 0.04908738521
_local7 = (this.angle_ + (_local6 * Math.sin((_local4 + ((_local5 * _arg1) / 1000)))));
//converted above code
//_local7 = (this.angle_ + (0.04908738521 * Math.sin((_local4 + ((18.84955592 * Elapsed time) / 1000)))));
_arg2.x = (_arg2.x + (_local3 * Math.cos(_local7))); // moving incrementing x
_arg2.y = (_arg2.y + (_local3 * Math.sin(_local7))); // moving incrementing y
}
else {
if (this._-1So._-1nH){ //"Parametric"
_local8 = (((_arg1 / this._-1So.lifetime_) * 2) * Math.PI);
_local9 = (Math.sin(_local8) * (((this.bulletId_ % 2)) ? 1 : -1)); //am guessing this choose 1 or -1, is_odd(bulletId) function ?
_local10 = (Math.sin((2 * _local8)) * ((((this.bulletId_ % 4))<2) ? 1 : -1)); //am guessing this choose 1 or -1
_local11 = Math.sin(this.angle_);
_local12 = Math.cos(this.angle_);
_arg2.x = (_arg2.x + (((_local9 * _local12) - (_local10 * _local11)) * this._-1So._-1EK));
_arg2.y = (_arg2.y + (((_local9 * _local11) + (_local10 * _local12)) * this._-1So._-1EK));
}
else {
if (this._-1So._-13q){ // "Boomerang"
_local13 = ((this._-1So.lifetime_ * (this._-1So.speed_ / 10000)) / 2);
if (_local3 > _local13){
_local3 = (_local13 - (_local3 - _local13));
};
};
_arg2.x = (_arg2.x + (_local3 * Math.cos(this.angle_))); //moving incrementing x
_arg2.y = (_arg2.y + (_local3 * Math.sin(this.angle_))); //moving incrementing y
if (this._-1So._-0so != 0){ //"Amplitude"
_local14 = (this._-1So._-0so * Math.sin((_local4 + ((((_arg1 / this._-1So.lifetime_) * this._-1So._-0uf) * 2) * Math.PI))));
_arg2.x = (_arg2.x + (_local14 * Math.cos((this.angle_ + (Math.PI / 2)))));
_arg2.y = (_arg2.y + (_local14 * Math.sin((this.angle_ + (Math.PI / 2)))));
};
};
};
}
override public function update(_arg1:int, _arg2:int):Boolean{ //(_arg1 must be current system time) ,_arg2 not used
//Projectile behaviour sin cos wave generator
//Using a time stamp to position relative to the start position in the direction of the angle
var _local5:Vector.<uint>;
var _local7:Player;
var _local8:Boolean;
var _local9:Boolean;
var _local10:Boolean;
var _local11:int;
var _local12:Boolean;
var _local3:int = (_arg1 - this.startTime_); // current_time-startTime_ this might be wrong need to find out what value is passed in _arg1
if (_local3 > this._-1So.lifetime_){
return (false); //its returning maybe delete the projectile after it's lifetime as ran out.
};
var _local4:Point = this._-bJ;
this._-Fx(_local3, _local4); //interesting _local3 current Elapsed time, _local4 2d point x,y current position maybe or start position
if (((!(this.moveTo(_local4.x, _local4.y))) || ((_-0U3.tileType_ == 0xFF)))){
if (this._-1JT){
map_.gs_.gsc_.squareHit(_arg1, this.bulletId_, this.ownerId_);
}
else {
if (_-0U3.obj_ != null){
_local5 = _-1aX._-dG(this.texture_);
map_.addObj(new HitEffect(_local5, 100, 3, this.angle_, this._-1So.speed_), _local4.x, _local4.y);
};
};
return (false);
};
if (((((!((_-0U3.obj_ == null))) && (((!(_-0U3.obj_.props_.isEnemy_)) || (!(this._-1Rp)))))) && (((_-0U3.obj_.props_.enemyOccupySquare_) || (((!(this._-1So._-dm)) && (_-0U3.obj_.props_.occupySquare_))))))){
if (this._-1JT){
map_.gs_.gsc_.otherHit(_arg1, this.bulletId_, this.ownerId_, _-0U3.obj_.objectId_);
}
else {
_local5 = _-1aX._-dG(this.texture_);
map_.addObj(new HitEffect(_local5, 100, 3, this.angle_, this._-1So.speed_), _local4.x, _local4.y);
};
return (false);
};
var _local6:GameObject = this._-0rF(_local4.x, _local4.y); //this block of code is also to do with the collision detection function
if (_local6 != null){
_local7 = map_.player_;
_local8 = !((_local7 == null));
_local9 = _local6.props_.isEnemy_;
//check to see if is (client player), or paused, etc
_local10 = ((((_local8) && (!(_local7.isPaused())))) && (((this._-1JT) || (((_local9) && ((this.ownerId_ == _local7.objectId_)))))));
if (_local10){
_local11 = GameObject._-0tU(this.damage_, _local6._-0C1, this._-1So._-1H2, _local6.condition_);
_local12 = false;
if (_local6._-0Hr <= _local11){
_local12 = true;
if (_local6.props_.isEnemy_){
doneAction(map_.gs_, Tutorial._-dK);
};
};
if (_local6 == _local7){
map_.gs_.gsc_.playerHit(this.bulletId_, this.ownerId_);
_local6.damage(this.containerType_, _local11, this._-1So.effects_, false, this);
}
else {
if (_local6.props_.isEnemy_){
map_.gs_.gsc_.enemyHit(_arg1, this.bulletId_, _local6.objectId_, _local12);
_local6.damage(this.containerType_, _local11, this._-1So.effects_, _local12, this);
}
else {
if (!this._-1So._-0Bn){
map_.gs_.gsc_.otherHit(_arg1, this.bulletId_, this.ownerId_, _local6.objectId_);
};
};
};
};
if (this._-1So._-0Bn){
this._-K1[_local6] = true;
}
else {
return (false);
};
};
return (true);
}
public function _-0rF(_arg1:Number, _arg2:Number):GameObject{ //i am guessing this is the collision detection function
// arg1 projectile x
// arg2 projectile y
var _local5:GameObject;
var _local6:Number;
var _local7:Number;
var _local8:Number;
var _local9:Number;
var _local3:Number = Number.MAX_VALUE;
var _local4:GameObject;
//This function is using values from the xml data for each projectile type
//_-1So._-0Bn MultiHit
for each (_local5 in map_.goDict_) { //iteration over each object enemy, player etc.
if (_local5._-01c()){
}
else {
if (_local5._-Vt()){
}
else {
if (((((this._-1Rp) && (_local5.props_.isEnemy_))) || (((this._-1JT) && (_local5.props_._-1bR))))){
if (!((_local5._-07) || (_local5.isPaused()))){
_local6 = (((_local5.x_ > _arg1)) ? (_local5.x_ - _arg1) : (_arg1 - _local5.x_));
_local7 = (((_local5.y_ > _arg2)) ? (_local5.y_ - _arg2) : (_arg2 - _local5.y_));
if (!(((_local6 > _local5.radius_)) || ((_local7 > _local5.radius_)))){
if (((this._-1So._-0Bn) && (!((this._-K1[_local5] == null))))){
}
else {
if (_local5 == map_.player_){
return (_local5);
};
_local8 = Math.sqrt(((_local6 * _local6) + (_local7 * _local7))); //distance calculations
_local9 = ((_local6 * _local6) + (_local7 * _local7)); //distance square calculation
if (_local9 < _local3){
_local3 = _local9;
_local4 = _local5;
};
};
};
};
};
};
};
};
return (_local4);
}
//drawing function are not need
override public function draw(_arg1:Vector.<IGraphicsData>, _arg2:_-17X, _arg3:int):void{ //drawing function are not need
var _local6:uint;
var _local7:uint;
if (!Parameters._-Cq){
return;
};
var _local4:BitmapData = this.texture_;
if (Parameters._-0x0 != 0){
switch (Parameters._-0x0){
case 1:
_local6 = 16777100;
_local7 = 0xFFFFFF;
break;
case 2:
_local6 = 16777100;
_local7 = 16777100;
break;
case 3:
_local6 = 0xFF0000;
_local7 = 0xFF0000;
break;
case 4:
_local6 = 0xFF;
_local7 = 0xFF;
break;
case 5:
_local6 = 0xFFFFFF;
_local7 = 0xFFFFFF;
break;
case 6:
_local6 = 0;
_local7 = 0;
break;
};
_local4 = TextureRedrawer.redraw(_local4, 120, true, _local7);
};
var _local5:Number = (((this.props_****tation_ == 0)) ? 0 : (_arg3 / this.props_****tation_));
this._-J1.x = x_;
this._-J1.y = y_;
this._-J1.z = z_;
this._-08T.draw(_arg1, this._-J1, (((this.angle_ - _arg2.angleRad_) + this.props_._-0pw) + _local5), _arg2.wToS_, _arg2, _local4);
if (this._-1So._-1a3){
map_.addObj(new _-0jZ(100, 0xFF00FF, 600, 0.5, _-1eQ._-0f0(3), _-1eQ._-0f0(3)), x_, y_);
map_.addObj(new _-0jZ(100, 0xFF00FF, 600, 0.5, _-1eQ._-0f0(3), _-1eQ._-0f0(3)), x_, y_);
map_.addObj(new _-0jZ(100, 0xFF00FF, 600, 0.5, _-1eQ._-0f0(3), _-1eQ._-0f0(3)), x_, y_);
};
}
//drawing function are not need
override public function drawShadow(_arg1:Vector.<IGraphicsData>, _arg2:_-17X, _arg3:int):void{ //drawing function are not need
if (!Parameters._-Cq){
return;
};
var _local4:Number = (this.props_._-0a5 / 400);
var _local5:Number = (30 * _local4);
var _local6:Number = (15 * _local4);
this._-Gg.matrix.createGradientBox((_local5 * 2), (_local6 * 2), 0, (_-0tw[0] - _local5), (_-0tw[1] - _local6));
_arg1.push(this._-Gg);
this._-17K.data.length = 0;
Vector.<Number>(this._-17K.data).push((_-0tw[0] - _local5), (_-0tw[1] - _local6), (_-0tw[0] + _local5), (_-0tw[1] - _local6), (_-0tw[0] + _local5), (_-0tw[1] + _local6), (_-0tw[0] - _local5), (_-0tw[1] + _local6));
_arg1.push(this._-17K);
_arg1.push(_-Bq.END_FILL);
}
}
}//package com.company.assembleegameclient.objects
Java jOryx - A Realm of the Mad God client, ProjectileControl, code
Code:
/* jOryx - A Realm of the Mad God client.
public class ProjectileControl extends AbstractControl {
private ProjectileDefinition projectile;
private ObjectType containerType;
private Spatial owner;
private boolean ally;
private Vector3f incrementVector;
private Vector3f directionVector;
private float lifeTime;
private float life;
private float angle;
private int bulletId;
private boolean initialized;
private static boolean reverseOscillation;
private float phase;
private float frequency;
private float amplitude;
private Vector3f location;
private boolean player;
private Vector3f amplitudeVector;
public ProjectileControl(ProjectileDefinition projectile, Spatial owner, ObjectType containerType, boolean ally, int bulletId, float angle, boolean player) {
this.projectile = projectile;
this.containerType = containerType;
this.ally = ally;
this.bulletId = bulletId;
this.angle = angle;
this.player = player;
this.owner = owner;
}
@override
public Control cloneForSpatial(Spatial spatial) {
// TODO Auto-generated method stub
return null;
}
@override
protected void controlUpdate(float tpf) {
if (!initialized) {
incrementVector = new Vector3f(((float)projectile.speed / 10f), 0, 0);
Quaternion rot = new Quaternion();
rot.fromAngleNormalAxis(-angle, Vector3f.UNIT_Z);
incrementVector = rot.multLocal(incrementVector);
lifeTime = projectile.lifetimeSeconds;
directionVector = incrementVector.normalize();
location = spatial.getLocalTranslation().clone();
if (projectile.amplitude != 0) {
if (!reverseOscillation) {
amplitudeVector = new Vector3f(0, projectile.amplitude, 0);
amplitudeVector = rot.multLocal(amplitudeVector);
reverseOscillation = true;
} else {
amplitudeVector = new Vector3f(0, -projectile.amplitude, 0);
amplitudeVector = rot.multLocal(amplitudeVector);
reverseOscillation = false;
}
} else {
amplitudeVector = new Vector3f(0, 0, 0);
}
if (projectile.frequency != 0) {
frequency = projectile.frequency;
} else {
frequency = 1;
}
initialized = true;
}
life += tpf;
Vector3f inc = incrementVector.mult(tpf);
location.addLocal(inc);
location.subtractLocal(amplitudeVector.mult(FastMath.sin(phase)));
phase += tpf * frequency * 10;
location.addLocal(amplitudeVector.mult(FastMath.sin(phase)));
spatial.setLocalTranslation(location);
// collisions
Ray ray = new Ray(spatial.getWorldTranslation(), directionVector);
CollisionResults cr = new CollisionResults();
List<Spatial> children = spatial.getParent().getChildren();
for (Spatial s : children) {
if (s == spatial) {
continue;
}
if (s == null) {
continue;
}
if (s == owner) {
continue;
}
if (s.getControl(NoMoveControl.class) == null && s.getControl(PlayerControl.class) == null && s.getControl(CharacterControl.class) == null) {
continue;
}
float distance = s.getLocalTranslation().distance(spatial.getLocalTranslation());
if (distance < 0.5f) {
// collided!
CharacterControl cc = s.getControl(CharacterControl.class);
PlayerControl pc = s.getControl(PlayerControl.class);
NoMoveControl nmc = s.getControl(NoMoveControl.class);
WorldState ws = JOryx.getSingleton().getStateManager().getState(WorldState.class);
// ignore if it's an ally bullet hitting a player
if (ally && pc != null) {
continue;
}
// ignore if it's an enemy bullet hitting a character
if (!ally && cc != null) {
continue;
}
// hit if player and hit is CC
if (player && cc != null && cc.isEnemy()) {
int damage = calculateDamage();
EnemyHitPacket php = new EnemyHitPacket();
php.bulletId = bulletId;
php.objectId = cc.getStatus().data.objectId;
php.time = ws.getClient().getTime();
ObjectType type = DatabaseState.getSingleton().getObjectType(cc.getStatus().objectType);
int hp = cc.getStatus().data.getStat(StatData.HP).value;
if (hp - damage <= 0) {
if (type.deathSound != null) {
AudioNode an = new AudioNode(JOryx.getSingleton().getAssetManager(), "Sounds/" + type.deathSound + ".wav");
an.play();
}
php.kill = true;
} else {
if (type.hitSound != null) {
AudioNode an = new AudioNode(JOryx.getSingleton().getAssetManager(), "Sounds/" + type.hitSound + ".wav");
an.play();
}
php.kill = false;
}
ws.makeNotification(cc.getStatus().data.objectId, "-" + damage, ColorRGBA.Red.asIntABGR());
try {
ws.getClient().sendSyncPacket(php);
} catch (IOException e) {
e.printStackTrace();
}
} else if (pc != null && pc.isPlayer()) {
// hit if unfriendly and hit local player
PlayerHitPacket ehp = new PlayerHitPacket();
ehp.bulletId = bulletId;
ehp.objectId = owner.getControl(ObjectControl.class).getStatus().data.objectId;
ObjectType type = DatabaseState.getSingleton().getObjectType(pc.getStatus().objectType);
AudioNode an = new AudioNode(JOryx.getSingleton().getAssetManager(), "Sounds/" + type.hitSound + ".wav");
an.play();
try {
ws.getClient().sendSyncPacket(ehp);
} catch (IOException e) {
e.printStackTrace();
}
} else if (nmc != null && player) {
// hit if square
SquareHitPacket shp = new SquareHitPacket();
shp.bulletId = bulletId;
shp.objectId = owner.getControl(ObjectControl.class).getStatus().data.objectId;
try {
ws.getClient().sendSyncPacket(shp);
} catch (IOException e) {
e.printStackTrace();
}
}
spatial.removeFromParent();
return;
}
}
if (life > lifeTime) {
spatial.removeFromParent();
}
}
@override
protected void controlRender(RenderManager rm, ViewPort vp) {
// TODO Auto-generated method stub
}
public int getBulletId() {
return bulletId;
}
private int calculateDamage() {
float ret = 0;
if (projectile.damage != 0) {
return projectile.damage;
}
ret = FastMath.rand.nextFloat() * (projectile.maxDamage - projectile.minDamage);
ret += projectile.minDamage;
if (player) {
ObjectControl oc = owner.getControl(ObjectControl.class);
int att = oc.getStatus().data.getStat(StatData.ATT).value + oc.getStatus().data.getStat(StatData.ATTBONUS).value;
float mult = 0.5f + ((float)att / 50f);
ret *= mult;
}
return Math****und(ret);
}
}
on a side note...
A modified version of this program was used to test a god mode method, basically there is 40 level 1 priest, they follow the targeted player around in the realm(only), teleport, heal, (exit the game, delete char and create a new priest), enter the nexus, enter the realm, teleport, heal, die, repeat, at anyone time there’s 4 priest healing giving a total of 400 hp a second. I may use this in the future to level the bots up quickly in the god lands.
I’ve updated the spam bots, trading bots, auto loot bots, am not releasing them to the public so please don’t ask me to release them in this thread. I’m not releasing publicly or privately so do me a favour and don't ask me