Index: manual/luatexref-t.tex
===================================================================
--- manual/luatexref-t.tex	(révision 5187)
+++ manual/luatexref-t.tex	(copie de travail)
@@ -9516,10 +9516,16 @@
 \NC pre        \NC \syntax{<node>}    \NC  pointer to the pre|-|break text\NC\NR
 \NC post       \NC \syntax{<node>}    \NC  pointer to the post|-|break text\NC\NR
 \NC replace    \NC \syntax{<node>}    \NC  pointer to the no|-|break text\NC\NR
+\NC penalty    \NC number              \NC  penalty associated with the discretionary\NC\NR
 \stoptabulate
 
 The subtype numbers~4 and~5 belong to the \quote{of-f-ice} explanation given elsewhere.
 
+The penalty field is always 0 by default. When it is 0, line breaking will use
+hyphenpenalty or exhyphenpenalty (default behaviour). When it is set to a
+non-zero value, line breaking will use the specified value. You can only change
+this field on the Lua side.
+
 A warning: never assign a node list to the pre, post or replace field
 unless you are sure its internal link structure is correct, otherwise
 an error may be result.
Index: source/texk/web2c/luatexdir/lua/lnodelib.c
===================================================================
--- source/texk/web2c/luatexdir/lua/lnodelib.c	(révision 5187)
+++ source/texk/web2c/luatexdir/lua/lnodelib.c	(copie de travail)
@@ -2853,6 +2853,8 @@
             fast_metatable_or_nil(vlink(post_break(n)));
         } else if (lua_key_eq(s, replace)) {
             fast_metatable_or_nil(vlink(no_break(n)));
+        } else if (lua_key_eq(s, penalty)) {
+            lua_pushnumber(L, disc_penalty(n));
         } else {
             lua_pushnil(L);
         }
@@ -3603,6 +3605,8 @@
             nodelib_pushdirect_or_nil(vlink(post_break(n)));
         } else if (lua_key_eq(s, replace)) {
             nodelib_pushdirect_or_nil(vlink(no_break(n)));
+        } else if (lua_key_eq(s, penalty)) {
+            lua_pushnumber(L, disc_penalty(n));
         } else {
             lua_pushnil(L);
         }
@@ -4798,6 +4802,8 @@
             set_disc_field(post_break(n), nodelib_getlist(L, 3));
         } else if (lua_key_eq(s, replace)) {
             set_disc_field(no_break(n), nodelib_getlist(L, 3));
+        } else if (lua_key_eq(s, penalty)) {
+            disc_penalty(n) = (halfword) lua_tointeger(L, 3);
         } else {
             return nodelib_cantset(L, n, s);
         }
@@ -5544,6 +5550,8 @@
             set_disc_field(post_break(n), nodelib_popdirect(3));
         } else if (lua_key_eq(s, replace)) {
             set_disc_field(no_break(n), nodelib_popdirect(3));
+        } else if (lua_key_eq(s, penalty)) {
+            disc_penalty(n) = (halfword) lua_tointeger(L, 3);
         } else {
             return nodelib_cantset(L, n, s);
         }
Index: source/texk/web2c/luatexdir/tex/linebreak.w
===================================================================
--- source/texk/web2c/luatexdir/tex/linebreak.w	(révision 5187)
+++ source/texk/web2c/luatexdir/tex/linebreak.w	(copie de travail)
@@ -1950,10 +1950,12 @@
                     int actual_penalty = hyphen_penalty;
                     if (subtype(cur_p) == automatic_disc)
                         actual_penalty = ex_hyphen_penalty;
+                     if (disc_penalty(cur_p) != 0)
+                        actual_penalty = (int) disc_penalty(cur_p);
                     s = vlink_pre_break(cur_p);
                     do_one_seven_eight(reset_disc_width);
                     if (s == null) {    /* trivial pre-break */
Index: source/texk/web2c/luatexdir/tex/texnodes.h
===================================================================
--- source/texk/web2c/luatexdir/tex/texnodes.h	(révision 5187)
+++ source/texk/web2c/luatexdir/tex/texnodes.h	(copie de travail)
@@ -151,7 +151,7 @@
    pointers are not really needed (8 instead of 10).
  */
 
-#  define disc_node_size 10
+#  define disc_node_size 11
 
 typedef enum {
     discretionary_disc = 0,
@@ -162,13 +162,14 @@
     select_disc,                /* second of a duo of syllable_discs */
 } discretionary_types;
 
-#  define pre_break_head(a)   ((a)+4)
-#  define post_break_head(a)  ((a)+6)
-#  define no_break_head(a)    ((a)+8)
+#  define pre_break_head(a)   ((a)+5)
+#  define post_break_head(a)  ((a)+7)
+#  define no_break_head(a)    ((a)+9)
 
-#  define pre_break(a)     vinfo((a)+2)
-#  define post_break(a)    vlink((a)+2)
-#  define no_break(a)      vlink((a)+3)
+#  define disc_penalty(a)    vlink((a)+2)
+#  define pre_break(a)     vinfo((a)+3)
+#  define post_break(a)    vlink((a)+3)
+#  define no_break(a)      vlink((a)+4)
 #  define tlink llink
 
 #  define vlink_pre_break(a)  vlink(pre_break_head(a))
Index: source/texk/web2c/luatexdir/tex/texnodes.w
===================================================================
--- source/texk/web2c/luatexdir/tex/texnodes.w	(révision 5187)
+++ source/texk/web2c/luatexdir/tex/texnodes.w	(copie de travail)
@@ -3082,6 +3082,8 @@
                 /* The |post_break| list of a discretionary node is indicated by a prefixed
                    `\.{\char'174}' instead of the `\..' before the |pre_break| list. */
                 tprint_esc("discretionary");
+                print_int(disc_penalty(p));
+                print_char('|');
                 if (vlink(no_break(p)) != null) {
                     tprint(" replacing ");
                     node_list_display(vlink(no_break(p)));
@@ -3479,6 +3481,7 @@
 {                               /* creates an empty |disc_node| */
     halfword p;                 /* the new node */
     p = new_node(disc_node, 0);
+    disc_penalty(p) = 0;
     return p;
 }
 
