//算符优先级
typedef struct _Priority
{
char op;
int isp;
int icp;
}Priority;
const int symbols = 8;
static Priority pri_table[symbols] =
{
{'#', 0, 0},
{'+', 3, 2},
{'-', 3, 2},
{'*', 5, 4},
{'/', 5, 4},
{'^', 6, 7},
{'(', 1, 8},
{')', 8, 1}
};
inline bool isDigit(char ch)
{
return ch >= '0' && ch <= '9';
}
inline bool opNumber(char ch)
{
return (( ch >= '0' && ch <= '9' || ch == '.') ||
( ch == '@' || ch == '#' || ch == '$' || ch == '%' || ch == '&' ) || (ch == 'R' || ch == 'P'));
}
inline bool isLetterUnderline(char ch)
{
return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || ch == '_';
}
inline bool FloatEqualZero(float f)
{
return (f >= -FLT_EPSILON && f <= FLT_EPSILON);
}
bool isDigitStr(const char * str , float &val)
{
bool bRet = false;
val = 0.00f;
if (str == NULL)
{
return bRet;
}
size_t len = strnlen(str,MAX_EXP);
if (len >= MAX_EXP)
{
return bRet;
}
float hasDot = false;
float w = 1;
for (int i=0; i<(int)len; ++i)
{
if (isDigit(str[i]) || str[i] == '.')
{
if(str[i] == '.')
{
if(hasDot)
{
bRet =false;
break;
}
hasDot = true;
}
else
{
if(hasDot)
{
w *= 0.1f;
val += (str[i] - '0') * w;
}
else
{
val = val * 10 + str[i] - '0';
}
}
}
else
{
bRet = false;
break;
}
}
return bRet;
}
typedef enum _NodeType
{
NODE_TYPE_OP,
NODE_TYPE_NUM,
NODE_TYPE_VAR,
NODE_TYPE_EXPAND_VAR,
NODE_TYPE_PARAM,
NODE_TYPE_RANDOM
}NodeType;
//中缀表达式建树
bool ExpTree::CreateExpTree(const char * str)
{
bool b = scanNode(str);
if (!b)
{
return false;
}
std::stack<ExpNode*> node_stack;
std::stack<ExpNode*> op_stack;
ExpNode temp_node;
temp_node.type = NODE_TYPE_OP;
temp_node.op = '#';
op_stack.push(&temp_node);
for (int i = 0; i < count; i++)
{
if (nodes[i].type == NODE_TYPE_NUM || nodes[i].type == NODE_TYPE_VAR ||
nodes[i].type == NODE_TYPE_PARAM || nodes[i].type == NODE_TYPE_RANDOM)
{
nodes[i].left = NULL;
nodes[i].right = NULL;
node_stack.push(&nodes[i]);
}
else if (nodes[i].type == NODE_TYPE_OP)
{
switch (nodes[i].op)
{
case '(':
{
op_stack.push(&nodes[i]);
}
break;
case ')':
{
while (op_stack.top()->op != '(')
{
ExpNode *op = op_stack.top();
op_stack.pop();
ExpNode *right = node_stack.top();
node_stack.pop();
ExpNode *left = node_stack.top();
node_stack.pop();
op->left = left;
op->right = right;
node_stack.push(op);
}
if (op_stack.empty())
{
return false;
}
op_stack.pop(); //弹出栈顶左括号
}
break;
case '+':
case '-':
case '*':
case '/':
case '^':
{
while (cmpSymbolPri(op_stack.top()->op, nodes[i].op) >= 0)
{
ExpNode *op = op_stack.top();
op_stack.pop();
ExpNode *right = node_stack.top();
node_stack.pop();
ExpNode *left = node_stack.top();
node_stack.pop();
op->left = left;
op->right = right;
node_stack.push(op);
}
op_stack.push(&nodes[i]);
}
break;
default:
return false;
break;
}
}
else
{
return false;
}
}
while (op_stack.top()->op != '#')
{
ExpNode *op = op_stack.top();
op_stack.pop();
ExpNode *right = node_stack.top();
node_stack.pop();
ExpNode *left = node_stack.top();
node_stack.pop();
op->left = left;
op->right = right;
node_stack.push(op);
}
op_stack.pop();
if(node_stack.size() != 1)
{
return false;
}
root = node_stack.top();
node_stack.pop();
return true;
}
float ExpTree::Value()
{
return valNode(root);
}
//计算
float ExpTree::cacul(float a, char op, float b)
{
float ret = 0.00f;
switch (op)
{
case '+':
ret = a + b;
break;
case '-':
ret = a - b;
break;
case '*':
ret = a * b;
break;
case '/':
{
if(!FloatEqualZero(b))
{
ret = a / b;
}
}
break;
case '^':
ret = pow(a, b);
break;
default:
break;
}
return ret;
}
//求值函数
float ExpTree::valNode(ExpNode* cur)
{
float res = 0.0f;
if (cur->type == NODE_TYPE_OP)
{
res = cacul(valNode(cur->left), cur->op, valNode(cur->right));
//计算随机上下限
if (cur->left->chValue[0] == 'R')
{
min_value = cacul(min_value,cur->op,valNode(cur->right));
max_value = cacul(max_value,cur->op,valNode(cur->right));
}
else if (cur->right->chValue[0] == 'R')
{
min_value = (valNode(cur->left),cur->op,min_value);
max_value = (valNode(cur->left),cur->op,max_value);
}
}
else
{
if (cur->type == NODE_TYPE_NUM)
{
res = cur->fValue * cur->sign;
}
else if (cur->type == NODE_TYPE_VAR || cur->type == NODE_TYPE_EXPAND_VAR || cur->type == NODE_TYPE_PARAM || cur->type == NODE_TYPE_RANDOM)
{
res = GetParamValue(cur->chValue) * cur->sign;
}
}
return res;
}
int ExpTree::cmpSymbolPri(const char &ispop, const char &icpop)
{
int pri_isp = -1;
int pri_icp = -1;
for (int i=0,j=0; i< symbols;i++)
{
if (pri_table[i].op == ispop)
{
pri_isp = pri_table[i].isp;
++j;
if (j == 2)
{
break;
}
}
if(pri_table[i].op == icpop)
{
pri_icp = pri_table[i].icp;
++j;
if (j == 2)
{
break;
}
}
}
return pri_isp - pri_icp;
}
bool ExpTree::scanNumber(const char * str, int len, float &val, int &bytes)
{
if (len < 0)
return false;
val = 0.00f;
bool hasDot = false;
float w = 1;
int i=0;
for(;i<len; i++)
{
if (isDigit(str[i]) || str[i] == '.')
{
if(str[i] == '.')
{
if(hasDot)
{
return false;;
}
hasDot = true;
}
else
{
if(hasDot)
{
w *= 0.1f;
val += (str[i] - '0') * w;
}
else
{
val = val * 10 + str[i] - '0';
}
}
}
else
{
break;
}
}
bytes = i-1;
return true;
}
bool ExpTree::scanSymbol(const char * str, int len, char * buf, int &bytes)
{
//最少两个字符'@' '#' '$' '%' 与一个字母的组合
if (len< 2)
{
return false;
}
int i=0;
buf[i] = str[i];
i++;
//首字符必须是字母或者数字或下划线
if (isLetterUnderline(str[i]))
{
buf[i] = str[i];
i++;
for (; i<len; i++)
{
//后序字符
if(isLetterUnderline(str[i]) || isDigit(str[i]))
{
buf[i] = str[i];
}
else
{
break;
}
}
}
else
{
return false;
}
buf[i] = '\0';
bytes = i-1;
return true;
}
bool ExpTree::scanExpandSymbol(const char * str, int len, char * buf, int &bytes)
{
//最少三个字符'&' 数字 与一个字母的组合
if (len< 3)
{
return false;
}
int i=0;
//'&'符号
buf[i] = str[i];
i++;
//首字符必须是字母或者数字或下划线
if (isLetterUnderline(str[i]))
{
buf[i] = str[i];
i++;
for (; i<len; i++)
{
//后序字符
if(isLetterUnderline(str[i]) || isDigit(str[i]))
{
buf[i] = str[i];
}
else
{
break;
}
}
}
else
{
return false;
}
buf[i] = '\0';
bytes = i-1;
return true;
}
bool ExpTree::scanRandom(const char * str, int len, char * buf, int &bytes)
{
//R[M,N] or R[M]
if (len < 6)
{
return false;
}
int i=0;
//R
buf[i] = str[i];
i++;
//[
if (str[i] != '[')
{
return false;
}
buf[i] = str[i];
i++;
bool find = false;
for (; i<len; i++)
{
buf[i] = str[i];
if(buf[i] == ']')
{
find = true;
break;
}
}
if (!find)
{
return false;
}
buf[i] = str[i];
i++;
buf[i] = '\0';
bytes = i-1;
return true;
}
bool ExpTree::scanParam(const char * str, int len, char * buf, int &bytes)
{
if (len < 2)
{
return false;
}
int i=0;
buf[i]=str[i];
i++;
buf[i]=str[i];
i++;
buf[i]='\0';
bytes = i-1;
return true;
}
float ExpTree::query_prop_value(char chr, const char* prop_name)
{
PERSISTID obj = PERSISTID();
float ret = 0.00f;
if (chr == '@') //自己
{
IGameClient* pGameClient = (IGameClient*)CHelper::GetGameClient();
obj = pGameClient->GetPlayer();
}
//else if (chr == '#')
//{
// obj = m_skill;
//}
//else if (chr == '$')
//{
// obj = m_target;
//}
//else if (chr == '%')
//{
// obj = m_target_skill;
//}
if (obj != PERSISTID())
{
ret = QueryPropValue(obj,prop_name);
}
return ret;
}
float ExpTree::query_expand_prop_value(const char* prop_name, char from)
{
float ret = 0.0f;
//ret = QueryPropValueBySource(pGameObject, m_self, prop_name, (RefreshPropSourceType)from);
ret = QueryPropValueBySource(prop_name,int(from));
return ret;
}
float ExpTree::GetParamValue(const char *szFormula)
{
float res = 0.0f;
int len = static_cast<int>(strnlen(szFormula, MAX_NODE_EXP-1));
if (len == 0 || len >= MAX_NODE_EXP-1)
{
return res;
}
if (isDigit(szFormula[0]) || szFormula[0] == '.')
{
bool hasDot = false;
float w = 1;
for(int i=0;i<len; i++)
{
if (isDigit(szFormula[i]) || szFormula[i] == '.')
{
if(szFormula[i] == '.')
{
if(hasDot)
{
res = 0.00f;
break;
}
hasDot = true;
}
else
{
if(hasDot)
{
w *= 0.1f;
res += (szFormula[i] - '0') * w;
}
else
{
res = res * 10 + szFormula[i] - '0';
}
}
}
else
{
res = 0.00f;
break;
}
}
}
else if(szFormula[0] == '@' || szFormula[0] == '#' || szFormula[0] == '$' || szFormula[0] == '%')
{
char var[MAX_NODE_EXP];
int i = 0;
//去掉头@ # $ %
while(i<len-1)
{
var[i]=szFormula[i+1];
i++;
}
var[i]=0;
res = query_prop_value(szFormula[0],var);
}
else if (szFormula[0] == '&')
{
char var[MAX_NODE_EXP];
//去掉 &
int i=0;
//获取参数
while(i<len-1)
{
var[i]=szFormula[i+1];
i++;
}
var[i]=0;
res = query_expand_prop_value(var, 3);
}
//判断是否是属性相关的变量
else if (szFormula[0] == 'P')
{
int index = szFormula[1] - '1';
if (index < MAX_PARAM)
{
res= param[index];
}
}
//判断是否是随机数相关的变量,格式R[P1,P2]或R[P1]
else if (szFormula[0] == 'R')
{
//查找是否有逗号
const char *cfind = strchr(szFormula, ',');
if (cfind == NULL)
{
//没有逗号,取一个变量的随机数
char var[MAX_NODE_EXP];
int i=0;
while(i<len-3)
{
var[i]=szFormula[2+i];
i++;
}
var[i]=0;
float max = GetParamValue(var);
res = (float)util_random_float(max);
//保存随机范围
min_value = 0.0f;
max_value = max;
}
else
{
//有逗号,取两个变量间的随机数
char var[MAX_NODE_EXP];
int split = (int)(cfind - szFormula);
int i=0;
while(i<split-2)
{
var[i]=szFormula[2+i];
i++;
}
var[i]=0;
float min = GetParamValue(var);
i=0;
while(i<len-split-2)
{
var[i]=szFormula[split+1+i];
i++;
}
var[i]=0;
float max = GetParamValue(var);
if (max < min)
{
//转化为合法的范围
float temp = min;
min = max;
max = temp;
}
res = min + (float)util_random_float((float)(max - min));
//保存随机范围
min_value = min;
max_value = max;
}
}
return res;
}
bool ExpTree::scanNode(const char * str)
{
int len = (int)strnlen(str,MAX_EXP-1);
if (len == MAX_EXP-1 || len == 0)
{
return false;
}
int i, sign;
//inNum标记当前是否可以输入操作数
bool inNum;
for(i = 0, sign = 1, inNum = true; i<len; i++)
{
if(opNumber(str[i]))
{
if(inNum)
{
int bytes = 0;
bool b = false;
if (isDigit(str[i]) || str[i] == '.')
{
nodes[count].type = NODE_TYPE_NUM;
b = scanNumber(&str[i],len-i,nodes[count].fValue, bytes);
}
else if (str[i] == '@' || str[i] == '#' || str[i] == '$' || str[i] == '%')
{
nodes[count].type = NODE_TYPE_VAR;
b = scanSymbol(&str[i],len-i, nodes[count].chValue, bytes);
}
else if (str[i] == '&')
{
nodes[count].type = NODE_TYPE_EXPAND_VAR;
b = scanExpandSymbol(&str[i],len-i, nodes[count].chValue, bytes);
}
else if (str[i] == 'R')
{
nodes[count].type = NODE_TYPE_RANDOM;
b = scanRandom(&str[i],len-i,nodes[count].chValue, bytes);
}
else if (str[i] == 'P')
{
nodes[count].type = NODE_TYPE_PARAM;
b = scanParam(&str[i],len-i,nodes[count].chValue, bytes);
}
else
{
return false;
}
if(!b)
{
return false;
}
i += bytes;
nodes[count].sign = sign;
count ++;
if (count > MAX_NODE)
{
return false;
}
sign = 1;
inNum = false;
}
else
{
return false;
}
}
else
{
switch(str[i])
{
case '(':
case ')':
{
nodes[count].type = NODE_TYPE_OP;
nodes[count].op = str[i];
count ++;
if (count > MAX_NODE)
{
return false;
}
}
break;
case '+':
case '-':
case '*':
case '/':
case '^':
{
if(inNum)
{
if(str[i] != '+' && str[i] != '-') throw true;
while(str[i] == '+' || str[i] == '-')
{
if(str[i] == '-')
sign *= -1;
i++;
}
i--;
}
else
{
nodes[count].type = NODE_TYPE_OP;
nodes[count].op = str[i];
count ++;
if (count > MAX_NODE)
{
return false;
}
inNum = true;
}
}
break;
default:
return false;
break;
}
}
}
return count > 0;
}
float ExpTree::calculate_param(const PERSISTID& skill,const char * szFormula, const float (&arg)[MAX_PARAM])
{
if (szFormula == NULL)
{
return 0.00f;
}
size_t len = strnlen(szFormula,MAX_EXP-1);
if (len == 0 || len == MAX_EXP-1)
{
return 0.00f;
}
memset(param,0,sizeof(param));
memcpy(param,arg,sizeof(float) * MAX_PARAM);
bool b = CreateExpTree(szFormula);
if (!b)
{
return 0.00f;
}
m_skill = skill;
min_value = 0.0f;
max_value = 0.0f;
return (float)Value();
}
void ExpTree::GetRandomLimits( float& min_value,float& max_value )
{
min_value = this->min_value;
max_value = this->max_value;
}
float QueryPropValue( const PERSISTID& obj, const char* prop_name )
{
float ret = 0.0f;
if (obj.IsNull() || strcmp(prop_name,"") == 0)
{
return ret;
}
IGameObject* pGameObject = (IGameObject*)CHelper::GetEntity(obj);
if (!pGameObject)
{
return ret;
}
if (pGameObject->FindProp(prop_name))
{
int prop_type = pGameObject->GetPropType(prop_name);
if (prop_type == VTYPE_INT)
{
ret = (float)pGameObject->QueryPropInt(prop_name);
}
else if(prop_type == VTYPE_FLOAT)
{
ret = (float)pGameObject->QueryPropFloat(prop_name);
}
else if (prop_type == VTYPE_DOUBLE)
{
ret = (float)pGameObject->QueryPropDouble(prop_name);
}
}
float add_value = 0.0f;
std::string add_prop = std::string(prop_name) + "Add";
if (pGameObject->FindProp(add_prop.c_str()))
{
int prop_type = pGameObject->GetPropType(add_prop.c_str());
if (prop_type == VTYPE_INT)
{
add_value = (float)pGameObject->QueryPropInt(add_prop.c_str());
}
else if(prop_type == VTYPE_FLOAT)
{
add_value = (float)pGameObject->QueryPropFloat(add_prop.c_str());
}
else if (prop_type == VTYPE_DOUBLE)
{
add_value = pGameObject->QueryPropDouble(add_prop.c_str());
}
}
return ret + add_value;
}
float QueryPropValueBySource( const char* prop_name, int source )
{
float res = 0.0f;
IGameClient* pGameClient = (IGameClient*)CHelper::GetGameClient();
PERSISTID obj = pGameClient->GetPlayer();
IGameObject* pGameObject = (IGameObject*)CHelper::GetEntity(obj);
if (pGameObject && prop_name && pGameObject->FindRecord("RefreshPropCompute"))
{
CVarList result;
pGameObject->FindRecordRow(CVarList() <<"RefreshPropCompute" << 0 << prop_name, result);
int row = result.IntVal(0);
if (row < 0)
{
return res;
}
int prop_type = pGameObject->GetRecordColType("RefreshPropCompute",source);
if (prop_type == VTYPE_INT)
{
res = (float)pGameObject->QueryRecordInt("RefreshPropCompute", row, source);
}
else if (prop_type == VTYPE_FLOAT)
{
res = (float)pGameObject->QueryRecordFloat("RefreshPropCompute", row, source);
}
else if (prop_type == VTYPE_DOUBLE)
{
res = (float)pGameObject->QueryRecordDouble("RefreshPropCompute", row, source);
}
}
return res;
}