Skip to content

Commit 32b0de6

Browse files
committed
Huge and cute wolf AI improvements
Wolf can now look at other entities (and sometimes with heart particle if entity is baby mob) Wolf can now breed like in Vanilla. Baby wolves will now follow adult wolves. Other improvements.
1 parent 0d12358 commit 32b0de6

File tree

11 files changed

+565
-44
lines changed

11 files changed

+565
-44
lines changed
Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
#region LICENSE
2+
3+
// The contents of this file are subject to the Common Public Attribution
4+
// License Version 1.0. (the "License"); you may not use this file except in
5+
// compliance with the License. You may obtain a copy of the License at
6+
// https://github.com/NiclasOlofsson/MiNET/blob/master/LICENSE.
7+
// The License is based on the Mozilla Public License Version 1.1, but Sections 14
8+
// and 15 have been added to cover use of software over a computer network and
9+
// provide for limited attribution for the Original Developer. In addition, Exhibit A has
10+
// been modified to be consistent with Exhibit B.
11+
//
12+
// Software distributed under the License is distributed on an "AS IS" basis,
13+
// WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
14+
// the specific language governing rights and limitations under the License.
15+
//
16+
// The Original Code is MiNET.
17+
//
18+
// The Original Developer is the Initial Developer. The Initial Developer of
19+
// the Original Code is Niclas Olofsson.
20+
//
21+
// All portions of the code written by Niclas Olofsson are Copyright (c) 2014-2018 Niclas Olofsson.
22+
// All Rights Reserved.
23+
24+
#endregion
25+
26+
using System.Linq;
27+
using System.Numerics;
28+
using AStarNavigator;
29+
using MiNET.Entities.Passive;
30+
using MiNET.Utils.Vectors;
31+
32+
namespace MiNET.Entities.Behaviors
33+
{
34+
public class BreedingBehavior : BehaviorBase
35+
{
36+
private readonly Mob _entity;
37+
private double _lookDistance;
38+
private int _duration;
39+
40+
public BreedingBehavior(Mob entity, double lookDistance = 5.0)
41+
{
42+
_entity = entity;
43+
_lookDistance = lookDistance;
44+
}
45+
46+
public override bool ShouldStart()
47+
{
48+
if (_entity.IsBaby || !_entity.IsInLove) return false;
49+
50+
return true;
51+
}
52+
53+
private Path _currentPath;
54+
55+
public override void OnTick(Entity[] entities)
56+
{
57+
var target = _entity.Level.Entities
58+
.OrderBy(p => Vector3.Distance(_entity.KnownPosition, p.Value.KnownPosition))
59+
.FirstOrDefault(p =>
60+
p.Value != _entity
61+
&& p.Value.IsInLove
62+
&& !p.Value.IsBaby
63+
&& _entity.DistanceTo(p.Value) < _lookDistance).Value;
64+
65+
if (target == null)
66+
return;
67+
68+
_duration = 1000;
69+
70+
var distanceToEntity = _entity.DistanceTo(target);
71+
72+
if (distanceToEntity < 1)
73+
{
74+
_entity.Velocity = Vector3.Zero;
75+
_entity.Controller.LookAt(target);
76+
77+
//if (_entity.Level.Random.Next(15) == 0)
78+
if (_entity.IsInLove)
79+
{
80+
var newPos = _entity.KnownPosition.Clone() as PlayerLocation;
81+
var mob = new Wolf(_entity.Level) { IsBaby = true };
82+
mob.KnownPosition = newPos + new Vector3(0, 0.5f, 0);
83+
mob.NoAi = true;
84+
mob.SpawnEntity();
85+
86+
_entity.IsInLove = false;
87+
_entity.BroadcastSetEntityData();
88+
89+
target.IsInLove = false;
90+
target.BroadcastSetEntityData();
91+
}
92+
return;
93+
}
94+
95+
if (_currentPath == null || _currentPath.NoPath())
96+
{
97+
var pathFinder = new Pathfinder();
98+
_currentPath = pathFinder.FindPath(_entity, target, _lookDistance);
99+
}
100+
101+
if (_currentPath.HavePath())
102+
{
103+
if (!_currentPath.GetNextTile(_entity, out Tile next))
104+
return;
105+
106+
_entity.Controller.RotateTowards(new Vector3((float) next.X + 0.5f, _entity.KnownPosition.Y, (float) next.Y + 0.5f));
107+
108+
if (distanceToEntity < 0.5f)
109+
{
110+
_entity.Velocity = Vector3.Zero;
111+
_currentPath = null;
112+
}
113+
else
114+
{
115+
var m = 2 - distanceToEntity;
116+
if (m <= 0)
117+
{
118+
m = 1;
119+
}
120+
else
121+
{
122+
m = m / 2.0;
123+
}
124+
_entity.Controller.MoveForward(1 * m, entities);
125+
}
126+
}
127+
else
128+
{
129+
_entity.Velocity = Vector3.Zero;
130+
_currentPath = null;
131+
}
132+
133+
_entity.Controller.LookAt(target);
134+
}
135+
136+
public override void OnEnd()
137+
{
138+
_entity.Velocity = Vector3.Zero;
139+
_entity.KnownPosition.Pitch = 0;
140+
_currentPath = null;
141+
}
142+
143+
144+
public override bool CanContinue()
145+
{
146+
return _duration-- > 0;
147+
}
148+
}
149+
}

