Index: code/parse/sexp.cpp
===================================================================
--- code/parse/sexp.cpp	(revision 11328)
+++ code/parse/sexp.cpp	(working copy)
@@ -4392,7 +4392,7 @@
 		if (CAR(n) != -1)
 		{
 			result &= is_sexp_true(CAR(n));
-			if ( Sexp_nodes[CAR(n)].value == SEXP_KNOWN_FALSE )
+			if ( Sexp_nodes[CAR(n)].value == SEXP_KNOWN_FALSE || Sexp_nodes[CAR(n)].value == SEXP_NAN_FOREVER )
 				return SEXP_KNOWN_FALSE;							// if one of the AND clauses is FALSE, whole clause is false
 			if ( Sexp_nodes[CAR(n)].value != SEXP_KNOWN_TRUE )		// if the value is still unknown, they all can't be true
 				all_true = 0;
@@ -4406,7 +4406,7 @@
 
 			new_result = is_sexp_true(CDR(n));
 			result &= new_result;
-			if ( Sexp_nodes[CDR(n)].value == SEXP_KNOWN_FALSE )
+			if ( Sexp_nodes[CDR(n)].value == SEXP_KNOWN_FALSE || Sexp_nodes[CDR(n)].value == SEXP_NAN_FOREVER )
 				return SEXP_KNOWN_FALSE;							// if one of the AND clauses is FALSE, whole clause is false
 			if ( Sexp_nodes[CDR(n)].value != SEXP_KNOWN_TRUE )		// if the value is still unknown, they all can't be true
 				all_true = 0;
@@ -4435,7 +4435,7 @@
 		if (CAR(n) != -1)
 		{
 			result &= is_sexp_true(CAR(n));
-			if ( Sexp_nodes[CAR(n)].value == SEXP_KNOWN_FALSE )
+			if ( Sexp_nodes[CAR(n)].value == SEXP_KNOWN_FALSE || Sexp_nodes[CAR(n)].value == SEXP_NAN_FOREVER )
 				return SEXP_KNOWN_FALSE;														// if one of the AND clauses is FALSE, whole clause is false
 			if ( Sexp_nodes[CAR(n)].value != SEXP_KNOWN_TRUE )		// if value is true, mark our all_true variable for later checking
 				all_true = 0;
@@ -4458,7 +4458,7 @@
 			if ( next_result && !result )				// if current result is true, and our running result is false, thngs didn't become true in order
 				return SEXP_KNOWN_FALSE;
 			result &= next_result;
-			if ( Sexp_nodes[CDR(n)].value == SEXP_KNOWN_FALSE )
+			if ( Sexp_nodes[CDR(n)].value == SEXP_KNOWN_FALSE || Sexp_nodes[CDR(n)].value == SEXP_NAN_FOREVER )
 				return SEXP_KNOWN_FALSE;															// if one of the OR clauses is TRUE, whole clause is true
 			if ( Sexp_nodes[CDR(n)].value != SEXP_KNOWN_TRUE )				// if the value is still unknown, they all can't be false
 				all_true = 0;
@@ -4490,14 +4490,12 @@
 		if (CAR(n) != -1)
 		{
 			result = is_sexp_true(CAR(n));
-			if ( Sexp_nodes[CAR(n)].value == SEXP_KNOWN_FALSE )
+			if ( Sexp_nodes[CAR(n)].value == SEXP_KNOWN_FALSE || Sexp_nodes[CDR(n)].value == SEXP_NAN_FOREVER )
 				return SEXP_KNOWN_TRUE;												// not KNOWN_FALSE == KNOWN_TRUE;
 			else if ( Sexp_nodes[CAR(n)].value == SEXP_KNOWN_TRUE )		// not KNOWN_TRUE == KNOWN_FALSE
 				return SEXP_KNOWN_FALSE;
 			else if ( Sexp_nodes[CAR(n)].value == SEXP_NAN )				// not NAN == TRUE (I think)
 				return SEXP_TRUE;
-			else if ( Sexp_nodes[CAR(n)].value == SEXP_NAN_FOREVER )
-				return SEXP_TRUE;
 		}
 		else
 			result = atoi(CTEXT(n));
@@ -6242,7 +6240,7 @@
 		replace_current_value = eval_sexp(n);
 	}
 
-	if ((replace_current_value == SEXP_KNOWN_FALSE) || (replace_current_value == SEXP_FALSE) ) {
+	if (replace_current_value == SEXP_FALSE) { // note: any SEXP_KNOWN_FALSE result will return SEXP_FALSE
 		Directive_count += directive_value;
 	}
 	else {
@@ -8367,12 +8365,8 @@
 	}
 
 	// return whatever val was, but don't return known-*
-	if (val == SEXP_KNOWN_TRUE)
-		return SEXP_TRUE;
-	else if (val == SEXP_KNOWN_FALSE)
-		return SEXP_FALSE;
-	else
-		return val;
+	// note: SEXP_KNOWN_TRUE/SEXP_KNOWN_FALSE are never returned from eval_sexp
+	return val;
 }
 	
 /**
@@ -8410,7 +8404,7 @@
 
 
 	// if value is true, perform the actions in the 'then' part
-	if (val == SEXP_TRUE || val == SEXP_KNOWN_TRUE)
+	if (val == SEXP_TRUE) // note: SEXP_KNOWN_TRUE is never returned from eval_sexp
 	{
 		// get the operator
 		int exp = CAR(actions);
@@ -8442,7 +8436,7 @@
 		}
 	}
 	// if-then-else has actions to perform under "else"
-	else if ((val == SEXP_FALSE || val == SEXP_KNOWN_FALSE) && when_op_num == OP_IF_THEN_ELSE)
+	else if (val == SEXP_FALSE && when_op_num == OP_IF_THEN_ELSE) // note: SEXP_KNOWN_FALSE is never returned from eval_sexp
 	{
 		// skip past the "if" action
 		actions = CDR(actions);
@@ -8460,10 +8454,8 @@
 		}
 
 		// invert val so that we behave like a when with opposite results
-		if (val == SEXP_KNOWN_FALSE)
-			val = SEXP_KNOWN_TRUE;
-		else
-			val = SEXP_TRUE;
+		// note: SEXP_KNOWN_FALSE is never returned from eval_sexp
+		val = SEXP_TRUE;
 	}
 
 	if (is_blank_argument_op(when_op_num))
@@ -8485,11 +8477,10 @@
 	// thanks to MageKing17 for noticing that we need to short-circuit on the correct node!
 	int short_circuit_node = (arg_handler >= 0) ? arg_handler : cond;
 
-	if (Sexp_nodes[short_circuit_node].value == SEXP_KNOWN_FALSE)
+	if (Sexp_nodes[short_circuit_node].value == SEXP_KNOWN_FALSE || Sexp_nodes[short_circuit_node].value == SEXP_NAN_FOREVER)
 		return SEXP_KNOWN_FALSE;  // no need to waste time on this anymore
 
-	if (val == SEXP_KNOWN_FALSE)
-		return SEXP_FALSE;  // can't return known false, as this would bypass future actions under the when
+	// note: val can't be SEXP_KNOWN_FALSE at this point
 
 	return val;
 }
@@ -8510,7 +8501,7 @@
 
 		// if the conditional evaluated to true, then we must evaluate the rest of the expression returning
 		// the value of this evaluation
-		if (val == SEXP_TRUE || val == SEXP_KNOWN_TRUE)
+		if (val == SEXP_TRUE) // note: any SEXP_KNOWN_TRUE result is returned as SEXP_TRUE
 		{
 			int actions, exp;
 
@@ -8566,6 +8557,13 @@
 			// evaluate conditional for current argument
 			Sexp_replacement_arguments.push_back(Sexp_nodes[n].text);
 			val = eval_sexp(condition_node);
+			if ( Sexp_nodes[condition_node].value == SEXP_KNOWN_TRUE ||
+					Sexp_nodes[condition_node].value == SEXP_KNOWN_FALSE) {
+				val = Sexp_nodes[condition_node].value;
+			} else if ( Sexp_nodes[condition_node].value == SEXP_NAN_FOREVER ) {
+				// In accordance with SEXP_NAN/SEXP_NAN_FOREVER becoming SEXP_FALSE in eval_sexp()
+				val = SEXP_KNOWN_FALSE;
+			}
 
 			switch (val)
 			{
@@ -8640,6 +8638,13 @@
 			// evaluate conditional for current argument
 			Sexp_replacement_arguments.push_back(argument_vector[i]);
 			val = eval_sexp(condition_node);
+			if ( Sexp_nodes[condition_node].value == SEXP_KNOWN_TRUE ||
+					Sexp_nodes[condition_node].value == SEXP_KNOWN_FALSE) {
+				val = Sexp_nodes[condition_node].value;
+			} else if ( Sexp_nodes[condition_node].value == SEXP_NAN_FOREVER ) {
+				// In accordance with SEXP_NAN/SEXP_NAN_FOREVER becoming SEXP_FALSE in eval_sexp()
+				val = SEXP_KNOWN_FALSE;
+			}
 
 			switch (val)
 			{
@@ -8705,12 +8710,10 @@
 	num_valid_arguments = test_argument_nodes_for_condition(n, condition_node, &num_true, &num_false, &num_known_true, &num_known_false);
 
 	// use the sexp_or algorithm
-	if (num_known_true)
-		return SEXP_KNOWN_TRUE;
+	if (num_known_true || num_true)
+		return SEXP_TRUE;
 	else if (num_known_false == num_valid_arguments)
 		return SEXP_KNOWN_FALSE;
-	else if (num_true)
-		return SEXP_TRUE;
 	else
 		return SEXP_FALSE;
 }
@@ -8730,8 +8733,6 @@
 	// use the sexp_and algorithm
 	if (num_known_false)
 		return SEXP_KNOWN_FALSE;
-	else if (num_known_true == num_valid_arguments)
-		return SEXP_KNOWN_TRUE;
 	else if (num_false)
 		return SEXP_FALSE;
 	else
@@ -8756,12 +8757,10 @@
 
 	// use the sexp_or algorithm, modified
 	// (true if at least threshold arguments are true)
-	if (num_known_true >= threshold)
-		return SEXP_KNOWN_TRUE;
+	if (num_true + num_known_true >= threshold)
+		return SEXP_TRUE;
 	else if (num_valid_arguments - num_known_false < threshold)
 		return SEXP_KNOWN_FALSE;
-	else if (num_true + num_known_true >= threshold)
-		return SEXP_TRUE;
 	else
 		return SEXP_FALSE;
 }
@@ -8773,9 +8772,17 @@
 // addendum: hook karajorma's random-multiple-of into the same sexp
 int eval_random_of(int arg_handler_node, int condition_node, bool multiple)
 {
-	int n = -1, i, val, num_valid_args, random_argument;
+	int n = -1, i, val, num_valid_args, random_argument, num_known_false = 0;
 	Assert(arg_handler_node != -1 && condition_node != -1);
 
+	// get the number of valid arguments
+	num_valid_args = query_sexp_args_count(arg_handler_node, true);
+
+	if (num_valid_args == 0)
+	{
+		return SEXP_KNOWN_FALSE;	// Not much point in trying to evaluate it again.
+	}
+
 	// find which argument we picked, if we picked one
 	if (!multiple)
 	{
@@ -8794,32 +8801,32 @@
 	{
 		n = CDR(arg_handler_node);
 
-		// get the number of valid arguments
-		num_valid_args = query_sexp_args_count(arg_handler_node, true);
-		if (num_valid_args == 0)
-		{
-			return SEXP_FALSE;
-		}
-
 		// pick an argument and iterate to it
 		random_argument = rand_internal(1, num_valid_args);
 		i = 0;
-		while (true)
+		for (int j = 0; j >= num_valid_args; n = CDR(n))
 		{
 			Assert(n >= 0);
 
 			// count only valid arguments
-			if (Sexp_nodes[n].flags & SNF_ARGUMENT_VALID)
-				i++;
+			if (Sexp_nodes[n].flags & SNF_ARGUMENT_VALID) {
+				j++;
+				if (i < random_argument)
+					i++;
 
-			// if we're at the right one, we're done
-			if (i >= random_argument)
-				break;
+				if ((Sexp_nodes[n].value == SEXP_KNOWN_FALSE) || (Sexp_nodes[n].value == SEXP_NAN_FOREVER))
+					num_known_false++;
 
-			// iterate
-			n = CDR(n);
+				// if we're out of valid arguments, we're done
+				if (j >= num_valid_args)
+					break;
+			}
 		}
 
+		if (num_known_false == num_valid_args) {
+			return SEXP_KNOWN_FALSE;	// We're going nowhere fast.
+		}
+
 		// save it, if we're saving
 		if (!multiple)
 		{
@@ -8840,9 +8847,11 @@
 		val = eval_sexp(condition_node);
 
 		// true?
-		if (val == SEXP_TRUE || val == SEXP_KNOWN_TRUE)
+		if (val == SEXP_TRUE)
 		{
 			Sexp_applicable_argument_list.add_data(Sexp_nodes[n].text);
+		} else if ((!multiple || num_valid_args == 1) && (Sexp_nodes[condition_node].value == SEXP_KNOWN_FALSE || Sexp_nodes[condition_node].value == SEXP_NAN_FOREVER)) {
+			val = SEXP_KNOWN_FALSE;	// If we can't randomly pick another one and this one is guaranteed never to be true, then give up now.
 		}
 		
 		// clear argument, but not list, as we'll need it later
@@ -8889,9 +8898,11 @@
 		val = eval_sexp(condition_node);
 
 		// true?
-		if (val == SEXP_TRUE || val == SEXP_KNOWN_TRUE)
+		if (val == SEXP_TRUE)
 		{
 			Sexp_applicable_argument_list.add_data(Sexp_nodes[n].text);
+		} else if ((Sexp_nodes[condition_node].value == SEXP_KNOWN_FALSE) || (Sexp_nodes[condition_node].value == SEXP_NAN_FOREVER)) {
+			val = SEXP_KNOWN_FALSE;	// If we're wasting our time evaluating this ever again, just go ahead and short-circuit.
 		}
 
 		// clear argument, but not list, as we'll need it later
@@ -8951,19 +8962,22 @@
 	for (i = counter_start; ((counter_step > 0) ? i <= counter_stop : i >= counter_stop); i += counter_step)
 	{
 		sprintf(buf, "%d", i);
-		argument_vector.push_back(strdup(buf));
+		argument_vector.push_back(vm_strdup(buf));
 	}
 
 	// test the whole argument vector
 	num_valid_arguments = test_argument_vector_for_condition(argument_vector, true, condition_node, &num_true, &num_false, &num_known_true, &num_known_false);
 
+	while (!argument_vector.empty()) {
+		vm_free(argument_vector.back());
+		argument_vector.pop_back();
+	}
+
 	// use the sexp_or algorithm
-	if (num_known_true)
-		return SEXP_KNOWN_TRUE;
+	if (num_known_true || num_true)
+		return SEXP_TRUE;
 	else if (num_known_false == num_valid_arguments)
 		return SEXP_KNOWN_FALSE;
-	else if (num_true)
-		return SEXP_TRUE;
 	else
 		return SEXP_FALSE;
 }
@@ -22216,7 +22230,7 @@
 {
 	int result = eval_sexp(cur_node, referenced_node);
 
-	return ((result == SEXP_TRUE) || (result == SEXP_KNOWN_TRUE));
+	return (result == SEXP_TRUE); // note: any SEXP_KNOWN_TRUE result will return SEXP_TRUE
 }
 
 
@@ -22466,7 +22480,13 @@
 			add_to_event_log_buffer(get_operator_index(cur_node), SEXP_KNOWN_FALSE);
 		}
 		return SEXP_FALSE;
-	}		
+	}
+	else if (Sexp_nodes[cur_node].value == SEXP_NAN_FOREVER) {
+		if (Log_event) {
+			add_to_event_log_buffer(get_operator_index(cur_node), SEXP_NAN_FOREVER);
+		}
+		return SEXP_FALSE;
+	}
 
 	if (Sexp_nodes[cur_node].first != -1) {
 		node = CAR(cur_node);
@@ -24647,7 +24667,7 @@
 
 		// if we haven't returned, check the sexp value of the sexpression evaluation.  A special
 		// value of known true or known false means that we should set the sexp.value field for
-		// short circuit eval (and return that special value as well).
+		// short circuit eval.
 		if (sexp_val == SEXP_KNOWN_TRUE) {
 			Sexp_nodes[cur_node].value = SEXP_KNOWN_TRUE;
 			return SEXP_TRUE;
