/
Reputation.cs
159 lines (140 loc) · 5.68 KB
/
Reputation.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
using UnityEngine;
using UnityEngine.UI;
using System.Collections;
using System.Collections.Generic;
using System;
namespace Reputations
{
public struct SingleReputation
{
public Attributes attributes;
public float timeElement;
public SingleReputation( Attributes _attributes, float _timeElement = 0f )
{
attributes = _attributes;
timeElement = _timeElement;
}
}
public class Reputation
{
[SerializeField]
[Range(0f, 1.0f)]
float timeBias = 0.5f;
[SerializeField]
[Range(0f, 1.0f)]
float goodBias = 0.5f;
[SerializeField]
[Range(0f, 1.0f)]
float evilBias = 0.5f;
public Attributes preferences = new Attributes();
Dictionary<IReputable, SingleReputation> reputables = new Dictionary<IReputable, SingleReputation>();
public Dictionary<IReputable, SingleReputation> Reputables
{
get { return reputables; }
}
public Reputation() { }
public Reputation( float _goodBias, float _evilBias, float _timeBias)
{
goodBias = _goodBias;
evilBias = _evilBias;
timeBias = _timeBias;
}
public SingleReputation GetReputable(IReputable reputable)
{
if (!reputables.ContainsKey(reputable))
{
reputables.Add(reputable, new SingleReputation(new Attributes()));
}
return reputables[reputable];
}
public void SetReputable(IReputable reputable, Attributes _attributes, float? _timeElement = null )
{
if (_timeElement != null)
{
reputables[reputable] = new SingleReputation(_attributes, (float)_timeElement);
}
else if (reputables.ContainsKey(reputable))
{
reputables[reputable] = new SingleReputation(_attributes, reputables[reputable].timeElement);
}
else
{
reputables[reputable] = new SingleReputation(_attributes, 0.5f);
}
}
/// <summary>
/// Change a reacter's opinion of a reputable based on a given set of attributes (generally will be attributes of an action the reactee took).
/// </summary>
/// <param name="reputable"></param>
/// <param name="attributes"></param>
public void ReactTo( IReputable reputable, Attributes attributes )
{
SingleReputation sR = GetReputable(reputable);
float currentReputation = Opinion(reputable);
float previousReputationBias = GetPreviousReputationBias( currentReputation, sR.timeElement );
Attributes newAttributes = NewAttributesValue(sR.attributes, attributes, previousReputationBias );
float newTimeElement = UpdateTimeElement(sR.timeElement);
SetReputable( reputable, newAttributes, newTimeElement);
}
private Attributes NewAttributesValue(Attributes _currentAttributes, Attributes _actionAttributes, float _bias = 0.5f )
{
return (Attributes)(_bias * _currentAttributes + (1 - _bias) * _actionAttributes);
}
/// <summary>
/// Generate the weight that the reacter will place on the current opinion of a reputable as opposed to the opinion of the input attributes
/// </summary>
/// <param name="reputation"></param>
/// <param name="timeElement"></param>
/// <returns></returns>
private float GetPreviousReputationBias(float reputation, float timeElement = 1f)
{
float value = (goodBias - evilBias) * reputation + evilBias;
return value * timeElement;
}
private float UpdateTimeElement( float _oldTimeElement )
{
float s = 2 * timeBias * timeBias;
return (s * _oldTimeElement + 1 - _oldTimeElement) / (1 - _oldTimeElement + s);
}
/// <summary>
/// If a reactee has some level of reputation help, then the reputation of that reactee will be given a boost
/// </summary>
/// <param name="reputation">The current reputation</param>
/// <param name="reputationHelp">Ranges from -1 to 1</param>
/// <returns>Modified reputation</returns>
public static float ApplyReputationHelp(float reputation, float reputationHelp = 0)
{
if (reputationHelp == 0) return reputation;
float newReputation = reputation;
if (reputationHelp < 0)
{
newReputation = reputation * reputationHelp + reputation;
}
else if (reputationHelp > 0)
{
newReputation = (1 - reputation) * reputationHelp + reputation;
}
return Mathf.Clamp(newReputation, 0f, 1f);
}
/// <summary>
/// Get the reacter's opinion of a reputatble.
/// </summary>
/// <param name="reputable"></param>
/// <param name="reputationHelp">A modifier of the output opinion. Ranges from -1 to 1.</param>
/// <returns></returns>
public float Opinion(IReputable reputable, float reputationHelp = 0f)
{
float reputation = Opinion( reputables[reputable].attributes );
return ApplyReputationHelp( reputation, reputationHelp );
}
/// <summary>
/// Get the reacter's opinion of a set of attributes.
/// </summary>
/// <param name="attributes"></param>
/// <returns></returns>
public float Opinion(Attributes attributes)
{
return Mathf.Pow(1 - preferences.Distance(attributes), 5f / 3f);
}
}
}