src/MiNET/MiNET/Entities/Behaviors/FindAttackableTargetBehavior.cs

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,9 @@
2323

2424
#endregion
2525

26-
using System;
2726
using System.Linq;
2827
using System.Numerics;
28+
using MiNET.Entities.Passive;
2929
using MiNET.Worlds;
3030

3131
namespace MiNET.Entities.Behaviors
@@ -140,6 +140,7 @@ public class FindAttackableEntityTargetBehavior<TEntity> : BehaviorBase, ITarget
140140
private readonly double _targetDistance;
141141
private readonly int _attackChance;
142142
private int _targetUnseenTicks = 0;
143+
private Entity _misssedEntity;
143144

144145
public FindAttackableEntityTargetBehavior(Mob entity, double targetDistance = 16, int attackChance = 10)
145146
{
@@ -150,7 +151,7 @@ public FindAttackableEntityTargetBehavior(Mob entity, double targetDistance = 16
150151

151152
public override bool ShouldStart()
152153
{
153-
if (_entity.Level.Random.Next(_attackChance) != 0)
154+
if (_entity.Level.Random.Next(150) != 0)
154155
{
155156
return false;
156157
}
@@ -163,6 +164,11 @@ public override bool ShouldStart()
163164
&& !p.Value.HealthManager.IsDead
164165
&& _entity.DistanceTo(p.Value) < _targetDistance).Value as TEntity;
165166

167+
if (target == _misssedEntity)
168+
{
169+
return false;
170+
}
171+
166172
if (target == null)
167173
{
168174
_entity.SetTarget(null);
@@ -183,13 +189,14 @@ public override bool CanContinue()
183189
{
184190
// Give the poor entity a chance to survive
185191
// Also makes it let go of unreachable targets
186-
if (_entity.Level.Random.Next(_attackChance) == 0)
192+
var target = _entity.Target;
193+
194+
if (_entity.Level.Random.Next(_attackChance * 10) == 0 && _entity.DistanceTo(target) > 4)
187195
{
196+
_misssedEntity = _entity.Target;
188197
return false;
189198
}
190199

191-
var target = _entity.Target;
192-
193200
if (target == null)
194201
return false;
195202

@@ -211,6 +218,15 @@ public override bool CanContinue()
211218
return false;
212219
}
213220

221+
if (_entity is Wolf )
222+
{
223+
Wolf wolf = _entity as Wolf;
224+
if (wolf.DistanceTo(wolf.Owner) > 10)
225+
{
226+
return false;
227+
}
228+
}
229+
214230
_entity.SetTarget(target); // This makes sense when we to attacked by targeting
215231

216232
return true;
Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
#region LICENSE
2+
3+
// The contents of this file are subject to the Common Public Attribution
4+
// License Version 1.0. (the "License"); you may not use this file except in
5+
// compliance with the License. You may obtain a copy of the License at
6+
// https://github.com/NiclasOlofsson/MiNET/blob/master/LICENSE.
7+
// The License is based on the Mozilla Public License Version 1.1, but Sections 14
8+
// and 15 have been added to cover use of software over a computer network and
9+
// provide for limited attribution for the Original Developer. In addition, Exhibit A has
10+
// been modified to be consistent with Exhibit B.
11+
//
12+
// Software distributed under the License is distributed on an "AS IS" basis,
13+
// WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for
14+
// the specific language governing rights and limitations under the License.
15+
//
16+
// The Original Code is MiNET.
17+
//
18+
// The Original Developer is the Initial Developer. The Initial Developer of
19+
// the Original Code is Niclas Olofsson.
20+
//
21+
// All portions of the code written by Niclas Olofsson are Copyright (c) 2014-2018 Niclas Olofsson.
22+
// All Rights Reserved.
23+
24+
#endregion
25+
26+
using System.Linq;
27+
using System.Numerics;
28+
using AStarNavigator;
29+
using MiNET.Entities.Passive;
30+
using MiNET.Utils.Vectors;
31+
32+
namespace MiNET.Entities.Behaviors
33+
{
34+
public class FollowAdultBehavior : BehaviorBase
35+
{
36+
private readonly Wolf _entity;
37+
38+
public FollowAdultBehavior(Wolf entity)
39+
{
40+
_entity = entity;
41+
}
42+
43+
public override bool ShouldStart()
44+
{
45+
if (!_entity.IsBaby) return false;
46+
47+
var target = _entity.Level.Entities
48+
.OrderBy(p => Vector3.Distance(_entity.KnownPosition, p.Value.KnownPosition))
49+
.FirstOrDefault(p =>
50+
p.Value != _entity
51+
&& p.Value is Wolf
52+
&& !p.Value.IsBaby
53+
&& _entity.DistanceTo(p.Value) < 20).Value;
54+
55+
if (target == null) return false;
56+
57+
return true;
58+
}
59+
60+
public override bool CanContinue()
61+
{
62+
return ShouldStart();
63+
}
64+
65+
private Path _currentPath;
66+
67+
public override void OnTick(Entity[] entities)
68+
{
69+
var target = _entity.Level.Entities
70+
.OrderBy(p => Vector3.Distance(_entity.KnownPosition, p.Value.KnownPosition))
71+
.FirstOrDefault(p =>
72+
p.Value != _entity
73+
&& p.Value is Wolf
74+
&& !p.Value.IsBaby
75+
&& _entity.DistanceTo(p.Value) < 20).Value;
76+
77+
if (target == null) return;
78+
79+
if (_entity.Level.Random.Next(80) != 0 && _entity.DistanceTo(target) < 3)
80+
{
81+
return;
82+
}
83+
84+
var distanceToEntity = _entity.DistanceTo(target);
85+
86+
if (distanceToEntity < 1.75)
87+
{
88+
_entity.Velocity = Vector3.Zero;
89+
_entity.Controller.LookAt(target);
90+
return;
91+
}
92+
93+
if (_currentPath == null || _currentPath.NoPath())
94+
{
95+
var pathFinder = new Pathfinder();
96+
_currentPath = pathFinder.FindPath(_entity, target, 20);
97+
}
98+
99+
if (_currentPath.HavePath())
100+
{
101+
if (!_currentPath.GetNextTile(_entity, out Tile next)) return;
102+
103+
_entity.Controller.RotateTowards(new Vector3((float) next.X + 0.5f, _entity.KnownPosition.Y, (float) next.Y + 0.5f));
104+
105+
if (distanceToEntity < 1.75)
106+
{
107+
_entity.Velocity = Vector3.Zero;
108+
_currentPath = null;
109+
}
110+
else
111+
{
112+
var m = 2 - distanceToEntity;
113+
if (m <= 0)
114+
{
115+
m = 1;
116+
}
117+
else
118+
{
119+
m = m / 2.0;
120+
}
121+
_entity.Controller.MoveForward(1 * m, entities);
122+
}
123+
}
124+
else
125+
{
126+
_entity.Velocity = Vector3.Zero;
127+
_currentPath = null;
128+
}
129+
130+
_entity.Controller.LookAt(target);
131+
}
132+
133+
private bool GetNextTile(out Tile next)
134+
{
135+
next = null;
136+
if (_currentPath.NoPath()) return false;
137+
138+
next = _currentPath.First();
139+
140+
BlockCoordinates currPos = (BlockCoordinates) _entity.KnownPosition;
141+
if ((int) next.X == currPos.X && (int) next.Y == currPos.Z)
142+
{
143+
_currentPath.Remove(next);
144+
145+
if (!GetNextTile(out next)) return false;
146+
}
147+
148+
return true;
149+
}
150+
151+
public double Distance(Player player, Tile tile)
152+
{
153+
Vector2 pos1 = new Vector2(player.KnownPosition.X, player.KnownPosition.Z);
154+
Vector2 pos2 = new Vector2((float) tile.X, (float) tile.Y);
155+
return (pos1 - pos2).Length();
156+
}
157+
158+
public override void OnEnd()
159+
{
160+
_entity.Velocity = Vector3.Zero;
161+
_entity.KnownPosition.Pitch = 0;
162+
_currentPath = null;
163+
}
164+
}
165+
}

0 commit comments

Comments
 (0)