
: foreach-char >r 1 #character >r
	begin r@ while
	r@ rover execute
	r> character# 1+ #character >r repeat
	r> drop r> drop
;

: #teamchar #teamcharid #character ;
: .dead? .health@ 1 < ;
// See if two characters are the same
: character= character# swap character# = ;

: mission-team-stack team-count dup stack swap
	for i 1- #teamchar dup .location@ LOCATION_MISSION =
		if dup .dead? not if pushs else drop then
		else drop then
	next
;

: team-stack-living team-count dup stack swap for
	i 1- #teamchar dup .dead? not if pushs else drop then
	next
;

: team-stack team-count dup stack swap for i 1- #teamchar pushs next ;

: team-stack-except ( character -- stack )
	team-count dup stack swap
	for
		over i 1- #teamchar character= not
		if
			i 1- #teamchar pushs
		then
	next nip
;

: #team-stack-shuffled team-stack shuffles swap resizes ;
: #team-stack-shuffled-except ( character number -- )
	swap team-stack-except shuffles swap resizes 
;

: foreach-team-char ( ' word -- ) team-stack swap popeach ;
: foreach-team-char-except ( character ' word -- )
	swap team-stack-except swap popeach ;

: foreach-team-char-shuffled ( ' word -- ) team-stack shuffles swap popeach ;
: foreach-mission-char-shuffled ( ' word -- ) mission-team-stack shuffles swap popeach ;


0 value pickchar
0 value checkchar
0 value checkword

internal{
: cmp2chars
//	dup character# pickchar character# 2dup #character swap #character swap .s cr  = if drop then;
	to checkchar checkword execute
	if checkchar to pickchar then
;

}

: teamrnd team-count 0= if 0 then; 0 team-count 1- grnd ;
: someone teamrnd #teamchar ;

: pick-team-char ( word -- matched-char ) ( word: [use checkchar and pickchar for comparisons] -- true/false to use test char )
	to checkword
	someone to pickchar
	internal{ ' cmp2chars } foreach-team-char-shuffled
	pickchar
;

: pick-mission-char ( word -- matched-char ) ( word: [use checkchar and pickchar for comparisons] -- true/false to use test char )
	to checkword
	someone to pickchar
	internal{ ' cmp2chars } foreach-mission-char-shuffled
	pickchar
;

: invstat CHAR_STAT_MAX swap - ;

: high 4 > ;
: low 2 < ;

// =================
// Effective stats
// =================

: sweffstat swap .effstat ;
: .morale STAT_MORALE 			sweffstat ;
: .attitude STAT_ATTITUDE 		sweffstat ; // attitude through wits mostly aren't used
: .temperament STAT_TEMPERAMENT 	sweffstat ; // but just in case
: .loyalty STAT_LOYALTY 		sweffstat ;
: .wits STAT_WITS 				sweffstat ;
: .strength STAT_STRENGTH 		sweffstat ;
: .medical STAT_MEDICAL 		sweffstat ;
: .mechanical STAT_MECHANICAL	sweffstat ;
: .shooting STAT_SHOOTING 		sweffstat ;
: .fitness STAT_FITNESS 		sweffstat ;

// =====================================
// COMBINED CHECKS (uses multiple stats)
// =====================================

// words to check if stats are revealed or not
// We got rid of this entire concept, just here for posterity

: angrystrong-revealed? 
	STAT_TEMPERAMENT over .knownstat@ not if drop false exit then
	STAT_STRENGTH swap .knownstat@ not if drop false exit then
	true
;

// words for inverting a stat, for checks where low = good

: .pessimism .attitude@ invstat ;
: .lowwits .wits@ invstat ;
: .disloyalty .loyalty@ invstat ;
: .anger .temperament@ invstat ;

// words used to check if someone passes a combined check

: paranoid?	dup .attitude@ low swap .wits@ high and ;
: oblivious? dup .attitude@ high swap .wits@ low and ;
: charming? dup .attitude@ high swap .wits@ high and ;
: grating? dup .attitude@ low swap .wits@ low and ;

// Change this to sociopath? later, more descriptive
: asshole? dup .temperament@ low swap .loyalty@ low and ;
: angrystrong? dup .temperament@ low swap .strength@ high and ;


// Probably not using the below four
: angry? dup .attitude@ low swap .temperament@ low and ;
: pumped? dup .attitude@ high swap .temperament@ low and ;
: cowardly? dup .attitude@ high swap .temperament@ high and ;
: whiny? dup .attitude@ low swap .temperament@ high and ;

// words used to see who is the highest in a combined check

: paranoidf
	dup paranoid? 0= if drop false exit then
	dup .wits@ swap .pessimism +
;

: charmingf
	dup charming? 0= if drop false exit then
	dup .wits@ swap .attitude@ +
;

: gratingf
	dup grating? 0= if drop false then;
	dup .pessimism swap .lowwits +
;

: obliviousf
	dup oblivious? 0= if drop false then;
	dup .attitude@ swap .lowwits +
;

: assholef
	dup asshole? 0= if drop false then;
	dup .anger swap .disloyalty +
;
: angrystrongf
	dup angrystrong? 0= if drop false then;
	dup .strength@ swap .anger +
;

(* TODO:
	- sensitive
	- weak
	- strong
*)

// words to compare your teammates for a check

: paranoidcheck checkchar paranoidf pickchar paranoidf > ;
: charmcheck checkchar charmingf pickchar charmingf > ;
: gratingcheck checkchar gratingf pickchar gratingf > ;
: obliviouscheck checkchar obliviousf pickchar obliviousf > ;
: aholecheck checkchar assholef pickchar assholef > ;
: ascheck checkchar angrystrongf pickchar angrystrongf > ;

// : ascheck checkchar pickchar checkchar angrystrongf pickchar angrystrongf 2dup > .s cr 2drop 2drop
//	checkchar angrystrongf pickchar angrystrongf > ;

// words used to start a check

: most-paranoid ' paranoidcheck pick-team-char ( -- false | chara true ) // variable results!
	paranoid? 0= if false then;
	pickchar true
;
: most-charming ' charmcheck pick-team-char ( -- false | chara true )
	charming? 0= if false then;
	pickchar true
;
: most-grating ' gratingcheck pick-team-char ( -- false | chara true )
	grating? 0= if false then;
	pickchar true
;
: most-oblivious ' obliviouscheck pick-team-char ( -- false | chara true )
	oblivious? 0= if false then;
	pickchar true
;

: most-ahole ' aholecheck pick-team-char ( -- false | chara true )
	asshole? 0= if false then;
	pickchar true
;

: most-angrystrong ' ascheck pick-team-char ( -- false | chara true )
	angrystrong? 0= if false then;
	pickchar true
;

: calmshot? dup .temperament@ high swap .shooting@ high and ;

: calmshotf
	dup calmshot? 0= if drop false then;
	dup .shooting@ swap .temperament@ +
;

: cscheck checkchar calmshotf pickchar calmshotf > ;

: most-calmshot ' cscheck pick-team-char ( -- false | chara true )
	calmshot? 0= if false then;
	pickchar true
;

// =============================
// SIMPLE CHECKS (uses one stat)
// =============================

: sadcheck checkchar .morale pickchar .morale < if 1 else 0 then ;
: happycheck checkchar .morale pickchar .morale > if 1 else 0 then ;

: strongcheck checkchar .strength pickchar .strength > if 1 else 0 then ;
: weakcheck checkchar .strength pickchar .strength < if 1 else 0 then ;

: fitcheck checkchar .fitness pickchar .fitness > if 1 else 0 then ;
: unfitcheck checkchar .fitness pickchar .fitness < if 1 else 0 then ;

: medicalcheck checkchar .medical pickchar .medical > ;
: mechaniccheck checkchar .mechanical pickchar .mechanical > ;
: shootcheck checkchar .shooting pickchar .shooting > if 1 else 0 then ;

: witscheck checkchar .wits@ pickchar .wits > if 1 else 0 then ;
: dumbcheck checkchar .wits@ pickchar .wits < if 1 else 0 then ;

: tempercheck checkchar .temperament pickchar .temperament < if 1 else 0 then ;
: calmcheck checkchar .temperament pickchar .temperament > if 1 else 0 then ;

: weaselcheck checkchar .loyalty pickchar .loyalty < if 1 else 0 then ;
: loyalcheck checkchar .loyalty pickchar .loyalty > if 1 else 0 then ;

: goofuscheck checkchar .attitude pickchar .attitude < if 1 else 0 then ;
: gallantcheck checkchar .attitude pickchar .attitude > if 1 else 0 then ;

// Words for finding the person with the most/least stats in a group

: smartest ' witscheck pick-team-char ;
: dumbest ' dumbcheck pick-team-char ;

: angriest ' tempercheck pick-team-char ;
: calmest ' calmcheck pick-team-char ;

: saddest ' sadcheck pick-team-char ;
: happiest ' happycheck pick-team-char ;

: weaselest ' weaselcheck pick-team-char ;
: loyalest ' loyalcheck pick-team-char ;

: goofus ' goofuscheck pick-team-char ;
: gallant ' gallantcheck pick-team-char ;

// skills

: strongest ' strongcheck pick-team-char ;
: weakest ' weakcheck pick-team-char ;

: fittest ' fitcheck pick-team-char ;
: unfittest ' unfitcheck pick-team-char ;

: medicalest ' medicalcheck pick-team-char ;
: mechanicest ' mechaniccheck pick-team-char ;
: shootest ' shootcheck pick-team-char ;

// Convenience words for making checks for 4 > or 2 < after finding

: strongest-pass strongest .strength high ;
: weakest-pass weakest .strength low ;

: mechanicest-pass mechanicest .mechanical high ;
: shootest-pass shootest .shooting high ;
: medicalest-pass medicalest .medical high ;

: fittest-pass fittest .fitness high ;
: unfittest-pass unfittest .fitness low ;

: angriest-pass angriest .temperament low ;
: calmest-pass calmest .temperament high ;

// STAT_MORALE saddest .effstat low - dependencies are really entangled
: saddest-pass saddest .morale low ;
: happiest-pass happiest .morale high ;

: weaselest-pass weaselest .loyalty low ;
: loyalest-pass loyalest .loyalty high ;

: goofus-pass goofus .attitude low ;
: gallant-pass gallant .attitude high ;

: smartest-pass smartest .wits high ;
: dumbest-pass dumbest .wits low ;

// checking and picking out a specific special character
// Below: word for picking any specialtype for this

0 value pickstnumber

: checkst? .specialtype@ pickstnumber = ;

: stpick ( specialtypeid -- char | 0 )
	to pickstnumber
	team-stack ' checkst? stack-filter
	if pops nip true else drop false then
;

: stpick-mission ( specialtypeid -- char | 0 )
	to pickstnumber
	mission-team-stack ' checkst? stack-filter
	if pops nip true else drop false then
;

// ==========================
// CONVENIENCE WORDS
// ==========================

: solo team-count-alive 2 < ;
: notsolo team-count-alive 1 > ;
: soloer 0 #teamchar ;

// ======================
// SUM CHECKS
// =======================

: sum-temperaments ( sum char -- sum ) .temperament + ;

: cool-average 0 ' sum-temperaments foreach-team-char
	dup team-count / swap
	"TOTAL TEMPERAMENT " type type " average " type dup type cr ;
	
: sum-strengths ( sum char -- sum ) .strength + ;
: sum-fitness .fitness + ;
: sum-shoots ( sum char -- sum ) .shooting + ;
: sum-medical .medical + ;
: sum-mechanic .mechanical + ;
: sum-wits .wits + ;
: sum-attitude .attitude + ; 
: sum-morale .morale + ;
: sum-loyalty .loyalty + ;

: fitness-total 0 ' sum-fitness foreach-team-char ;
: strength-total 0 ' sum-strengths foreach-team-char ;
: shooting-total 0 ' sum-shoots foreach-team-char ;
: medical-total 0 ' sum-medical foreach-team-char ;
: mechanic-total 0 ' sum-mechanic foreach-team-char ;
: wits-total 0 ' sum-wits foreach-team-char ;
: gallant-total 0 ' sum-attitude foreach-team-char ;
: calm-total 0 ' sum-temperaments foreach-team-char ;
: morale-total 0 ' sum-morale foreach-team-char ;
: loyalty-total 0 ' sum-loyalty foreach-team-char ;

: loyalty-average loyalty-total team-count / ;

// ======================
// COOL IT
// ======================

0 value cool-it
: cool-it++
//	1 ' cool-it +!
//	' cool-it ++
	1 2 rnd ' cool-it +!
;
: cool-it-7
	cool-it 3 >
	// At this amount, can get a cool-it reward on the 3rd use of it if lucky... 2, 2, use
;
: cooled-it
	0 to cool-it
;

// ==============
// EXAMPLES BELOW
// ==============

: charname .name@ type ;

// Test to find the biggest ASSHOLE
: asstest ' aholecheck pick-team-char
	asshole? 0= if "NO ASSHOLES" print then;
	pickchar charname " IS THE BIGGEST ASSHOLE." print
	($ "TEMPERAMENT: " .. pickchar .temperament@ $) print
	($ "LOYALTY: " .. pickchar .loyalty@ $) print
;
