3615 lines
72 KiB
C++
3615 lines
72 KiB
C++
|
#include "game.h"
|
||
|
#include "combat.h"
|
||
|
#include "animate.h"
|
||
|
#include "statedef.h"
|
||
|
//#include "sample.h"
|
||
|
#include "Sound.h"
|
||
|
#include "pap.h"
|
||
|
#include "pcom.h"
|
||
|
#include "overlay.h"
|
||
|
#include "mfx.h"
|
||
|
#include "eway.h"
|
||
|
#include "psystem.h"
|
||
|
#include "poly.h"
|
||
|
#include "dirt.h"
|
||
|
|
||
|
#ifdef TARGET_DC
|
||
|
#include "DIManager.h"
|
||
|
#endif
|
||
|
|
||
|
SLONG people_allowed_to_hit_each_other(Thing *p_victim,Thing *p_agressor);
|
||
|
|
||
|
extern SLONG set_face_thing(Thing *p_person,Thing *p_target);
|
||
|
extern void e_draw_3d_line(SLONG x1,SLONG y1,SLONG z1,SLONG x2,SLONG y2,SLONG z2);
|
||
|
extern void e_draw_3d_line_col(SLONG x1,SLONG y1,SLONG z1,SLONG x2,SLONG y2,SLONG z2,SLONG r,SLONG g,SLONG b);
|
||
|
SLONG check_combat_hit_with_person(Thing *p_victim,SLONG x,SLONG y,SLONG z,struct GameFightCol *fight,Thing *p_agressor,SLONG *ret_angle);
|
||
|
SLONG check_combat_grapple_with_person(Thing *p_victim,MAPCO16 x,MAPCO16 y,MAPCO16 z,struct GameFightCol *fight,Thing *p_agressor,SLONG *ret_angle,SLONG grapple);
|
||
|
extern void reset_gang_attack(Thing *p_target);
|
||
|
extern void scare_gang_attack(Thing *p_target);
|
||
|
extern SLONG person_has_gun_out(Thing *p_person);
|
||
|
extern void drop_current_gun(Thing *p_person,SLONG change_anim);
|
||
|
extern SLONG is_person_dead(Thing *p_person);
|
||
|
extern SLONG is_person_ko(Thing *p_person);
|
||
|
extern void add_damage_value_thing(Thing *p_thing,SLONG value);
|
||
|
extern SLONG set_person_kick_near(Thing *p_person,SLONG dist);
|
||
|
extern SLONG dist_to_target(Thing *p_person_a,Thing *p_person_b);
|
||
|
extern SLONG is_person_ko_and_lay_down(Thing *p_person);
|
||
|
|
||
|
extern SLONG person_on_floor(Thing *p_person);
|
||
|
|
||
|
extern SLONG is_there_room_behind_person(Thing *p_person, SLONG hit_from_behind);
|
||
|
|
||
|
#define FIGHT_ANGLE_RANGE (400)
|
||
|
|
||
|
extern SLONG set_person_stomp(Thing *p_person);
|
||
|
|
||
|
#define STANCE_MAX_FIND 8
|
||
|
#define STANCE_RADIUS 0x200
|
||
|
|
||
|
THING_INDEX found[16];
|
||
|
|
||
|
#ifdef UNUSED
|
||
|
struct ComboHistory combo_histories[MAX_HISTORY];
|
||
|
struct BlockingHistory block_histories[MAX_HISTORY];
|
||
|
#endif
|
||
|
struct GangAttack gang_attacks[MAX_HISTORY];
|
||
|
|
||
|
//
|
||
|
// I've changed this to a 2d array, but may change back to structure if one element becomes > byte
|
||
|
//
|
||
|
struct FightTree
|
||
|
{
|
||
|
UBYTE Anim;
|
||
|
UBYTE Finish;
|
||
|
UBYTE NextPunch1;
|
||
|
UBYTE NextPunch2;
|
||
|
UBYTE NextKick1;
|
||
|
UBYTE NextKick2;
|
||
|
UBYTE NextJump;
|
||
|
UBYTE NextBlock;
|
||
|
UBYTE Damage;
|
||
|
UBYTE HitType;
|
||
|
};
|
||
|
|
||
|
#define FIGHT_TREE_DAMAGE 8
|
||
|
#define FIGHT_TREE_HIT_TYPE 9
|
||
|
|
||
|
|
||
|
//struct FighTree fight_tree[]=
|
||
|
SWORD fight_tree[][10]=
|
||
|
{
|
||
|
{0 ,0 ,1 ,1 ,6 ,6 ,0 ,0 ,0 ,COMBAT_NONE},
|
||
|
{ANIM_PUNCH_COMBO1 ,2 ,3 ,0 ,11,11,0 ,0 ,10,COMBAT_PUNCH }, // 1
|
||
|
{ANIM_PUNCH_RETURN1 ,0 ,1 ,1 ,0 ,0 ,0 ,0 ,0 ,COMBAT_NONE}, // 2
|
||
|
{ANIM_PUNCH_COMBO2 ,4 ,5 ,1 ,12,12,0 ,0 ,30,COMBAT_PUNCH}, // 3
|
||
|
{ANIM_PUNCH_RETURN2 ,0 ,1 ,1 ,0 ,0 ,0 ,0 ,0 ,COMBAT_NONE}, // 4
|
||
|
{ANIM_PUNCH_COMBO3 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,60,COMBAT_PUNCH}, // 5
|
||
|
|
||
|
{ANIM_KICK_COMBO1 ,7 ,7 ,7 ,8 ,0 ,0 ,0 ,10,COMBAT_KICK}, // 6
|
||
|
{ANIM_KICK_RETURN1 ,0 ,1 ,0 ,6 ,0 ,0 ,0 ,0 ,COMBAT_NONE}, // 7
|
||
|
{ANIM_KICK_COMBO2 ,9 ,13,13,10,0 ,0 ,0 ,30,COMBAT_KICK}, // 8
|
||
|
{ANIM_KICK_RETURN2 ,0 ,1 ,0 ,6 ,0 ,0 ,0 ,0 ,COMBAT_NONE}, // 9
|
||
|
{ANIM_KICK_COMBO3 ,0 ,0 ,0 ,6 ,0 ,0 ,0 ,60,COMBAT_KICK}, // 10
|
||
|
|
||
|
{ANIM_PUNCH_COMBO2b ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,30,COMBAT_KICK}, // 11
|
||
|
{ANIM_PUNCH_COMBO3b ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,80,COMBAT_KICK}, // 12
|
||
|
{ANIM_KICK_COMBO3b ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,80,COMBAT_PUNCH}, // 13
|
||
|
|
||
|
{ANIM_KNIFE_ATTACK1 ,15,16,0 ,0 ,0 ,0 ,0 ,30,COMBAT_KNIFE }, // 14
|
||
|
{ANIM_KNIFE_ATTACK1_RET ,0 ,14,14,0 ,0 ,0 ,0 ,0 ,COMBAT_NONE}, // 15
|
||
|
{ANIM_KNIFE_ATTACK2 ,17,18,14,0 ,0 ,0 ,0 ,60,COMBAT_KNIFE}, // 16
|
||
|
{ANIM_KNIFE_ATTACK2_RET ,0 ,14,14,0 ,0 ,0 ,0 ,0 ,COMBAT_NONE}, // 17
|
||
|
{ANIM_KNIFE_ATTACK3 ,0 ,0 ,0 ,0 ,0 ,0 ,0 ,80,COMBAT_KNIFE}, // 18
|
||
|
|
||
|
{ANIM_BAT_HIT1 ,20,21,0 ,0 ,0 ,0 ,0 ,60,COMBAT_KNIFE }, // 19
|
||
|
{ANIM_BAT_HIT1_RET ,0,19,0 ,0 ,0 ,0 ,0 ,0,COMBAT_NONE }, // 20
|
||
|
{ANIM_BAT_HIT2 ,0,0,0 ,0 ,0 ,0 ,0 ,90,COMBAT_KNIFE }, // 21
|
||
|
};
|
||
|
|
||
|
|
||
|
// front upper
|
||
|
// front middle
|
||
|
// front lower
|
||
|
|
||
|
// behind upper
|
||
|
// behind middle
|
||
|
// behind lower
|
||
|
|
||
|
UBYTE take_hit[7][2]=
|
||
|
{
|
||
|
{ANIM_KD_FRONT_LOW,1},
|
||
|
{ANIM_HIT_FRONT_MID,0},
|
||
|
{ANIM_HIT_FRONT_HI,0},
|
||
|
{ANIM_KD_BACK_LOW,1},
|
||
|
{ANIM_HIT_BACK_MID,0},
|
||
|
{ANIM_HIT_BACK_HI,0},
|
||
|
{0,0}
|
||
|
};
|
||
|
|
||
|
|
||
|
|
||
|
//
|
||
|
// Data Hiding
|
||
|
//
|
||
|
SLONG get_anim_and_node_for_action(UBYTE current_node,UBYTE action,UWORD *new_anim)
|
||
|
{
|
||
|
SLONG new_node;
|
||
|
|
||
|
new_node=fight_tree[current_node][action];
|
||
|
*new_anim=fight_tree[new_node][0];
|
||
|
return(new_node);
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
SLONG get_combat_type_for_node(UBYTE current_node)
|
||
|
{
|
||
|
return(fight_tree[current_node][9]);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
SWORD punches[4][5]=
|
||
|
{
|
||
|
{ANIM_PUNCH_COMBO1,ANIM_PUNCH_COMBO2,ANIM_PUNCH_COMBO3,0,0},
|
||
|
{ANIM_PUNCH3,ANIM_PUNCH1,0,0,0},
|
||
|
{ANIM_PUNCH2,0,0,0,0},
|
||
|
{0,0,0,0,0}
|
||
|
};
|
||
|
|
||
|
SWORD kicks[4][5]=
|
||
|
{
|
||
|
{ANIM_KICK_COMBO1,ANIM_KICK_COMBO2,ANIM_KICK_COMBO3,0,0},
|
||
|
{ANIM_KICK2,ANIM_KICK_ROUND1,0,0,0},
|
||
|
{ANIM_KICK3,0,0,0,0},
|
||
|
{0,0,0,0,0}
|
||
|
};
|
||
|
|
||
|
|
||
|
struct Grapples
|
||
|
{
|
||
|
UWORD Anim;
|
||
|
SWORD Dist;
|
||
|
SWORD Range;
|
||
|
SWORD Angle;
|
||
|
SWORD DAngle;
|
||
|
SWORD Peep;
|
||
|
};
|
||
|
|
||
|
struct Grapples grapples[]=
|
||
|
{
|
||
|
{ANIM_PISTOL_WHIP,75,65,1024,0,1},
|
||
|
{ANIM_STRANGLE, 50,20, 0,0,2},
|
||
|
{ANIM_HEADBUTT, 65,20, 0,0,2},
|
||
|
{ANIM_GRAB_ARM, 60,20, 0,0,1},
|
||
|
// {ANIM_SNAP_KNECK,75,65,1024,0,1},
|
||
|
{0,0,0,0,0},
|
||
|
};
|
||
|
|
||
|
SWORD grapple[]=
|
||
|
{
|
||
|
ANIM_SNAP_KNECK,
|
||
|
0
|
||
|
};
|
||
|
|
||
|
void init_gangattack(void)
|
||
|
{
|
||
|
memset((UBYTE*)gang_attacks,0,sizeof(GangAttack)*MAX_HISTORY);
|
||
|
}
|
||
|
|
||
|
SLONG get_gangattack(Thing *p_person)
|
||
|
{
|
||
|
UWORD c0;
|
||
|
SLONG oldest=0,best=0;
|
||
|
for(c0=1;c0<MAX_HISTORY;c0++)
|
||
|
{
|
||
|
SLONG ticks;
|
||
|
|
||
|
ticks=((UWORD)GAME_TURN)-gang_attacks[c0].LastUsed;
|
||
|
|
||
|
if( ticks>oldest)
|
||
|
{
|
||
|
oldest=ticks;
|
||
|
best=c0;
|
||
|
}
|
||
|
if(gang_attacks[c0].Owner==0)
|
||
|
{
|
||
|
p_person->Genus.Person->GangAttack=c0;
|
||
|
gang_attacks[c0].Owner=THING_NUMBER(p_person);
|
||
|
gang_attacks[c0].Index=0;
|
||
|
gang_attacks[c0].Count=0;
|
||
|
gang_attacks[c0].LastUsed=(UWORD)GAME_TURN;
|
||
|
memset(&gang_attacks[c0].Perp[0],0,16);
|
||
|
|
||
|
return(c0);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if(best)
|
||
|
{
|
||
|
Thing *p_owner;
|
||
|
|
||
|
|
||
|
p_owner=TO_THING(gang_attacks[best].Owner);
|
||
|
p_owner->Genus.Person->GangAttack=0;
|
||
|
p_person->Genus.Person->GangAttack=best;
|
||
|
gang_attacks[best].Owner=THING_NUMBER(p_person);
|
||
|
memset(&gang_attacks[best].Perp[0],0,16);
|
||
|
// memset(&gang_attacks[best].PerpDiag[0],0,8);
|
||
|
gang_attacks[best].Index=0;
|
||
|
gang_attacks[best].Count=0;
|
||
|
gang_attacks[best].LastUsed=(UWORD)GAME_TURN;
|
||
|
}
|
||
|
ASSERT(best);
|
||
|
return(best);
|
||
|
}
|
||
|
|
||
|
#ifdef UNUSED
|
||
|
SLONG get_history(Thing *p_person)
|
||
|
{
|
||
|
UWORD c0;
|
||
|
SLONG oldest=0,best=0;
|
||
|
for(c0=1;c0<MAX_HISTORY;c0++)
|
||
|
{
|
||
|
SLONG ticks;
|
||
|
|
||
|
ticks=((UWORD)GAME_TURN)-combo_histories[c0].LastUsed;
|
||
|
|
||
|
if( ticks>oldest)
|
||
|
{
|
||
|
oldest=ticks;
|
||
|
best=c0;
|
||
|
}
|
||
|
if(combo_histories[c0].Owner==0)
|
||
|
{
|
||
|
p_person->Genus.Person->ComboHistory=c0;
|
||
|
combo_histories[c0].Owner=THING_NUMBER(p_person);
|
||
|
combo_histories[c0].Index=0;
|
||
|
combo_histories[c0].Count=0;
|
||
|
|
||
|
return(c0);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if(best)
|
||
|
{
|
||
|
Thing *p_owner;
|
||
|
p_owner=TO_THING(combo_histories[best].Owner);
|
||
|
p_owner->Genus.Person->ComboHistory=0;
|
||
|
p_person->Genus.Person->ComboHistory=best;
|
||
|
combo_histories[best].Owner=THING_NUMBER(p_person);
|
||
|
combo_histories[best].Index=0;
|
||
|
combo_histories[best].Count=0;
|
||
|
}
|
||
|
return(best);
|
||
|
}
|
||
|
|
||
|
SLONG get_block_history(Thing *p_person)
|
||
|
{
|
||
|
UWORD c0;
|
||
|
SLONG oldest=0,best=0;
|
||
|
for(c0=1;c0<MAX_HISTORY;c0++)
|
||
|
{
|
||
|
SLONG ticks;
|
||
|
|
||
|
ticks=((UWORD)GAME_TURN)-block_histories[c0].LastUsed;
|
||
|
|
||
|
if( ticks>oldest)
|
||
|
{
|
||
|
oldest=ticks;
|
||
|
best=c0;
|
||
|
}
|
||
|
if(block_histories[c0].Owner==0)
|
||
|
{
|
||
|
p_person->Genus.Person->BlockHistory=c0;
|
||
|
block_histories[c0].Owner=THING_NUMBER(p_person);
|
||
|
block_histories[c0].Index=0;
|
||
|
block_histories[c0].Count=0;
|
||
|
|
||
|
return(c0);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if(best)
|
||
|
{
|
||
|
Thing *p_owner;
|
||
|
p_owner=TO_THING(block_histories[best].Owner);
|
||
|
|
||
|
p_owner->Genus.Person->BlockHistory=0;
|
||
|
p_person->Genus.Person->BlockHistory=best;
|
||
|
|
||
|
block_histories[best].Owner=THING_NUMBER(p_person);
|
||
|
block_histories[best].Index=0;
|
||
|
block_histories[best].Count=0;
|
||
|
}
|
||
|
return(best);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
SLONG find_possible_combat_target(struct GameFightCol *p_fight,SLONG x,SLONG y,SLONG z,Thing *p_thing,Thing **p_victim)
|
||
|
{
|
||
|
SLONG i;
|
||
|
SLONG hit;
|
||
|
SLONG angle;
|
||
|
|
||
|
Thing *t_thing;
|
||
|
|
||
|
//
|
||
|
// Find all the people near us.
|
||
|
//
|
||
|
|
||
|
// THING_INDEX found[16];
|
||
|
SLONG found_upto;
|
||
|
|
||
|
found_upto = THING_find_sphere(x, y, z, 0x280, found, 16, (1 << CLASS_PERSON));
|
||
|
|
||
|
//
|
||
|
// Check each person in turn.
|
||
|
//
|
||
|
|
||
|
hit = 0;
|
||
|
|
||
|
for (i = 0; i < found_upto; i++)
|
||
|
{
|
||
|
t_thing = TO_THING(found[i]);
|
||
|
|
||
|
if (t_thing != p_thing)
|
||
|
{
|
||
|
if (check_combat_hit_with_person(
|
||
|
t_thing,
|
||
|
x, y, z,
|
||
|
p_fight,
|
||
|
p_thing,
|
||
|
&angle) > 0)
|
||
|
{
|
||
|
hit += p_fight->Damage+5;
|
||
|
*p_victim = t_thing;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return hit;
|
||
|
|
||
|
/*
|
||
|
|
||
|
SLONG dx,dz;
|
||
|
SLONG index;
|
||
|
Thing *t_thing;
|
||
|
SLONG hit=0;
|
||
|
SLONG angle;
|
||
|
|
||
|
for(dx=-2;dx<3;dx++)
|
||
|
for(dz=-2;dz<3;dz++)
|
||
|
{
|
||
|
SLONG mx,mz;
|
||
|
mx=(x>>ELE_SHIFT)+dx;
|
||
|
mz=(z>>ELE_SHIFT)+dz;
|
||
|
index=MAP[MAP_INDEX(mx,mz)].MapWho;
|
||
|
while(index)
|
||
|
{
|
||
|
t_thing = TO_THING(index);
|
||
|
if(t_thing!=p_thing)
|
||
|
{
|
||
|
LogText(" found a thing at dx dz %d %d of type %d\n",dx,dz,t_thing->DrawType);
|
||
|
switch(t_thing->DrawType)
|
||
|
{
|
||
|
case DT_ROT_MULTI:
|
||
|
LogText(" its a figure \n");
|
||
|
if(check_combat_hit_with_person(t_thing,x,y,z,p_fight,p_thing,&angle)>0)
|
||
|
{
|
||
|
hit+=p_fight->Damage;
|
||
|
*p_victim=t_thing;
|
||
|
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
|
||
|
}
|
||
|
}
|
||
|
index = t_thing->Child;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return(hit);
|
||
|
|
||
|
*/
|
||
|
}
|
||
|
|
||
|
SLONG find_possible_grapple_target(struct GameFightCol *p_fight,SLONG x,SLONG y,SLONG z,Thing *p_thing,Thing **p_victim,SLONG grapple)
|
||
|
{
|
||
|
SLONG i;
|
||
|
SLONG hit;
|
||
|
SLONG angle;
|
||
|
|
||
|
Thing *t_thing;
|
||
|
|
||
|
//
|
||
|
// Find all the people near us.
|
||
|
//
|
||
|
|
||
|
// THING_INDEX found[16];
|
||
|
SLONG found_upto;
|
||
|
|
||
|
found_upto = THING_find_sphere(x, y, z, 0x280, found, 16, (1 << CLASS_PERSON));
|
||
|
|
||
|
//
|
||
|
// Check each person in turn.
|
||
|
//
|
||
|
|
||
|
hit = 0;
|
||
|
|
||
|
for (i = 0; i < found_upto; i++)
|
||
|
{
|
||
|
t_thing = TO_THING(found[i]);
|
||
|
if(p_thing!=t_thing)
|
||
|
if(people_allowed_to_hit_each_other(t_thing,p_thing))
|
||
|
{
|
||
|
if (t_thing != p_thing && t_thing->SubState!=SUB_STATE_GRAPPLE_HOLD &&t_thing->SubState!=SUB_STATE_GRAPPLE_HELD&&t_thing->SubState!=SUB_STATE_GRAPPLE_ATTACK && t_thing->SubState!=SUB_STATE_ESCAPE && t_thing->State!=STATE_DEAD && !is_person_ko(t_thing) && t_thing->Draw.Tweened->CurrentAnim!=ANIM_PISTOL_WHIP_TAKE)
|
||
|
{
|
||
|
if (check_combat_grapple_with_person(
|
||
|
t_thing,
|
||
|
x, y, z,
|
||
|
p_fight,
|
||
|
p_thing,
|
||
|
&angle,grapple) > 0)
|
||
|
{
|
||
|
hit += 1000;
|
||
|
*p_victim = t_thing;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return hit;
|
||
|
|
||
|
/*
|
||
|
|
||
|
SLONG dx,dz;
|
||
|
SLONG index;
|
||
|
Thing *t_thing;
|
||
|
SLONG hit=0;
|
||
|
SLONG angle;
|
||
|
|
||
|
|
||
|
for(dx=-2;dx<3;dx++)
|
||
|
for(dz=-2;dz<3;dz++)
|
||
|
{
|
||
|
SLONG mx,mz;
|
||
|
mx=(x>>ELE_SHIFT)+dx;
|
||
|
mz=(z>>ELE_SHIFT)+dz;
|
||
|
index=MAP[MAP_INDEX(mx,mz)].MapWho;
|
||
|
while(index)
|
||
|
{
|
||
|
t_thing = TO_THING(index);
|
||
|
if(t_thing!=p_thing)
|
||
|
{
|
||
|
LogText(" found a thing at dx dz %d %d of type %d\n",dx,dz,t_thing->DrawType);
|
||
|
switch(t_thing->DrawType)
|
||
|
{
|
||
|
case DT_ROT_MULTI:
|
||
|
LogText(" its a figure \n");
|
||
|
if(check_combat_grapple_with_person(t_thing,x,y,z,p_fight,p_thing,&angle)>0)
|
||
|
{
|
||
|
hit+=1000;
|
||
|
*p_victim=t_thing;
|
||
|
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
|
||
|
}
|
||
|
}
|
||
|
index = t_thing->Child;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return(hit);
|
||
|
|
||
|
*/
|
||
|
}
|
||
|
|
||
|
SLONG find_hit_value(Thing *p_person,SLONG anim,Thing **p_victim)
|
||
|
{
|
||
|
GameKeyFrame *current;
|
||
|
struct GameFightCol *fight_info;
|
||
|
SLONG x,y,z;
|
||
|
SLONG dx,dy,dz;
|
||
|
SLONG hits=0;
|
||
|
|
||
|
current=global_anim_array[p_person->Genus.Person->AnimType][anim];
|
||
|
|
||
|
calc_sub_objects_position(p_person,p_person->Draw.Tweened->AnimTween,0,&x,&y,&z);
|
||
|
x+=p_person->WorldPos.X>>8;
|
||
|
y+=p_person->WorldPos.Y>>8;
|
||
|
z+=p_person->WorldPos.Z>>8;
|
||
|
// calc_sub_objects_position_keys(p_person,p_person->Draw.Tweened->AnimTween,0,&dx,&dy,&dz,anim_array[anim],anim_array[anim]->NextFrame);
|
||
|
|
||
|
while(current)
|
||
|
{
|
||
|
if(current->Fight)
|
||
|
{
|
||
|
hits+=find_possible_combat_target(current->Fight,x,y,z,p_person,p_victim);
|
||
|
}
|
||
|
current=current->NextFrame;
|
||
|
}
|
||
|
return(hits);
|
||
|
}
|
||
|
|
||
|
SLONG find_grapple_value(Thing *p_person,SLONG anim,Thing **p_victim,SLONG grapple)
|
||
|
{
|
||
|
GameKeyFrame *current;
|
||
|
struct GameFightCol *fight_info;
|
||
|
SLONG x,y,z;
|
||
|
SLONG dx,dy,dz;
|
||
|
SLONG hits=0;
|
||
|
|
||
|
current=global_anim_array[p_person->Genus.Person->AnimType][anim];
|
||
|
|
||
|
// calc_sub_objects_position(p_person,p_person->Draw.Tweened->AnimTween,SUB_OBJECT_PELVIS,&x,&y,&z);
|
||
|
x=p_person->WorldPos.X>>8;
|
||
|
y=p_person->WorldPos.Y>>8;
|
||
|
z=p_person->WorldPos.Z>>8;
|
||
|
// calc_sub_objects_position_keys(p_person,p_person->Draw.Tweened->AnimTween,0,&dx,&dy,&dz,anim_array[anim],anim_array[anim]->NextFrame);
|
||
|
|
||
|
hits+=find_possible_grapple_target(0,x,y,z,p_person,p_victim,grapple);
|
||
|
return(hits);
|
||
|
}
|
||
|
|
||
|
void set_grapple_pos(Thing *p_person,Thing *p_victim,SLONG dist,SLONG anim,SLONG grapple)
|
||
|
{
|
||
|
SLONG dx,dy,dz,len;
|
||
|
SLONG angle;
|
||
|
|
||
|
GameCoord new_position;
|
||
|
|
||
|
dx =- (SIN(p_person->Draw.Tweened->Angle)*dist)>>16;
|
||
|
dz =- (COS(p_person->Draw.Tweened->Angle)*dist)>>16;
|
||
|
|
||
|
new_position.X = p_person->WorldPos.X+(dx<<8);
|
||
|
new_position.Y = p_person->WorldPos.Y;
|
||
|
new_position.Z = p_person->WorldPos.Z+(dz<<8);
|
||
|
|
||
|
move_thing_on_map(p_victim,&new_position);
|
||
|
|
||
|
p_victim->Draw.Tweened->Angle=(p_person->Draw.Tweened->Angle+grapples[grapple].Angle+1024)&2047;
|
||
|
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
SLONG set_grapple(Thing *p_person,Thing *p_victim,SLONG anim,SLONG grapple)
|
||
|
{
|
||
|
UBYTE taunt_prob = 0;
|
||
|
set_face_thing(p_person,p_victim);
|
||
|
set_anim(p_person,anim);
|
||
|
p_person->Genus.Person->Target=THING_NUMBER(p_victim);
|
||
|
ASSERT(p_person->Genus.Person->Target !=THING_NUMBER(p_person));
|
||
|
ASSERT(TO_THING(p_person->Genus.Person->Target)->Class==CLASS_PERSON);
|
||
|
|
||
|
p_victim->Genus.Person->Target=THING_NUMBER(p_person);
|
||
|
ASSERT(p_victim->Genus.Person->Target !=THING_NUMBER(p_victim));
|
||
|
ASSERT(TO_THING(p_victim->Genus.Person->Target)->Class==CLASS_PERSON);
|
||
|
|
||
|
switch(anim)
|
||
|
{
|
||
|
case ANIM_SNAP_KNECK:
|
||
|
// if (p_person->Genus.Person->Flags & FLAG_PERSON_GUN_OUT)
|
||
|
set_anim(p_victim,ANIM_DIE_KNECK);
|
||
|
|
||
|
set_grapple_pos(p_person,p_victim,70,anim,grapple);
|
||
|
p_victim->SubState=SUB_STATE_GRAPPLEE;
|
||
|
p_person->SubState=SUB_STATE_GRAPPLE;
|
||
|
|
||
|
break;
|
||
|
case ANIM_PISTOL_WHIP:
|
||
|
set_anim(p_victim,ANIM_PISTOL_WHIP_TAKE);
|
||
|
set_grapple_pos(p_person,p_victim,70,anim,grapple);
|
||
|
p_victim->SubState=SUB_STATE_GRAPPLEE;
|
||
|
p_person->SubState=SUB_STATE_GRAPPLE;
|
||
|
break;
|
||
|
|
||
|
case ANIM_GRAB_ARM:
|
||
|
set_grapple_pos(p_person,p_victim,90,anim,grapple);
|
||
|
|
||
|
set_anim(p_victim,ANIM_GRAB_ARMV);
|
||
|
p_victim->Genus.Person->Action=ACTION_GRAPPLEE;
|
||
|
p_victim->Genus.Person->Escape=0;
|
||
|
p_victim->SubState=SUB_STATE_GRAPPLE_HELD;
|
||
|
p_person->SubState=SUB_STATE_GRAPPLE;
|
||
|
break;
|
||
|
case ANIM_STRANGLE:
|
||
|
set_grapple_pos(p_person,p_victim,100,anim,grapple);
|
||
|
|
||
|
set_anim(p_victim,ANIM_STRANGLE_VICTIM);
|
||
|
p_victim->Genus.Person->Action=ACTION_GRAPPLEE;
|
||
|
p_victim->Genus.Person->Escape=0;
|
||
|
p_victim->SubState=SUB_STATE_STRANGLEV;
|
||
|
p_person->SubState=SUB_STATE_STRANGLE;
|
||
|
taunt_prob=50;
|
||
|
break;
|
||
|
case ANIM_HEADBUTT:
|
||
|
set_grapple_pos(p_person,p_victim,100,anim,grapple);
|
||
|
|
||
|
set_anim(p_victim,ANIM_HEADBUTT_VICTIM);
|
||
|
p_victim->Genus.Person->Action=ACTION_GRAPPLEE;
|
||
|
p_victim->Genus.Person->Escape=0;
|
||
|
p_victim->SubState=SUB_STATE_HEADBUTTV;
|
||
|
p_person->SubState=SUB_STATE_HEADBUTT;
|
||
|
taunt_prob=50;
|
||
|
break;
|
||
|
}
|
||
|
set_generic_person_state_function(p_person,STATE_FIGHTING);
|
||
|
|
||
|
set_generic_person_state_function(p_victim,STATE_FIGHTING);
|
||
|
p_victim->Genus.Person->Flags |= FLAG_PERSON_HELPLESS;
|
||
|
p_person->Genus.Person->Action=ACTION_GRAPPLE;
|
||
|
scare_gang_attack(p_person);
|
||
|
|
||
|
#ifndef PSX
|
||
|
if ((Random()&0xff)<taunt_prob) // not too often or it gets annoying
|
||
|
{
|
||
|
SLONG sound=0;
|
||
|
|
||
|
switch (p_person->Genus.Person->PersonType)
|
||
|
{
|
||
|
/* case PERSON_DARCI:
|
||
|
if (Random()&3)
|
||
|
sound=SOUND_Range(S_DARCI_FIGHT_TAUNT_START,S_DARCI_FIGHT_TAUNT_END);
|
||
|
else
|
||
|
sound=SOUND_Range(S_DARCI_DEADSAFE_TAUNT_START,S_DARCI_DEADSAFE_TAUNT_END);
|
||
|
break;*/
|
||
|
case PERSON_ROPER:// Only Roper moves currently have a taunt_prob greater than zero...
|
||
|
if (Random()&2)
|
||
|
sound=SOUND_Range(S_ROPER_FIGHT_TAUNT_START,S_ROPER_FIGHT_TAUNT_END);
|
||
|
else
|
||
|
sound=SOUND_Range(S_ROPER_DEADSAFE_TAUNT_START,S_ROPER_DEADSAFE_TAUNT_END);
|
||
|
break;
|
||
|
}
|
||
|
if (sound) MFX_play_thing(THING_NUMBER(p_person),sound,MFX_QUEUED|MFX_SHORT_QUEUE,p_person);
|
||
|
}
|
||
|
#endif
|
||
|
//
|
||
|
// The sound of a breaking neck!
|
||
|
//
|
||
|
/*
|
||
|
PCOM_oscillate_tympanum(
|
||
|
PCOM_SOUND_FIGHT,
|
||
|
p_person,
|
||
|
p_person->WorldPos.X >> 8,
|
||
|
p_person->WorldPos.Y >> 8,
|
||
|
p_person->WorldPos.Z >> 8);
|
||
|
*/
|
||
|
|
||
|
return(0);
|
||
|
}
|
||
|
|
||
|
SLONG find_best_grapple(Thing *p_person)
|
||
|
{
|
||
|
SLONG c0=0;
|
||
|
SLONG best=-1,best_hit=0,hit;
|
||
|
Thing *p_target=0,*best_target=0;
|
||
|
SLONG only_kneck=0;
|
||
|
SLONG iam=1;
|
||
|
#ifndef PSX
|
||
|
if(p_person->Genus.Person->AnimType==ANIM_TYPE_ROPER)
|
||
|
{
|
||
|
|
||
|
iam=2;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
/*
|
||
|
if (p_person->Genus.Person->PersonType != PERSON_DARCI)
|
||
|
{
|
||
|
//
|
||
|
// Only let Darci grapple because otherwise set_anim() crashes
|
||
|
//
|
||
|
|
||
|
return NULL;
|
||
|
}
|
||
|
*/
|
||
|
// don't let roper grapple, cos junior asked for him not to
|
||
|
// if (p_person->Genus.Person->AnimType == ANIM_TYPE_ROPER) return NULL;
|
||
|
//
|
||
|
|
||
|
if(!p_person->Genus.Person->PlayerID || p_person->Genus.Person->Mode==PERSON_MODE_FIGHT)
|
||
|
{
|
||
|
//
|
||
|
// skip neck snap for non players
|
||
|
//
|
||
|
c0=1;
|
||
|
}
|
||
|
if((p_person->Genus.Person->PlayerID && p_person->SubState==SUB_STATE_STEP_FORWARD && p_person->Draw.Tweened->FrameIndex<3) || ((!p_person->Genus.Person->PlayerID) && ((GAME_TURN+THING_NUMBER(p_person))&0x3)==0))
|
||
|
{
|
||
|
only_kneck=0;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
only_kneck=1;
|
||
|
if(c0==1)
|
||
|
{
|
||
|
//
|
||
|
//kneck snap has been skipped
|
||
|
//
|
||
|
return(0);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
while(grapples[c0].Anim)
|
||
|
{
|
||
|
if(grapples[c0].Peep&iam)
|
||
|
{
|
||
|
hit=find_grapple_value(p_person,grapples[c0].Anim,&p_target,c0);
|
||
|
if(hit>best_hit)
|
||
|
{
|
||
|
best=c0;
|
||
|
best_hit=hit;
|
||
|
best_target=p_target;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
c0++;
|
||
|
if(only_kneck && c0==1)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
if(best>=0)
|
||
|
{
|
||
|
// if(best_target)
|
||
|
if(best_target&&(best_target->Genus.Person->AnimType!=ANIM_TYPE_ROPER)) // junior doesn't want darci grappling roper.
|
||
|
{
|
||
|
if (best_target->Genus.Person->PersonType == PERSON_MIB1 ||
|
||
|
best_target->Genus.Person->PersonType == PERSON_MIB2 ||
|
||
|
best_target->Genus.Person->PersonType == PERSON_MIB3)
|
||
|
{
|
||
|
//
|
||
|
// You can't throw MIB
|
||
|
//
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
if (grapples[best].Anim == ANIM_PISTOL_WHIP)
|
||
|
{
|
||
|
//
|
||
|
// You can't pistol whip people the combat training people.
|
||
|
//
|
||
|
|
||
|
if (best_target->Genus.Person->pcom_ai == PCOM_AI_FIGHT_TEST)
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (grapples[best].Anim == ANIM_STRANGLE ||
|
||
|
grapples[best].Anim == ANIM_HEADBUTT)
|
||
|
{
|
||
|
//
|
||
|
// The victim is thrown forawrd at the end of some grapples. If
|
||
|
// they are too near a wall or a fence, they will go through.
|
||
|
//
|
||
|
|
||
|
extern SLONG is_there_room_in_front_of_me(Thing *p_person, SLONG how_much_room);
|
||
|
|
||
|
if (!is_there_room_in_front_of_me(p_person, 150))
|
||
|
{
|
||
|
/*
|
||
|
extern void add_damage_text(SWORD x,SWORD y,SWORD z,CBYTE *text);
|
||
|
|
||
|
add_damage_text(
|
||
|
p_person->WorldPos.X >> 8,
|
||
|
p_person->WorldPos.Y + 0x6000 >> 8,
|
||
|
p_person->WorldPos.Z >> 8,
|
||
|
"Better not grapple!");
|
||
|
*/
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
set_grapple(p_person,best_target,grapples[best].Anim,best);
|
||
|
return(1);
|
||
|
}
|
||
|
return(0); //grapple[best]);
|
||
|
}
|
||
|
else
|
||
|
return(0);
|
||
|
}
|
||
|
|
||
|
#ifdef UNUSED
|
||
|
void set_combo_history(SLONG history,SLONG power,SLONG index)
|
||
|
{
|
||
|
SLONG pos;
|
||
|
pos=combo_histories[history].Index;
|
||
|
|
||
|
combo_histories[history].Power[pos]=power;
|
||
|
combo_histories[history].Moves[pos]=index;
|
||
|
combo_histories[history].Times[pos]=(UWORD)GAME_TURN;
|
||
|
combo_histories[history].Index=(++pos)%MAX_MOVES;
|
||
|
if(combo_histories[history].Count<MAX_MOVES)
|
||
|
combo_histories[history].Count++;
|
||
|
combo_histories[history].LastUsed=(UWORD)GAME_TURN;
|
||
|
|
||
|
|
||
|
}
|
||
|
|
||
|
void set_combo_history_result(Thing *p_person,SLONG res)
|
||
|
{
|
||
|
SLONG pos;
|
||
|
SLONG history;
|
||
|
|
||
|
history=p_person->Genus.Person->ComboHistory;
|
||
|
|
||
|
pos=combo_histories[history].Index;
|
||
|
pos--;
|
||
|
if(pos<0)
|
||
|
pos=MAX_MOVES-1;
|
||
|
|
||
|
combo_histories[history].Result[pos]=res;
|
||
|
|
||
|
}
|
||
|
|
||
|
void set_block_history_result(UBYTE history,SLONG perp,SLONG res,SLONG height)
|
||
|
{
|
||
|
SLONG pos;
|
||
|
pos=block_histories[history].Index;
|
||
|
|
||
|
block_histories[history].Attack[pos]=height;
|
||
|
block_histories[history].Times[pos]=(UWORD)GAME_TURN;
|
||
|
block_histories[history].Perp[pos]=(UWORD)perp;
|
||
|
block_histories[history].Flags[pos]=res;
|
||
|
block_histories[history].Index=(++pos)%MAX_MOVES;
|
||
|
if(block_histories[history].Count<MAX_MOVES)
|
||
|
block_histories[history].Count++;
|
||
|
block_histories[history].LastUsed=(UWORD)GAME_TURN;
|
||
|
|
||
|
|
||
|
}
|
||
|
#endif
|
||
|
/*
|
||
|
void set_block_history(SLONG history,SLONG attack,SLONG perp)
|
||
|
{
|
||
|
SLONG pos;
|
||
|
pos=block_histories[history].Index;
|
||
|
|
||
|
block_histories[history].Attack[pos]=attack;
|
||
|
block_histories[history].Times[pos]=(UWORD)GAME_TURN;
|
||
|
block_histories[history].Perp[pos]=(UWORD)perp;
|
||
|
block_histories[history].Flags[pos]=0;
|
||
|
block_histories[history].Index=(++pos)%MAX_MOVES;
|
||
|
if(block_histories[history].Count<MAX_MOVES)
|
||
|
block_histories[history].Count++;
|
||
|
block_histories[history].LastUsed=(UWORD)GAME_TURN;
|
||
|
|
||
|
|
||
|
}
|
||
|
|
||
|
void set_block_history_result(Thing *p_person,SLONG attack,SLONG perp,SLONG res,SLONG height)
|
||
|
{
|
||
|
SLONG pos;
|
||
|
SLONG history;
|
||
|
|
||
|
history=p_person->Genus.Person->BlockHistory;
|
||
|
|
||
|
pos=block_histories[history].Index;
|
||
|
count=combo_histories[history].Count;
|
||
|
while(count)
|
||
|
{
|
||
|
pos--;
|
||
|
if(pos<0)
|
||
|
pos=MAX_MOVES-1;
|
||
|
if(block_histories[pos].Perp==perp && block_histories[pos].Attack==attack)
|
||
|
{
|
||
|
block_histories[history].Flags[pos]=res;
|
||
|
block_histories[history].Attack[pos]=height;
|
||
|
return;
|
||
|
}
|
||
|
count--;
|
||
|
}
|
||
|
}
|
||
|
*/
|
||
|
|
||
|
void func(void)
|
||
|
{
|
||
|
// printf("hello");
|
||
|
}
|
||
|
|
||
|
SLONG find_anim_fight_height(SLONG anim,SLONG person)
|
||
|
{
|
||
|
struct GameKeyFrame *f;
|
||
|
|
||
|
f=global_anim_array[person][anim];
|
||
|
while(f)
|
||
|
{
|
||
|
if(f->Fight)
|
||
|
{
|
||
|
return(f->Fight->Height);
|
||
|
}
|
||
|
if(f->Flags&ANIM_FLAG_LAST_FRAME)
|
||
|
return(0);
|
||
|
f=f->NextFrame;
|
||
|
}
|
||
|
return(0);
|
||
|
}
|
||
|
|
||
|
SLONG should_i_block(Thing *p_person,Thing *p_agressor,SLONG anim)
|
||
|
{
|
||
|
SLONG pos;
|
||
|
SLONG history;
|
||
|
SLONG count;
|
||
|
SLONG perp;
|
||
|
SLONG block_prob=(20*256)/100; //20% <<8
|
||
|
SLONG fheight;
|
||
|
SLONG same=0,other=0;
|
||
|
SLONG can_see=0;
|
||
|
|
||
|
if(p_person->Genus.Person->PlayerID)
|
||
|
{
|
||
|
if(p_person->SubState==SUB_STATE_STEP_FORWARD)
|
||
|
{
|
||
|
//
|
||
|
// player moving backwards is autoblock
|
||
|
//
|
||
|
if(p_person->Draw.Tweened->CurrentAnim==ANIM_FIGHT_STEP_S)
|
||
|
{
|
||
|
return(1);
|
||
|
}
|
||
|
|
||
|
|
||
|
}
|
||
|
return(0);
|
||
|
}
|
||
|
|
||
|
fheight=find_anim_fight_height(anim,p_agressor->Genus.Person->AnimType);
|
||
|
|
||
|
perp=THING_NUMBER(p_agressor);
|
||
|
/*
|
||
|
history=p_person->Genus.Person->BlockHistory;
|
||
|
if(history==0)
|
||
|
{
|
||
|
block_prob-=20;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
|
||
|
//
|
||
|
// the prob of blocking is equal to the probability of that person doing that move
|
||
|
//
|
||
|
pos=block_histories[history].Index;
|
||
|
count=combo_histories[history].Count;
|
||
|
while(count&& (same+other)<4)
|
||
|
{
|
||
|
pos--;
|
||
|
if(pos<0)
|
||
|
pos=MAX_MOVES-1;
|
||
|
// the right chap
|
||
|
if(block_histories[history].Perp[pos]==perp)// && block_histories[pos].Attack==attack)
|
||
|
{
|
||
|
|
||
|
//
|
||
|
// count the number of times that move has been done and not done
|
||
|
//
|
||
|
if(block_histories[history].Attack[pos]==fheight)
|
||
|
same++;
|
||
|
else
|
||
|
other++;
|
||
|
}
|
||
|
count--;
|
||
|
}
|
||
|
if(same+other>0)
|
||
|
{
|
||
|
|
||
|
block_prob+=(same*256)>>2;///(same+other);
|
||
|
}
|
||
|
}
|
||
|
block_prob+=GET_SKILL(p_person)*12;
|
||
|
*/
|
||
|
|
||
|
block_prob=60+GET_SKILL(p_person)*12;
|
||
|
|
||
|
if(!can_a_see_b(p_person,p_agressor))
|
||
|
{
|
||
|
//
|
||
|
// if you can't see the enemy then reduce chances of blocking
|
||
|
//
|
||
|
block_prob>>=1;
|
||
|
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// must never be impossible to hit clipped to a skill related value
|
||
|
//
|
||
|
if(block_prob>150+GET_SKILL(p_person)*5)
|
||
|
block_prob=150+GET_SKILL(p_person)*5;
|
||
|
|
||
|
#ifndef PSX
|
||
|
{
|
||
|
CBYTE str[100];
|
||
|
sprintf(str,"block prob %d same %d other %d \n",(block_prob*100)>>8,same,other);
|
||
|
//CONSOLE_text(str);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
|
||
|
if((rand()&255)<block_prob)
|
||
|
return(1);
|
||
|
else
|
||
|
return(0);
|
||
|
|
||
|
}
|
||
|
|
||
|
#ifdef UNUSED
|
||
|
void calc_combo_power(Thing *p_person)
|
||
|
{
|
||
|
SLONG history,pos;
|
||
|
SLONG count,moves=0;
|
||
|
history=p_person->Genus.Person->ComboHistory;
|
||
|
pos=combo_histories[history].Index;
|
||
|
pos--;
|
||
|
count=combo_histories[history].Count;
|
||
|
while(count)
|
||
|
{
|
||
|
if(pos<0)
|
||
|
pos=MAX_MOVES-1;
|
||
|
|
||
|
if((UWORD)GAME_TURN-combo_histories[history].Times[pos]>70)
|
||
|
break;
|
||
|
if(combo_histories[history].Result[pos]==1)
|
||
|
{
|
||
|
moves++;
|
||
|
}
|
||
|
else
|
||
|
moves--;
|
||
|
|
||
|
pos--;
|
||
|
count--;
|
||
|
}
|
||
|
if(moves<0)
|
||
|
moves=0;
|
||
|
p_person->Genus.Person->Power=moves;
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
SLONG find_best_punch(Thing *p_person, ULONG flag)
|
||
|
{
|
||
|
SLONG c0=0;
|
||
|
SLONG best=-1,best_hit=0,hit;
|
||
|
Thing *p_target=0,*best_target=0;
|
||
|
SLONG power,best_power;
|
||
|
SLONG history;
|
||
|
|
||
|
|
||
|
calc_combo_power(p_person);
|
||
|
|
||
|
power=p_person->Genus.Person->Power;
|
||
|
history=p_person->Genus.Person->ComboHistory;
|
||
|
if(!history)
|
||
|
history=get_history(p_person);
|
||
|
|
||
|
power>>=1;
|
||
|
best_power=power;
|
||
|
while(power>=0)
|
||
|
{
|
||
|
c0=0;
|
||
|
if(best_power==0&&punches[power][0])
|
||
|
best_power=power;
|
||
|
|
||
|
while(punches[power][c0])
|
||
|
{
|
||
|
hit=find_hit_value(p_person,punches[power][c0],&p_target);
|
||
|
if(hit>best_hit)
|
||
|
{
|
||
|
best=c0;
|
||
|
best_hit=hit;
|
||
|
best_target=p_target;
|
||
|
}
|
||
|
c0++;
|
||
|
}
|
||
|
if(best>=0)
|
||
|
break;
|
||
|
power--;
|
||
|
}
|
||
|
|
||
|
if(best>=0)
|
||
|
{
|
||
|
extern SLONG set_face_thing(Thing *p_person,Thing *p_target);
|
||
|
if(best_target)
|
||
|
set_face_thing(p_person,best_target);
|
||
|
set_combo_history(history,power,best);
|
||
|
ASSERT(punches[power][best]);
|
||
|
return(punches[power][best]);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (flag & FIND_BEST_USE_DEFAULT)
|
||
|
{
|
||
|
ASSERT(punches[best_power][0]);
|
||
|
return(punches[best_power][0]);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return(0);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
SLONG find_best_kick(Thing *p_person, ULONG flag)
|
||
|
{
|
||
|
SLONG c0=0;
|
||
|
SLONG best=-1,best_hit=-1,hit;
|
||
|
Thing *p_target;
|
||
|
SLONG power,best_power=0;
|
||
|
SLONG history;
|
||
|
|
||
|
calc_combo_power(p_person);
|
||
|
power=p_person->Genus.Person->Power;
|
||
|
history=p_person->Genus.Person->ComboHistory;
|
||
|
if(!history)
|
||
|
history=get_history(p_person);
|
||
|
|
||
|
power>>=1;
|
||
|
while(power>=0)
|
||
|
{
|
||
|
c0=0;
|
||
|
if(best_power==0&&punches[power][0])
|
||
|
best_power=power;
|
||
|
|
||
|
while(kicks[power][c0])
|
||
|
{
|
||
|
hit=find_hit_value(p_person,kicks[power][c0],&p_target);
|
||
|
if(hit>best_hit)
|
||
|
{
|
||
|
best=c0;
|
||
|
best_hit=hit;
|
||
|
}
|
||
|
|
||
|
|
||
|
c0++;
|
||
|
}
|
||
|
if(best>=0)
|
||
|
break;
|
||
|
|
||
|
power--;
|
||
|
}
|
||
|
|
||
|
if(best>=0)
|
||
|
{
|
||
|
|
||
|
set_combo_history(history,power,best);
|
||
|
return(kicks[power][best]);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
//
|
||
|
// Did not find a connecting kick.
|
||
|
//
|
||
|
|
||
|
if (flag & FIND_BEST_USE_DEFAULT)
|
||
|
{
|
||
|
return kicks[best_power][0];
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return NULL;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#ifndef PSX
|
||
|
#ifndef TARGET_DC
|
||
|
void show_fight_range(Thing *p_thing)
|
||
|
{
|
||
|
SLONG temp_angle,temp_angle2;
|
||
|
SLONG x,z;
|
||
|
struct GameFightCol *fight;
|
||
|
SLONG dist;
|
||
|
|
||
|
x=p_thing->WorldPos.X>>8;
|
||
|
z=p_thing->WorldPos.Z>>8;
|
||
|
|
||
|
|
||
|
fight=p_thing->Draw.Tweened->CurrentFrame->Fight;
|
||
|
temp_angle=+(fight->Angle<<3)-p_thing->Draw.Tweened->Angle;
|
||
|
temp_angle-=(FIGHT_ANGLE_RANGE>>1);
|
||
|
if(temp_angle<0)
|
||
|
temp_angle=2048+temp_angle;
|
||
|
temp_angle=temp_angle&2047;
|
||
|
|
||
|
e_draw_3d_line(x,0,z,x+(COS(temp_angle)>>8),0,z+(SIN(temp_angle)>>8) );
|
||
|
|
||
|
temp_angle2=temp_angle+FIGHT_ANGLE_RANGE;
|
||
|
temp_angle2=temp_angle2&2047;
|
||
|
e_draw_3d_line(x,0,z,x+(COS(temp_angle2)>>8),0,z+(SIN(temp_angle2)>>8) );
|
||
|
/*
|
||
|
dist=fight->Dist1;
|
||
|
e_draw_3d_line(x+((SIN(temp_angle)*dist)>>16),0,z+((COS(temp_angle)*dist)>>16),x+((SIN(temp_angle2)*dist)>>16),0,z+((COS(temp_angle2)*dist)>>16) );
|
||
|
|
||
|
dist=fight->Dist2;
|
||
|
e_draw_3d_line(x+((SIN(temp_angle)*dist)>>16),0,z+((COS(temp_angle)*dist)>>16),x+((SIN(temp_angle2)*dist)>>16),0,z+((COS(temp_angle2)*dist)>>16) );
|
||
|
*/
|
||
|
}
|
||
|
#endif
|
||
|
#endif
|
||
|
|
||
|
|
||
|
//
|
||
|
// using the combat distances
|
||
|
//
|
||
|
SLONG check_combat_hit_with_person(Thing *p_victim,MAPCO16 x,MAPCO16 y,MAPCO16 z,struct GameFightCol *fight,Thing *p_agressor,SLONG *ret_angle)
|
||
|
{
|
||
|
SLONG dist,dx,dy,dz,adx,adz;
|
||
|
SLONG mx,my,mz;
|
||
|
SLONG victim_add_y=0;
|
||
|
|
||
|
if(p_agressor->Draw.Tweened->CurrentAnim==ANIM_FIGHT_STOMP)
|
||
|
{
|
||
|
// if((p_victim->Genus.Person->Flags&FLAG_PERSON_KO)==0)
|
||
|
if(!is_person_ko_and_lay_down(p_victim))
|
||
|
return(0);
|
||
|
victim_add_y=100;
|
||
|
}
|
||
|
if(p_victim->Genus.Person->Flags&FLAG_PERSON_KO)
|
||
|
{
|
||
|
if(p_agressor->Draw.Tweened->CurrentAnim!=ANIM_FIGHT_STOMP)
|
||
|
{
|
||
|
return(0);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
if(is_person_dead(p_victim))
|
||
|
return(0);
|
||
|
|
||
|
|
||
|
calc_sub_objects_position(p_victim,p_victim->Draw.Tweened->AnimTween,0,&mx,&my,&mz);
|
||
|
|
||
|
mx+=p_victim->WorldPos.X>>8;
|
||
|
my+=p_victim->WorldPos.Y>>8;
|
||
|
mz+=p_victim->WorldPos.Z>>8;
|
||
|
|
||
|
LogText(" thing pos %d %d %d \n",mx,my,mz);
|
||
|
|
||
|
dx=mx-x;
|
||
|
dy=my-y;
|
||
|
dz=mz-z;
|
||
|
|
||
|
LogText(" dx %d dz %d \n",dx,dz);
|
||
|
|
||
|
adx=abs(dx);
|
||
|
adz=abs(dz);
|
||
|
|
||
|
//
|
||
|
// compares my pelvis with his, but what if he is lay down and i am stood up
|
||
|
//
|
||
|
if(abs(dy+victim_add_y)>100)
|
||
|
{
|
||
|
// ASSERT(0); // Just for now!!!
|
||
|
|
||
|
return(0); // height wrong
|
||
|
}
|
||
|
|
||
|
if (p_agressor->Draw.Tweened->CurrentAnim == ANIM_FIGHT_STOMP)
|
||
|
{
|
||
|
//
|
||
|
// Some special stomp hit code! Find out where the agressors foot is.
|
||
|
//
|
||
|
|
||
|
SLONG fx;
|
||
|
SLONG fy;
|
||
|
SLONG fz;
|
||
|
SLONG pass=0;
|
||
|
|
||
|
calc_sub_objects_position(
|
||
|
p_agressor,
|
||
|
p_agressor->Draw.Tweened->AnimTween,
|
||
|
SUB_OBJECT_RIGHT_FOOT,
|
||
|
&fx,
|
||
|
&fy,
|
||
|
&fz);
|
||
|
|
||
|
fx += p_agressor->WorldPos.X >> 8;
|
||
|
fy += p_agressor->WorldPos.Y >> 8;
|
||
|
fz += p_agressor->WorldPos.Z >> 8;
|
||
|
|
||
|
|
||
|
|
||
|
for(pass=0;pass<3;pass++)
|
||
|
{
|
||
|
|
||
|
if(pass>0)
|
||
|
{
|
||
|
SLONG ob=SUB_OBJECT_HEAD;
|
||
|
if(pass==2)
|
||
|
ob=SUB_OBJECT_RIGHT_TIBIA;
|
||
|
|
||
|
|
||
|
calc_sub_objects_position(p_victim,p_victim->Draw.Tweened->AnimTween,ob,&mx,&my,&mz);
|
||
|
|
||
|
mx+=p_victim->WorldPos.X>>8;
|
||
|
my+=p_victim->WorldPos.Y>>8;
|
||
|
mz+=p_victim->WorldPos.Z>>8;
|
||
|
|
||
|
|
||
|
}
|
||
|
|
||
|
dx = abs(mx - fx);
|
||
|
dz = abs(mz - fz);
|
||
|
|
||
|
dist = QDIST2(dx,dz);
|
||
|
|
||
|
if (dist < 0x53)
|
||
|
{
|
||
|
//
|
||
|
// Near enough to pelvis!
|
||
|
//
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
}
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
|
||
|
dist=QDIST2(adx,adz);
|
||
|
|
||
|
LogText(" dist %d range %d-%d \n",dist,fight->Dist1,fight->Dist2);
|
||
|
|
||
|
#define COMBAT_HIT_DIST_LEEWAY 0x30
|
||
|
|
||
|
// if (dist > fight->Dist1 && dist < fight->Dist2)
|
||
|
|
||
|
// if (WITHIN(dist, fight->Dist1 - COMBAT_HIT_DIST_LEEWAY, fight->Dist2 + COMBAT_HIT_DIST_LEEWAY))
|
||
|
//
|
||
|
// if distance pretty near do an angle check
|
||
|
//
|
||
|
if (WITHIN(dist, 0, fight->Dist2 + COMBAT_HIT_DIST_LEEWAY+128))
|
||
|
{
|
||
|
SLONG angle,temp_angle;
|
||
|
|
||
|
if(fight->Dist1<40)
|
||
|
{
|
||
|
//
|
||
|
// we are intersecting the enemy
|
||
|
//
|
||
|
if(dist<35)
|
||
|
return(1);
|
||
|
}
|
||
|
|
||
|
LogText(" dist ok \n");
|
||
|
|
||
|
angle=-Arctan(-dx,dz)-512;
|
||
|
if(angle<0)
|
||
|
angle=2048+angle;
|
||
|
angle=angle&2047;
|
||
|
|
||
|
*ret_angle=angle;
|
||
|
|
||
|
|
||
|
angle-=((fight->Angle<<3)-p_agressor->Draw.Tweened->Angle);
|
||
|
|
||
|
LogText(" angle diff %d \n",angle);
|
||
|
|
||
|
|
||
|
|
||
|
if(angle<0)
|
||
|
angle=2048+angle;
|
||
|
angle=angle&2047;
|
||
|
|
||
|
if(angle<(FIGHT_ANGLE_RANGE>>1)||angle>2048-(FIGHT_ANGLE_RANGE>>1))
|
||
|
{
|
||
|
//
|
||
|
// angle is good check the distance exactly
|
||
|
//
|
||
|
// if (WITHIN(dist, fight->Dist1 - COMBAT_HIT_DIST_LEEWAY, fight->Dist2 + COMBAT_HIT_DIST_LEEWAY))
|
||
|
if (WITHIN(dist, 0, fight->Dist2 + COMBAT_HIT_DIST_LEEWAY))
|
||
|
{
|
||
|
return(1);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
//
|
||
|
// near miss
|
||
|
//
|
||
|
PCOM_attack_happened_but_missed(p_victim,p_agressor);
|
||
|
|
||
|
return(0);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// ANGLE WRONG
|
||
|
if(angle<(FIGHT_ANGLE_RANGE>>0)||angle>2048-(FIGHT_ANGLE_RANGE>>0))
|
||
|
{
|
||
|
//
|
||
|
// near miss
|
||
|
//
|
||
|
PCOM_attack_happened_but_missed(p_victim,p_agressor);
|
||
|
|
||
|
}
|
||
|
return(0);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
//
|
||
|
// Distance Wrong
|
||
|
//
|
||
|
return(0);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
SLONG check_combat_grapple_with_person(Thing *p_victim,MAPCO16 x,MAPCO16 y,MAPCO16 z,struct GameFightCol *fight,Thing *p_agressor,SLONG *ret_angle,SLONG grapple)
|
||
|
{
|
||
|
SLONG dist,dx,dy,dz,adx,adz;
|
||
|
SLONG mx,my,mz;
|
||
|
struct Grapples *pg;
|
||
|
|
||
|
pg=&grapples[grapple];
|
||
|
|
||
|
// calc_sub_objects_position(p_victim,p_victim->Draw.Tweened->AnimTween,SUB_OBJECT_PELVIS,&mx,&my,&mz);
|
||
|
mx=p_victim->WorldPos.X>>8;
|
||
|
my=p_victim->WorldPos.Y>>8;
|
||
|
mz=p_victim->WorldPos.Z>>8;
|
||
|
|
||
|
|
||
|
|
||
|
dx=mx-x;
|
||
|
dy=my-y;
|
||
|
dz=mz-z;
|
||
|
|
||
|
|
||
|
|
||
|
adx=abs(dx);
|
||
|
adz=abs(dz);
|
||
|
|
||
|
if(abs(dy)>50)
|
||
|
return(0); // height wrong
|
||
|
|
||
|
dist=QDIST2(adx,adz);
|
||
|
/*
|
||
|
#ifndef PSX
|
||
|
{
|
||
|
CBYTE str[100];
|
||
|
sprintf(str,"grapple dist %d dx %d dz %d\n",dist,dx,dz);
|
||
|
CONSOLE_text(str);
|
||
|
}
|
||
|
#endif
|
||
|
*/
|
||
|
|
||
|
|
||
|
|
||
|
if(abs(dist-pg->Dist)<pg->Range) //if(dist>10 && dist<140)
|
||
|
{
|
||
|
SLONG angle,temp_angle;
|
||
|
|
||
|
LogText(" dist ok \n");
|
||
|
|
||
|
//
|
||
|
// Angle I'm looking at relative to him
|
||
|
// I'e for a kneck snap should be looking in same dir
|
||
|
|
||
|
angle=((p_victim->Draw.Tweened->Angle+2048)&2047)-((p_agressor->Draw.Tweened->Angle+2048)&2047);
|
||
|
angle=(angle+2048)&2047;
|
||
|
|
||
|
// MSG_add(" his %d mine %d diff %d \n",p_victim->Draw.Tweened->Angle,p_agressor->Draw.Tweened->Angle,angle);
|
||
|
|
||
|
angle+=(pg->Angle-1024)&2047;
|
||
|
|
||
|
if(angle>160&&angle< 2048-160)
|
||
|
return(0);
|
||
|
|
||
|
|
||
|
angle=Arctan(-dx,dz);
|
||
|
if(angle<0)
|
||
|
angle=2048+angle;
|
||
|
angle=angle&2047;
|
||
|
|
||
|
*ret_angle=angle;
|
||
|
|
||
|
// e_draw_3d_line_col(x,y,z,x+(COS(angle)>>8),y,z+(SIN(angle)>>8) ,255,0,0);
|
||
|
|
||
|
|
||
|
MSG_add(" angle to him %d myangle %d\n",angle,p_agressor->Draw.Tweened->Angle);
|
||
|
|
||
|
//
|
||
|
// victim should be in the direction I'm facing
|
||
|
//
|
||
|
angle-=(p_agressor->Draw.Tweened->Angle);
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
if(angle<0)
|
||
|
angle=2048+angle;
|
||
|
angle=angle&2047;
|
||
|
|
||
|
if(angle<(FIGHT_ANGLE_RANGE>>1)||angle>2048-(FIGHT_ANGLE_RANGE>>1))
|
||
|
{
|
||
|
SLONG dx,dz;
|
||
|
LogText(" angle ok \n");
|
||
|
return(1);
|
||
|
}
|
||
|
|
||
|
else
|
||
|
{
|
||
|
// MSG_add(" ANGLE WRONG angle dif %d",angle);
|
||
|
return(0);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return(0);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// Returns TRUE if he is behind me.
|
||
|
//
|
||
|
|
||
|
SLONG check_hit_from_behind(Thing *p_me, Thing *p_him)
|
||
|
{
|
||
|
SLONG mx;
|
||
|
SLONG my;
|
||
|
SLONG mz;
|
||
|
|
||
|
SLONG hx;
|
||
|
SLONG hy;
|
||
|
SLONG hz;
|
||
|
|
||
|
SLONG dx;
|
||
|
SLONG dz;
|
||
|
|
||
|
SLONG dprod;
|
||
|
|
||
|
ASSERT(p_me ->Class == CLASS_PERSON);
|
||
|
ASSERT(p_him->Class == CLASS_PERSON);
|
||
|
|
||
|
//
|
||
|
// My pelvis.
|
||
|
//
|
||
|
|
||
|
calc_sub_objects_position(
|
||
|
p_me,
|
||
|
p_me->Draw.Tweened->AnimTween,
|
||
|
0,
|
||
|
&mx,
|
||
|
&my,
|
||
|
&mz);
|
||
|
|
||
|
mx += p_me->WorldPos.X >> 8;
|
||
|
mz += p_me->WorldPos.Z >> 8;
|
||
|
|
||
|
//
|
||
|
// His pelvis.
|
||
|
//
|
||
|
|
||
|
calc_sub_objects_position(
|
||
|
p_him,
|
||
|
p_him->Draw.Tweened->AnimTween,
|
||
|
0,
|
||
|
&hx,
|
||
|
&hy,
|
||
|
&hz);
|
||
|
|
||
|
hx += p_him->WorldPos.X >> 8;
|
||
|
hz += p_him->WorldPos.Z >> 8;
|
||
|
|
||
|
//
|
||
|
// The direction I am facing in.
|
||
|
//
|
||
|
|
||
|
dx = -SIN(p_me->Draw.Tweened->Angle);
|
||
|
dz = -COS(p_me->Draw.Tweened->Angle);
|
||
|
|
||
|
//
|
||
|
// The vector from me to him.
|
||
|
//
|
||
|
|
||
|
SLONG vx = hx - mx;
|
||
|
SLONG vz = hz - mz;
|
||
|
|
||
|
dprod = dx*vx + dz*vz;
|
||
|
|
||
|
if (dprod < 0)
|
||
|
{
|
||
|
//
|
||
|
// He is behind me.
|
||
|
//
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
//
|
||
|
// He is in front of me.
|
||
|
//
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
#if 0
|
||
|
|
||
|
SLONG check_hit_from_behind(Thing *p_victim,struct GameFightCol *fight,Thing *p_agressor,SLONG *ret_angle)
|
||
|
{
|
||
|
SLONG dist,dx,dy,dz,adx,adz;
|
||
|
SLONG mx,my,mz;
|
||
|
SLONG x,y,z;
|
||
|
|
||
|
calc_sub_objects_position(p_agressor,p_agressor->Draw.Tweened->AnimTween,0,&x,&y,&z);
|
||
|
|
||
|
x+=p_agressor->WorldPos.X>>8;
|
||
|
y+=p_agressor->WorldPos.Y>>8;
|
||
|
z+=p_agressor->WorldPos.Z>>8;
|
||
|
|
||
|
calc_sub_objects_position(p_victim,p_victim->Draw.Tweened->AnimTween,0,&mx,&my,&mz);
|
||
|
|
||
|
mx+=p_victim->WorldPos.X>>8;
|
||
|
my+=p_victim->WorldPos.Y>>8;
|
||
|
mz+=p_victim->WorldPos.Z>>8;
|
||
|
|
||
|
LogText(" thing pos %d %d %d \n",mx,my,mz);
|
||
|
|
||
|
dx=mx-x;
|
||
|
dy=my-y;
|
||
|
dz=mz-z;
|
||
|
|
||
|
LogText(" dx %d dz %d \n",dx,dz);
|
||
|
|
||
|
|
||
|
if(abs(dy)>150)
|
||
|
return(0); // height wrong
|
||
|
|
||
|
|
||
|
{
|
||
|
SLONG angle,temp_angle;
|
||
|
|
||
|
|
||
|
angle=Arctan(-dx,dz);
|
||
|
if(angle<0)
|
||
|
angle=2048+angle;
|
||
|
angle=angle&2047;
|
||
|
|
||
|
*ret_angle=angle;
|
||
|
|
||
|
MSG_add(" angle to him %d hisangle %d\n",angle,p_victim->Draw.Tweened->Angle);
|
||
|
angle-=(p_victim->Draw.Tweened->Angle);
|
||
|
|
||
|
|
||
|
|
||
|
if(angle<0)
|
||
|
angle=2048+angle;
|
||
|
angle=angle&2047;
|
||
|
|
||
|
MSG_add("RESULT angle %d \n",angle);
|
||
|
|
||
|
if(angle>400 && angle<1024+600)
|
||
|
{
|
||
|
return(0);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return(1);
|
||
|
|
||
|
}
|
||
|
/*
|
||
|
if(angle<(FIGHT_ANGLE_RANGE>>1)||angle>2048-(FIGHT_ANGLE_RANGE>>1))
|
||
|
{
|
||
|
return(-2);
|
||
|
}
|
||
|
|
||
|
else
|
||
|
{
|
||
|
SLONG dx,dz;
|
||
|
LogText(" angle ok \n");
|
||
|
return(1);
|
||
|
}
|
||
|
*/
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
#endif
|
||
|
|
||
|
|
||
|
/*
|
||
|
|
||
|
//
|
||
|
// behind, where they hit from behind?
|
||
|
// height 0,1,2 (feet, torso head)
|
||
|
//
|
||
|
|
||
|
void set_person_dead_combat(Thing *p_thing,Thing *p_aggressor,SLONG death_type,SLONG behind,SLONG height)
|
||
|
{
|
||
|
DrawTween *draw_info;
|
||
|
WaveParams die;
|
||
|
UWORD frame;
|
||
|
|
||
|
ASSERT(WITHIN(behind, 0, 1));
|
||
|
ASSERT(WITHIN(height, 0, 2));
|
||
|
|
||
|
//
|
||
|
// Make the person do the correct animation for the height
|
||
|
// at which the attack occured.
|
||
|
//
|
||
|
|
||
|
draw_info = p_thing->Draw.Tweened;
|
||
|
frame = knock_down[behind*3+height][0];
|
||
|
draw_info->CurrentFrame = global_anim_array[p_thing->Genus.Person->AnimType][frame];
|
||
|
draw_info->CurrentAnim = frame;
|
||
|
draw_info->NextFrame = draw_info->CurrentFrame->NextFrame;
|
||
|
draw_info->QueuedFrame = 0;
|
||
|
draw_info->AnimTween = 0;
|
||
|
|
||
|
//
|
||
|
// Create a sound effect.
|
||
|
//
|
||
|
|
||
|
die.Priority = 0;
|
||
|
die.Flags = WAVE_CARTESIAN;
|
||
|
die.Mode.Cartesian.Scale = (128<<8);
|
||
|
die.Mode.Cartesian.X = p_thing->WorldPos.X;
|
||
|
die.Mode.Cartesian.Y = p_thing->WorldPos.Y;
|
||
|
die.Mode.Cartesian.Z = p_thing->WorldPos.Z;
|
||
|
|
||
|
switch(p_thing->Genus.Person->PersonType)
|
||
|
{
|
||
|
case PERSON_COP:
|
||
|
play_quick_wave_old(&die,S_MALE_DIE_2,0,0);
|
||
|
break;
|
||
|
case PERSON_DARCI:
|
||
|
switch(death_type)
|
||
|
{
|
||
|
case HIT_TYPE_GUN_SHOT_H:
|
||
|
case HIT_TYPE_GUN_SHOT_M:
|
||
|
case HIT_TYPE_GUN_SHOT_L:
|
||
|
default:
|
||
|
play_quick_wave_old(&die,S_FEMALE_DIE_2,0,0);
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Make the person die.
|
||
|
//
|
||
|
|
||
|
set_person_dying(p_thing);
|
||
|
|
||
|
//
|
||
|
// If we know who killed us...
|
||
|
//
|
||
|
|
||
|
if (p_aggressor)
|
||
|
{
|
||
|
p_aggressor->Genus.Person->Target = NULL;
|
||
|
p_aggressor->Genus.Person->InWay = NULL;
|
||
|
|
||
|
if(p_aggressor->Genus.Person->PlayerID)
|
||
|
{
|
||
|
//
|
||
|
// Its a player so keep score
|
||
|
//
|
||
|
|
||
|
GAME_SCORE(p_aggressor->Genus.Person->PlayerID-1) += 50;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
*/
|
||
|
|
||
|
SLONG is_combo_anim(SLONG anim)
|
||
|
{
|
||
|
return
|
||
|
anim == ANIM_PUNCH_COMBO3 ||
|
||
|
anim == ANIM_PUNCH_COMBO3b ||
|
||
|
anim == ANIM_KICK_COMBO3 ||
|
||
|
anim == ANIM_KICK_COMBO3b;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
extern Thing *talk_thing;
|
||
|
void check_eway_talk(SLONG stop);
|
||
|
|
||
|
SLONG apply_hit_to_person(Thing *p_thing,SLONG angle,SLONG type,SLONG damage,Thing *p_aggressor,struct GameFightCol *fight)
|
||
|
{
|
||
|
SLONG hit_wave;
|
||
|
DrawTween *draw_info;
|
||
|
// WaveParams hit;
|
||
|
SLONG behind;
|
||
|
SLONG block=0;
|
||
|
UBYTE player_hit=0;
|
||
|
UBYTE skill=1,shot=0,stomped=0,ko=0,ko_ed=0,batted=0,knifed=0;
|
||
|
GameCoord vec;
|
||
|
SLONG nad=0, taunt_prob=15;
|
||
|
|
||
|
switch(type)
|
||
|
{
|
||
|
case HIT_TYPE_GUN_SHOT_H:
|
||
|
case HIT_TYPE_GUN_SHOT_M:
|
||
|
case HIT_TYPE_GUN_SHOT_L:
|
||
|
|
||
|
|
||
|
case HIT_TYPE_GUN_SHOT_PISTOL:
|
||
|
case HIT_TYPE_GUN_SHOT_SHOTGUN:
|
||
|
case HIT_TYPE_GUN_SHOT_AK47:
|
||
|
shot=1;
|
||
|
if(!p_thing->Genus.Person->PlayerID)
|
||
|
p_thing->Flags|=FLAGS_PERSON_BEEN_SHOT;
|
||
|
}
|
||
|
|
||
|
if(p_thing->Genus.Person->PlayerID)
|
||
|
{
|
||
|
player_hit=1;
|
||
|
}
|
||
|
|
||
|
if(p_aggressor)
|
||
|
{
|
||
|
SLONG node;
|
||
|
SLONG hit_anim,hit;
|
||
|
ASSERT(p_aggressor->Class==CLASS_PERSON);
|
||
|
|
||
|
|
||
|
if(player_hit||p_aggressor->Genus.Person->PlayerID)
|
||
|
{
|
||
|
//
|
||
|
// one of them is a player
|
||
|
//
|
||
|
if(!(p_thing->Genus.Person->Flags&FLAG_PERSON_KO)) //target not lay down
|
||
|
{
|
||
|
//
|
||
|
// can our fist physically reach them?
|
||
|
//
|
||
|
if(!shot)
|
||
|
if(!there_is_a_los_things(p_thing,p_aggressor,LOS_FLAG_IGNORE_SEETHROUGH_FENCE_FLAG|LOS_FLAG_IGNORE_PRIMS|LOS_FLAG_IGNORE_UNDERGROUND_CHECK))
|
||
|
{
|
||
|
return(0);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
node=p_aggressor->Genus.Person->CombatNode;
|
||
|
if(node<0)
|
||
|
node=0;
|
||
|
// ASSERT(node>=0);
|
||
|
|
||
|
// damage=0;
|
||
|
|
||
|
hit_anim=p_aggressor->Draw.Tweened->CurrentAnim;
|
||
|
switch(hit_anim)
|
||
|
{
|
||
|
case ANIM_KICK_NAD:
|
||
|
if (SOUND_Gender(p_thing)==1)
|
||
|
{
|
||
|
// has nads
|
||
|
damage+=50;
|
||
|
nad=1;
|
||
|
taunt_prob=75; // a lot more common for comedic effect
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
damage+=10;
|
||
|
}
|
||
|
break;
|
||
|
case ANIM_BAT_HIT1:
|
||
|
case ANIM_BAT_HIT2:
|
||
|
batted=1; //fall through
|
||
|
case ANIM_FLYKICK_START:
|
||
|
case ANIM_FLYKICK_LAND:
|
||
|
case ANIM_FLYKICK_FALL:
|
||
|
// these are all fancy moves so let's taunt more often
|
||
|
taunt_prob+=10;
|
||
|
// fall through
|
||
|
case ANIM_KICK_BEHIND:
|
||
|
damage+=20; //fall through
|
||
|
case ANIM_KICK_RIGHT:
|
||
|
case ANIM_KICK_LEFT:
|
||
|
damage+=30; //fall through
|
||
|
case ANIM_PUNCH_COMBO3:
|
||
|
case ANIM_PUNCH_COMBO3b:
|
||
|
case ANIM_KICK_COMBO3:
|
||
|
case ANIM_KICK_COMBO3b:
|
||
|
|
||
|
if (p_thing->Genus.Person->PersonType == PERSON_MIB1 ||
|
||
|
p_thing->Genus.Person->PersonType == PERSON_MIB2 ||
|
||
|
p_thing->Genus.Person->PersonType == PERSON_MIB3)
|
||
|
{
|
||
|
//
|
||
|
// You can't knock out MIB! They're too hard.
|
||
|
//
|
||
|
}
|
||
|
else
|
||
|
if (p_thing->Genus.Person->Flags2 & FLAG2_PERSON_INVULNERABLE)
|
||
|
{
|
||
|
//
|
||
|
// Invulnerable people can't be knocked out!
|
||
|
//
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ko = TRUE;
|
||
|
}
|
||
|
|
||
|
if (p_thing->Genus.Person->pcom_ai == PCOM_AI_FIGHT_TEST)
|
||
|
{
|
||
|
//
|
||
|
// Fight test dummys can die from special moves. Even if they
|
||
|
// are invulnerable.
|
||
|
//
|
||
|
|
||
|
if (((p_thing->Genus.Person->pcom_ai_other & PCOM_COMBAT_COMBO_PPP) && (hit_anim == ANIM_PUNCH_COMBO3) ) ||
|
||
|
((p_thing->Genus.Person->pcom_ai_other & PCOM_COMBAT_COMBO_KKK) && (hit_anim == ANIM_KICK_COMBO3) ) ||
|
||
|
((p_thing->Genus.Person->pcom_ai_other & PCOM_COMBAT_COMBO_ANY) && is_combo_anim(hit_anim) ) ||
|
||
|
((p_thing->Genus.Person->pcom_ai_other & PCOM_COMBAT_SIDE_KICK) && (hit_anim == ANIM_KICK_RIGHT || hit_anim == ANIM_KICK_LEFT)) ||
|
||
|
((p_thing->Genus.Person->pcom_ai_other & PCOM_COMBAT_BACK_KICK) && (hit_anim == ANIM_KICK_BEHIND) ))
|
||
|
{
|
||
|
ko = TRUE;
|
||
|
|
||
|
p_thing->Genus.Person->Health = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// damage+=4;
|
||
|
break;
|
||
|
case ANIM_FIGHT_STOMP:
|
||
|
damage+=50;
|
||
|
stomped=1;
|
||
|
break;
|
||
|
case ANIM_KICK_NEAR:
|
||
|
damage=40;
|
||
|
break;
|
||
|
case ANIM_KNIFE_ATTACK1:
|
||
|
damage=30;
|
||
|
knifed=1;
|
||
|
break;
|
||
|
case ANIM_KNIFE_ATTACK2:
|
||
|
damage=50;
|
||
|
knifed=1;
|
||
|
break;
|
||
|
case ANIM_KNIFE_ATTACK3:
|
||
|
damage=70;
|
||
|
knifed=1;
|
||
|
break;
|
||
|
|
||
|
}
|
||
|
|
||
|
if ((Random()&0xff)<taunt_prob) // not too often or it gets annoying
|
||
|
{
|
||
|
SLONG sound=0;
|
||
|
|
||
|
switch (p_aggressor->Genus.Person->PersonType)
|
||
|
{
|
||
|
case PERSON_DARCI:
|
||
|
if (Random()&3)
|
||
|
sound=SOUND_Range(S_DARCI_FIGHT_TAUNT_START,S_DARCI_FIGHT_TAUNT_END);
|
||
|
else
|
||
|
sound=SOUND_Range(S_DARCI_DEADSAFE_TAUNT_START,S_DARCI_DEADSAFE_TAUNT_END);
|
||
|
break;
|
||
|
case PERSON_ROPER:
|
||
|
if (Random()&2)
|
||
|
sound=SOUND_Range(S_ROPER_FIGHT_TAUNT_START,S_ROPER_FIGHT_TAUNT_END);
|
||
|
else
|
||
|
sound=SOUND_Range(S_ROPER_DEADSAFE_TAUNT_START,S_ROPER_DEADSAFE_TAUNT_END);
|
||
|
break;
|
||
|
case PERSON_COP:
|
||
|
sound=SOUND_Range(S_COP_TAUNT_START,S_COP_TAUNT_END);
|
||
|
break;
|
||
|
case PERSON_CIV:
|
||
|
break;
|
||
|
case PERSON_THUG_RASTA:
|
||
|
sound=SOUND_Range(S_RASTA_TAUNT_START,S_RASTA_TAUNT_END);
|
||
|
break;
|
||
|
case PERSON_THUG_GREY:
|
||
|
sound=SOUND_Range(S_GGREY_TAUNT_START,S_GGREY_TAUNT_END);
|
||
|
break;
|
||
|
case PERSON_THUG_RED:
|
||
|
if (THING_NUMBER(p_aggressor)&1)
|
||
|
sound=SOUND_Range(S_GRED_TAUNT_START,S_GRED_TAUNT_END);
|
||
|
else
|
||
|
sound=SOUND_Range(S_GRED2_TAUNT_START,S_GRED2_TAUNT_END);
|
||
|
break;
|
||
|
}
|
||
|
if (sound) MFX_play_thing(THING_NUMBER(p_aggressor),sound,MFX_QUEUED|MFX_SHORT_QUEUE,p_aggressor);
|
||
|
}
|
||
|
|
||
|
|
||
|
if(hit=fight_tree[node][FIGHT_TREE_DAMAGE])
|
||
|
{
|
||
|
damage+=hit;
|
||
|
}
|
||
|
|
||
|
// ASSERT(damage);
|
||
|
|
||
|
}
|
||
|
else
|
||
|
if(damage<30)
|
||
|
{
|
||
|
damage=30;
|
||
|
}
|
||
|
if(is_person_ko_and_lay_down(p_thing))
|
||
|
{
|
||
|
//
|
||
|
// checked all through this function, so may as well have a local flag
|
||
|
//
|
||
|
|
||
|
//
|
||
|
// victim is unconscious
|
||
|
//
|
||
|
ko_ed=1;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
if(p_aggressor->Genus.Person->PersonType==PERSON_ROPER)
|
||
|
{
|
||
|
if(shot)
|
||
|
damage<<=1;
|
||
|
else
|
||
|
damage+=20;
|
||
|
|
||
|
}
|
||
|
if(p_aggressor->Genus.Person->PlayerID)
|
||
|
{
|
||
|
//
|
||
|
// more skill better aim with guns, more strength harder you hit
|
||
|
//
|
||
|
if(shot)
|
||
|
damage+=NET_PLAYER(p_aggressor->Genus.Person->PlayerID-1)->Genus.Player->Skill;
|
||
|
else
|
||
|
damage+=NET_PLAYER(p_aggressor->Genus.Person->PlayerID-1)->Genus.Player->Strength;
|
||
|
}
|
||
|
|
||
|
if(player_hit)
|
||
|
{
|
||
|
|
||
|
//
|
||
|
// player hit by player
|
||
|
//
|
||
|
void PCOM_new_gang_attack(Thing *p_person, Thing *p_target);
|
||
|
if(shot==0)
|
||
|
if(p_aggressor->Genus.Person->PlayerID)
|
||
|
{
|
||
|
//
|
||
|
// give victim a gang attack group
|
||
|
//
|
||
|
PCOM_new_gang_attack(p_aggressor, p_thing);
|
||
|
}
|
||
|
|
||
|
damage>>=1;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
//
|
||
|
// skillful people get hurt less
|
||
|
//
|
||
|
skill=GET_SKILL(p_thing);
|
||
|
damage-=skill;
|
||
|
|
||
|
if(damage<=0)
|
||
|
{
|
||
|
damage=2;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
//
|
||
|
//skillful people hurt you more
|
||
|
//
|
||
|
damage+=GET_SKILL(p_aggressor);
|
||
|
|
||
|
{
|
||
|
extern void emergency_uncarry(Thing *p_person);
|
||
|
|
||
|
ASSERT(p_thing->Class == CLASS_PERSON);
|
||
|
|
||
|
if (p_thing->Genus.Person->Flags2 & FLAG2_PERSON_CARRYING)
|
||
|
{
|
||
|
emergency_uncarry(p_thing);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (p_thing->SubState==SUB_STATE_BLOCK && (type==0 || type > HIT_TYPE_GUN_SHOT_L))
|
||
|
{
|
||
|
block = 1;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
p_thing->Genus.Person->Agression-=damage;
|
||
|
if(p_thing->Genus.Person->Agression>0)
|
||
|
p_thing->Genus.Person->Agression=0;
|
||
|
|
||
|
|
||
|
p_aggressor->Genus.Person->Agression+=damage;
|
||
|
if(p_aggressor->Genus.Person->Agression<0)
|
||
|
p_aggressor->Genus.Person->Agression=0;
|
||
|
}
|
||
|
|
||
|
|
||
|
// if((p_thing->Genus.Person->Flags&FLAG_PERSON_KO))
|
||
|
|
||
|
if(ko_ed)
|
||
|
{
|
||
|
//
|
||
|
// you are knocked out, and the bad guy is not stomping you
|
||
|
//
|
||
|
if(!stomped && !shot)
|
||
|
{
|
||
|
return(0);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// you are stomped so leave stomped true
|
||
|
}
|
||
|
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
//
|
||
|
// can'y be stomped if your not ko'ed
|
||
|
//
|
||
|
stomped=0;
|
||
|
}
|
||
|
|
||
|
if(is_person_dead(p_thing))
|
||
|
return(0);
|
||
|
|
||
|
if (p_thing->SubState==SUB_STATE_GRAPPLE_HELD||p_thing->SubState==SUB_STATE_GRAPPLE_ATTACK||p_thing->SubState==SUB_STATE_ESCAPE)
|
||
|
return(0);
|
||
|
|
||
|
behind=check_hit_from_behind(p_thing,p_aggressor);
|
||
|
if(behind>0)
|
||
|
behind=1;
|
||
|
else
|
||
|
behind=0;
|
||
|
|
||
|
//
|
||
|
// if victim is player then set victim to attack aggressor
|
||
|
//
|
||
|
if(shot==0)
|
||
|
{
|
||
|
if(p_thing->Genus.Person->PlayerID)
|
||
|
{
|
||
|
if(p_thing->Genus.Person->Target==0)
|
||
|
{
|
||
|
extern void person_enter_fight_mode(Thing *p_person);
|
||
|
person_enter_fight_mode(p_thing);
|
||
|
p_thing->Genus.Person->Target=THING_NUMBER(p_aggressor);
|
||
|
ASSERT(p_thing->Genus.Person->Target !=THING_NUMBER(p_thing));
|
||
|
ASSERT(TO_THING(p_thing->Genus.Person->Target)->Class==CLASS_PERSON);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//should look up in a table what anim to go into given the type of hit
|
||
|
//and their current state
|
||
|
|
||
|
// for now just bodge a hit anim
|
||
|
|
||
|
draw_info=p_thing->Draw.Tweened;
|
||
|
|
||
|
MFX_stop(THING_NUMBER(p_thing),S_SEARCH_END);
|
||
|
|
||
|
if(block==0)
|
||
|
{
|
||
|
SLONG pain=0;
|
||
|
if(p_thing==talk_thing)
|
||
|
{
|
||
|
PainSound(p_thing);
|
||
|
pain=1;
|
||
|
check_eway_talk(1);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// The sound of the hit
|
||
|
//
|
||
|
|
||
|
switch(type)
|
||
|
{
|
||
|
case HIT_TYPE_GUN_SHOT_H:
|
||
|
case HIT_TYPE_GUN_SHOT_M:
|
||
|
case HIT_TYPE_GUN_SHOT_L:
|
||
|
case HIT_TYPE_GUN_SHOT_PISTOL:
|
||
|
case HIT_TYPE_GUN_SHOT_SHOTGUN:
|
||
|
case HIT_TYPE_GUN_SHOT_AK47:
|
||
|
/* hit_wave = ((rand()*(S_PUNCH_END-S_PUNCH_START))>>16)+S_PUNCH_START;
|
||
|
hit_wave = S_MALE_DIE_1;
|
||
|
MFX_play_xyz(0,hit_wave,0,p_thing->WorldPos.X,p_thing->WorldPos.Y,p_thing->WorldPos.Z);*/
|
||
|
|
||
|
break;
|
||
|
default:
|
||
|
// a droplet of blood
|
||
|
calc_sub_objects_position(
|
||
|
p_aggressor,
|
||
|
p_aggressor->Draw.Tweened->AnimTween,
|
||
|
SUB_OBJECT_LEFT_HAND,
|
||
|
&vec.X,
|
||
|
&vec.Y,
|
||
|
&vec.Z);
|
||
|
vec.X+=(Random()&0x1f);
|
||
|
vec.Y+=(Random()&0x1f);
|
||
|
vec.Z+=(Random()&0x1f);
|
||
|
vec.X<<=8; vec.Y<<=8; vec.Z<<=8;
|
||
|
vec.X+=p_thing->WorldPos.X;
|
||
|
vec.Y+=p_thing->WorldPos.Y;
|
||
|
vec.Z+=p_thing->WorldPos.Z;
|
||
|
|
||
|
|
||
|
//#ifndef VERSION_GERMAN
|
||
|
if(VIOLENCE)
|
||
|
DIRT_new_water(vec.X>>8, vec.Y>>8, vec.Z>>8, (Random()&0xf)-7, 0, (Random()&0xf)-7, DIRT_TYPE_BLOOD);
|
||
|
//#endif
|
||
|
if (knifed)
|
||
|
{
|
||
|
//#ifndef PSX
|
||
|
hit_wave = SOUND_Range(S_STAB_START,S_STAB_END);
|
||
|
MFX_play_xyz(0,hit_wave,0,p_thing->WorldPos.X,p_thing->WorldPos.Y,p_thing->WorldPos.Z);
|
||
|
//#else
|
||
|
|
||
|
#ifdef PSX
|
||
|
MFX_play_thing(THING_NUMBER(p_aggressor),S_KNIFE_START+(Random()&1),0,p_aggressor);
|
||
|
#endif
|
||
|
//#endif
|
||
|
|
||
|
//#ifndef VERSION_GERMAN
|
||
|
if(VIOLENCE)
|
||
|
for (hit_wave=0;hit_wave<5;hit_wave++)
|
||
|
DIRT_new_water(vec.X>>8, vec.Y>>8, vec.Z>>8, (Random()&0xf)-7, 0, (Random()&0xf)-7, DIRT_TYPE_BLOOD);
|
||
|
//#endif
|
||
|
}
|
||
|
else
|
||
|
if (batted)
|
||
|
{
|
||
|
//#ifndef PSX
|
||
|
if (SOUND_Gender(p_thing)==1)
|
||
|
hit_wave = SOUND_Range(S_BAT_MALE_START,S_BAT_MALE_END);
|
||
|
else
|
||
|
hit_wave = SOUND_Range(S_BAT_FEMALE_START,S_BAT_FEMALE_END);
|
||
|
|
||
|
//#else
|
||
|
// hit_wave = S_BAT_MALE_START;
|
||
|
//#endif
|
||
|
MFX_play_xyz(0,hit_wave,0,p_thing->WorldPos.X,p_thing->WorldPos.Y,p_thing->WorldPos.Z);
|
||
|
|
||
|
}
|
||
|
else
|
||
|
if (nad)
|
||
|
MFX_play_thing(THING_NUMBER(p_thing),SOUND_Range(S_KICK_IN_THE_NUTS_START,S_KICK_IN_THE_NUTS_END),0,p_thing);
|
||
|
else
|
||
|
{
|
||
|
hit_wave = S_PUNCH_START+(GAME_TURN&3);
|
||
|
MFX_play_xyz(0,hit_wave,0,p_thing->WorldPos.X,p_thing->WorldPos.Y,p_thing->WorldPos.Z);
|
||
|
if(!pain)
|
||
|
PainSound(p_thing);
|
||
|
}
|
||
|
// do a lil bloodsplat
|
||
|
|
||
|
if(VIOLENCE)
|
||
|
{
|
||
|
calc_sub_objects_position(
|
||
|
p_thing,
|
||
|
p_thing->Draw.Tweened->AnimTween,
|
||
|
SUB_OBJECT_LEFT_HAND,
|
||
|
&vec.X,
|
||
|
&vec.Y,
|
||
|
&vec.Z);
|
||
|
vec.X+=(Random()&0x1f);
|
||
|
vec.Y+=(Random()&0x1f);
|
||
|
vec.Z+=(Random()&0x1f);
|
||
|
vec.X<<=8; vec.Y<<=8; vec.Z<<=8;
|
||
|
vec.X+=p_thing->WorldPos.X;
|
||
|
vec.Y+=p_thing->WorldPos.Y;
|
||
|
vec.Z+=p_thing->WorldPos.Z;
|
||
|
//#ifndef VERSION_GERMAN
|
||
|
PARTICLE_Add(vec.X,vec.Y,vec.Z,0,0,0,
|
||
|
POLY_PAGE_SMOKECLOUD2,2+((Random()&3)<<2),0x7FFF0000,
|
||
|
PFLAG_SPRITEANI|PFLAG_SPRITELOOP|PFLAG_FADE,10,75,1,20,5);
|
||
|
//#endif
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if ((p_thing->Genus.Person->pcom_bent & PCOM_BENT_PLAYERKILL) && (!p_aggressor || !p_aggressor->Genus.Person->PlayerID))
|
||
|
{
|
||
|
//
|
||
|
// Only the player can hurt this person.
|
||
|
//
|
||
|
}
|
||
|
else
|
||
|
if (p_thing->Genus.Person->Flags2 & FLAG2_PERSON_INVULNERABLE)
|
||
|
{
|
||
|
//
|
||
|
// Nothing hurts this person.
|
||
|
//
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
//
|
||
|
// Actually hurt the person.
|
||
|
//
|
||
|
|
||
|
p_thing->Genus.Person->Health -= damage;
|
||
|
#ifdef PSX
|
||
|
// Shock the player dependant on damage
|
||
|
if (p_thing->Genus.Person->PlayerID)
|
||
|
{
|
||
|
SLONG dam=(damage<<4)+96;
|
||
|
if (dam>255) dam=255;
|
||
|
PSX_SetShock(1,dam);
|
||
|
}
|
||
|
#endif
|
||
|
#ifdef TARGET_DC
|
||
|
if ( p_thing->Genus.Person->PlayerID )
|
||
|
{
|
||
|
Vibrate ( 5.0f, (float)( (damage<<4)+94 ) * 0.002f, 0.0f );
|
||
|
}
|
||
|
if ( p_aggressor->Genus.Person->PlayerID )
|
||
|
{
|
||
|
switch(type)
|
||
|
{
|
||
|
case HIT_TYPE_GUN_SHOT_H:
|
||
|
case HIT_TYPE_GUN_SHOT_M:
|
||
|
case HIT_TYPE_GUN_SHOT_L:
|
||
|
case HIT_TYPE_GUN_SHOT_PISTOL:
|
||
|
case HIT_TYPE_GUN_SHOT_SHOTGUN:
|
||
|
case HIT_TYPE_GUN_SHOT_AK47:
|
||
|
// You don't get a vibro from hitting someone with a gun (just from shooting it, done elsewhere).
|
||
|
break;
|
||
|
default:
|
||
|
// Hand-to-hand combat. Feel the knuckles crunch into their nose.
|
||
|
// Less damage-dependant jolt this time.
|
||
|
Vibrate ( 5.0f, (float)( (damage<<2)+120 ) * 0.004f, 0.0f );
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// make damage value display on screen and drift upwards
|
||
|
//
|
||
|
|
||
|
// add_damage_value_thing(p_thing,damage>>1);
|
||
|
|
||
|
if(p_thing->Genus.Person->Health<=0)
|
||
|
{
|
||
|
if (p_aggressor)
|
||
|
{
|
||
|
p_aggressor->Genus.Person->Flags2 |= FLAG2_PERSON_IS_MURDERER;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// death type will one day be hit from behind or shot from front or ...
|
||
|
//
|
||
|
|
||
|
p_thing->Genus.Person->Health = 0;
|
||
|
|
||
|
if(stomped && ko_ed==0)
|
||
|
{
|
||
|
ASSERT(0);
|
||
|
}
|
||
|
if (!is_there_room_behind_person(p_thing, behind))
|
||
|
{
|
||
|
behind = !behind;
|
||
|
}
|
||
|
|
||
|
if(ko_ed) //(p_thing->Genus.Person->Flags&FLAG_PERSON_KO))
|
||
|
{
|
||
|
p_thing->Genus.Person->Flags &= ~(FLAG_PERSON_KO | FLAG_PERSON_HELPLESS);
|
||
|
|
||
|
set_person_dead(
|
||
|
p_thing,
|
||
|
p_aggressor,
|
||
|
PERSON_DEATH_TYPE_COMBAT_PRONE,
|
||
|
behind,
|
||
|
0);
|
||
|
}
|
||
|
else
|
||
|
if(fight)
|
||
|
{
|
||
|
set_person_dead(
|
||
|
p_thing,
|
||
|
p_aggressor,
|
||
|
PERSON_DEATH_TYPE_COMBAT,
|
||
|
behind,
|
||
|
fight->Height & 0x3);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
SLONG death_type=PERSON_DEATH_TYPE_COMBAT;
|
||
|
extern SLONG really_on_floor(Thing *p_person);
|
||
|
|
||
|
if(shot)
|
||
|
{
|
||
|
if(person_on_floor(p_thing)&&p_thing->OnFace==0&&really_on_floor(p_thing))
|
||
|
{
|
||
|
switch(type)
|
||
|
{
|
||
|
case HIT_TYPE_GUN_SHOT_PISTOL:
|
||
|
death_type=PERSON_DEATH_TYPE_SHOT_PISTOL;
|
||
|
break;
|
||
|
case HIT_TYPE_GUN_SHOT_SHOTGUN:
|
||
|
death_type=PERSON_DEATH_TYPE_SHOT_SHOTGUN;
|
||
|
break;
|
||
|
case HIT_TYPE_GUN_SHOT_AK47:
|
||
|
death_type=PERSON_DEATH_TYPE_SHOT_AK47;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// ASSERT(0);
|
||
|
death_type=PERSON_DEATH_TYPE_COMBAT;
|
||
|
|
||
|
}
|
||
|
|
||
|
}
|
||
|
set_person_dead(
|
||
|
p_thing,
|
||
|
p_aggressor,
|
||
|
death_type,
|
||
|
behind,
|
||
|
0);
|
||
|
}
|
||
|
|
||
|
return(damage);
|
||
|
}
|
||
|
|
||
|
if(!shot)
|
||
|
{
|
||
|
if(person_has_gun_out(p_thing))
|
||
|
{
|
||
|
// ASSERT(0);
|
||
|
drop_current_gun(p_thing,0);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
if(p_aggressor->Genus.Person->PlayerID)
|
||
|
{
|
||
|
//its a player so keep score
|
||
|
|
||
|
track_enemy(p_thing);
|
||
|
|
||
|
GAME_SCORE(p_aggressor->Genus.Person->PlayerID-1)+=10;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Turn to face aggressor. unless you are a player
|
||
|
//
|
||
|
|
||
|
if(!p_thing->Genus.Person->PlayerID)
|
||
|
// if((p_thing->Genus.Person->Flags&FLAG_PERSON_KO)==0)
|
||
|
if(!ko_ed)
|
||
|
if(!behind)
|
||
|
set_face_thing(p_thing, p_aggressor);
|
||
|
|
||
|
// switch(fight->Height)
|
||
|
//
|
||
|
// Tell the AI module that you've been hit. (only by a player for now)
|
||
|
//
|
||
|
|
||
|
// if(p_aggressor->Genus.Person->PlayerID)
|
||
|
if( !ko_ed && p_thing->Genus.Person->PlayerID==0)
|
||
|
{
|
||
|
PCOM_attack_happened(
|
||
|
p_thing,
|
||
|
p_aggressor);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// if((p_thing->Genus.Person->Flags&FLAG_PERSON_KO)==0)
|
||
|
if(!ko_ed)
|
||
|
{
|
||
|
SLONG anim,flag;
|
||
|
SLONG height;
|
||
|
UBYTE history;
|
||
|
|
||
|
if(fight)
|
||
|
{
|
||
|
height=fight->Height;
|
||
|
height&=3;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
height=2;
|
||
|
}
|
||
|
|
||
|
MSG_add(" take hit height %d behind %d \n",height,behind);
|
||
|
ASSERT(height+behind*3<=5);
|
||
|
anim = take_hit[height+behind*3][0];
|
||
|
flag = take_hit[height+behind*3][1];
|
||
|
|
||
|
#ifdef UNUSED
|
||
|
history=p_thing->Genus.Person->BlockHistory;
|
||
|
if(history==0)
|
||
|
history=get_block_history(p_thing);
|
||
|
if(block&&height!=0)
|
||
|
{
|
||
|
set_block_history_result(history,THING_NUMBER(p_aggressor),1,height); //1 is blocked
|
||
|
|
||
|
}
|
||
|
else
|
||
|
#endif
|
||
|
|
||
|
if(block&&height!=0)
|
||
|
{
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
|
||
|
#ifdef UNUSED
|
||
|
set_block_history_result(history,THING_NUMBER(p_aggressor),0,height); //0 is not blocked
|
||
|
#endif
|
||
|
|
||
|
|
||
|
|
||
|
// if(hit_anim==ANIM_KICK_RIGHT || hit_anim==ANIM_KICK_LEFT || hit_anim==ANIM_KICK_BEHIND || hit_anim==ANIM_PUNCH_COMBO3 || hit_anim==ANIM_KICK_COMBO3|| hit_anim==ANIM_KICK_COMBO3b|| hit_anim==ANIM_PUNCH_COMBO3b)
|
||
|
if(ko)
|
||
|
{
|
||
|
//
|
||
|
// not really dead, just knocked out
|
||
|
//
|
||
|
p_thing->Genus.Person->Agression=-60; //make them backoff
|
||
|
|
||
|
if (!is_there_room_behind_person(p_thing, behind))
|
||
|
{
|
||
|
behind = !behind;
|
||
|
}
|
||
|
|
||
|
set_person_dead(
|
||
|
p_thing,
|
||
|
0,
|
||
|
PERSON_DEATH_TYPE_STAY_ALIVE,
|
||
|
behind,
|
||
|
0);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if(height==0)
|
||
|
{
|
||
|
extern void sweep_feet(Thing *p_person,Thing *p_aggressor,SLONG death_type);
|
||
|
|
||
|
sweep_feet(p_thing,p_aggressor,0);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if(shot && p_thing->Genus.Person->PlayerID && p_thing->State==STATE_MOVEING)
|
||
|
{
|
||
|
//
|
||
|
// players don't recoil when shot if moveing
|
||
|
//
|
||
|
return(damage);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
|
||
|
if(nad)
|
||
|
{
|
||
|
set_person_recoil(p_thing,ANIM_KICK_NAD_TAKE,flag);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
set_person_recoil(p_thing,anim,flag);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
SLONG anim;
|
||
|
|
||
|
//
|
||
|
// Is this person on their front or back?
|
||
|
//
|
||
|
|
||
|
switch(person_is_lying_on_what(p_thing))
|
||
|
{
|
||
|
case PERSON_ON_HIS_FRONT:
|
||
|
anim = ANIM_FIGHT_STOMPED_BACK;
|
||
|
break;
|
||
|
|
||
|
case PERSON_ON_HIS_BACK:
|
||
|
anim = ANIM_FIGHT_STOMPED_FRONT;
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
// headbutted people cause a crash
|
||
|
ASSERT(0);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
set_person_ko_recoil(p_thing,anim,0);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Make sure that others can hear the hoo-har.
|
||
|
//
|
||
|
|
||
|
PCOM_oscillate_tympanum(
|
||
|
PCOM_SOUND_FIGHT,
|
||
|
p_aggressor,
|
||
|
p_aggressor->WorldPos.X >> 8,
|
||
|
p_aggressor->WorldPos.Y >> 8,
|
||
|
p_aggressor->WorldPos.Z >> 8);
|
||
|
|
||
|
|
||
|
if(block)
|
||
|
return(0);
|
||
|
else
|
||
|
return(damage);
|
||
|
}
|
||
|
|
||
|
extern UBYTE semtex;
|
||
|
|
||
|
SLONG people_allowed_to_hit_each_other(Thing *p_victim,Thing *p_agressor)
|
||
|
{
|
||
|
ULONG will_hit=0xffffffff;
|
||
|
|
||
|
if(p_agressor->Genus.Person->PlayerID==0)
|
||
|
if(p_agressor->Genus.Person->Target&&p_agressor->Genus.Person->Target==THING_NUMBER(p_victim))
|
||
|
{
|
||
|
|
||
|
|
||
|
if(p_agressor->Genus.Person->PersonType==PERSON_COP)
|
||
|
ASSERT(p_victim->Genus.Person->PersonType!=PERSON_COP); //cop deliberatly hitting other cop
|
||
|
if(p_agressor->Genus.Person->PersonType==PERSON_ROPER)
|
||
|
{
|
||
|
if(p_victim->Genus.Person->PersonType==PERSON_TRAMP)
|
||
|
{
|
||
|
extern UBYTE estate;
|
||
|
if(estate)
|
||
|
return(0);
|
||
|
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// deliberate aimed blow
|
||
|
//
|
||
|
return(1);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Bodyguards aren't allowed to hit the person they're protecting.
|
||
|
//
|
||
|
|
||
|
if (p_agressor->Genus.Person->pcom_ai == PCOM_AI_BODYGUARD)
|
||
|
{
|
||
|
UWORD i_client = EWAY_get_person(p_agressor->Genus.Person->pcom_ai_other);
|
||
|
|
||
|
if (i_client == THING_NUMBER(p_victim))
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// People in the same gang like eachother.
|
||
|
//
|
||
|
|
||
|
if (p_victim->Genus.Person->pcom_bent & p_agressor->Genus.Person->pcom_bent & PCOM_BENT_GANG)
|
||
|
{
|
||
|
if (p_victim ->Genus.Person->pcom_colour ==
|
||
|
p_agressor->Genus.Person->pcom_colour)
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
switch(p_agressor->Genus.Person->PersonType)
|
||
|
{
|
||
|
case PERSON_DARCI:
|
||
|
//
|
||
|
// won't hit cops or roper
|
||
|
//
|
||
|
|
||
|
if(p_victim->Genus.Person->Flags2&FLAG2_PERSON_GUILTY)
|
||
|
return(1);
|
||
|
|
||
|
if(VIOLENCE==0)
|
||
|
{
|
||
|
if(p_victim->Genus.Person->PersonType==PERSON_CIV&& (p_victim->Genus.Person->Flags2 & FLAG2_PERSON_FAKE_WANDER))
|
||
|
{
|
||
|
return(0);
|
||
|
}
|
||
|
if((p_victim->Genus.Person->PersonType==PERSON_CIV && p_victim->Genus.Person->pcom_ai == PCOM_AI_CIV)||p_victim->Genus.Person->PersonType==PERSON_HOSTAGE)
|
||
|
{
|
||
|
return(0);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
#if DARCI_HITS_COPS
|
||
|
will_hit^=(/*(1<<PERSON_COP)|*/(1<<PERSON_ROPER));
|
||
|
#else
|
||
|
will_hit ^= (1<<PERSON_COP)| (1<<PERSON_ROPER);
|
||
|
#endif
|
||
|
|
||
|
if(semtex)
|
||
|
will_hit ^= (1<<PERSON_TRAMP);
|
||
|
|
||
|
break;
|
||
|
|
||
|
case PERSON_TRAMP:
|
||
|
if(semtex)
|
||
|
{
|
||
|
will_hit ^= (1<<PERSON_DARCI);
|
||
|
will_hit^=((1<<PERSON_THUG_GREY)|(1<<PERSON_THUG_RASTA)|(1<<PERSON_THUG_RED));
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
|
||
|
case PERSON_ROPER:
|
||
|
|
||
|
if(p_agressor->Genus.Person->PlayerID==0)
|
||
|
if(p_victim->Genus.Person->PersonType==PERSON_TRAMP)
|
||
|
{
|
||
|
|
||
|
extern UBYTE estate;
|
||
|
if(estate)
|
||
|
{
|
||
|
return(0);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
if(VIOLENCE==0)
|
||
|
{
|
||
|
if(p_victim->Genus.Person->PersonType==PERSON_CIV&& (p_victim->Genus.Person->Flags2 & FLAG2_PERSON_FAKE_WANDER))
|
||
|
{
|
||
|
return(0);
|
||
|
}
|
||
|
if((p_victim->Genus.Person->PersonType==PERSON_CIV && p_victim->Genus.Person->pcom_ai == PCOM_AI_CIV)||p_victim->Genus.Person->PersonType==PERSON_HOSTAGE)
|
||
|
{
|
||
|
return(0);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// won't hit darci or cops
|
||
|
//
|
||
|
#if DARCI_HITS_COPS
|
||
|
will_hit^=(/*(1<<PERSON_COP)|*/(1<<PERSON_DARCI));
|
||
|
#else
|
||
|
will_hit^=((1<<PERSON_COP)|(1<<PERSON_DARCI));
|
||
|
#endif
|
||
|
break;
|
||
|
|
||
|
case PERSON_COP:
|
||
|
//
|
||
|
// will hit any fellon
|
||
|
//
|
||
|
// ASSERT(p_victim->Genus.Person->PersonType!=PERSON_COP);
|
||
|
if(p_victim->Genus.Person->Flags&FLAG_PERSON_FELON)
|
||
|
{
|
||
|
ASSERT(p_victim->Genus.Person->PersonType!=PERSON_COP);
|
||
|
return(1);
|
||
|
}
|
||
|
if(p_victim->Genus.Person->Flags2&FLAG2_PERSON_GUILTY)
|
||
|
{
|
||
|
ASSERT(p_victim->Genus.Person->PersonType!=PERSON_COP);
|
||
|
return(1);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// won't hit darci, other cops,roper or civilians
|
||
|
//
|
||
|
will_hit^=((1<<PERSON_COP)|(1<<PERSON_DARCI)|(1<<PERSON_ROPER));
|
||
|
/*
|
||
|
#if DARCI_HITS_COPS
|
||
|
will_hit^=((1<<PERSON_COP));
|
||
|
#else
|
||
|
will_hit^=((1<<PERSON_COP)|(1<<PERSON_DARCI)|(1<<PERSON_ROPER)|(1<<PERSON_CIV));
|
||
|
#endif
|
||
|
*/
|
||
|
break;
|
||
|
case PERSON_THUG_GREY:
|
||
|
case PERSON_THUG_RASTA:
|
||
|
case PERSON_THUG_RED:
|
||
|
if(p_agressor->Genus.Person->PlayerID)
|
||
|
{
|
||
|
//
|
||
|
// player is a thug, they can hit anyone
|
||
|
//
|
||
|
|
||
|
return(1);
|
||
|
}
|
||
|
//
|
||
|
// can't hit other thugs or MIB's
|
||
|
//
|
||
|
will_hit^=((1<<PERSON_THUG_GREY)|(1<<PERSON_THUG_RASTA)|(1<<PERSON_THUG_RED));
|
||
|
will_hit^=((1<<PERSON_MIB1)|(1<<PERSON_MIB2)|(1<<PERSON_MIB3));
|
||
|
if(semtex)
|
||
|
will_hit ^= (1<<PERSON_TRAMP);
|
||
|
|
||
|
|
||
|
break;
|
||
|
case PERSON_MIB1:
|
||
|
case PERSON_MIB2:
|
||
|
case PERSON_MIB3:
|
||
|
|
||
|
|
||
|
//
|
||
|
// won't hit someone of same group && colour, unless it's deliberate see above
|
||
|
//
|
||
|
|
||
|
/*
|
||
|
if(p_victim->Genus.Person->pcom_colour==p_agressor->Genus.Person->pcom_colour &&
|
||
|
p_victim->Genus.Person->pcom_group==p_agressor->Genus.Person->pcom_group)
|
||
|
{
|
||
|
return(0);
|
||
|
}
|
||
|
*/
|
||
|
|
||
|
//
|
||
|
// won't hit other MIB's
|
||
|
//
|
||
|
will_hit^=((1<<PERSON_MIB1)|(1<<PERSON_MIB2)|(1<<PERSON_MIB3));
|
||
|
break;
|
||
|
|
||
|
}
|
||
|
if(will_hit & (1<<p_victim->Genus.Person->PersonType))
|
||
|
{
|
||
|
//
|
||
|
// The flags have spoken and they have said yes, strike him...
|
||
|
//
|
||
|
|
||
|
if ((p_victim ->Genus.Person->pcom_bent & PCOM_BENT_GANG) &&
|
||
|
(p_agressor->Genus.Person->pcom_bent & PCOM_BENT_GANG) &&
|
||
|
(p_victim ->Genus.Person->pcom_colour == p_agressor->Genus.Person->pcom_colour))
|
||
|
{
|
||
|
//
|
||
|
// Don't hit someone in your own gang.
|
||
|
//
|
||
|
|
||
|
return(0);
|
||
|
}
|
||
|
|
||
|
if(p_agressor->Genus.Person->PersonType==PERSON_COP)
|
||
|
ASSERT(p_victim->Genus.Person->PersonType!=PERSON_COP); //cop deliberatly hitting other cop
|
||
|
return(1);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return(0);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
SLONG find_combat_target(struct GameFightCol *p_fight,SLONG x,SLONG y,SLONG z,Thing *p_thing)
|
||
|
{
|
||
|
SLONG i;
|
||
|
SLONG hit;
|
||
|
SLONG angle;
|
||
|
|
||
|
Thing *t_thing;
|
||
|
|
||
|
//
|
||
|
// Find all the people near us.
|
||
|
//
|
||
|
|
||
|
// THING_INDEX found[16];
|
||
|
SLONG found_upto;
|
||
|
|
||
|
found_upto = THING_find_sphere(x, y, z, 0x280, found, 16, (1 << CLASS_PERSON));
|
||
|
|
||
|
//
|
||
|
// Check each person in turn.
|
||
|
//
|
||
|
|
||
|
hit = 0;
|
||
|
|
||
|
for (i = 0; i < found_upto; i++)
|
||
|
{
|
||
|
t_thing = TO_THING(found[i]);
|
||
|
|
||
|
if (t_thing != p_thing) //&& t_thing->SubState!=SUB_STATE_BLOCK)
|
||
|
{
|
||
|
if(people_allowed_to_hit_each_other(t_thing,p_thing))
|
||
|
{
|
||
|
|
||
|
if(t_thing->SubState!=SUB_STATE_FLIPING)
|
||
|
if(t_thing->Draw.Tweened->CurrentAnim!=ANIM_SLIDER_HOLD)
|
||
|
if(t_thing->Draw.Tweened->CurrentAnim!=ANIM_KICK_NS)
|
||
|
if(t_thing->Draw.Tweened->CurrentAnim!=ANIM_LEG_SWEEP)
|
||
|
{
|
||
|
if (check_combat_hit_with_person(
|
||
|
t_thing,
|
||
|
x, y, z,
|
||
|
p_fight,
|
||
|
p_thing,
|
||
|
&angle) > 0)
|
||
|
{
|
||
|
hit += apply_hit_to_person(t_thing,0,0,0,p_thing,p_fight);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return hit;
|
||
|
|
||
|
/*
|
||
|
|
||
|
|
||
|
SLONG dx,dz;
|
||
|
SLONG index;
|
||
|
Thing *t_thing;
|
||
|
SLONG hit=0;
|
||
|
SLONG angle;
|
||
|
|
||
|
for(dx=-2;dx<3;dx++)
|
||
|
for(dz=-2;dz<3;dz++)
|
||
|
{
|
||
|
SLONG mx,mz;
|
||
|
mx=(x>>ELE_SHIFT)+dx;
|
||
|
mz=(z>>ELE_SHIFT)+dz;
|
||
|
index=MAP[MAP_INDEX(mx,mz)].MapWho;
|
||
|
while(index)
|
||
|
{
|
||
|
t_thing = TO_THING(index);
|
||
|
if(t_thing!=p_thing)
|
||
|
{
|
||
|
LogText(" found a thing at dx dz %d %d of type %d\n",dx,dz,t_thing->DrawType);
|
||
|
switch(t_thing->DrawType)
|
||
|
{
|
||
|
case DT_ROT_MULTI:
|
||
|
LogText(" its a figure \n");
|
||
|
if(check_combat_hit_with_person(t_thing,x,y,z,p_fight,p_thing,&angle)>0)
|
||
|
{
|
||
|
hit+=apply_hit_to_person(t_thing,0,0,0,p_thing,p_fight);
|
||
|
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
|
||
|
}
|
||
|
}
|
||
|
index = t_thing->Child;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return(hit);
|
||
|
|
||
|
*/
|
||
|
}
|
||
|
|
||
|
|
||
|
SLONG apply_violence(Thing *p_thing)
|
||
|
{
|
||
|
|
||
|
struct GameFightCol *fight_info;
|
||
|
SLONG hits=0,count=0;
|
||
|
SLONG x,y,z;
|
||
|
// show_fight_range(p_thing);
|
||
|
calc_sub_objects_position(p_thing,p_thing->Draw.Tweened->AnimTween,0,&x,&y,&z);
|
||
|
x+=p_thing->WorldPos.X>>8;
|
||
|
y+=p_thing->WorldPos.Y>>8;
|
||
|
z+=p_thing->WorldPos.Z>>8;
|
||
|
|
||
|
LogText(" thing apply's violence\n");
|
||
|
fight_info=p_thing->Draw.Tweened->CurrentFrame->Fight;
|
||
|
|
||
|
while(fight_info&&count++<5)
|
||
|
{
|
||
|
|
||
|
LogText(" my pos %d %d %d \n",x,y,z);
|
||
|
|
||
|
hits+=find_combat_target(fight_info,x,y,z,p_thing);
|
||
|
fight_info=fight_info->Next;
|
||
|
}
|
||
|
ASSERT(count<5);
|
||
|
return(hits);
|
||
|
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// changed to return if it found someone to hit
|
||
|
//
|
||
|
SLONG find_attack_stance(
|
||
|
Thing *p_person,
|
||
|
SLONG attack_direction,
|
||
|
SLONG attack_distance,
|
||
|
SLONG attack_range,
|
||
|
Thing **stance_target,
|
||
|
GameCoord *stance_position,
|
||
|
SLONG *stance_angle)
|
||
|
{
|
||
|
SLONG i;
|
||
|
SLONG dx;
|
||
|
SLONG dy;
|
||
|
SLONG dz;
|
||
|
SLONG angle;
|
||
|
SLONG dist;
|
||
|
SLONG dangle;
|
||
|
SLONG wangle;
|
||
|
SLONG px;
|
||
|
SLONG py;
|
||
|
SLONG pz;
|
||
|
SLONG score;
|
||
|
SLONG min_dist;
|
||
|
SLONG max_dist;
|
||
|
|
||
|
Thing *p_target;
|
||
|
|
||
|
SLONG best_score;
|
||
|
SLONG best_angle;
|
||
|
Thing *best_target;
|
||
|
SLONG best_dist;
|
||
|
SLONG best_dx;
|
||
|
SLONG best_dz;
|
||
|
SLONG ox,oy,oz;
|
||
|
|
||
|
SLONG found_upto;
|
||
|
|
||
|
//
|
||
|
// Find all nearby people.
|
||
|
//
|
||
|
|
||
|
found_upto = THING_find_sphere(
|
||
|
p_person->WorldPos.X >> 8,
|
||
|
p_person->WorldPos.Y >> 8,
|
||
|
p_person->WorldPos.Z >> 8,
|
||
|
STANCE_RADIUS,
|
||
|
found,
|
||
|
STANCE_MAX_FIND,
|
||
|
THING_FIND_PEOPLE);
|
||
|
|
||
|
//
|
||
|
// Initialise stance.
|
||
|
//
|
||
|
|
||
|
best_target = NULL;
|
||
|
best_dist = 0;
|
||
|
best_dx = 0;
|
||
|
best_dz = 0;
|
||
|
best_angle = p_person->Draw.Tweened->Angle;
|
||
|
best_score = -INFINITY;
|
||
|
|
||
|
//
|
||
|
// The distance people are away who we consider.
|
||
|
//
|
||
|
|
||
|
#define STANCE_DIST_LEEWAY 0x60
|
||
|
|
||
|
min_dist = attack_distance - attack_range; //STANCE_DIST_LEEWAY;
|
||
|
max_dist = attack_distance + attack_range; //STANCE_DIST_LEEWAY;
|
||
|
|
||
|
//
|
||
|
// The angle that dangle is calculated relative to.
|
||
|
//
|
||
|
|
||
|
wangle = p_person->Draw.Tweened->Angle;
|
||
|
|
||
|
switch(attack_direction)
|
||
|
{
|
||
|
case FIND_DIR_FRONT: wangle += 0; break;
|
||
|
case FIND_DIR_BACK: wangle += 1024; break;
|
||
|
case FIND_DIR_LEFT: wangle += 512; break;
|
||
|
case FIND_DIR_RIGHT: wangle -= 512; break;
|
||
|
case FIND_DIR_TURN_LEFT: wangle += 256; break;
|
||
|
case FIND_DIR_TURN_RIGHT: wangle -= 256; break;
|
||
|
|
||
|
default:
|
||
|
ASSERT(0);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
wangle &= 2047;
|
||
|
|
||
|
//
|
||
|
// Look for the best person.
|
||
|
//
|
||
|
|
||
|
for (i = 0; i < found_upto; i++)
|
||
|
{
|
||
|
p_target = TO_THING(found[i]);
|
||
|
|
||
|
if (p_target == p_person)
|
||
|
{
|
||
|
//
|
||
|
// Ignore yourself!
|
||
|
//
|
||
|
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
// if ((p_target->State == STATE_DEAD || p_target->State == STATE_DYING) && !(p_target->Genus.Person->Flags&FLAG_PERSON_KO))
|
||
|
if(is_person_dead(p_target))
|
||
|
{
|
||
|
//
|
||
|
// Ignore dead people, but not knocked out people.
|
||
|
//
|
||
|
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
calc_sub_objects_position(p_target,p_target->Draw.Tweened->AnimTween,SUB_OBJECT_PELVIS,&ox,&oy,&oz);
|
||
|
dx = ox+(p_target->WorldPos.X - p_person->WorldPos.X >> 8);
|
||
|
dy = oy+(p_target->WorldPos.Y - p_person->WorldPos.Y >> 8);
|
||
|
dz = oz+(p_target->WorldPos.Z - p_person->WorldPos.Z >> 8);
|
||
|
|
||
|
dist = QDIST2(abs(dx),abs(dz));
|
||
|
|
||
|
if (!WITHIN(dist, min_dist, max_dist))
|
||
|
{
|
||
|
//
|
||
|
// Distance out of range.
|
||
|
//
|
||
|
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
angle = calc_angle(dx,dz) + 1024;
|
||
|
angle &= 2047;
|
||
|
dangle = angle_diff(angle, wangle);
|
||
|
|
||
|
//
|
||
|
// How important dangle is compared to distance.
|
||
|
//
|
||
|
|
||
|
#define STANCE_DANGLE_IMPORTANCE 4
|
||
|
|
||
|
//
|
||
|
// Score this dist and dangle.
|
||
|
//
|
||
|
|
||
|
switch(attack_direction)
|
||
|
{
|
||
|
case FIND_DIR_FRONT:
|
||
|
case FIND_DIR_BACK:
|
||
|
case FIND_DIR_LEFT:
|
||
|
case FIND_DIR_RIGHT:
|
||
|
|
||
|
if (abs(dangle) > 300)
|
||
|
{
|
||
|
//
|
||
|
// Out of range dangle.
|
||
|
//
|
||
|
|
||
|
score = -INFINITY;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
score = 0;
|
||
|
score -= dist;
|
||
|
score -= abs(dangle) << STANCE_DANGLE_IMPORTANCE;
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
|
||
|
case FIND_DIR_TURN_LEFT:
|
||
|
|
||
|
if (0 && !WITHIN(dangle, -512, 256))
|
||
|
{
|
||
|
//
|
||
|
// Out of range dangle.
|
||
|
//
|
||
|
|
||
|
score = -INFINITY;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
score = 0;
|
||
|
score -= dist;
|
||
|
score -= abs(dangle) << STANCE_DANGLE_IMPORTANCE;
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
|
||
|
case FIND_DIR_TURN_RIGHT:
|
||
|
|
||
|
if (0 && !WITHIN(dangle, -256, +512))
|
||
|
{
|
||
|
//
|
||
|
// Out of range dangle.
|
||
|
//
|
||
|
|
||
|
score = -INFINITY;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
score = 0;
|
||
|
score -= dist;
|
||
|
score -= abs(dangle) << STANCE_DANGLE_IMPORTANCE;
|
||
|
}
|
||
|
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
ASSERT(0);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Is this a better person to hit?
|
||
|
//
|
||
|
|
||
|
if (score > best_score)
|
||
|
{
|
||
|
best_score = score;
|
||
|
best_target = p_target;
|
||
|
best_angle = angle;
|
||
|
best_dx = ox;
|
||
|
best_dz = oz;
|
||
|
best_dist = dist;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (best_target)
|
||
|
{
|
||
|
//
|
||
|
// Turn to the correct dangle.
|
||
|
//
|
||
|
|
||
|
switch(attack_direction)
|
||
|
{
|
||
|
case FIND_DIR_FRONT: dangle = 0; break;
|
||
|
case FIND_DIR_BACK: dangle = 1024; break;
|
||
|
case FIND_DIR_LEFT: dangle = -512; break;
|
||
|
case FIND_DIR_RIGHT: dangle = +512; break;
|
||
|
case FIND_DIR_TURN_LEFT: dangle = 0; break;
|
||
|
case FIND_DIR_TURN_RIGHT: dangle = 0; break;
|
||
|
|
||
|
default:
|
||
|
ASSERT(0);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
angle = best_angle + dangle;
|
||
|
angle &= 2047;
|
||
|
|
||
|
//
|
||
|
// Move the correct distance from the person.
|
||
|
//
|
||
|
|
||
|
dx = SIN(best_angle) * attack_distance >> 16;
|
||
|
dz = COS(best_angle) * attack_distance >> 16;
|
||
|
|
||
|
px = (best_target->WorldPos.X >> 8) + dx+best_dx;
|
||
|
pz = (best_target->WorldPos.Z >> 8) + dz+best_dz;
|
||
|
|
||
|
py = PAP_calc_height_at_thing(p_person,px,pz);
|
||
|
|
||
|
ASSERT(WITHIN(px, 0, (PAP_SIZE_HI << PAP_SHIFT_HI) - 1));
|
||
|
ASSERT(WITHIN(pz, 0, (PAP_SIZE_HI << PAP_SHIFT_HI) - 1));
|
||
|
|
||
|
*stance_target = best_target;
|
||
|
*stance_angle = angle;
|
||
|
stance_position->X = px << 8;
|
||
|
stance_position->Y = py << 8;
|
||
|
stance_position->Z = pz << 8;
|
||
|
return(1);
|
||
|
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
*stance_target = NULL;
|
||
|
*stance_angle = p_person->Draw.Tweened->Angle;
|
||
|
*stance_position = p_person->WorldPos;
|
||
|
return(0);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// returns true if its hitting a human
|
||
|
//
|
||
|
SLONG turn_to_target(
|
||
|
Thing *p_person,
|
||
|
SLONG find_dir)
|
||
|
{
|
||
|
Thing *stance_target;
|
||
|
GameCoord stance_position;
|
||
|
SLONG stance_angle;
|
||
|
SLONG ret;
|
||
|
|
||
|
ret=find_attack_stance(
|
||
|
p_person,
|
||
|
find_dir&FIND_DIR_MASK,
|
||
|
0x80, // Hard-code the fight distance.
|
||
|
0x60, // hard code the fight range
|
||
|
&stance_target,
|
||
|
&stance_position,
|
||
|
&stance_angle);
|
||
|
|
||
|
//
|
||
|
// Move to the new position.
|
||
|
//
|
||
|
|
||
|
// actually no move_thing_on_map(p_person, &stance_position);
|
||
|
|
||
|
//
|
||
|
// Turn to face the target.
|
||
|
//
|
||
|
|
||
|
if(ret)
|
||
|
{
|
||
|
/*
|
||
|
if(find_dir&FIND_DIR_DONT_TURN)
|
||
|
{
|
||
|
switch(find_dir&FIND_DIR_MASK)
|
||
|
{
|
||
|
case FIND_DIR_LEFT:
|
||
|
stance_angle+=512;
|
||
|
break;
|
||
|
case FIND_DIR_RIGHT:
|
||
|
stance_angle-=512;
|
||
|
break;
|
||
|
case FIND_DIR_BACK:
|
||
|
stance_angle+=1024;
|
||
|
break;
|
||
|
|
||
|
}
|
||
|
|
||
|
}
|
||
|
*/
|
||
|
}
|
||
|
// reset_gang_attack(p_person);
|
||
|
p_person->Draw.Tweened->Angle = stance_angle&2047;
|
||
|
if(stance_target)
|
||
|
{
|
||
|
if(p_person->Genus.Person->Target==0)
|
||
|
{
|
||
|
p_person->Genus.Person->Target=THING_NUMBER(stance_target);
|
||
|
ASSERT(TO_THING(p_person->Genus.Person->Target)->Class==CLASS_PERSON);
|
||
|
ASSERT(p_person->Genus.Person->Target !=THING_NUMBER(p_person));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if(stance_target)
|
||
|
return(THING_NUMBER(stance_target));
|
||
|
return(-ret);
|
||
|
}
|
||
|
|
||
|
SLONG turn_to_direction_and_find_target(Thing *p_person,SLONG find_dir)
|
||
|
{
|
||
|
Thing *stance_target;
|
||
|
GameCoord stance_position;
|
||
|
SLONG stance_angle;
|
||
|
SLONG ret;
|
||
|
|
||
|
ret=find_attack_stance(
|
||
|
p_person,
|
||
|
find_dir&FIND_DIR_MASK,
|
||
|
0xf0, // Hard-code the fight distance.
|
||
|
0xd0, // hard code the fight range
|
||
|
&stance_target,
|
||
|
&stance_position,
|
||
|
&stance_angle);
|
||
|
|
||
|
|
||
|
|
||
|
//
|
||
|
// Turn to face the target.
|
||
|
//
|
||
|
|
||
|
switch(find_dir&FIND_DIR_MASK)
|
||
|
{
|
||
|
case FIND_DIR_LEFT:
|
||
|
stance_angle+=512;
|
||
|
break;
|
||
|
case FIND_DIR_RIGHT:
|
||
|
stance_angle-=512;
|
||
|
break;
|
||
|
case FIND_DIR_BACK:
|
||
|
stance_angle+=1024;
|
||
|
break;
|
||
|
|
||
|
}
|
||
|
|
||
|
// reset_gang_attack(p_person);
|
||
|
p_person->Draw.Tweened->Angle = stance_angle&2047;
|
||
|
if(stance_target)
|
||
|
{
|
||
|
p_person->Genus.Person->Target=THING_NUMBER(stance_target);
|
||
|
ASSERT(TO_THING(p_person->Genus.Person->Target)->Class==CLASS_PERSON);
|
||
|
ASSERT(p_person->Genus.Person->Target !=THING_NUMBER(p_person));
|
||
|
|
||
|
return(THING_NUMBER(stance_target));
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
//
|
||
|
// no target in this direction
|
||
|
//
|
||
|
p_person->Genus.Person->Target=0;
|
||
|
return(0);
|
||
|
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
SLONG turn_to_target_and_punch(Thing *p_person)
|
||
|
{
|
||
|
SLONG ret;
|
||
|
SLONG anim;
|
||
|
//
|
||
|
// Turn...
|
||
|
//
|
||
|
|
||
|
ret=turn_to_target(
|
||
|
p_person,
|
||
|
FIND_DIR_FRONT);
|
||
|
|
||
|
//
|
||
|
// ... and punch!
|
||
|
//
|
||
|
|
||
|
anim=set_person_punch(p_person);
|
||
|
if(ret>0&& anim)
|
||
|
{
|
||
|
Thing *p_target;
|
||
|
p_target=TO_THING(ret);
|
||
|
|
||
|
if(should_i_block(p_target,p_person,anim))
|
||
|
p_target->Genus.Person->Flags|=FLAG_PERSON_REQUEST_BLOCK;
|
||
|
|
||
|
}
|
||
|
|
||
|
return(ret);
|
||
|
}
|
||
|
|
||
|
SLONG turn_to_target_and_kick(Thing *p_person)
|
||
|
{
|
||
|
SLONG ret;
|
||
|
SLONG anim;
|
||
|
Thing *p_target;
|
||
|
//
|
||
|
// Turn...
|
||
|
//
|
||
|
|
||
|
ret=turn_to_target(
|
||
|
p_person,
|
||
|
FIND_DIR_FRONT);
|
||
|
|
||
|
//
|
||
|
// ... and kick!
|
||
|
//
|
||
|
|
||
|
p_target=TO_THING(ret);
|
||
|
if(ret&&is_person_ko_and_lay_down(p_target)) //(p_target->Genus.Person->Flags&FLAG_PERSON_KO))
|
||
|
{
|
||
|
set_person_stomp(p_person);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
SLONG dist=0;
|
||
|
if(ret && (dist=dist_to_target(p_person,TO_THING(ret)))<120)
|
||
|
anim=set_person_kick_near(p_person,dist);
|
||
|
else
|
||
|
anim=set_person_kick(p_person);
|
||
|
if(ret>0 && anim)
|
||
|
{
|
||
|
Thing *p_target;
|
||
|
p_target=TO_THING(ret);
|
||
|
if(should_i_block(p_target,p_person,anim))
|
||
|
p_target->Genus.Person->Flags|=FLAG_PERSON_REQUEST_BLOCK;
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return(ret);
|
||
|
}
|
||
|
|
||
|
|
||
|
Thing *is_person_under_attack_low_level(Thing *p_person,SLONG any_state,SLONG radius)
|
||
|
{
|
||
|
SLONG i;
|
||
|
// UWORD found[8];
|
||
|
SLONG num;
|
||
|
Thing *p_found;
|
||
|
|
||
|
SLONG dx;
|
||
|
SLONG dz;
|
||
|
SLONG dist;
|
||
|
|
||
|
SLONG best_dist = INFINITY;
|
||
|
Thing *best_person = NULL;
|
||
|
|
||
|
//
|
||
|
// any_state is old!
|
||
|
//
|
||
|
|
||
|
ASSERT(any_state == FALSE);
|
||
|
|
||
|
num = THING_find_sphere(
|
||
|
p_person->WorldPos.X >> 8,
|
||
|
p_person->WorldPos.Y >> 8,
|
||
|
p_person->WorldPos.Z >> 8,
|
||
|
radius,
|
||
|
found,
|
||
|
8,
|
||
|
1 << CLASS_PERSON);
|
||
|
|
||
|
for (i = 0; i < num; i++)
|
||
|
{
|
||
|
p_found = TO_THING(found[i]);
|
||
|
|
||
|
if (p_found == p_person)
|
||
|
{
|
||
|
//
|
||
|
// Ignore yourself.
|
||
|
//
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// if (p_found->State == STATE_DEAD ||
|
||
|
// p_found->State == STATE_DYING&&!(p_found->Genus.Person->Flags&FLAG_PERSON_KO))
|
||
|
if(is_person_dead(p_found))
|
||
|
{
|
||
|
//
|
||
|
// Ignore dead or dying people, but not ko'ed
|
||
|
//
|
||
|
}
|
||
|
else
|
||
|
if (p_found->Genus.Person->Flags & FLAG_PERSON_ARRESTED)
|
||
|
{
|
||
|
//
|
||
|
// Ignore arrested people.
|
||
|
//
|
||
|
}
|
||
|
else
|
||
|
if (abs(p_found->WorldPos.Y - p_person->WorldPos.Y) < 0x4000)
|
||
|
{
|
||
|
if (p_found->Genus.Person->pcom_ai_state == PCOM_AI_STATE_KILLING ||
|
||
|
p_found->Genus.Person->pcom_ai_state == PCOM_AI_STATE_NAVTOKILL)
|
||
|
{
|
||
|
//
|
||
|
// Is he attacking me?
|
||
|
//
|
||
|
|
||
|
Thing *p_attacking = NULL;
|
||
|
|
||
|
if (p_found->Genus.Person->pcom_ai_arg)
|
||
|
{
|
||
|
p_attacking = TO_THING(p_found->Genus.Person->pcom_ai_arg);
|
||
|
}
|
||
|
|
||
|
if (p_attacking == p_person || (p_attacking && p_attacking->Genus.Person->pcom_ai == PCOM_AI_BODYGUARD && p_attacking->Genus.Person->pcom_ai_other == THING_NUMBER(p_person)))
|
||
|
{
|
||
|
//
|
||
|
// Yes! He is a candidate for being an answer.
|
||
|
//
|
||
|
|
||
|
dx = p_found->WorldPos.X - p_person->WorldPos.X >> 8;
|
||
|
dz = p_found->WorldPos.Z - p_person->WorldPos.Z >> 8;
|
||
|
|
||
|
dist = abs(dx) + abs(dz);
|
||
|
|
||
|
if (dist < best_dist)
|
||
|
{
|
||
|
best_dist = dist;
|
||
|
best_person = p_found;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return best_person;
|
||
|
}
|
||
|
|
||
|
Thing *is_person_under_attack(Thing *p_person)
|
||
|
{
|
||
|
return(is_person_under_attack_low_level(p_person,0,0x800));
|
||
|
}
|
||
|
|