diff -pur quiz-4.7.x-1.x-dev/multichoice.module quiz-4.7.x-1.x-local/multichoice.module
--- quiz-4.7.x-1.x-dev/multichoice.module	2006-11-28 00:37:50.000000000 +0100
+++ quiz-4.7.x-1.x-local/multichoice.module	2007-07-31 08:48:05.000000000 +0200
@@ -36,7 +36,9 @@ function multichoice_access($op, $node) 
  * Implementation of hook_node_info().
  */
 function multichoice_node_info() {
-  return array('multichoice' => array('name' => t('multichoice'), 'base' => 'multichoice'));
+/// prefix quiz parts (multichoice, matching, fillblank, etc.) with 'quiz -'
+/// those nodes types are then grouped, and that ease content addition in the jungle..
+  return array('multichoice' => array('name' => t('quiz - Multiple choice'), 'base' => 'multichoice'));
 }
 
 /**
@@ -74,10 +76,11 @@ function multichoice_form(&$node) {
   );
   $form['body_filter']['format'] = filter_form($node->format);
 
-  $form['multiple_answers'] = array(
-    '#type' => 'checkbox',
-    '#title' => t('Multiple answers'),
-    '#default_value' => $node->multiple_answers,
+  $form['properties'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Settings'),
+    '#collapsible' => TRUE,
+    '#collapsed' => TRUE,
   );
 
   // Determine number of answer rows to display
@@ -87,6 +90,49 @@ function multichoice_form(&$node) {
   if ($_POST['edit']['more']) {
     $node->rows += 5;
   }
+
+  $form['properties']['multiple_answers'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('Multiple answers'),
+    '#default_value' => (isset($node->multiple_answers) ? $node->multiple_answers : 0),
+  )
+
+  // prevent from automatic click without thinking about the answer:
+/// this may happen when you take the same quiz too often but do not
+/// understand the feedback (then just click the position known to be the right
+/// one, but don't know why)... sure one can simply memorise the full answer,
+/// but it may be harder, especialy when the answers look similar...
+  $form['properties']['shuffled_answers'] = array(
+    '#type' => 'checkbox',
+    '#title' => t('shuffle answers order'),
+    '#default_value' => (isset($node->shuffled_answers) ? $node->shuffled_answers : 0),
+    '#description' => t('Check that box if the answers should be displayed in a random order.'),
+  );
+
+  // ovewrite global setting: use of inline drop-down list when answers are short (often one word)
+/// question: choose the right tense for this sentense
+///           when he !l! in, we were still playing
+/// answers: 1) came
+///          2) comes
+///          3) will come
+/// a selection list is shown here at the location marked  !l! ;)
+  $form['properties']['printable_answers'] = array(
+    '#type' => 'select',
+    '#title' => t('display'),
+    '#default_value' => (isset($node->printable_answers) ? $node->printable_answers : check_plain(variable_get('quiz_default_answer_displaying', 1))),
+    '#options' => array(0 => t('web-only/compact'), 1 => t('printable/full'), ),
+    '#description' => t('Do you want all the answers visible at the same time?'),
+  );
+
+  // ovewrite global setting: use of automatic/basic scoring or advanced/personalized one
+  $form['properties']['extend_scoring'] = array(
+    '#type' => 'select',
+    '#title' => t('scoring'),
+    '#default_value' => (isset($node->extend_scoring) ? $node->extend_scoring : check_plain(variable_get('quiz_default_answer_scoring', 0))),
+    '#options' => array(0 => t('automatic {0}||{1}'), 1 => t('personalized {-3, -2, -1, 0}||{1, 2, 3, 4, 5}'), ),
+    '#description' => t('Please fill the answers and choose the correct ones, then Preview if you change the score handlling.'),
+  );
+
   $answers = $node->answers;
 
   // Display answer rows
@@ -97,11 +143,28 @@ function multichoice_form(&$node) {
     '#theme' => 'multichoice_form'
   );
   
+  $points_list = array();
+  for ($i = -3; $i < 6; $i++) {
+    $points_list[$i] = $i;
+  }
+  
   for ($i = 0; $i < $node->rows; $i++) {
-    $form['answers'][$i]['correct'] = array(
-      '#type' => 'checkbox',
-      '#default_value' => $answers[$i]['points'],
-    );
+    if($node->extend_scoring) {
+/// each answer can have different point(s), not only 0 || 1.
+/// read <http://drupal.org/node/15934> clairem's example on CMS (http://drupal.org/comment/reply/15934/26603)
+      $form['answers'][$i]['correct'] = array(
+        '#type' => 'select',
+        '#default_value' => $answers[$i]['points'],
+        '#options' => $points_list,
+        '#description' => t('>0 if correct.'), // explains/reminds how it works.
+      );
+    }
+    else {
+      $form['answers'][$i]['correct'] = array(
+        '#type' => 'checkbox',
+        '#default_value' => $answers[$i]['points'],
+      );
+    }
     $form['answers'][$i]['answer'] = array(
       '#type' => 'textarea',
       '#default_value' => $answers[$i]['answer'],
@@ -128,6 +191,7 @@ function multichoice_form(&$node) {
   $form['more'] = array(
     '#type' => 'checkbox',
     '#title' => t('I need more answers'),
+    '#description' => t("If the amount of boxes above isn't enough, check this box and click the Preview button below to add some more.") .t(' Let it checked after previewing..'),
   );
 
   return $form;
@@ -142,7 +206,9 @@ function multichoice_validate(&$node) {
   $node->teaser = 0;
   $node->promote = 0;
 
-  if (!$node->nid && empty($_POST)) return;
+  if (!$node->nid && empty($_POST)) {
+    return;
+  }
 
   // Validate body
   if (!$node->body) {
@@ -155,7 +221,7 @@ function multichoice_validate(&$node) {
 
   while(list($key, $answer) = each($node->answers)) {
 
-    if ($answer['correct']) {
+    if ($answer['correct'] > 0) {
       if ($corrects && !$node->multiple_answers) {
         form_set_error('multiple_answers', t('Single choice yet multiple correct answers are present'));
       }
@@ -181,7 +247,7 @@ function multichoice_validate(&$node) {
  * Implementation of hook_insert().
  */
 function multichoice_insert(&$node) {
-  db_query("INSERT INTO {quiz_question} (nid, properties) VALUES(%d, '%s')", $node->nid, serialize(array('multiple_answers' => $node->multiple_answers)));
+  db_query("INSERT INTO {quiz_question} (nid, properties) VALUES(%d, '%s')", $node->nid, serialize(array('multiple_answers' => $node->multiple_answers, 'shuffled_answers' => $node->shuffled_answers, 'printable_answers' => $node->printable_answers, 'extend_scoring' => $node->extend_scoring, )));
   
   while(list($key, $value) = each($node->answers)) {
     if (trim($value['answer']) != "")
@@ -194,12 +260,11 @@ function multichoice_insert(&$node) {
  * Implementation of hook_update().
  */
 function multichoice_update($node) {
-  db_query("UPDATE {quiz_question} SET properties = '%s' WHERE nid = %d", serialize(array('multiple_answers' => $node->multiple_answers)), $node->nid);
+  db_query("UPDATE {quiz_question} SET properties = '%s' WHERE nid = %d", serialize(array('multiple_answers' => $node->multiple_answers, 'shuffled_answers' => $node->shuffled_answers, 'printable_answers' => $node->printable_answers, 'extend_scoring' => $node->extend_scoring, )), $node->nid);
   
   while(list($key, $value) = each($node->answers)) {
     if ($value['aid']) {
-      $value['answer'] = trim($value['answer']);
-      if ($value['delete'] == 1 || empty($value['answer'])) {
+      if ($value['delete'] == 1 || empty(trim($value['answer']))) {
         //Delete this entry
         db_query("DELETE FROM {quiz_question_answer} WHERE aid = %d", $value['aid']);
       } else {
@@ -239,6 +304,9 @@ function multichoice_load($node) {
   
   $additions->properties = unserialize($additions->properties);
   $additions->multiple_answers = $additions->properties['multiple_answers'];
+  $additions->shuffled_answers = $additions->properties['shuffled_answers'];
+  $additions->printable_answers = $additions->properties['printable_answers'];
+  $additions->extend_scoring = $additions->properties['extend_scoring'];
   
   return $additions;
 }
@@ -283,34 +351,97 @@ function multichoice_help($section) {
  *   HTML output
  */
 function multichoice_render_question($node) {
-  // Radio buttons for single selection questions, checkboxes for multiselect
-  if ($node->multiple_answers == 0) {
-    $type = 'radios';
+  $question = check_markup($node->body, $node->format, FALSE);
+  $ok = eregi("![a-z]!", $question, $tag);
+  $prefix = '';
+  /// full interface : should always be the default.
+  if ($node->printable_answers != 0) {
+
+    // Radio buttons for single selection questions, checkboxes for multiselect
+    if (!$node->multiple_answers) {
+      $type = 'radios';
+    }
+    else {
+      $type = 'checkboxes';
+    }
+
+    if ($ok) {
+      $prefix .= str_replace($tag[0], '', $question); // remove useless tag
+    }
+    else {
+      $prefix .= $question;
+    }
+    $prefix .= '<div class="multichoice_answer_text">';
+    $suffix = '</div>'; // class="multichoice_answer_text"
+
+  }
+  /// compact interface : here having a default answer ("can't answer") is
+  /// usefull :) but this interface can be used only if choices are one-line...
+  else {
+
+    // simple select for single selection questions, select multiple for multiselect
+    $type = 'select';
+
+    if ($ok) {
+      $prefix .= substr($question, 0, strpos($question, $tag[0], 0)); // head..
+    }
+    else {
+      $prefix .= $question;
+    }
+    $prefix .= '<span class="multichoice_answer_text">';
+    $suffix = '</span>'; // class="multichoice_answer_text"
+    if ($ok) {
+      $suffix .= substr($question, strpos($question, $tag[0], 0) + 3); // tail..
+    }
+
+  }
+
+  if ($node->multiple_answers) {
+    //$desc = t('Please choose the correct answers from 1 to %maxCount', array('%maxCount' => $node->multiple_answers)); // precious hint
+    $desc = t('Please choose from 1 to %maxCount correct answer(s)', array('%maxCount' => count($node->answers)));
+
   }
   else {
-    $type = 'checkboxes';
+    $desc = t('Please choose the right aswer');
   }
 
+//// do it here ?
+  if ($node->shuffled_answers) {
+    shuffle($node->answers);
+  }
   // Get options
   $options = array();
 
+//// or do it here ?
+  if ($node->shuffled_answers) {
+    shuffle($node->answers);
+  }
+
   while(list($key, $answer) = each($node->answers)) {
     if (empty($answer['correct']) && empty($answer['answer']) && empty($answer['feedback'])) {
       unset($node->answers[$key]);
     }
     else {
-      $options[$key] = '<div class="multichoice_answer_text">'. check_markup($answer['answer'], $node->filter, FALSE) .'</div>';
+      $options[$key] = (($node->printable_answers) ? check_markup($answer['answer'], $node->filter, FALSE) : check_plain($answer['answer']));
     }
   }
   
-  $form['start'] = array('#type' => 'markup', '#value' => '<div class="multichoice_form">');
-  $form['question'] = array('#type' => 'markup', '#value' => check_markup($node->body, $node->format, FALSE));
+//// or do it here ?
+//  if ($node->shuffled_answers) {
+//    shuffle($options);
+//  }
   
   // Create form
   $form['tries'] = array(
     '#type' => $type,
-    '#options' => $options,
+    '#prefix' => $prefix,
+    '#options' => array_merge(
+       array( -1 => t(check_plain(variable_get('quiz_question_unanswer_text', 'skip this question'))), ),
+       $options),
     '#default_value' => -1,
+    '#multiple' => $node->multiple_answers,
+    '#suffix' => $suffix,
+    '#description' => $desc,
   );
   $form['submit'] = array(
     '#type' => 'submit',
@@ -329,8 +460,9 @@ function multichoice_render_question($no
  * @return
  *   Array of results, in the form of:
  *   array(
- *     'answers' => array of correct answer(s)
+ *     'answers' => array of correct answer(s) & feedback(s) & point(s)
  *     'tried' => array of selected answer(s)
+ *     'properties' => array of question propertie(s)
  *   );
  */
 function multichoice_evaluate_question($nid) {
@@ -338,20 +470,21 @@ function multichoice_evaluate_question($
   $results = array();
 
   if (isset($_POST['edit']['tries'])) {
+    $results['answers'] = $question->answers;
     if (is_array($_POST['edit']['tries'])) {
-
       // Multi-answer question
       while(list($key, $try) = each($_POST['edit']['tries'])) {
-        $results['answers'] = $question->answers;
         $results['tried'][] = $question->answers[$try]['aid'];
       }
     }
     else {
-
       // Single-answer question
-      $results['answers'] = $question->answers;
       $results['tried'][] = $question->answers[$_POST['edit']['tries']]['aid'];
     }
+/// like answers, some properties may change when a node is edited.
+/// we need to keep and restore the exact context of the quiz.
+/// and last but not least, some of those properties are needed when computing the score...
+    $results['properties'] = $question->properties;
   }
   //Unset $_POST, otherwise it tries to use the previous answers on the next page...
   unset($_POST['edit']['tries']);
@@ -361,9 +494,22 @@ function multichoice_evaluate_question($
 }
 
 //Old claculate result function
-function multichoice_calculate_result($answers, $tried) {
+function multichoice_calculate_result($answers, $tried, $properties) {  
+  $results = multichoice_calculate_results($answers, $tried, $properties);
+  return $results['succes']; 
+/// we should use only the new now :)
+/// so, it's better to change these lines in quiz.module
+///    $s = module_invoke($r['type'], 'calculate_result', $r['answer']['answers'], $r['answer']['tried']);
+///    $num_correct += $s;
+/// by the following ones:
+///    $s = module_invoke($r['type'], 'calculate_results', $r['answer']['answers'], $r['answer']['tried'], $r['answer']['properties']);
+///    $num_correct += $s['succes'];
+
+/// The following (old code slightly modified) works... 
+/// exept when there are many True answers for single-answer question type.
+/*
   while(list($key, $answer) = each($answers)) {
-    if ($answer['points'] == 1) {
+    if ($answer['points'] > 0) {
       if (($key = array_search($answer['aid'], $tried)) !== FALSE) {
         //Correct answer was selected, so lets take that out the tried list
         unset($tried[$key]);
@@ -377,15 +523,19 @@ function multichoice_calculate_result($a
   //Finally - have we got any answers left?
   //If so - they weren't knocked out as one of the correct ones so logically they must be incorrect!
   if (count($tried) > 0) return 0;
-
   
   //Finally, we can consider this correct if its passed the above tests!
   return 1;
+*/
 }
 
 //New singing and dancing one
-function multichoice_calculate_results($answers, $tried, $showPoints = FALSE, $showFeedback = FALSE) {
-  //Create results table
+/// call changed ! there's an additional $properties parameter...
+function multichoice_calculate_results($answers, $tried, $properties, $showPoints = FALSE, $showFeedback = FALSE) {
+  $winPoints = 0;
+  $maxPoints = 0;
+
+  //Create results table while computing the score
   $rows = array();
   $correctAnswers = array();
   
@@ -393,23 +543,39 @@ function multichoice_calculate_results($
     $cols = array();
     
     $cols[] = $answer['answer'];
-    if($showPoints) $cols[] = (($answer['points'] == 0) ? theme_multichoice_unselected() : theme_multichoice_selected());
+     if ($showPoints) {
+       $cols[] = (($answer['points'] <= 0) ? theme_multichoice_unselected() : theme_multichoice_selected());
+     }
     $isSelected = (array_search($answer['aid'], $tried) !== FALSE);
     $cols[] = ($isSelected ? theme_multichoice_selected() : theme_multichoice_unselected());
-    if($showFeedback) $cols[] = ($isSelected ? '<div class="quiz_answer_feedback">'. $answer['feedback'] .'</div>' : '');
+    if($showFeedback) { 
+      $cols[] = ($isSelected ? '<div class="quiz_answer_feedback">'. $answer['feedback'] .'</div>' : '');
+     }
   
     $rows[] = $cols;
-  
-  	
-  	if($answer['points'] > 0) {
-  	  $correctAnswers[] = $answer['aid'];
-  	}
-  }
 
+  //Scoring.. begin
+    if($answer['points'] > 0) {
+      $correctAnswers[] = $answer['aid'];
+      if ($properties['multiple_answers']) {
+        $maxPoints += $answer['points'];
+      }
+      else {
+        $maxPoints = max($maxPoints, $answer['points']);
+      }
+    }
+    $winPoints += $answer['points'];
+
+  //Scoring.. end
+  if ($properties['multiple_answers']) {
+    //$succes = ($maxPoints == $winPoints) ? 1 : 0 ;
+    $succes = ($correctAnswers === $tried) ? 1 : 0;
+  }
+  else {
+    $succes = (int)($winPoints > 0);
+  }
   
-  if($correctAnswers === $tried) { $score = 1; } else { $score = 0; }
-  
-  return array('score' => $score, 'resultstable' => $rows);
+  return array('score' => $succes, 'succes' => $succes, 'resultstable' => $rows, 'maxPoints' => $maxPoints, 'winPoints' => $winPoints, ); //future way
 }
 
 /**
@@ -446,10 +612,10 @@ function theme_multichoice_form($form) {
 
   // Format table header
   $header = array(
-    array('data' => t('Correct')),
-    array('data' => t('Answer'), 'style' => 'width:250px;'),
-    array('data' => t('Feedback'), 'style' => 'width:250px;'),
-    array('data' => t('Delete')),
+    array('data' => (($node->extend_scoring) ? t('Score') : t('Correct')), ),
+    array('data' => t('Answer'), 'style' => 'width:45%;', ),
+    array('data' => t('Feedback'), 'style' => 'width:45%;', ),
+    array('data' => t('Delete'), ),
   );
 
   // Format table rows
@@ -492,7 +658,8 @@ function theme_multichoice_unselected(){
  * Theme function for the multichoice form
  */
 function theme_multichoice_render_question($form){
-  $output = '';
+  $output = '<div class="multichoice_form">'; // was $form['start']
   $output .= form_render($form);
+  $output .= '</div>'; // class="multichoice_form"
   return $output;
 }
diff -pur quiz-4.7.x-1.x-dev/quiz.module quiz-4.7.x-1.x-local/quiz.module
--- quiz-4.7.x-1.x-dev/quiz.module	2006-11-28 00:32:52.000000000 +0100
+++ quiz-4.7.x-1.x-local/quiz.module	2007-07-31 09:17:08.000000000 +0200
@@ -508,6 +508,15 @@ function theme_quiz_view(&$node, $teaser
   // Format Quiz Dates
   $output .= '<h3>'. t('%quiz start/end', array('%quiz' => $quiz_name)) .'</h3>';
   if(!$node->quiz_always){
+  	// if we are previewing, make sure the dates are timestamps and not form arrays
+  	if (is_array($node->quiz_open)) {
+  	  quiz_translate_form_date(&$node, 'quiz_open');
+  	}
+  	if (is_array($node->quiz_close)) {
+  	  quiz_translate_form_date(&$node, 'quiz_close');
+  	}
+
+    // format the availability info
     $output .= "<p>" . format_date($node->quiz_open) . " &mdash; " . format_date($node->quiz_close) ."</p>";
     $output .= "<p><strong>". t('Days %quiz live for', array('%quiz' => $quiz_name)) ."</strong> " . floor((strtotime($node->close) - strtotime($node->open)) / 60 / 60 / 24) . "</p>";
 
@@ -553,10 +562,12 @@ function theme_quiz_view(&$node, $teaser
     $output .= '</div>'."\n";
   }
 
-  // Format quiz questions
-  $output .= '<h3>'. t('%quiz Questions', array('%quiz' => $quiz_name)) .'</h3>';
-  $questions = _quiz_get_questions();
-  $output .= theme('quiz_question_table', $questions);
+  // Format Quiz Questions
+  if(is_numeric(arg(1))){
+    $output .= '<h3>'. t('%quiz Questions', array('%quiz' => $quiz_name)) .'</h3>';
+    $questions = _quiz_get_questions();
+    $output .= theme('quiz_question_table', $questions);
+  }
   
   return $output;
 }
@@ -825,7 +836,7 @@ function quiz_calculate_score($rid) {
   while($r = db_fetch_array($result)) {
   	$question_count++;
     $r['answer'] = unserialize($r['answer']);
-    $s = module_invoke($r['type'], 'calculate_result', $r['answer']['answers'], $r['answer']['tried']);
+    $s = module_invoke($r['type'], 'calculate_result', $r['answer']['answers'], $r['answer']['tried'], $r['answer']['properties']);
     $num_correct += $s;
     $r['score'] = $s; // I think this is legacy
   }
@@ -1583,7 +1594,7 @@ function theme_quiz_admin($results) {
  * @param $results
  *   An array of quiz information
  * @return
- *   Themed html
+ *   Themed HTML
  */
 function theme_quiz_get_user_results($results){
     $output = '';
@@ -1702,7 +1713,7 @@ function theme_quiz_score_incorrect(){
  * @param $num_of_question
  *   The number of questions for this quiz as returned by quiz_get_number_of_questions()
  * @return
- *   Themed html
+ *   Themed HTML
  */
 function theme_quiz_progress($question_number, $num_of_question){
   
@@ -1712,7 +1723,7 @@ function theme_quiz_progress($question_n
   // Get the current question # by adding one
   $current_question = $question_number + 1;
   
-  // return html
+  // return HTML
   $output = '';
   $output .= '<div id="quiz_progress">';
   $output .= t('Question %x of %y', array('%x' => $current_question, '%y' => $num_of_question));
@@ -1730,7 +1741,7 @@ function theme_quiz_progress($question_n
  * @param $question_node
  *   The question node
  * @return
- *   Themed html
+ *   Themed HTML
  */
 function theme_quiz_take_question($quiz, $question_node){
 
@@ -1761,7 +1772,7 @@ function theme_quiz_take_question($quiz,
  * @param $summary
  *   Filtered text of the summary
  * @return
- *   Themed html
+ *   Themed HTML
  */
 function theme_quiz_take_summary($quiz, $questions, $score, $summary){
 
@@ -1794,7 +1805,7 @@ function theme_quiz_take_summary($quiz, 
  * @param $summary
  *   Filtered text of the summary
  * @return
- *   Themed html
+ *   Themed HTML
  */
 function theme_quiz_admin_summary($quiz, $questions, $score, $summary){
 
@@ -1826,7 +1837,7 @@ function theme_quiz_admin_summary($quiz,
  * @param $summary
  *   Filtered text of the summary
  * @return
- *   Themed html
+ *   Themed HTML
  */
 function theme_quiz_user_summary($quiz, $questions, $score, $summary){
 
@@ -1857,7 +1868,7 @@ function theme_quiz_user_summary($quiz, 
  * @param $showFeedback
  *   binary flag for whether to show question feedback
  * @return
- *   Themed html
+ *   Themed HTML
  */
 function theme_quiz_feedback($questions, $showPoints = TRUE, $showFeedback = FALSE){
   $rows = array();
@@ -1888,7 +1899,7 @@ function theme_quiz_feedback($questions,
     $cols[] = array('data' => $q_output, 'class'=> 'quiz_summary_qcell');
 
     // Get the score result for each question.
-    if($result['score'] == 1) {
+    if($result['score'] > 0) {
       $cols[] = array('data' => theme('quiz_score_correct'), 'class' => 'quiz_summary_qcell');
     }
     else {
