tRevamped fighting code; the protagonist is penalised (cops may intervene and attack, probability of successful flight is halved) - vaccinewars - be a doctor and try to vaccinate the world (HTM) git clone git://src.adamsgaard.dk/vaccinewars (DIR) Log (DIR) Files (DIR) Refs (DIR) README (DIR) LICENSE --- (DIR) commit 43ce87336da1f84fc60b983b800e7590003cd8f0 (DIR) parent 93331be9af913e2a14cdf0c878fef43c2cd549af (HTM) Author: Ben Webb <ben@salilab.org> Date: Thu, 5 Apr 2001 01:13:05 +0000 Revamped fighting code; the protagonist is penalised (cops may intervene and attack, probability of successful flight is halved) Diffstat: M TODO | 2 +- M src/dopewars.c | 11 ++--------- M src/dopewars.h | 12 +++++++----- M src/message.c | 6 +++--- M src/serverside.c | 159 +++++++++++++++++++++---------- M src/serverside.h | 2 -- 6 files changed, 120 insertions(+), 72 deletions(-) --- (DIR) diff --git a/TODO b/TODO t@@ -1,4 +1,4 @@ -- Tidy up display of high scores in GUI client +DONE - Tidy up display of high scores in GUI client - Revamp player-player fighting; use same system for fighting the cops and for fighting other players (perhaps the cops can intervene in fights); add SWAT teams, soldiers, etc. as dealers get more and more guns (DIR) diff --git a/src/dopewars.c b/src/dopewars.c t@@ -545,7 +545,7 @@ GSList *AddPlayer(int fd,Player *NewPlayer,GSList *First) { NewPlayer->Bank=0; NewPlayer->Bitches.Carried=8; NewPlayer->CopIndex=0; - NewPlayer->Health=MaxHealth(NewPlayer,NewPlayer->Bitches.Carried); + NewPlayer->Health=100; NewPlayer->CoatSize=100; NewPlayer->Flags=0; NewPlayer->ReadBuf.Data=NewPlayer->WriteBuf.Data=NULL; t@@ -554,6 +554,7 @@ GSList *AddPlayer(int fd,Player *NewPlayer,GSList *First) { InitAbilities(NewPlayer); if (Server) NewPlayer->fd=fd; NewPlayer->FightArray=NULL; + NewPlayer->Attacking=NULL; return g_slist_append(First,(gpointer)NewPlayer); } t@@ -602,14 +603,6 @@ void CopyPlayer(Player *Dest,Player *Src) { Dest->Flags=Src->Flags; } -int MaxHealth(Player *Play,int NumBitches) { - if (IsCop(Play)) - return (Cop[Play->CopIndex-1].Health+ - NumBitches*Cop[Play->CopIndex-1].DeputyHealth); - else - return (80+NumBitches*20); -} - gboolean IsCop(Player *Play) { return (Play->CopIndex>0); } (DIR) diff --git a/src/dopewars.h b/src/dopewars.h t@@ -70,6 +70,8 @@ typedef long price_t; typedef long long price_t; #endif +/* "Abilities" are protocol extensions, which are negotiated between the + client and server at connect-time. */ #define A_PLAYERID 0 /* Use numeric IDs rather than player names in network messages */ #define A_DRUGVALUE 1 /* Server keeps track of purchase price of drugs */ t@@ -77,9 +79,9 @@ typedef long long price_t; #define A_TSTRING 3 /* We understand the %Txx (tstring) notation */ #define A_NUM 4 typedef struct ABILITIES { - gboolean Local[A_NUM]; - gboolean Remote[A_NUM]; - gboolean Shared[A_NUM]; + gboolean Local[A_NUM]; /* Abilities that we have */ + gboolean Remote[A_NUM]; /* Those that the other end of the connection has */ + gboolean Shared[A_NUM]; /* Abilites shared by us and the remote host */ } Abilities; struct NAMES { t@@ -292,7 +294,8 @@ struct PLAYER_T { Player *OnBehalfOf; ConnBuf ReadBuf,WriteBuf; Abilities Abil; - GPtrArray *FightArray; + GPtrArray *FightArray; /* If non-NULL, a list of players in a fight */ + Player *Attacking; /* The player that this player is attacking */ gint CopIndex; /* if >0, then this player is a cop, described by Cop[CopIndex-1] if ==0, this is a normal player that has killed no cops t@@ -347,7 +350,6 @@ int CountPlayers(GSList *First); GSList *AddPlayer(int fd,Player *NewPlayer,GSList *First); void UpdatePlayer(Player *Play); void CopyPlayer(Player *Dest,Player *Src); -int MaxHealth(Player *Play,int NumBitches); void ClearInventory(Inventory *Guns,Inventory *Drugs); int IsCarryingRandom(Player *Play,int amount); void ChangeSpaceForInventory(Inventory *Guns,Inventory *Drugs, (DIR) diff --git a/src/message.c b/src/message.c t@@ -1170,13 +1170,13 @@ void FormatFightMessage(Player *To,GString *text,Player *Attacker, ArmPercent<80 ? _("heavily armed") : _("armed to the teeth"); if (DefendName[0]) { - if (IsCop(Defender)) { + if (IsCop(Defender) && !AttackName[0]) { if (Bitches==0) { - dpg_string_sprintfa(text,_("%s, %s, is chasing you, man!"), + dpg_string_sprintfa(text,_("%s - %s - is chasing you, man!"), DefendName,Armament); } else { dpg_string_sprintfa(text, - _("%s and %d %tde, %s, are chasing you, man!"), + _("%s and %d %tde - %s - are chasing you, man!"), DefendName,Bitches,BitchesName,Armament); } } else { (DIR) diff --git a/src/serverside.c b/src/serverside.c t@@ -1187,6 +1187,10 @@ void CopsAttackPlayer(Player *Play) { gint CopIndex,NumDeputy,GunIndex; CopIndex=1-Play->CopIndex; + if (CopIndex<0) { + g_warning(_("Cops cannot attack other cops!")); + return; + } if (CopIndex > NumCop) CopIndex=NumCop; Cops=g_new(Player,1); FirstServer=AddPlayer(0,Cops,FirstServer); t@@ -1200,7 +1204,7 @@ void CopsAttackPlayer(Player *Play) { GunIndex=Cop[CopIndex-1].GunIndex; if (GunIndex>=NumGun) GunIndex=NumGun-1; Cops->Guns[GunIndex].Carried=NumDeputy+1; - Cops->Health=MaxHealth(Cops,NumDeputy); + Cops->Health=100; Play->EventNum++; AttackPlayer(Cops,Play); t@@ -1217,41 +1221,37 @@ void AttackPlayer(Player *Play,Player *Attacked) { if (Play->FightArray && Attacked->FightArray) { if (Play->FightArray==Attacked->FightArray) { - g_warning("Players are already in a fight!"); + g_warning(_("Players are already in a fight!")); } else { - g_warning("Players are already in separate fights!"); + g_warning(_("Players are already in separate fights!")); } return; } - if (Play->FightArray) { - FightArray=Play->FightArray; - AddPlayerToFight(Attacked,FightArray,Play,TRUE); - } else if (Attacked->FightArray) { - FightArray=Attacked->FightArray; - AddPlayerToFight(Play,FightArray,Attacked,TRUE); + if (!Play->FightArray && !Attacked->FightArray) { + FightArray = g_ptr_array_new(); } else { - FightArray=g_ptr_array_new(); - AddPlayerToFight(Attacked,FightArray,Play,TRUE); - AddPlayerToFight(Play,FightArray,Attacked,FALSE); + FightArray = Play->FightArray ? Play->FightArray : Attacked->FightArray; + } + + if (!Play->FightArray) { + Play->ResyncNum=Play->EventNum; + g_ptr_array_add(FightArray,Play); + } + if (!Attacked->FightArray) { + Attacked->ResyncNum=Attacked->EventNum; + g_ptr_array_add(FightArray,Attacked); } + Play->FightArray=Attacked->FightArray=FightArray; + Play->EventNum=Attacked->EventNum=E_FIGHT; + + Play->Attacking = Attacked; + + SendFightMessage(Attacked,Play,0,F_ARRIVED,FALSE,TRUE,NULL); Fire(Play); } -void AddPlayerToFight(Player *NewPlay,GPtrArray *Fight,Player *Other, - gboolean Inform) { -/* Adds the player "NewPlay" to the fight "Fight", and informs any */ -/* players already in the fight of the new player's arrival, if */ -/* "Inform" is TRUE. "Other" is a player already in the fight. */ - NewPlay->FightArray=Fight; - NewPlay->ResyncNum=NewPlay->EventNum; - NewPlay->EventNum=E_FIGHT; - - g_ptr_array_add(Fight,NewPlay); - if (Inform) SendFightMessage(NewPlay,Other,0,F_ARRIVED,FALSE,TRUE,NULL); -} - gboolean IsOpponent(Player *Play,Player *Other) { /* Returns TRUE if player "Other" is not allied with player "Play" */ return TRUE; t@@ -1273,10 +1273,9 @@ void HandleDamage(Player *Defend,Player *Attack,int Damage, AddInventory(Drugs,Defend->Drugs,NumDrug); Defend->Health=0; } else if (Defend->Bitches.Carried>0 && - Defend->Health-Damage <= - MaxHealth(Defend,Defend->Bitches.Carried-1)) { + Defend->Health<=Damage) { LoseBitch(Defend,Guns,Drugs); - Defend->Health=MaxHealth(Defend,Defend->Bitches.Carried); + Defend->Health=100; *BitchesKilled=1; } else { Defend->Health-=Damage; t@@ -1352,7 +1351,11 @@ void RunFromCombat(Player *Play) { if (!Play || !Play->FightArray) return; - EscapeProb=50; + EscapeProb=60; + +/* Penalise players that are attacking others */ + if (Play->Attacking) EscapeProb/=2; + RandNum=brandom(0,100); if (RandNum<EscapeProb) { t@@ -1366,7 +1369,7 @@ void RunFromCombat(Player *Play) { WithdrawFromCombat(Play); Play->EventNum=Play->ResyncNum; SendEvent(Play); } else { - SendFightMessage(Play,NULL,0,F_MSG,FALSE,FALSE,"You can't get away!"); + SendFightMessage(Play,NULL,0,F_MSG,FALSE,FALSE,_("You can't get away!")); AllowNextShooter(Play); DoReturnFire(Play); } t@@ -1400,10 +1403,56 @@ void CheckForKilledPlayers(Player *Play) { g_ptr_array_free(KilledPlayers,FALSE); } +static void CheckCopsIntervene(Player *Play) { +/* If "Play" is attacking someone, and no cops are currently present, */ +/* then have the cops intervene (with a probability dependent on the */ +/* current location's PolicePresence) */ + gint ArrayInd; + Player *Defend; + + if (!Play || !Play->FightArray) return; /* Sanity check */ + + if (!Play->Attacking) return; /* Cops don't attack "innocent victims" ;) */ + + if (brandom(0,100) > Location[(int)Play->IsAt].PolicePresence) { + return; /* The cops shouldn't _always_ attack (unless P.P. == 100) */ + } + + for (ArrayInd=0;Play->FightArray && ArrayInd<Play->FightArray->len; + ArrayInd++) { + Defend=(Player *)g_ptr_array_index(Play->FightArray,ArrayInd); + if (IsCop(Defend)) return; /* We don't want _more_ cops! */ + } + + /* OK - let 'em have it... */ + CopsAttackPlayer(Play); +} + +static Player *GetFireTarget(Player *Play) { +/* Returns a suitable player (or cop) for "Play" to fire at. If "Play" */ +/* is attacking a designated target already, return that, otherwise */ +/* return the first valid opponent in the player's FightArray. */ + Player *Defend; + gint ArrayInd; + + if (Play->Attacking && g_slist_find(FirstServer,(gpointer)Play->Attacking)) { + return Play->Attacking; + } else { + Play->Attacking=NULL; + for (ArrayInd=0;ArrayInd<Play->FightArray->len;ArrayInd++) { + Defend=(Player *)g_ptr_array_index(Play->FightArray,ArrayInd); + if (Defend && Defend!=Play && IsOpponent(Play,Defend)) { + return Defend; + } + } + } + return NULL; +} + void Fire(Player *Play) { -/* Fires all weapons of player "Play" at all opponents, and resets */ -/* the fight timeout (the reload time) */ - int Damage,ArrayInd,i,j; +/* Fires all weapons of player "Play" at an opponent, and resets */ +/* the fight timeout (the reload time) */ + int Damage,i,j; int AttackRating,DefendRating; int BitchesKilled; gboolean Loot; t@@ -1416,29 +1465,28 @@ void Fire(Player *Play) { AllowNextShooter(Play); if (FightTimeout) SetFightTimeout(Play); - for (ArrayInd=0;ArrayInd<Play->FightArray->len;ArrayInd++) { - Defend=(Player *)g_ptr_array_index(Play->FightArray,ArrayInd); - - if (Defend && Defend!=Play && IsOpponent(Play,Defend)) { - Damage=0; BitchesKilled=0; Loot=FALSE; - if (TotalGunsCarried(Play)>0) { - GetFightRatings(Play,Defend,&AttackRating,&DefendRating); - if (brandom(0,AttackRating)>brandom(0,DefendRating)) { - FightPoint=F_HIT; - for (i=0;i<NumGun;i++) for (j=0;j<Play->Guns[i].Carried;j++) { - Damage+=brandom(0,Gun[i].Damage); - } - if (Damage==0) Damage=1; - HandleDamage(Defend,Play,Damage,&BitchesKilled,&Loot); - } else FightPoint=F_MISS; - } else FightPoint=F_STAND; - SendFightMessage(Play,Defend,BitchesKilled,FightPoint,Loot,TRUE,NULL); - } + Defend = GetFireTarget(Play); + if (Defend) { + Damage=0; BitchesKilled=0; Loot=FALSE; + if (TotalGunsCarried(Play)>0) { + GetFightRatings(Play,Defend,&AttackRating,&DefendRating); + if (brandom(0,AttackRating)>brandom(0,DefendRating)) { + FightPoint=F_HIT; + for (i=0;i<NumGun;i++) for (j=0;j<Play->Guns[i].Carried;j++) { + Damage+=brandom(0,Gun[i].Damage); + } + if (Damage==0) Damage=1; + HandleDamage(Defend,Play,Damage,&BitchesKilled,&Loot); + } else FightPoint=F_MISS; + } else FightPoint=F_STAND; + SendFightMessage(Play,Defend,BitchesKilled,FightPoint,Loot,TRUE,NULL); } CheckForKilledPlayers(Play); /* Careful, as we might have killed Player "Play" */ if (g_slist_find(FirstServer,(gpointer)Play)) DoReturnFire(Play); + + if (g_slist_find(FirstServer,(gpointer)Play)) CheckCopsIntervene(Play); } gboolean CanPlayerFire(Player *Play) { t@@ -1501,6 +1549,7 @@ void WithdrawFromCombat(Player *Play) { int i,j; gboolean FightDone; Player *Attack,*Defend; + GSList *list; if (!Play->FightArray) return; t@@ -1516,6 +1565,11 @@ void WithdrawFromCombat(Player *Play) { if (!FightDone) break; } + for (list=FirstServer;list;list=g_slist_next(list)) { + Attack=(Player *)list->data; + if (Attack->Attacking==Play) Attack->Attacking=NULL; + } + SendFightLeave(Play,FightDone); g_ptr_array_remove(Play->FightArray,(gpointer)Play); t@@ -1535,6 +1589,7 @@ void WithdrawFromCombat(Player *Play) { g_ptr_array_free(Play->FightArray,TRUE); } Play->FightArray=NULL; + Play->Attacking=NULL; } int RandomOffer(Player *To) { t@@ -1818,7 +1873,7 @@ void HandleAnswer(Player *From,Player *To,char *answer) { case E_DOCTOR: if (From->Cash >= From->DocPrice) { From->Cash -= From->DocPrice; - From->Health=MaxHealth(From,From->Bitches.Carried); + From->Health=100; SendPlayerData(From); } /* FinishFightWithHardass(From,NULL);*/ (DIR) diff --git a/src/serverside.h b/src/serverside.h t@@ -69,8 +69,6 @@ gboolean CheckHighScoreFile(); int HighScoreRead(struct HISCORE *MultiScore,struct HISCORE *AntiqueScore); void CopsAttackPlayer(Player *Play); void AttackPlayer(Player *Play,Player *Attacked); -void AddPlayerToFight(Player *NewPlay,GPtrArray *Fight,Player *Other, - gboolean Inform); gboolean IsOpponent(Player *Play,Player *Other); void Fire(Player *Play); void WithdrawFromCombat(Player *Play);